blob: ae0dc88aee619ba0e378436a49b74268506eda6e [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP attributes management routines.
2 Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "linklist.h"
24#include "prefix.h"
25#include "memory.h"
26#include "vector.h"
27#include "vty.h"
28#include "stream.h"
29#include "log.h"
30#include "hash.h"
31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_attr.h"
34#include "bgpd/bgp_route.h"
35#include "bgpd/bgp_aspath.h"
36#include "bgpd/bgp_community.h"
37#include "bgpd/bgp_debug.h"
38#include "bgpd/bgp_packet.h"
39#include "bgpd/bgp_ecommunity.h"
40
41/* Attribute strings for logging. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -070042static const struct message attr_str [] =
paul718e3742002-12-13 20:15:29 +000043{
44 { BGP_ATTR_ORIGIN, "ORIGIN" },
45 { BGP_ATTR_AS_PATH, "AS_PATH" },
46 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
47 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
48 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
49 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
50 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
51 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
52 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
53 { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" },
54 { BGP_ATTR_DPA, "DPA" },
55 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
56 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
57 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
58 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000059 { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
60 { BGP_ATTR_AS4_PATH, "AS4_PATH" },
61 { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
62 { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
paul718e3742002-12-13 20:15:29 +000063};
Stephen Hemminger9bddac42009-05-15 09:59:51 -070064static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000065
Stephen Hemminger9bddac42009-05-15 09:59:51 -070066static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000067
paul94f2b392005-06-28 12:44:16 +000068static void *
Paul Jakma923de652007-04-29 18:25:17 +000069cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000070{
Paul Jakma923de652007-04-29 18:25:17 +000071 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000072 struct cluster_list *cluster;
73
74 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
75 cluster->length = val->length;
76
77 if (cluster->length)
78 {
79 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
80 memcpy (cluster->list, val->list, val->length);
81 }
82 else
83 cluster->list = NULL;
84
85 cluster->refcnt = 0;
86
87 return cluster;
88}
89
90/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000091static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000092cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000093{
94 struct cluster_list tmp;
95 struct cluster_list *cluster;
96
97 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000098 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +000099
100 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
101 cluster->refcnt++;
102 return cluster;
103}
104
105int
106cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
107{
108 int i;
109
110 for (i = 0; i < cluster->length / 4; i++)
111 if (cluster->list[i].s_addr == originator.s_addr)
112 return 1;
113 return 0;
114}
115
paul94f2b392005-06-28 12:44:16 +0000116static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000117cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000118{
Paul Jakma923de652007-04-29 18:25:17 +0000119 struct cluster_list * cluster = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +0000120 unsigned int key = 0;
121 int length;
122 caddr_t pnt;
123
124 length = cluster->length;
125 pnt = (caddr_t) cluster->list;
126
127 while (length)
128 key += pnt[--length];
129
130 return key;
131}
132
paul94f2b392005-06-28 12:44:16 +0000133static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100134cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000135{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100136 const struct cluster_list * cluster1 = p1;
137 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000138
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100139 return (cluster1->length == cluster2->length &&
140 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000141}
142
paul94f2b392005-06-28 12:44:16 +0000143static void
paul718e3742002-12-13 20:15:29 +0000144cluster_free (struct cluster_list *cluster)
145{
146 if (cluster->list)
147 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
148 XFREE (MTYPE_CLUSTER, cluster);
149}
150
Chris Caputo228da422009-07-18 05:44:03 +0000151#if 0
paul94f2b392005-06-28 12:44:16 +0000152static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000153cluster_dup (struct cluster_list *cluster)
154{
155 struct cluster_list *new;
156
Stephen Hemminger393deb92008-08-18 14:13:29 -0700157 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000158 new->length = cluster->length;
159
160 if (cluster->length)
161 {
162 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
163 memcpy (new->list, cluster->list, cluster->length);
164 }
165 else
166 new->list = NULL;
167
168 return new;
169}
Chris Caputo228da422009-07-18 05:44:03 +0000170#endif
paul718e3742002-12-13 20:15:29 +0000171
paul94f2b392005-06-28 12:44:16 +0000172static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000173cluster_intern (struct cluster_list *cluster)
174{
175 struct cluster_list *find;
176
177 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
178 find->refcnt++;
179
180 return find;
181}
182
183void
184cluster_unintern (struct cluster_list *cluster)
185{
186 struct cluster_list *ret;
187
188 if (cluster->refcnt)
189 cluster->refcnt--;
190
191 if (cluster->refcnt == 0)
192 {
193 ret = hash_release (cluster_hash, cluster);
194 cluster_free (cluster);
195 }
196}
197
paul94f2b392005-06-28 12:44:16 +0000198static void
199cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000200{
201 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
202}
Chris Caputo228da422009-07-18 05:44:03 +0000203
204static void
205cluster_finish (void)
206{
207 hash_free (cluster_hash);
208 cluster_hash = NULL;
209}
paul718e3742002-12-13 20:15:29 +0000210
211/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700212static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000213
paul94f2b392005-06-28 12:44:16 +0000214static void
paul718e3742002-12-13 20:15:29 +0000215transit_free (struct transit *transit)
216{
217 if (transit->val)
218 XFREE (MTYPE_TRANSIT_VAL, transit->val);
219 XFREE (MTYPE_TRANSIT, transit);
220}
221
Paul Jakma923de652007-04-29 18:25:17 +0000222
paul94f2b392005-06-28 12:44:16 +0000223static void *
Paul Jakma923de652007-04-29 18:25:17 +0000224transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000225{
226 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000227 return p;
paul718e3742002-12-13 20:15:29 +0000228}
229
paul94f2b392005-06-28 12:44:16 +0000230static struct transit *
paul718e3742002-12-13 20:15:29 +0000231transit_intern (struct transit *transit)
232{
233 struct transit *find;
234
235 find = hash_get (transit_hash, transit, transit_hash_alloc);
236 if (find != transit)
237 transit_free (transit);
238 find->refcnt++;
239
240 return find;
241}
242
243void
244transit_unintern (struct transit *transit)
245{
246 struct transit *ret;
247
248 if (transit->refcnt)
249 transit->refcnt--;
250
251 if (transit->refcnt == 0)
252 {
253 ret = hash_release (transit_hash, transit);
254 transit_free (transit);
255 }
256}
257
paul94f2b392005-06-28 12:44:16 +0000258static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000259transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000260{
Paul Jakma923de652007-04-29 18:25:17 +0000261 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000262 unsigned int key = 0;
263 int length;
264 caddr_t pnt;
265
266 length = transit->length;
267 pnt = (caddr_t) transit->val;
268
269 while (length)
270 key += pnt[--length];
271
272 return key;
273}
274
paul94f2b392005-06-28 12:44:16 +0000275static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100276transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000277{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100278 const struct transit * transit1 = p1;
279 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000280
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100281 return (transit1->length == transit2->length &&
282 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000283}
284
paul94f2b392005-06-28 12:44:16 +0000285static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800286transit_init (void)
paul718e3742002-12-13 20:15:29 +0000287{
288 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
289}
Chris Caputo228da422009-07-18 05:44:03 +0000290
291static void
292transit_finish (void)
293{
294 hash_free (transit_hash);
295 transit_hash = NULL;
296}
paul718e3742002-12-13 20:15:29 +0000297
298/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700299static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000300
Paul Jakmafb982c22007-05-04 20:15:47 +0000301static struct attr_extra *
302bgp_attr_extra_new (void)
303{
304 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
305}
306
307void
308bgp_attr_extra_free (struct attr *attr)
309{
310 if (attr->extra)
311 {
312 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
313 attr->extra = NULL;
314 }
315}
316
317struct attr_extra *
318bgp_attr_extra_get (struct attr *attr)
319{
320 if (!attr->extra)
321 attr->extra = bgp_attr_extra_new();
322 return attr->extra;
323}
324
325/* Shallow copy of an attribute
326 * Though, not so shallow that it doesn't copy the contents
327 * of the attr_extra pointed to by 'extra'
328 */
329void
330bgp_attr_dup (struct attr *new, struct attr *orig)
331{
332 *new = *orig;
333 if (orig->extra)
334 {
335 new->extra = bgp_attr_extra_new();
336 *new->extra = *orig->extra;
337 }
338}
339
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000340unsigned long int
341attr_count (void)
342{
343 return attrhash->count;
344}
345
346unsigned long int
347attr_unknown_count (void)
348{
349 return transit_hash->count;
350}
351
paul718e3742002-12-13 20:15:29 +0000352unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000353attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000354{
Paul Jakma923de652007-04-29 18:25:17 +0000355 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000356 unsigned int key = 0;
357
358 key += attr->origin;
359 key += attr->nexthop.s_addr;
360 key += attr->med;
361 key += attr->local_pref;
Paul Jakma41367172007-08-06 15:24:51 +0000362 if (attr->pathlimit.as)
363 {
364 key += attr->pathlimit.ttl;
365 key += attr->pathlimit.as;
366 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000367
368 if (attr->extra)
369 {
370 key += attr->extra->aggregator_as;
371 key += attr->extra->aggregator_addr.s_addr;
372 key += attr->extra->weight;
373 key += attr->extra->mp_nexthop_global_in.s_addr;
374 }
375
paul718e3742002-12-13 20:15:29 +0000376 if (attr->aspath)
377 key += aspath_key_make (attr->aspath);
378 if (attr->community)
379 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000380
381 if (attr->extra)
382 {
383 if (attr->extra->ecommunity)
384 key += ecommunity_hash_make (attr->extra->ecommunity);
385 if (attr->extra->cluster)
386 key += cluster_hash_key_make (attr->extra->cluster);
387 if (attr->extra->transit)
388 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000389
390#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000391 {
392 int i;
393
394 key += attr->extra->mp_nexthop_len;
395 for (i = 0; i < 16; i++)
396 key += attr->extra->mp_nexthop_global.s6_addr[i];
397 for (i = 0; i < 16; i++)
398 key += attr->extra->mp_nexthop_local.s6_addr[i];
399 }
paul718e3742002-12-13 20:15:29 +0000400#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000401 }
paul718e3742002-12-13 20:15:29 +0000402
403 return key;
404}
405
406int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100407attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000408{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100409 const struct attr * attr1 = p1;
410 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000411
paul718e3742002-12-13 20:15:29 +0000412 if (attr1->flag == attr2->flag
413 && attr1->origin == attr2->origin
414 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000415 && attr1->aspath == attr2->aspath
416 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000417 && attr1->med == attr2->med
Paul Jakma41367172007-08-06 15:24:51 +0000418 && attr1->local_pref == attr2->local_pref
419 && attr1->pathlimit.ttl == attr2->pathlimit.ttl
420 && attr1->pathlimit.as == attr2->pathlimit.as)
Paul Jakmafb982c22007-05-04 20:15:47 +0000421 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100422 const struct attr_extra *ae1 = attr1->extra;
423 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000424
425 if (ae1 && ae2
426 && ae1->aggregator_as == ae2->aggregator_as
427 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
428 && ae1->weight == ae2->weight
429#ifdef HAVE_IPV6
430 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
431 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
432 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
433#endif /* HAVE_IPV6 */
434 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
435 && ae1->ecommunity == ae2->ecommunity
436 && ae1->cluster == ae2->cluster
437 && ae1->transit == ae2->transit)
438 return 1;
439 else if (ae1 || ae2)
440 return 0;
441 /* neither attribute has extra attributes, so they're same */
442 return 1;
443 }
paul718e3742002-12-13 20:15:29 +0000444 else
445 return 0;
446}
447
paul94f2b392005-06-28 12:44:16 +0000448static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100449attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000450{
451 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
452}
453
paul94f2b392005-06-28 12:44:16 +0000454static void
Chris Caputo228da422009-07-18 05:44:03 +0000455attrhash_finish (void)
456{
457 hash_free (attrhash);
458 attrhash = NULL;
459}
460
461static void
paul718e3742002-12-13 20:15:29 +0000462attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
463{
464 struct attr *attr = backet->data;
465
466 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
467 inet_ntoa (attr->nexthop), VTY_NEWLINE);
468}
469
470void
471attr_show_all (struct vty *vty)
472{
473 hash_iterate (attrhash,
474 (void (*)(struct hash_backet *, void *))
475 attr_show_all_iterator,
476 vty);
477}
478
paul94f2b392005-06-28 12:44:16 +0000479static void *
Paul Jakma923de652007-04-29 18:25:17 +0000480bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000481{
Paul Jakma923de652007-04-29 18:25:17 +0000482 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000483 struct attr *attr;
484
485 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
486 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000487 if (val->extra)
488 {
489 attr->extra = bgp_attr_extra_new ();
490 *attr->extra = *val->extra;
491 }
paul718e3742002-12-13 20:15:29 +0000492 attr->refcnt = 0;
493 return attr;
494}
495
496/* Internet argument attribute. */
497struct attr *
498bgp_attr_intern (struct attr *attr)
499{
500 struct attr *find;
501
502 /* Intern referenced strucutre. */
503 if (attr->aspath)
504 {
505 if (! attr->aspath->refcnt)
506 attr->aspath = aspath_intern (attr->aspath);
507 else
508 attr->aspath->refcnt++;
509 }
510 if (attr->community)
511 {
512 if (! attr->community->refcnt)
513 attr->community = community_intern (attr->community);
514 else
515 attr->community->refcnt++;
516 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000517 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000518 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000519 struct attr_extra *attre = attr->extra;
520
521 if (attre->ecommunity)
522 {
523 if (! attre->ecommunity->refcnt)
524 attre->ecommunity = ecommunity_intern (attre->ecommunity);
525 else
526 attre->ecommunity->refcnt++;
527 }
528 if (attre->cluster)
529 {
530 if (! attre->cluster->refcnt)
531 attre->cluster = cluster_intern (attre->cluster);
532 else
533 attre->cluster->refcnt++;
534 }
535 if (attre->transit)
536 {
537 if (! attre->transit->refcnt)
538 attre->transit = transit_intern (attre->transit);
539 else
540 attre->transit->refcnt++;
541 }
paul718e3742002-12-13 20:15:29 +0000542 }
543
544 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
545 find->refcnt++;
546
547 return find;
548}
549
Paul Jakma03e214c2007-04-29 18:31:07 +0000550
paul718e3742002-12-13 20:15:29 +0000551/* Make network statement's attribute. */
552struct attr *
553bgp_attr_default_set (struct attr *attr, u_char origin)
554{
555 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000556 bgp_attr_extra_get (attr);
557
paul718e3742002-12-13 20:15:29 +0000558 attr->origin = origin;
559 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
560 attr->aspath = aspath_empty ();
561 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000562 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000563 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
564#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000565 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000566#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000567
paul718e3742002-12-13 20:15:29 +0000568 return attr;
569}
570
Paul Jakma03e214c2007-04-29 18:31:07 +0000571
paul718e3742002-12-13 20:15:29 +0000572/* Make network statement's attribute. */
573struct attr *
574bgp_attr_default_intern (u_char origin)
575{
576 struct attr attr;
577 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000578 struct attr_extra *attre;
579
580 memset (&attr, 0, sizeof (struct attr));
581 attre = bgp_attr_extra_get (&attr);
582
Paul Jakma03e214c2007-04-29 18:31:07 +0000583 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000584
585 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000586 bgp_attr_extra_free (&attr);
587
paul718e3742002-12-13 20:15:29 +0000588 aspath_unintern (new->aspath);
589 return new;
590}
591
592struct attr *
593bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
594 struct aspath *aspath,
595 struct community *community, int as_set)
596{
597 struct attr attr;
598 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000599 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000600
601 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000602 attre = bgp_attr_extra_get (&attr);
603
paul718e3742002-12-13 20:15:29 +0000604 /* Origin attribute. */
605 attr.origin = origin;
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
607
608 /* AS path attribute. */
609 if (aspath)
610 attr.aspath = aspath_intern (aspath);
611 else
612 attr.aspath = aspath_empty ();
613 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
614
615 /* Next hop attribute. */
616 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
617
618 if (community)
619 {
620 attr.community = community;
621 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
622 }
623
Paul Jakmafb982c22007-05-04 20:15:47 +0000624 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000625#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000626 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000627#endif
628 if (! as_set)
629 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
630 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
631 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000632 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000633 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000634 attre->aggregator_as = bgp->as;
635 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000636
637 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000638 bgp_attr_extra_free (&attr);
639
paul718e3742002-12-13 20:15:29 +0000640 aspath_unintern (new->aspath);
641 return new;
642}
643
644/* Free bgp attribute and aspath. */
645void
646bgp_attr_unintern (struct attr *attr)
647{
648 struct attr *ret;
649 struct aspath *aspath;
650 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000651 struct ecommunity *ecommunity = NULL;
652 struct cluster_list *cluster = NULL;
653 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000654
655 /* Decrement attribute reference. */
656 attr->refcnt--;
657 aspath = attr->aspath;
658 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000659 if (attr->extra)
660 {
661 ecommunity = attr->extra->ecommunity;
662 cluster = attr->extra->cluster;
663 transit = attr->extra->transit;
664 }
paul718e3742002-12-13 20:15:29 +0000665
666 /* If reference becomes zero then free attribute object. */
667 if (attr->refcnt == 0)
668 {
669 ret = hash_release (attrhash, attr);
670 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000671 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000672 XFREE (MTYPE_ATTR, attr);
673 }
674
675 /* aspath refcount shoud be decrement. */
676 if (aspath)
677 aspath_unintern (aspath);
678 if (community)
679 community_unintern (community);
680 if (ecommunity)
681 ecommunity_unintern (ecommunity);
682 if (cluster)
683 cluster_unintern (cluster);
684 if (transit)
685 transit_unintern (transit);
686}
687
688void
689bgp_attr_flush (struct attr *attr)
690{
691 if (attr->aspath && ! attr->aspath->refcnt)
692 aspath_free (attr->aspath);
693 if (attr->community && ! attr->community->refcnt)
694 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000695 if (attr->extra)
696 {
697 struct attr_extra *attre = attr->extra;
698 if (attre->ecommunity && ! attre->ecommunity->refcnt)
699 ecommunity_free (attre->ecommunity);
700 if (attre->cluster && ! attre->cluster->refcnt)
701 cluster_free (attre->cluster);
702 if (attre->transit && ! attre->transit->refcnt)
703 transit_free (attre->transit);
704 }
paul718e3742002-12-13 20:15:29 +0000705}
706
Paul Jakma41367172007-08-06 15:24:51 +0000707/* Parse AS_PATHLIMIT attribute in an UPDATE */
708static int
709bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
710 struct attr *attr, u_char flag, u_char *startp)
711{
712 bgp_size_t total;
713
714 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
715
Paul Jakmaa15cfd12008-06-01 14:29:03 +0000716 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
717 || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
Paul Jakma41367172007-08-06 15:24:51 +0000718 {
719 zlog (peer->log, LOG_ERR,
720 "AS-Pathlimit attribute flag isn't transitive %d", flag);
721 bgp_notify_send_with_data (peer,
722 BGP_NOTIFY_UPDATE_ERR,
723 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
724 startp, total);
725 return -1;
726 }
727
728 if (length != 5)
729 {
730 zlog (peer->log, LOG_ERR,
731 "AS-Pathlimit length, %u, is not 5", length);
732 bgp_notify_send_with_data (peer,
733 BGP_NOTIFY_UPDATE_ERR,
734 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
735 startp, total);
736 return -1;
737 }
738
739 attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer));
740 attr->pathlimit.as = stream_getl (BGP_INPUT(peer));
741 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
742 return 0;
743}
paul718e3742002-12-13 20:15:29 +0000744/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000745static int
paul718e3742002-12-13 20:15:29 +0000746bgp_attr_origin (struct peer *peer, bgp_size_t length,
747 struct attr *attr, u_char flag, u_char *startp)
748{
749 bgp_size_t total;
750
751 /* total is entire attribute length include Attribute Flags (1),
752 Attribute Type code (1) and Attribute length (1 or 2). */
753 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
754
755 /* If any recognized attribute has Attribute Flags that conflict
756 with the Attribute Type Code, then the Error Subcode is set to
757 Attribute Flags Error. The Data field contains the erroneous
758 attribute (type, length and value). */
759 if (flag != BGP_ATTR_FLAG_TRANS)
760 {
761 zlog (peer->log, LOG_ERR,
762 "Origin attribute flag isn't transitive %d", flag);
763 bgp_notify_send_with_data (peer,
764 BGP_NOTIFY_UPDATE_ERR,
765 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
766 startp, total);
767 return -1;
768 }
769
770 /* If any recognized attribute has Attribute Length that conflicts
771 with the expected length (based on the attribute type code), then
772 the Error Subcode is set to Attribute Length Error. The Data
773 field contains the erroneous attribute (type, length and
774 value). */
775 if (length != 1)
776 {
777 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
778 length);
779 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
780 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
781 startp, total);
782 return -1;
783 }
784
785 /* Fetch origin attribute. */
786 attr->origin = stream_getc (BGP_INPUT (peer));
787
788 /* If the ORIGIN attribute has an undefined value, then the Error
789 Subcode is set to Invalid Origin Attribute. The Data field
790 contains the unrecognized attribute (type, length and value). */
791 if ((attr->origin != BGP_ORIGIN_IGP)
792 && (attr->origin != BGP_ORIGIN_EGP)
793 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
794 {
795 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
796 attr->origin);
797
798 bgp_notify_send_with_data (peer,
799 BGP_NOTIFY_UPDATE_ERR,
800 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
801 startp, total);
802 return -1;
803 }
804
805 /* Set oring attribute flag. */
806 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
807
808 return 0;
809}
Chris Hallcddb8112010-08-09 22:31:37 +0400810/* Parse AS path information. This function is wrapper of aspath_parse.
811 *
812 * Parses AS_PATH or AS4_PATH.
813 *
814 * Returns: if valid: address of struct aspath in the hash of known aspaths,
815 * with reference count incremented.
816 * else: NULL
817 *
818 * NB: empty AS path (length == 0) is valid. The returned struct aspath will
819 * have segments == NULL and str == zero length string (unique).
820 */
821static struct aspath *
paul718e3742002-12-13 20:15:29 +0000822bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Chris Hallcddb8112010-08-09 22:31:37 +0400823 struct attr *attr, u_char flag, u_char *startp, int as4_path)
paul718e3742002-12-13 20:15:29 +0000824{
Chris Hallcddb8112010-08-09 22:31:37 +0400825 u_char require ;
826 struct aspath *asp ;
paul718e3742002-12-13 20:15:29 +0000827
Chris Hallcddb8112010-08-09 22:31:37 +0400828 /* Check the attribute flags */
829 require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
830 : BGP_ATTR_FLAG_TRANS ;
paul718e3742002-12-13 20:15:29 +0000831
Chris Hallcddb8112010-08-09 22:31:37 +0400832 if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require)
paul718e3742002-12-13 20:15:29 +0000833 {
Chris Hallcddb8112010-08-09 22:31:37 +0400834 const char* path_type ;
835 bgp_size_t total;
836
837 path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
838
839 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000840 zlog (peer->log, LOG_ERR,
Chris Hallcddb8112010-08-09 22:31:37 +0400841 "%s attribute flag isn't transitive %d", path_type, flag) ;
842
843 if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL))
844 zlog (peer->log, LOG_ERR,
845 "%s attribute flag must %sbe optional %d", path_type,
846 (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ;
847
848 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
849
paul718e3742002-12-13 20:15:29 +0000850 bgp_notify_send_with_data (peer,
851 BGP_NOTIFY_UPDATE_ERR,
852 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
853 startp, total);
paul718e3742002-12-13 20:15:29 +0000854
Chris Hallcddb8112010-08-09 22:31:37 +0400855 return NULL ;
856 } ;
857
858 /* Parse the AS_PATH/AS4_PATH body.
859 *
860 * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN
861 * AS4_PATH 4Byte ASN
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000862 */
Chris Hallcddb8112010-08-09 22:31:37 +0400863 asp = aspath_parse (peer->ibuf, length,
864 as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000865
Chris Hallcddb8112010-08-09 22:31:37 +0400866 if (asp != NULL)
867 {
868 attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
869 : BGP_ATTR_AS_PATH) ;
870 }
871 else
paul718e3742002-12-13 20:15:29 +0000872 {
873 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
Chris Hallcddb8112010-08-09 22:31:37 +0400874
875 /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */
paul718e3742002-12-13 20:15:29 +0000876 bgp_notify_send (peer,
877 BGP_NOTIFY_UPDATE_ERR,
878 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Chris Hallcddb8112010-08-09 22:31:37 +0400879 } ;
paul718e3742002-12-13 20:15:29 +0000880
Chris Hallcddb8112010-08-09 22:31:37 +0400881 return asp ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000882}
883
884static int bgp_attr_aspath_check( struct peer *peer,
885 struct attr *attr)
886{
887 /* These checks were part of bgp_attr_aspath, but with
888 * as4 we should to check aspath things when
889 * aspath synthesizing with as4_path has already taken place.
890 * Otherwise we check ASPATH and use the synthesized thing, and that is
891 * not right.
892 * So do the checks later, i.e. here
893 */
894 struct bgp *bgp = peer->bgp;
895 struct aspath *aspath;
896
paul718e3742002-12-13 20:15:29 +0000897 bgp = peer->bgp;
898
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300899 /* Confederation sanity check. */
900 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
901 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
902 {
903 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
904 bgp_notify_send (peer,
905 BGP_NOTIFY_UPDATE_ERR,
906 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
907 return -1;
908 }
909
paul718e3742002-12-13 20:15:29 +0000910 /* First AS check for EBGP. */
911 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
912 {
913 if (peer_sort (peer) == BGP_PEER_EBGP
914 && ! aspath_firstas_check (attr->aspath, peer->as))
915 {
916 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400917 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000918 bgp_notify_send (peer,
919 BGP_NOTIFY_UPDATE_ERR,
920 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
921 return -1;
922 }
923 }
924
925 /* local-as prepend */
926 if (peer->change_local_as &&
927 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
928 {
929 aspath = aspath_dup (attr->aspath);
930 aspath = aspath_add_seq (aspath, peer->change_local_as);
931 aspath_unintern (attr->aspath);
932 attr->aspath = aspath_intern (aspath);
933 }
934
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000935 return 0;
936
937}
938
paul718e3742002-12-13 20:15:29 +0000939/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000940static int
paul718e3742002-12-13 20:15:29 +0000941bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
942 struct attr *attr, u_char flag, u_char *startp)
943{
944 bgp_size_t total;
945
946 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
947
948 /* Flag check. */
949 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
950 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
951 {
952 zlog (peer->log, LOG_ERR,
953 "Origin attribute flag isn't transitive %d", flag);
954 bgp_notify_send_with_data (peer,
955 BGP_NOTIFY_UPDATE_ERR,
956 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
957 startp, total);
958 return -1;
959 }
960
961 /* Check nexthop attribute length. */
962 if (length != 4)
963 {
964 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
965 length);
966
967 bgp_notify_send_with_data (peer,
968 BGP_NOTIFY_UPDATE_ERR,
969 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
970 startp, total);
971 return -1;
972 }
973
974 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
975 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
976
977 return 0;
978}
979
980/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000981static int
paul718e3742002-12-13 20:15:29 +0000982bgp_attr_med (struct peer *peer, bgp_size_t length,
983 struct attr *attr, u_char flag, u_char *startp)
984{
985 bgp_size_t total;
986
987 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
988
989 /* Length check. */
990 if (length != 4)
991 {
992 zlog (peer->log, LOG_ERR,
993 "MED attribute length isn't four [%d]", length);
994
995 bgp_notify_send_with_data (peer,
996 BGP_NOTIFY_UPDATE_ERR,
997 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
998 startp, total);
999 return -1;
1000 }
1001
1002 attr->med = stream_getl (peer->ibuf);
1003
1004 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1005
1006 return 0;
1007}
1008
1009/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +00001010static int
paul718e3742002-12-13 20:15:29 +00001011bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
1012 struct attr *attr, u_char flag)
1013{
1014 /* If it is contained in an UPDATE message that is received from an
1015 external peer, then this attribute MUST be ignored by the
1016 receiving speaker. */
1017 if (peer_sort (peer) == BGP_PEER_EBGP)
1018 {
paul9985f832005-02-09 15:51:56 +00001019 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001020 return 0;
1021 }
1022
1023 if (length == 4)
1024 attr->local_pref = stream_getl (peer->ibuf);
1025 else
1026 attr->local_pref = 0;
1027
1028 /* Set atomic aggregate flag. */
1029 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1030
1031 return 0;
1032}
1033
1034/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001035static int
paul718e3742002-12-13 20:15:29 +00001036bgp_attr_atomic (struct peer *peer, bgp_size_t length,
1037 struct attr *attr, u_char flag)
1038{
1039 if (length != 0)
1040 {
1041 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1042
1043 bgp_notify_send (peer,
1044 BGP_NOTIFY_UPDATE_ERR,
1045 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1046 return -1;
1047 }
1048
1049 /* Set atomic aggregate flag. */
1050 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1051
1052 return 0;
1053}
1054
1055/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001056static int
paul718e3742002-12-13 20:15:29 +00001057bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1058 struct attr *attr, u_char flag)
1059{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001060 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001061 struct attr_extra *attre = bgp_attr_extra_get (attr);
1062
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001063 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1064 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1065 wantedlen = 8;
1066
1067 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001068 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001069 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001070
1071 bgp_notify_send (peer,
1072 BGP_NOTIFY_UPDATE_ERR,
1073 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1074 return -1;
1075 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001076
1077 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1078 attre->aggregator_as = stream_getl (peer->ibuf);
1079 else
1080 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001081 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001082
1083 /* Set atomic aggregate flag. */
1084 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1085
1086 return 0;
1087}
1088
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001089/* New Aggregator attribute */
1090static int
1091bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1092 struct attr *attr, as_t *as4_aggregator_as,
1093 struct in_addr *as4_aggregator_addr)
1094{
1095 if (length != 8)
1096 {
1097 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1098
1099 bgp_notify_send (peer,
1100 BGP_NOTIFY_UPDATE_ERR,
1101 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1102 return -1;
1103 }
1104 *as4_aggregator_as = stream_getl (peer->ibuf);
1105 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1106
1107 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1108
1109 return 0;
1110}
1111
1112/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1113 */
1114static int
1115bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1116 struct aspath *as4_path, as_t as4_aggregator,
1117 struct in_addr *as4_aggregator_addr)
1118{
1119 int ignore_as4_path = 0;
1120 struct aspath *newpath;
1121 struct attr_extra *attre = attr->extra;
1122
1123 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1124 {
1125 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1126 * if given.
1127 * It is worth a warning though, because the peer really
1128 * should not send them
1129 */
1130 if (BGP_DEBUG(as4, AS4))
1131 {
1132 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1133 zlog_debug ("[AS4] %s %s AS4_PATH",
1134 peer->host, "AS4 capable peer, yet it sent");
1135
1136 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1137 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1138 peer->host, "AS4 capable peer, yet it sent");
1139 }
1140
1141 return 0;
1142 }
1143
1144 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1145 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1146 {
1147 /* Hu? This is not supposed to happen at all!
1148 * got as4_path and no aspath,
1149 * This should already
1150 * have been handled by 'well known attributes missing'
1151 * But... yeah, paranoia
1152 * Take this as a "malformed attribute"
1153 */
1154 zlog (peer->log, LOG_ERR,
1155 "%s BGP not AS4 capable peer sent AS4_PATH but"
1156 " no AS_PATH, cant do anything here", peer->host);
1157 bgp_notify_send (peer,
1158 BGP_NOTIFY_UPDATE_ERR,
1159 BGP_NOTIFY_UPDATE_MAL_ATTR);
1160 return -1;
1161 }
1162
1163 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1164 * because that may override AS4_PATH
1165 */
1166 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1167 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001168 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1169 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001170 assert (attre);
1171
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001172 /* received both.
1173 * if the as_number in aggregator is not AS_TRANS,
1174 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1175 * and the Aggregator shall be taken as
1176 * info on the aggregating node, and the AS_PATH
1177 * shall be taken as the AS_PATH
1178 * otherwise
1179 * the Aggregator shall be ignored and the
1180 * AS4_AGGREGATOR shall be taken as the
1181 * Aggregating node and the AS_PATH is to be
1182 * constructed "as in all other cases"
1183 */
1184 if ( attre->aggregator_as != BGP_AS_TRANS )
1185 {
1186 /* ignore */
1187 if ( BGP_DEBUG(as4, AS4))
1188 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1189 " send AGGREGATOR != AS_TRANS and"
1190 " AS4_AGGREGATOR, so ignore"
1191 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1192 ignore_as4_path = 1;
1193 }
1194 else
1195 {
1196 /* "New_aggregator shall be taken as aggregator" */
1197 attre->aggregator_as = as4_aggregator;
1198 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1199 }
1200 }
1201 else
1202 {
1203 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1204 * That is bogus - but reading the conditions
1205 * we have to handle AS4_AGGREGATOR as if it were
1206 * AGGREGATOR in that case
1207 */
1208 if ( BGP_DEBUG(as4, AS4))
1209 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1210 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1211 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001212 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001213 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1214 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1215 }
1216 }
1217
1218 /* need to reconcile NEW_AS_PATH and AS_PATH */
1219 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1220 {
1221 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1222 aspath_unintern (attr->aspath);
1223 attr->aspath = aspath_intern (newpath);
1224 }
1225 return 0;
1226}
1227
paul718e3742002-12-13 20:15:29 +00001228/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001229static int
paul718e3742002-12-13 20:15:29 +00001230bgp_attr_community (struct peer *peer, bgp_size_t length,
1231 struct attr *attr, u_char flag)
1232{
1233 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001234 {
1235 attr->community = NULL;
1236 return 0;
1237 }
paul718e3742002-12-13 20:15:29 +00001238 else
1239 {
paul5228ad22004-06-04 17:58:18 +00001240 attr->community =
1241 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001242 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001243 }
1244
1245 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1246
1247 return 0;
1248}
1249
1250/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001251static int
paul718e3742002-12-13 20:15:29 +00001252bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1253 struct attr *attr, u_char flag)
1254{
1255 if (length != 4)
1256 {
1257 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1258
1259 bgp_notify_send (peer,
1260 BGP_NOTIFY_UPDATE_ERR,
1261 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1262 return -1;
1263 }
1264
Paul Jakmafb982c22007-05-04 20:15:47 +00001265 (bgp_attr_extra_get (attr))->originator_id.s_addr
1266 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001267
1268 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1269
1270 return 0;
1271}
1272
1273/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001274static int
paul718e3742002-12-13 20:15:29 +00001275bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1276 struct attr *attr, u_char flag)
1277{
1278 /* Check length. */
1279 if (length % 4)
1280 {
1281 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1282
1283 bgp_notify_send (peer,
1284 BGP_NOTIFY_UPDATE_ERR,
1285 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1286 return -1;
1287 }
1288
Paul Jakmafb982c22007-05-04 20:15:47 +00001289 (bgp_attr_extra_get (attr))->cluster
1290 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001291
paul9985f832005-02-09 15:51:56 +00001292 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001293
1294 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1295
1296 return 0;
1297}
1298
1299/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001300int
paul718e3742002-12-13 20:15:29 +00001301bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1302 struct bgp_nlri *mp_update)
1303{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001304 afi_t afi;
1305 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001306 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001307 size_t start;
paul718e3742002-12-13 20:15:29 +00001308 int ret;
1309 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001310 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001311
1312 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001313 s = BGP_INPUT(peer);
1314 start = stream_get_getp(s);
1315
1316 /* safe to read statically sized header? */
1317#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001318#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001319 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001320 {
1321 zlog_info ("%s: %s sent invalid length, %lu",
1322 __func__, peer->host, (unsigned long)length);
1323 return -1;
1324 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001325
paul718e3742002-12-13 20:15:29 +00001326 /* Load AFI, SAFI. */
1327 afi = stream_getw (s);
1328 safi = stream_getc (s);
1329
1330 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001331 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001332
Paul Jakma03292802008-06-07 20:37:10 +00001333 if (LEN_LEFT < attre->mp_nexthop_len)
1334 {
1335 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1336 __func__, peer->host, attre->mp_nexthop_len);
1337 return -1;
1338 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001339
paul718e3742002-12-13 20:15:29 +00001340 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001341 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001342 {
1343 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001344 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001345 /* Probably needed for RFC 2283 */
1346 if (attr->nexthop.s_addr == 0)
1347 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001348 break;
1349 case 12:
1350 {
1351 u_int32_t rd_high;
1352 u_int32_t rd_low;
1353
1354 rd_high = stream_getl (s);
1355 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001356 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001357 }
1358 break;
1359#ifdef HAVE_IPV6
1360 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001361 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001362 break;
1363 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001364 stream_get (&attre->mp_nexthop_global, s, 16);
1365 stream_get (&attre->mp_nexthop_local, s, 16);
1366 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001367 {
1368 char buf1[INET6_ADDRSTRLEN];
1369 char buf2[INET6_ADDRSTRLEN];
1370
1371 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001372 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 +00001373 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001374 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001375 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001376 buf2, INET6_ADDRSTRLEN));
1377
Paul Jakmafb982c22007-05-04 20:15:47 +00001378 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001379 }
1380 break;
1381#endif /* HAVE_IPV6 */
1382 default:
Paul Jakma03292802008-06-07 20:37:10 +00001383 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1384 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001385 return -1;
paul718e3742002-12-13 20:15:29 +00001386 }
1387
Paul Jakma03292802008-06-07 20:37:10 +00001388 if (!LEN_LEFT)
1389 {
1390 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1391 __func__, peer->host);
1392 return -1;
1393 }
paul718e3742002-12-13 20:15:29 +00001394
Paul Jakma6e4ab122007-04-10 19:36:48 +00001395 {
1396 u_char val;
1397 if ((val = stream_getc (s)))
1398 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1399 peer->host, val);
1400 }
1401
1402 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001403 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001404 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001405 {
1406 zlog_info ("%s: (%s) Failed to read NLRI",
1407 __func__, peer->host);
1408 return -1;
1409 }
paul718e3742002-12-13 20:15:29 +00001410
1411 if (safi != BGP_SAFI_VPNV4)
1412 {
1413 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001414 if (ret < 0)
1415 {
1416 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1417 __func__, peer->host);
1418 return -1;
1419 }
paul718e3742002-12-13 20:15:29 +00001420 }
1421
1422 mp_update->afi = afi;
1423 mp_update->safi = safi;
1424 mp_update->nlri = stream_pnt (s);
1425 mp_update->length = nlri_len;
1426
paul9985f832005-02-09 15:51:56 +00001427 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001428
1429 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001430#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001431}
1432
1433/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001434int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001435bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001436 struct bgp_nlri *mp_withdraw)
1437{
1438 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001439 afi_t afi;
1440 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001441 u_int16_t withdraw_len;
1442 int ret;
1443
1444 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001445
1446#define BGP_MP_UNREACH_MIN_SIZE 3
1447 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1448 return -1;
1449
paul718e3742002-12-13 20:15:29 +00001450 afi = stream_getw (s);
1451 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001452
1453 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001454
1455 if (safi != BGP_SAFI_VPNV4)
1456 {
1457 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1458 if (ret < 0)
1459 return -1;
1460 }
1461
1462 mp_withdraw->afi = afi;
1463 mp_withdraw->safi = safi;
1464 mp_withdraw->nlri = stream_pnt (s);
1465 mp_withdraw->length = withdraw_len;
1466
paul9985f832005-02-09 15:51:56 +00001467 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001468
1469 return 0;
1470}
1471
1472/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001473static int
paul718e3742002-12-13 20:15:29 +00001474bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1475 struct attr *attr, u_char flag)
1476{
1477 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001478 {
1479 if (attr->extra)
1480 attr->extra->ecommunity = NULL;
1481 }
paul718e3742002-12-13 20:15:29 +00001482 else
1483 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001484 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001485 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001486 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001487 }
1488 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1489
1490 return 0;
1491}
1492
1493/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001494static int
paul718e3742002-12-13 20:15:29 +00001495bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1496 u_char type, bgp_size_t length, u_char *startp)
1497{
1498 bgp_size_t total;
1499 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001500 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001501
hassof4184462005-02-01 20:13:16 +00001502 if (BGP_DEBUG (normal, NORMAL))
1503 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1504 peer->host, type, length);
1505
paul718e3742002-12-13 20:15:29 +00001506 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001507 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001508 "Unknown attribute type %d length %d is received", type, length);
1509
1510 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001511 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001512
1513 /* Adjest total length to include type and length. */
1514 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1515
1516 /* If any of the mandatory well-known attributes are not recognized,
1517 then the Error Subcode is set to Unrecognized Well-known
1518 Attribute. The Data field contains the unrecognized attribute
1519 (type, length and value). */
1520 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1521 {
1522 /* Adjust startp to do not include flag value. */
1523 bgp_notify_send_with_data (peer,
1524 BGP_NOTIFY_UPDATE_ERR,
1525 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1526 startp, total);
1527 return -1;
1528 }
1529
1530 /* Unrecognized non-transitive optional attributes must be quietly
1531 ignored and not passed along to other BGP peers. */
1532 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1533 return 0;
1534
1535 /* If a path with recognized transitive optional attribute is
1536 accepted and passed along to other BGP peers and the Partial bit
1537 in the Attribute Flags octet is set to 1 by some previous AS, it
1538 is not set back to 0 by the current AS. */
1539 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1540
1541 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001542 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001543 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001544
Paul Jakmafb982c22007-05-04 20:15:47 +00001545 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001546
1547 if (transit->val)
1548 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1549 transit->length + total);
1550 else
1551 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1552
1553 memcpy (transit->val + transit->length, startp, total);
1554 transit->length += total;
1555
1556 return 0;
1557}
1558
1559/* Read attribute of update packet. This function is called from
1560 bgp_update() in bgpd.c. */
1561int
1562bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1563 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1564{
1565 int ret;
1566 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001567 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001568 bgp_size_t length;
1569 u_char *startp, *endp;
1570 u_char *attr_endp;
1571 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001572 /* we need the as4_path only until we have synthesized the as_path with it */
1573 /* same goes for as4_aggregator */
1574 struct aspath *as4_path = NULL;
1575 as_t as4_aggregator = 0;
1576 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001577
1578 /* Initialize bitmap. */
1579 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1580
1581 /* End pointer of BGP attribute. */
1582 endp = BGP_INPUT_PNT (peer) + size;
1583
1584 /* Get attributes to the end of attribute length. */
1585 while (BGP_INPUT_PNT (peer) < endp)
1586 {
1587 /* Check remaining length check.*/
1588 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1589 {
gdtc29fdba2004-12-09 14:46:46 +00001590 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001591 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001592 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001593 peer->host,
1594 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001595
1596 bgp_notify_send (peer,
1597 BGP_NOTIFY_UPDATE_ERR,
1598 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1599 return -1;
1600 }
1601
1602 /* Fetch attribute flag and type. */
1603 startp = BGP_INPUT_PNT (peer);
1604 flag = stream_getc (BGP_INPUT (peer));
1605 type = stream_getc (BGP_INPUT (peer));
1606
Paul Jakma370b64a2007-12-22 16:49:52 +00001607 /* Check whether Extended-Length applies and is in bounds */
1608 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1609 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1610 {
1611 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001612 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001613 peer->host,
1614 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1615
1616 bgp_notify_send (peer,
1617 BGP_NOTIFY_UPDATE_ERR,
1618 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1619 return -1;
1620 }
1621
paul718e3742002-12-13 20:15:29 +00001622 /* Check extended attribue length bit. */
1623 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1624 length = stream_getw (BGP_INPUT (peer));
1625 else
1626 length = stream_getc (BGP_INPUT (peer));
1627
1628 /* If any attribute appears more than once in the UPDATE
1629 message, then the Error Subcode is set to Malformed Attribute
1630 List. */
1631
1632 if (CHECK_BITMAP (seen, type))
1633 {
1634 zlog (peer->log, LOG_WARNING,
1635 "%s error BGP attribute type %d appears twice in a message",
1636 peer->host, type);
1637
1638 bgp_notify_send (peer,
1639 BGP_NOTIFY_UPDATE_ERR,
1640 BGP_NOTIFY_UPDATE_MAL_ATTR);
1641 return -1;
1642 }
1643
1644 /* Set type to bitmap to check duplicate attribute. `type' is
1645 unsigned char so it never overflow bitmap range. */
1646
1647 SET_BITMAP (seen, type);
1648
1649 /* Overflow check. */
1650 attr_endp = BGP_INPUT_PNT (peer) + length;
1651
1652 if (attr_endp > endp)
1653 {
1654 zlog (peer->log, LOG_WARNING,
1655 "%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);
1656 bgp_notify_send (peer,
1657 BGP_NOTIFY_UPDATE_ERR,
1658 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1659 return -1;
1660 }
1661
1662 /* OK check attribute and store it's value. */
1663 switch (type)
1664 {
1665 case BGP_ATTR_ORIGIN:
1666 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1667 break;
1668 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001669 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1670 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001671 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001672 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001673 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1674 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001675 break;
paul718e3742002-12-13 20:15:29 +00001676 case BGP_ATTR_NEXT_HOP:
1677 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1678 break;
1679 case BGP_ATTR_MULTI_EXIT_DISC:
1680 ret = bgp_attr_med (peer, length, attr, flag, startp);
1681 break;
1682 case BGP_ATTR_LOCAL_PREF:
1683 ret = bgp_attr_local_pref (peer, length, attr, flag);
1684 break;
1685 case BGP_ATTR_ATOMIC_AGGREGATE:
1686 ret = bgp_attr_atomic (peer, length, attr, flag);
1687 break;
1688 case BGP_ATTR_AGGREGATOR:
1689 ret = bgp_attr_aggregator (peer, length, attr, flag);
1690 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001691 case BGP_ATTR_AS4_AGGREGATOR:
1692 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1693 break;
paul718e3742002-12-13 20:15:29 +00001694 case BGP_ATTR_COMMUNITIES:
1695 ret = bgp_attr_community (peer, length, attr, flag);
1696 break;
1697 case BGP_ATTR_ORIGINATOR_ID:
1698 ret = bgp_attr_originator_id (peer, length, attr, flag);
1699 break;
1700 case BGP_ATTR_CLUSTER_LIST:
1701 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1702 break;
1703 case BGP_ATTR_MP_REACH_NLRI:
1704 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1705 break;
1706 case BGP_ATTR_MP_UNREACH_NLRI:
1707 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1708 break;
1709 case BGP_ATTR_EXT_COMMUNITIES:
1710 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1711 break;
Paul Jakma41367172007-08-06 15:24:51 +00001712 case BGP_ATTR_AS_PATHLIMIT:
1713 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1714 break;
paul718e3742002-12-13 20:15:29 +00001715 default:
1716 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1717 break;
1718 }
1719
1720 /* If error occured immediately return to the caller. */
1721 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001722 {
1723 zlog (peer->log, LOG_WARNING,
1724 "%s: Attribute %s, parse error",
1725 peer->host,
1726 LOOKUP (attr_str, type));
1727 bgp_notify_send (peer,
1728 BGP_NOTIFY_UPDATE_ERR,
1729 BGP_NOTIFY_UPDATE_MAL_ATTR);
1730 return ret;
1731 }
paul718e3742002-12-13 20:15:29 +00001732
1733 /* Check the fetched length. */
1734 if (BGP_INPUT_PNT (peer) != attr_endp)
1735 {
1736 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001737 "%s: BGP attribute %s, fetch error",
1738 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001739 bgp_notify_send (peer,
1740 BGP_NOTIFY_UPDATE_ERR,
1741 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1742 return -1;
1743 }
1744 }
1745
1746 /* Check final read pointer is same as end pointer. */
1747 if (BGP_INPUT_PNT (peer) != endp)
1748 {
1749 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001750 "%s BGP attribute %s, length mismatch",
1751 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001752 bgp_notify_send (peer,
1753 BGP_NOTIFY_UPDATE_ERR,
1754 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1755 return -1;
1756 }
1757
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001758 /*
1759 * At this place we can see whether we got AS4_PATH and/or
1760 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1761 * We can not do this before we've read all attributes because
1762 * the as4 handling does not say whether AS4_PATH has to be sent
1763 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1764 * in relationship to AGGREGATOR.
1765 * So, to be defensive, we are not relying on any order and read
1766 * all attributes first, including these 32bit ones, and now,
1767 * afterwards, we look what and if something is to be done for as4.
1768 */
1769 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1770 as4_aggregator, &as4_aggregator_addr))
1771 return -1;
1772
1773 /* At this stage, we have done all fiddling with as4, and the
1774 * resulting info is in attr->aggregator resp. attr->aspath
1775 * so we can chuck as4_aggregator and as4_path alltogether in
1776 * order to save memory
1777 */
1778 if ( as4_path )
1779 {
1780 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1781 as4_path = NULL;
1782 /* The flag that we got this is still there, but that does not
1783 * do any trouble
1784 */
1785 }
1786 /*
1787 * The "rest" of the code does nothing with as4_aggregator.
1788 * there is no memory attached specifically which is not part
1789 * of the attr.
1790 * so ignoring just means do nothing.
1791 */
1792 /*
1793 * Finally do the checks on the aspath we did not do yet
1794 * because we waited for a potentially synthesized aspath.
1795 */
1796 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1797 {
1798 ret = bgp_attr_aspath_check( peer, attr );
1799 if ( ret < 0 )
1800 return ret;
1801 }
1802
paul718e3742002-12-13 20:15:29 +00001803 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001804 if (attr->extra && attr->extra->transit)
1805 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001806
1807 return 0;
1808}
1809
1810/* Well-known attribute check. */
1811int
1812bgp_attr_check (struct peer *peer, struct attr *attr)
1813{
1814 u_char type = 0;
1815
1816 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1817 type = BGP_ATTR_ORIGIN;
1818
1819 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1820 type = BGP_ATTR_AS_PATH;
1821
1822 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1823 type = BGP_ATTR_NEXT_HOP;
1824
1825 if (peer_sort (peer) == BGP_PEER_IBGP
1826 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1827 type = BGP_ATTR_LOCAL_PREF;
1828
1829 if (type)
1830 {
1831 zlog (peer->log, LOG_WARNING,
1832 "%s Missing well-known attribute %d.",
1833 peer->host, type);
1834 bgp_notify_send_with_data (peer,
1835 BGP_NOTIFY_UPDATE_ERR,
1836 BGP_NOTIFY_UPDATE_MISS_ATTR,
1837 &type, 1);
1838 return -1;
1839 }
1840 return 0;
1841}
1842
1843int stream_put_prefix (struct stream *, struct prefix *);
1844
1845/* Make attribute packet. */
1846bgp_size_t
1847bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1848 struct stream *s, struct attr *attr, struct prefix *p,
1849 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001850 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001851{
paulfe69a502005-09-10 16:55:02 +00001852 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001853 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001854 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001855 int send_as4_path = 0;
1856 int send_as4_aggregator = 0;
1857 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001858
1859 if (! bgp)
1860 bgp = bgp_get_default ();
1861
1862 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001863 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001864
1865 /* Origin attribute. */
1866 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1867 stream_putc (s, BGP_ATTR_ORIGIN);
1868 stream_putc (s, 1);
1869 stream_putc (s, attr->origin);
1870
1871 /* AS path attribute. */
1872
1873 /* If remote-peer is EBGP */
1874 if (peer_sort (peer) == BGP_PEER_EBGP
1875 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001876 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001877 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001878 {
1879 aspath = aspath_dup (attr->aspath);
1880
1881 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1882 {
1883 /* Strip the confed info, and then stuff our path CONFED_ID
1884 on the front */
1885 aspath = aspath_delete_confed_seq (aspath);
1886 aspath = aspath_add_seq (aspath, bgp->confed_id);
1887 }
1888 else
1889 {
1890 aspath = aspath_add_seq (aspath, peer->local_as);
1891 if (peer->change_local_as)
1892 aspath = aspath_add_seq (aspath, peer->change_local_as);
1893 }
1894 }
1895 else if (peer_sort (peer) == BGP_PEER_CONFED)
1896 {
1897 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1898 aspath = aspath_dup (attr->aspath);
1899 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1900 }
1901 else
1902 aspath = attr->aspath;
1903
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001904 /* If peer is not AS4 capable, then:
1905 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1906 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1907 * types are in it (i.e. exclude them if they are there)
1908 * AND do this only if there is at least one asnum > 65535 in the path!
1909 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1910 * all ASnums > 65535 to BGP_AS_TRANS
1911 */
paul718e3742002-12-13 20:15:29 +00001912
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001913 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1914 stream_putc (s, BGP_ATTR_AS_PATH);
1915 aspath_sizep = stream_get_endp (s);
1916 stream_putw (s, 0);
1917 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1918
1919 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1920 * in the path
1921 */
1922 if (!use32bit && aspath_has_as4 (aspath))
1923 send_as4_path = 1; /* we'll do this later, at the correct place */
1924
paul718e3742002-12-13 20:15:29 +00001925 /* Nexthop attribute. */
1926 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1927 {
1928 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1929 stream_putc (s, BGP_ATTR_NEXT_HOP);
1930 stream_putc (s, 4);
1931 if (safi == SAFI_MPLS_VPN)
1932 {
1933 if (attr->nexthop.s_addr == 0)
1934 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1935 else
1936 stream_put_ipv4 (s, attr->nexthop.s_addr);
1937 }
1938 else
1939 stream_put_ipv4 (s, attr->nexthop.s_addr);
1940 }
1941
1942 /* MED attribute. */
1943 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1944 {
1945 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1946 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1947 stream_putc (s, 4);
1948 stream_putl (s, attr->med);
1949 }
1950
1951 /* Local preference. */
1952 if (peer_sort (peer) == BGP_PEER_IBGP ||
1953 peer_sort (peer) == BGP_PEER_CONFED)
1954 {
1955 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1956 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1957 stream_putc (s, 4);
1958 stream_putl (s, attr->local_pref);
1959 }
1960
1961 /* Atomic aggregate. */
1962 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1963 {
1964 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1965 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1966 stream_putc (s, 0);
1967 }
1968
1969 /* Aggregator. */
1970 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1971 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001972 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001973
1974 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001975 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1976 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001977
1978 if (use32bit)
1979 {
1980 /* AS4 capable peer */
1981 stream_putc (s, 8);
1982 stream_putl (s, attr->extra->aggregator_as);
1983 }
1984 else
1985 {
1986 /* 2-byte AS peer */
1987 stream_putc (s, 6);
1988
1989 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1990 if ( attr->extra->aggregator_as > 65535 )
1991 {
1992 stream_putw (s, BGP_AS_TRANS);
1993
1994 /* we have to send AS4_AGGREGATOR, too.
1995 * we'll do that later in order to send attributes in ascending
1996 * order.
1997 */
1998 send_as4_aggregator = 1;
1999 }
2000 else
2001 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2002 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002003 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002004 }
2005
2006 /* Community attribute. */
2007 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2008 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2009 {
2010 if (attr->community->size * 4 > 255)
2011 {
2012 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2013 stream_putc (s, BGP_ATTR_COMMUNITIES);
2014 stream_putw (s, attr->community->size * 4);
2015 }
2016 else
2017 {
2018 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2019 stream_putc (s, BGP_ATTR_COMMUNITIES);
2020 stream_putc (s, attr->community->size * 4);
2021 }
2022 stream_put (s, attr->community->val, attr->community->size * 4);
2023 }
2024
2025 /* Route Reflector. */
2026 if (peer_sort (peer) == BGP_PEER_IBGP
2027 && from
2028 && peer_sort (from) == BGP_PEER_IBGP)
2029 {
2030 /* Originator ID. */
2031 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2032 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2033 stream_putc (s, 4);
2034
2035 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002036 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002037 else
2038 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002039
2040 /* Cluster list. */
2041 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2042 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2043
Paul Jakma9eda90c2007-08-30 13:36:17 +00002044 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002045 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002046 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002047 /* If this peer configuration's parent BGP has cluster_id. */
2048 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2049 stream_put_in_addr (s, &bgp->cluster_id);
2050 else
2051 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002052 stream_put (s, attr->extra->cluster->list,
2053 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002054 }
2055 else
2056 {
2057 stream_putc (s, 4);
2058 /* If this peer configuration's parent BGP has cluster_id. */
2059 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2060 stream_put_in_addr (s, &bgp->cluster_id);
2061 else
2062 stream_put_in_addr (s, &bgp->router_id);
2063 }
2064 }
2065
2066#ifdef HAVE_IPV6
2067 /* If p is IPv6 address put it into attribute. */
2068 if (p->family == AF_INET6)
2069 {
2070 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002071 struct attr_extra *attre = attr->extra;
2072
2073 assert (attr->extra);
2074
paul718e3742002-12-13 20:15:29 +00002075 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2076 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002077 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002078 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002079 stream_putw (s, AFI_IP6); /* AFI */
2080 stream_putc (s, safi); /* SAFI */
2081
Paul Jakmafb982c22007-05-04 20:15:47 +00002082 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002083
Paul Jakmafb982c22007-05-04 20:15:47 +00002084 if (attre->mp_nexthop_len == 16)
2085 stream_put (s, &attre->mp_nexthop_global, 16);
2086 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002087 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002088 stream_put (s, &attre->mp_nexthop_global, 16);
2089 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002090 }
2091
2092 /* SNPA */
2093 stream_putc (s, 0);
2094
paul718e3742002-12-13 20:15:29 +00002095 /* Prefix write. */
2096 stream_put_prefix (s, p);
2097
2098 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002099 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002100 }
2101#endif /* HAVE_IPV6 */
2102
2103 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2104 {
2105 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002106
2107 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2108 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002109 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002110 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002111 stream_putw (s, AFI_IP); /* AFI */
2112 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2113
2114 stream_putc (s, 4);
2115 stream_put_ipv4 (s, attr->nexthop.s_addr);
2116
2117 /* SNPA */
2118 stream_putc (s, 0);
2119
paul718e3742002-12-13 20:15:29 +00002120 /* Prefix write. */
2121 stream_put_prefix (s, p);
2122
2123 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002124 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002125 }
2126
2127 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2128 {
2129 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002130
2131 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2132 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002133 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002134 stream_putc (s, 0); /* Length of this attribute. */
2135 stream_putw (s, AFI_IP); /* AFI */
2136 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2137
2138 stream_putc (s, 12);
2139 stream_putl (s, 0);
2140 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002141 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002142
2143 /* SNPA */
2144 stream_putc (s, 0);
2145
paul718e3742002-12-13 20:15:29 +00002146 /* Tag, RD, Prefix write. */
2147 stream_putc (s, p->prefixlen + 88);
2148 stream_put (s, tag, 3);
2149 stream_put (s, prd->val, 8);
2150 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2151
2152 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002153 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002154 }
2155
2156 /* Extended Communities attribute. */
2157 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2158 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2159 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002160 struct attr_extra *attre = attr->extra;
2161
2162 assert (attre);
2163
2164 if (peer_sort (peer) == BGP_PEER_IBGP
2165 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002166 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002167 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002168 {
2169 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2170 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002171 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002172 }
2173 else
2174 {
2175 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2176 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002177 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002178 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002179 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002180 }
2181 else
2182 {
paul5228ad22004-06-04 17:58:18 +00002183 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002184 int tbit;
2185 int ecom_tr_size = 0;
2186 int i;
2187
Paul Jakmafb982c22007-05-04 20:15:47 +00002188 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002189 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002190 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002191 tbit = *pnt;
2192
2193 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2194 continue;
2195
2196 ecom_tr_size++;
2197 }
2198
2199 if (ecom_tr_size)
2200 {
2201 if (ecom_tr_size * 8 > 255)
2202 {
2203 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2204 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2205 stream_putw (s, ecom_tr_size * 8);
2206 }
2207 else
2208 {
2209 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2210 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2211 stream_putc (s, ecom_tr_size * 8);
2212 }
2213
Paul Jakmafb982c22007-05-04 20:15:47 +00002214 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002215 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002216 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002217 tbit = *pnt;
2218
2219 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2220 continue;
2221
2222 stream_put (s, pnt, 8);
2223 }
2224 }
paul718e3742002-12-13 20:15:29 +00002225 }
paul718e3742002-12-13 20:15:29 +00002226 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002227
2228 if ( send_as4_path )
2229 {
2230 /* If the peer is NOT As4 capable, AND */
2231 /* there are ASnums > 65535 in path THEN
2232 * give out AS4_PATH */
2233
2234 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2235 * path segments!
2236 * Hm, I wonder... confederation things *should* only be at
2237 * the beginning of an aspath, right? Then we should use
2238 * aspath_delete_confed_seq for this, because it is already
2239 * there! (JK)
2240 * Folks, talk to me: what is reasonable here!?
2241 */
2242 aspath = aspath_delete_confed_seq (aspath);
2243
2244 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2245 stream_putc (s, BGP_ATTR_AS4_PATH);
2246 aspath_sizep = stream_get_endp (s);
2247 stream_putw (s, 0);
2248 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2249 }
2250
2251 if (aspath != attr->aspath)
2252 aspath_free (aspath);
2253
2254 if ( send_as4_aggregator )
2255 {
2256 assert (attr->extra);
2257
2258 /* send AS4_AGGREGATOR, at this place */
2259 /* this section of code moved here in order to ensure the correct
2260 * *ascending* order of attributes
2261 */
2262 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2263 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2264 stream_putc (s, 8);
2265 stream_putl (s, attr->extra->aggregator_as);
2266 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2267 }
Paul Jakma41367172007-08-06 15:24:51 +00002268
2269 /* AS-Pathlimit */
2270 if (attr->pathlimit.ttl)
2271 {
2272 u_int32_t as = attr->pathlimit.as;
2273
2274 /* should already have been done in announce_check(),
2275 * but just in case..
2276 */
2277 if (!as)
2278 as = peer->local_as;
2279
2280 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2281 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2282 stream_putc (s, 5);
2283 stream_putc (s, attr->pathlimit.ttl);
2284 stream_putl (s, as);
2285 }
2286
paul718e3742002-12-13 20:15:29 +00002287 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002288 if (attr->extra && attr->extra->transit)
2289 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002290
2291 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002292 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002293}
2294
2295bgp_size_t
2296bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2297 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002298 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002299{
2300 unsigned long cp;
2301 unsigned long attrlen_pnt;
2302 bgp_size_t size;
2303
paul9985f832005-02-09 15:51:56 +00002304 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002305
2306 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2307 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2308
paul9985f832005-02-09 15:51:56 +00002309 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002310 stream_putc (s, 0); /* Length of this attribute. */
2311
2312 stream_putw (s, family2afi (p->family));
2313
2314 if (safi == SAFI_MPLS_VPN)
2315 {
2316 /* SAFI */
2317 stream_putc (s, BGP_SAFI_VPNV4);
2318
2319 /* prefix. */
2320 stream_putc (s, p->prefixlen + 88);
2321 stream_put (s, tag, 3);
2322 stream_put (s, prd->val, 8);
2323 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2324 }
2325 else
2326 {
2327 /* SAFI */
2328 stream_putc (s, safi);
2329
2330 /* prefix */
2331 stream_put_prefix (s, p);
2332 }
2333
2334 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002335 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002336 stream_putc_at (s, attrlen_pnt, size);
2337
paul9985f832005-02-09 15:51:56 +00002338 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002339}
2340
2341/* Initialization of attribute. */
2342void
paulfe69a502005-09-10 16:55:02 +00002343bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002344{
paul718e3742002-12-13 20:15:29 +00002345 aspath_init ();
2346 attrhash_init ();
2347 community_init ();
2348 ecommunity_init ();
2349 cluster_init ();
2350 transit_init ();
2351}
2352
Chris Caputo228da422009-07-18 05:44:03 +00002353void
2354bgp_attr_finish (void)
2355{
2356 aspath_finish ();
2357 attrhash_finish ();
2358 community_finish ();
2359 ecommunity_finish ();
2360 cluster_finish ();
2361 transit_finish ();
2362}
2363
paul718e3742002-12-13 20:15:29 +00002364/* Make attribute packet. */
2365void
paula3845922003-10-18 01:30:50 +00002366bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2367 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002368{
2369 unsigned long cp;
2370 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002371 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002372 struct aspath *aspath;
2373
2374 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002375 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002376
2377 /* Place holder of length. */
2378 stream_putw (s, 0);
2379
2380 /* Origin attribute. */
2381 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2382 stream_putc (s, BGP_ATTR_ORIGIN);
2383 stream_putc (s, 1);
2384 stream_putc (s, attr->origin);
2385
2386 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002387
2388 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2389 stream_putc (s, BGP_ATTR_AS_PATH);
2390 aspath_lenp = stream_get_endp (s);
2391 stream_putw (s, 0);
2392
2393 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002394
2395 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002396 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2397 if(prefix != NULL
2398#ifdef HAVE_IPV6
2399 && prefix->family != AF_INET6
2400#endif /* HAVE_IPV6 */
2401 )
2402 {
2403 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2404 stream_putc (s, BGP_ATTR_NEXT_HOP);
2405 stream_putc (s, 4);
2406 stream_put_ipv4 (s, attr->nexthop.s_addr);
2407 }
paul718e3742002-12-13 20:15:29 +00002408
2409 /* MED attribute. */
2410 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2411 {
2412 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2413 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2414 stream_putc (s, 4);
2415 stream_putl (s, attr->med);
2416 }
2417
2418 /* Local preference. */
2419 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2420 {
2421 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2422 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2423 stream_putc (s, 4);
2424 stream_putl (s, attr->local_pref);
2425 }
2426
2427 /* Atomic aggregate. */
2428 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2429 {
2430 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2431 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2432 stream_putc (s, 0);
2433 }
2434
2435 /* Aggregator. */
2436 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2437 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002438 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002439 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2440 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002441 stream_putc (s, 8);
2442 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002443 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002444 }
2445
2446 /* Community attribute. */
2447 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2448 {
2449 if (attr->community->size * 4 > 255)
2450 {
2451 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2452 stream_putc (s, BGP_ATTR_COMMUNITIES);
2453 stream_putw (s, attr->community->size * 4);
2454 }
2455 else
2456 {
2457 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2458 stream_putc (s, BGP_ATTR_COMMUNITIES);
2459 stream_putc (s, attr->community->size * 4);
2460 }
2461 stream_put (s, attr->community->val, attr->community->size * 4);
2462 }
2463
paula3845922003-10-18 01:30:50 +00002464#ifdef HAVE_IPV6
2465 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002466 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2467 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002468 {
2469 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002470 struct attr_extra *attre = attr->extra;
2471
paula3845922003-10-18 01:30:50 +00002472 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2473 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002474 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002475
2476 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002477 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002478 stream_putw(s, AFI_IP6); /* AFI */
2479 stream_putc(s, SAFI_UNICAST); /* SAFI */
2480
2481 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002482 stream_putc(s, attre->mp_nexthop_len);
2483 stream_put(s, &attre->mp_nexthop_global, 16);
2484 if (attre->mp_nexthop_len == 32)
2485 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002486
2487 /* SNPA */
2488 stream_putc(s, 0);
2489
2490 /* Prefix */
2491 stream_put_prefix(s, prefix);
2492
2493 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002494 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002495 }
2496#endif /* HAVE_IPV6 */
2497
Paul Jakma41367172007-08-06 15:24:51 +00002498 /* AS-Pathlimit */
2499 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2500 {
2501 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2502 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2503 stream_putc (s, 5);
2504 stream_putc (s, attr->pathlimit.ttl);
2505 stream_putl (s, attr->pathlimit.as);
2506 }
2507
paul718e3742002-12-13 20:15:29 +00002508 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002509 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002510 stream_putw_at (s, cp, len);
2511}