blob: 5e7536aed4dd18226e3dbc9e335d3526d9a9d337 [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}
810
811/* Parse AS path information. This function is wrapper of
812 aspath_parse. */
paul94f2b392005-06-28 12:44:16 +0000813static int
paul718e3742002-12-13 20:15:29 +0000814bgp_attr_aspath (struct peer *peer, bgp_size_t length,
815 struct attr *attr, u_char flag, u_char *startp)
816{
paul718e3742002-12-13 20:15:29 +0000817 bgp_size_t total;
818
819 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
820
821 /* Flag check. */
822 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
823 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
824 {
825 zlog (peer->log, LOG_ERR,
Paul Jakmaa15cfd12008-06-01 14:29:03 +0000826 "As-Path attribute flag isn't transitive %d", flag);
paul718e3742002-12-13 20:15:29 +0000827 bgp_notify_send_with_data (peer,
828 BGP_NOTIFY_UPDATE_ERR,
829 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
830 startp, total);
831 return -1;
832 }
833
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000834 /*
835 * peer with AS4 => will get 4Byte ASnums
836 * otherwise, will get 16 Bit
837 */
838 attr->aspath = aspath_parse (peer->ibuf, length,
839 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
840
paul718e3742002-12-13 20:15:29 +0000841 /* In case of IBGP, length will be zero. */
paul718e3742002-12-13 20:15:29 +0000842 if (! attr->aspath)
843 {
844 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
845 bgp_notify_send (peer,
846 BGP_NOTIFY_UPDATE_ERR,
847 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
848 return -1;
849 }
850
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000851 /* Forward pointer. */
852/* stream_forward_getp (peer->ibuf, length);*/
853
854 /* Set aspath attribute flag. */
855 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
856
857 return 0;
858}
859
860static int bgp_attr_aspath_check( struct peer *peer,
861 struct attr *attr)
862{
863 /* These checks were part of bgp_attr_aspath, but with
864 * as4 we should to check aspath things when
865 * aspath synthesizing with as4_path has already taken place.
866 * Otherwise we check ASPATH and use the synthesized thing, and that is
867 * not right.
868 * So do the checks later, i.e. here
869 */
870 struct bgp *bgp = peer->bgp;
871 struct aspath *aspath;
872
paul718e3742002-12-13 20:15:29 +0000873 bgp = peer->bgp;
874
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300875 /* Confederation sanity check. */
876 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
877 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
878 {
879 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
880 bgp_notify_send (peer,
881 BGP_NOTIFY_UPDATE_ERR,
882 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
883 return -1;
884 }
885
paul718e3742002-12-13 20:15:29 +0000886 /* First AS check for EBGP. */
887 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
888 {
889 if (peer_sort (peer) == BGP_PEER_EBGP
890 && ! aspath_firstas_check (attr->aspath, peer->as))
891 {
892 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400893 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000894 bgp_notify_send (peer,
895 BGP_NOTIFY_UPDATE_ERR,
896 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
897 return -1;
898 }
899 }
900
901 /* local-as prepend */
902 if (peer->change_local_as &&
903 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
904 {
905 aspath = aspath_dup (attr->aspath);
906 aspath = aspath_add_seq (aspath, peer->change_local_as);
907 aspath_unintern (attr->aspath);
908 attr->aspath = aspath_intern (aspath);
909 }
910
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000911 return 0;
912
913}
914
915/* Parse AS4 path information. This function is another wrapper of
916 aspath_parse. */
917static int
918bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
919 struct attr *attr, struct aspath **as4_path)
920{
921 *as4_path = aspath_parse (peer->ibuf, length, 1);
paul718e3742002-12-13 20:15:29 +0000922
923 /* Set aspath attribute flag. */
Paul Jakma370b64a2007-12-22 16:49:52 +0000924 if (as4_path)
925 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
paul718e3742002-12-13 20:15:29 +0000926
927 return 0;
928}
929
930/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000931static int
paul718e3742002-12-13 20:15:29 +0000932bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
933 struct attr *attr, u_char flag, u_char *startp)
934{
935 bgp_size_t total;
936
937 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
938
939 /* Flag check. */
940 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
941 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
942 {
943 zlog (peer->log, LOG_ERR,
944 "Origin attribute flag isn't transitive %d", flag);
945 bgp_notify_send_with_data (peer,
946 BGP_NOTIFY_UPDATE_ERR,
947 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
948 startp, total);
949 return -1;
950 }
951
952 /* Check nexthop attribute length. */
953 if (length != 4)
954 {
955 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
956 length);
957
958 bgp_notify_send_with_data (peer,
959 BGP_NOTIFY_UPDATE_ERR,
960 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
961 startp, total);
962 return -1;
963 }
964
965 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
966 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
967
968 return 0;
969}
970
971/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000972static int
paul718e3742002-12-13 20:15:29 +0000973bgp_attr_med (struct peer *peer, bgp_size_t length,
974 struct attr *attr, u_char flag, u_char *startp)
975{
976 bgp_size_t total;
977
978 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
979
980 /* Length check. */
981 if (length != 4)
982 {
983 zlog (peer->log, LOG_ERR,
984 "MED attribute length isn't four [%d]", length);
985
986 bgp_notify_send_with_data (peer,
987 BGP_NOTIFY_UPDATE_ERR,
988 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
989 startp, total);
990 return -1;
991 }
992
993 attr->med = stream_getl (peer->ibuf);
994
995 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
996
997 return 0;
998}
999
1000/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +00001001static int
paul718e3742002-12-13 20:15:29 +00001002bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
1003 struct attr *attr, u_char flag)
1004{
1005 /* If it is contained in an UPDATE message that is received from an
1006 external peer, then this attribute MUST be ignored by the
1007 receiving speaker. */
1008 if (peer_sort (peer) == BGP_PEER_EBGP)
1009 {
paul9985f832005-02-09 15:51:56 +00001010 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001011 return 0;
1012 }
1013
1014 if (length == 4)
1015 attr->local_pref = stream_getl (peer->ibuf);
1016 else
1017 attr->local_pref = 0;
1018
1019 /* Set atomic aggregate flag. */
1020 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1021
1022 return 0;
1023}
1024
1025/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001026static int
paul718e3742002-12-13 20:15:29 +00001027bgp_attr_atomic (struct peer *peer, bgp_size_t length,
1028 struct attr *attr, u_char flag)
1029{
1030 if (length != 0)
1031 {
1032 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1033
1034 bgp_notify_send (peer,
1035 BGP_NOTIFY_UPDATE_ERR,
1036 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1037 return -1;
1038 }
1039
1040 /* Set atomic aggregate flag. */
1041 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1042
1043 return 0;
1044}
1045
1046/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001047static int
paul718e3742002-12-13 20:15:29 +00001048bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1049 struct attr *attr, u_char flag)
1050{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001051 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001052 struct attr_extra *attre = bgp_attr_extra_get (attr);
1053
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001054 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1055 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1056 wantedlen = 8;
1057
1058 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001059 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001060 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001061
1062 bgp_notify_send (peer,
1063 BGP_NOTIFY_UPDATE_ERR,
1064 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1065 return -1;
1066 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001067
1068 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1069 attre->aggregator_as = stream_getl (peer->ibuf);
1070 else
1071 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001072 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001073
1074 /* Set atomic aggregate flag. */
1075 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1076
1077 return 0;
1078}
1079
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001080/* New Aggregator attribute */
1081static int
1082bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1083 struct attr *attr, as_t *as4_aggregator_as,
1084 struct in_addr *as4_aggregator_addr)
1085{
1086 if (length != 8)
1087 {
1088 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1089
1090 bgp_notify_send (peer,
1091 BGP_NOTIFY_UPDATE_ERR,
1092 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1093 return -1;
1094 }
1095 *as4_aggregator_as = stream_getl (peer->ibuf);
1096 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1097
1098 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1099
1100 return 0;
1101}
1102
1103/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1104 */
1105static int
1106bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1107 struct aspath *as4_path, as_t as4_aggregator,
1108 struct in_addr *as4_aggregator_addr)
1109{
1110 int ignore_as4_path = 0;
1111 struct aspath *newpath;
1112 struct attr_extra *attre = attr->extra;
1113
1114 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1115 {
1116 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1117 * if given.
1118 * It is worth a warning though, because the peer really
1119 * should not send them
1120 */
1121 if (BGP_DEBUG(as4, AS4))
1122 {
1123 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1124 zlog_debug ("[AS4] %s %s AS4_PATH",
1125 peer->host, "AS4 capable peer, yet it sent");
1126
1127 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1128 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1129 peer->host, "AS4 capable peer, yet it sent");
1130 }
1131
1132 return 0;
1133 }
1134
1135 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1136 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1137 {
1138 /* Hu? This is not supposed to happen at all!
1139 * got as4_path and no aspath,
1140 * This should already
1141 * have been handled by 'well known attributes missing'
1142 * But... yeah, paranoia
1143 * Take this as a "malformed attribute"
1144 */
1145 zlog (peer->log, LOG_ERR,
1146 "%s BGP not AS4 capable peer sent AS4_PATH but"
1147 " no AS_PATH, cant do anything here", peer->host);
1148 bgp_notify_send (peer,
1149 BGP_NOTIFY_UPDATE_ERR,
1150 BGP_NOTIFY_UPDATE_MAL_ATTR);
1151 return -1;
1152 }
1153
1154 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1155 * because that may override AS4_PATH
1156 */
1157 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1158 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001159 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1160 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001161 assert (attre);
1162
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001163 /* received both.
1164 * if the as_number in aggregator is not AS_TRANS,
1165 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1166 * and the Aggregator shall be taken as
1167 * info on the aggregating node, and the AS_PATH
1168 * shall be taken as the AS_PATH
1169 * otherwise
1170 * the Aggregator shall be ignored and the
1171 * AS4_AGGREGATOR shall be taken as the
1172 * Aggregating node and the AS_PATH is to be
1173 * constructed "as in all other cases"
1174 */
1175 if ( attre->aggregator_as != BGP_AS_TRANS )
1176 {
1177 /* ignore */
1178 if ( BGP_DEBUG(as4, AS4))
1179 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1180 " send AGGREGATOR != AS_TRANS and"
1181 " AS4_AGGREGATOR, so ignore"
1182 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1183 ignore_as4_path = 1;
1184 }
1185 else
1186 {
1187 /* "New_aggregator shall be taken as aggregator" */
1188 attre->aggregator_as = as4_aggregator;
1189 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1190 }
1191 }
1192 else
1193 {
1194 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1195 * That is bogus - but reading the conditions
1196 * we have to handle AS4_AGGREGATOR as if it were
1197 * AGGREGATOR in that case
1198 */
1199 if ( BGP_DEBUG(as4, AS4))
1200 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1201 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1202 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001203 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001204 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1205 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1206 }
1207 }
1208
1209 /* need to reconcile NEW_AS_PATH and AS_PATH */
1210 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1211 {
1212 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1213 aspath_unintern (attr->aspath);
1214 attr->aspath = aspath_intern (newpath);
1215 }
1216 return 0;
1217}
1218
paul718e3742002-12-13 20:15:29 +00001219/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001220static int
paul718e3742002-12-13 20:15:29 +00001221bgp_attr_community (struct peer *peer, bgp_size_t length,
1222 struct attr *attr, u_char flag)
1223{
1224 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001225 {
1226 attr->community = NULL;
1227 return 0;
1228 }
paul718e3742002-12-13 20:15:29 +00001229 else
1230 {
paul5228ad22004-06-04 17:58:18 +00001231 attr->community =
1232 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001233 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001234 }
1235
1236 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1237
1238 return 0;
1239}
1240
1241/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001242static int
paul718e3742002-12-13 20:15:29 +00001243bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1244 struct attr *attr, u_char flag)
1245{
1246 if (length != 4)
1247 {
1248 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1249
1250 bgp_notify_send (peer,
1251 BGP_NOTIFY_UPDATE_ERR,
1252 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1253 return -1;
1254 }
1255
Paul Jakmafb982c22007-05-04 20:15:47 +00001256 (bgp_attr_extra_get (attr))->originator_id.s_addr
1257 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001258
1259 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1260
1261 return 0;
1262}
1263
1264/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001265static int
paul718e3742002-12-13 20:15:29 +00001266bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1267 struct attr *attr, u_char flag)
1268{
1269 /* Check length. */
1270 if (length % 4)
1271 {
1272 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1273
1274 bgp_notify_send (peer,
1275 BGP_NOTIFY_UPDATE_ERR,
1276 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1277 return -1;
1278 }
1279
Paul Jakmafb982c22007-05-04 20:15:47 +00001280 (bgp_attr_extra_get (attr))->cluster
1281 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001282
paul9985f832005-02-09 15:51:56 +00001283 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001284
1285 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1286
1287 return 0;
1288}
1289
1290/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001291int
paul718e3742002-12-13 20:15:29 +00001292bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1293 struct bgp_nlri *mp_update)
1294{
1295 u_int16_t afi;
1296 u_char safi;
paul718e3742002-12-13 20:15:29 +00001297 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001298 size_t start;
paul718e3742002-12-13 20:15:29 +00001299 int ret;
1300 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001301 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001302
1303 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001304 s = BGP_INPUT(peer);
1305 start = stream_get_getp(s);
1306
1307 /* safe to read statically sized header? */
1308#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001309#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001310 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001311 {
1312 zlog_info ("%s: %s sent invalid length, %lu",
1313 __func__, peer->host, (unsigned long)length);
1314 return -1;
1315 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001316
paul718e3742002-12-13 20:15:29 +00001317 /* Load AFI, SAFI. */
1318 afi = stream_getw (s);
1319 safi = stream_getc (s);
1320
1321 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001322 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001323
Paul Jakma03292802008-06-07 20:37:10 +00001324 if (LEN_LEFT < attre->mp_nexthop_len)
1325 {
1326 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1327 __func__, peer->host, attre->mp_nexthop_len);
1328 return -1;
1329 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001330
paul718e3742002-12-13 20:15:29 +00001331 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001332 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001333 {
1334 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001335 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001336 /* Probably needed for RFC 2283 */
1337 if (attr->nexthop.s_addr == 0)
1338 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001339 break;
1340 case 12:
1341 {
1342 u_int32_t rd_high;
1343 u_int32_t rd_low;
1344
1345 rd_high = stream_getl (s);
1346 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001347 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001348 }
1349 break;
1350#ifdef HAVE_IPV6
1351 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001352 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001353 break;
1354 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001355 stream_get (&attre->mp_nexthop_global, s, 16);
1356 stream_get (&attre->mp_nexthop_local, s, 16);
1357 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001358 {
1359 char buf1[INET6_ADDRSTRLEN];
1360 char buf2[INET6_ADDRSTRLEN];
1361
1362 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001363 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 +00001364 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001365 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001366 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001367 buf2, INET6_ADDRSTRLEN));
1368
Paul Jakmafb982c22007-05-04 20:15:47 +00001369 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001370 }
1371 break;
1372#endif /* HAVE_IPV6 */
1373 default:
Paul Jakma03292802008-06-07 20:37:10 +00001374 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1375 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001376 return -1;
paul718e3742002-12-13 20:15:29 +00001377 }
1378
Paul Jakma03292802008-06-07 20:37:10 +00001379 if (!LEN_LEFT)
1380 {
1381 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1382 __func__, peer->host);
1383 return -1;
1384 }
paul718e3742002-12-13 20:15:29 +00001385
Paul Jakma6e4ab122007-04-10 19:36:48 +00001386 {
1387 u_char val;
1388 if ((val = stream_getc (s)))
1389 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1390 peer->host, val);
1391 }
1392
1393 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001394 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001395 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001396 {
1397 zlog_info ("%s: (%s) Failed to read NLRI",
1398 __func__, peer->host);
1399 return -1;
1400 }
paul718e3742002-12-13 20:15:29 +00001401
1402 if (safi != BGP_SAFI_VPNV4)
1403 {
1404 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001405 if (ret < 0)
1406 {
1407 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1408 __func__, peer->host);
1409 return -1;
1410 }
paul718e3742002-12-13 20:15:29 +00001411 }
1412
1413 mp_update->afi = afi;
1414 mp_update->safi = safi;
1415 mp_update->nlri = stream_pnt (s);
1416 mp_update->length = nlri_len;
1417
paul9985f832005-02-09 15:51:56 +00001418 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001419
1420 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001421#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001422}
1423
1424/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001425int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001426bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001427 struct bgp_nlri *mp_withdraw)
1428{
1429 struct stream *s;
1430 u_int16_t afi;
1431 u_char safi;
paul718e3742002-12-13 20:15:29 +00001432 u_int16_t withdraw_len;
1433 int ret;
1434
1435 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001436
1437#define BGP_MP_UNREACH_MIN_SIZE 3
1438 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1439 return -1;
1440
paul718e3742002-12-13 20:15:29 +00001441 afi = stream_getw (s);
1442 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001443
1444 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001445
1446 if (safi != BGP_SAFI_VPNV4)
1447 {
1448 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1449 if (ret < 0)
1450 return -1;
1451 }
1452
1453 mp_withdraw->afi = afi;
1454 mp_withdraw->safi = safi;
1455 mp_withdraw->nlri = stream_pnt (s);
1456 mp_withdraw->length = withdraw_len;
1457
paul9985f832005-02-09 15:51:56 +00001458 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001459
1460 return 0;
1461}
1462
1463/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001464static int
paul718e3742002-12-13 20:15:29 +00001465bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1466 struct attr *attr, u_char flag)
1467{
1468 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001469 {
1470 if (attr->extra)
1471 attr->extra->ecommunity = NULL;
1472 }
paul718e3742002-12-13 20:15:29 +00001473 else
1474 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001475 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001476 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001477 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001478 }
1479 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1480
1481 return 0;
1482}
1483
1484/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001485static int
paul718e3742002-12-13 20:15:29 +00001486bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1487 u_char type, bgp_size_t length, u_char *startp)
1488{
1489 bgp_size_t total;
1490 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001491 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001492
hassof4184462005-02-01 20:13:16 +00001493 if (BGP_DEBUG (normal, NORMAL))
1494 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1495 peer->host, type, length);
1496
paul718e3742002-12-13 20:15:29 +00001497 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001498 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001499 "Unknown attribute type %d length %d is received", type, length);
1500
1501 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001502 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001503
1504 /* Adjest total length to include type and length. */
1505 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1506
1507 /* If any of the mandatory well-known attributes are not recognized,
1508 then the Error Subcode is set to Unrecognized Well-known
1509 Attribute. The Data field contains the unrecognized attribute
1510 (type, length and value). */
1511 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1512 {
1513 /* Adjust startp to do not include flag value. */
1514 bgp_notify_send_with_data (peer,
1515 BGP_NOTIFY_UPDATE_ERR,
1516 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1517 startp, total);
1518 return -1;
1519 }
1520
1521 /* Unrecognized non-transitive optional attributes must be quietly
1522 ignored and not passed along to other BGP peers. */
1523 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1524 return 0;
1525
1526 /* If a path with recognized transitive optional attribute is
1527 accepted and passed along to other BGP peers and the Partial bit
1528 in the Attribute Flags octet is set to 1 by some previous AS, it
1529 is not set back to 0 by the current AS. */
1530 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1531
1532 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001533 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001534 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001535
Paul Jakmafb982c22007-05-04 20:15:47 +00001536 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001537
1538 if (transit->val)
1539 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1540 transit->length + total);
1541 else
1542 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1543
1544 memcpy (transit->val + transit->length, startp, total);
1545 transit->length += total;
1546
1547 return 0;
1548}
1549
1550/* Read attribute of update packet. This function is called from
1551 bgp_update() in bgpd.c. */
1552int
1553bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1554 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1555{
1556 int ret;
1557 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001558 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001559 bgp_size_t length;
1560 u_char *startp, *endp;
1561 u_char *attr_endp;
1562 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001563 /* we need the as4_path only until we have synthesized the as_path with it */
1564 /* same goes for as4_aggregator */
1565 struct aspath *as4_path = NULL;
1566 as_t as4_aggregator = 0;
1567 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001568
1569 /* Initialize bitmap. */
1570 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1571
1572 /* End pointer of BGP attribute. */
1573 endp = BGP_INPUT_PNT (peer) + size;
1574
1575 /* Get attributes to the end of attribute length. */
1576 while (BGP_INPUT_PNT (peer) < endp)
1577 {
1578 /* Check remaining length check.*/
1579 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1580 {
gdtc29fdba2004-12-09 14:46:46 +00001581 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001582 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001583 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001584 peer->host,
1585 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001586
1587 bgp_notify_send (peer,
1588 BGP_NOTIFY_UPDATE_ERR,
1589 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1590 return -1;
1591 }
1592
1593 /* Fetch attribute flag and type. */
1594 startp = BGP_INPUT_PNT (peer);
1595 flag = stream_getc (BGP_INPUT (peer));
1596 type = stream_getc (BGP_INPUT (peer));
1597
Paul Jakma370b64a2007-12-22 16:49:52 +00001598 /* Check whether Extended-Length applies and is in bounds */
1599 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1600 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1601 {
1602 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001603 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001604 peer->host,
1605 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1606
1607 bgp_notify_send (peer,
1608 BGP_NOTIFY_UPDATE_ERR,
1609 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1610 return -1;
1611 }
1612
paul718e3742002-12-13 20:15:29 +00001613 /* Check extended attribue length bit. */
1614 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1615 length = stream_getw (BGP_INPUT (peer));
1616 else
1617 length = stream_getc (BGP_INPUT (peer));
1618
1619 /* If any attribute appears more than once in the UPDATE
1620 message, then the Error Subcode is set to Malformed Attribute
1621 List. */
1622
1623 if (CHECK_BITMAP (seen, type))
1624 {
1625 zlog (peer->log, LOG_WARNING,
1626 "%s error BGP attribute type %d appears twice in a message",
1627 peer->host, type);
1628
1629 bgp_notify_send (peer,
1630 BGP_NOTIFY_UPDATE_ERR,
1631 BGP_NOTIFY_UPDATE_MAL_ATTR);
1632 return -1;
1633 }
1634
1635 /* Set type to bitmap to check duplicate attribute. `type' is
1636 unsigned char so it never overflow bitmap range. */
1637
1638 SET_BITMAP (seen, type);
1639
1640 /* Overflow check. */
1641 attr_endp = BGP_INPUT_PNT (peer) + length;
1642
1643 if (attr_endp > endp)
1644 {
1645 zlog (peer->log, LOG_WARNING,
1646 "%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);
1647 bgp_notify_send (peer,
1648 BGP_NOTIFY_UPDATE_ERR,
1649 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1650 return -1;
1651 }
1652
1653 /* OK check attribute and store it's value. */
1654 switch (type)
1655 {
1656 case BGP_ATTR_ORIGIN:
1657 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1658 break;
1659 case BGP_ATTR_AS_PATH:
1660 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1661 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001662 case BGP_ATTR_AS4_PATH:
1663 ret = bgp_attr_as4_path (peer, length, attr, &as4_path );
1664 break;
paul718e3742002-12-13 20:15:29 +00001665 case BGP_ATTR_NEXT_HOP:
1666 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1667 break;
1668 case BGP_ATTR_MULTI_EXIT_DISC:
1669 ret = bgp_attr_med (peer, length, attr, flag, startp);
1670 break;
1671 case BGP_ATTR_LOCAL_PREF:
1672 ret = bgp_attr_local_pref (peer, length, attr, flag);
1673 break;
1674 case BGP_ATTR_ATOMIC_AGGREGATE:
1675 ret = bgp_attr_atomic (peer, length, attr, flag);
1676 break;
1677 case BGP_ATTR_AGGREGATOR:
1678 ret = bgp_attr_aggregator (peer, length, attr, flag);
1679 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001680 case BGP_ATTR_AS4_AGGREGATOR:
1681 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1682 break;
paul718e3742002-12-13 20:15:29 +00001683 case BGP_ATTR_COMMUNITIES:
1684 ret = bgp_attr_community (peer, length, attr, flag);
1685 break;
1686 case BGP_ATTR_ORIGINATOR_ID:
1687 ret = bgp_attr_originator_id (peer, length, attr, flag);
1688 break;
1689 case BGP_ATTR_CLUSTER_LIST:
1690 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1691 break;
1692 case BGP_ATTR_MP_REACH_NLRI:
1693 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1694 break;
1695 case BGP_ATTR_MP_UNREACH_NLRI:
1696 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1697 break;
1698 case BGP_ATTR_EXT_COMMUNITIES:
1699 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1700 break;
Paul Jakma41367172007-08-06 15:24:51 +00001701 case BGP_ATTR_AS_PATHLIMIT:
1702 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1703 break;
paul718e3742002-12-13 20:15:29 +00001704 default:
1705 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1706 break;
1707 }
1708
1709 /* If error occured immediately return to the caller. */
1710 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001711 {
1712 zlog (peer->log, LOG_WARNING,
1713 "%s: Attribute %s, parse error",
1714 peer->host,
1715 LOOKUP (attr_str, type));
1716 bgp_notify_send (peer,
1717 BGP_NOTIFY_UPDATE_ERR,
1718 BGP_NOTIFY_UPDATE_MAL_ATTR);
1719 return ret;
1720 }
paul718e3742002-12-13 20:15:29 +00001721
1722 /* Check the fetched length. */
1723 if (BGP_INPUT_PNT (peer) != attr_endp)
1724 {
1725 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001726 "%s: BGP attribute %s, fetch error",
1727 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001728 bgp_notify_send (peer,
1729 BGP_NOTIFY_UPDATE_ERR,
1730 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1731 return -1;
1732 }
1733 }
1734
1735 /* Check final read pointer is same as end pointer. */
1736 if (BGP_INPUT_PNT (peer) != endp)
1737 {
1738 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001739 "%s BGP attribute %s, length mismatch",
1740 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001741 bgp_notify_send (peer,
1742 BGP_NOTIFY_UPDATE_ERR,
1743 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1744 return -1;
1745 }
1746
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001747 /*
1748 * At this place we can see whether we got AS4_PATH and/or
1749 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1750 * We can not do this before we've read all attributes because
1751 * the as4 handling does not say whether AS4_PATH has to be sent
1752 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1753 * in relationship to AGGREGATOR.
1754 * So, to be defensive, we are not relying on any order and read
1755 * all attributes first, including these 32bit ones, and now,
1756 * afterwards, we look what and if something is to be done for as4.
1757 */
1758 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1759 as4_aggregator, &as4_aggregator_addr))
1760 return -1;
1761
1762 /* At this stage, we have done all fiddling with as4, and the
1763 * resulting info is in attr->aggregator resp. attr->aspath
1764 * so we can chuck as4_aggregator and as4_path alltogether in
1765 * order to save memory
1766 */
1767 if ( as4_path )
1768 {
1769 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1770 as4_path = NULL;
1771 /* The flag that we got this is still there, but that does not
1772 * do any trouble
1773 */
1774 }
1775 /*
1776 * The "rest" of the code does nothing with as4_aggregator.
1777 * there is no memory attached specifically which is not part
1778 * of the attr.
1779 * so ignoring just means do nothing.
1780 */
1781 /*
1782 * Finally do the checks on the aspath we did not do yet
1783 * because we waited for a potentially synthesized aspath.
1784 */
1785 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1786 {
1787 ret = bgp_attr_aspath_check( peer, attr );
1788 if ( ret < 0 )
1789 return ret;
1790 }
1791
paul718e3742002-12-13 20:15:29 +00001792 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001793 if (attr->extra && attr->extra->transit)
1794 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001795
1796 return 0;
1797}
1798
1799/* Well-known attribute check. */
1800int
1801bgp_attr_check (struct peer *peer, struct attr *attr)
1802{
1803 u_char type = 0;
1804
1805 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1806 type = BGP_ATTR_ORIGIN;
1807
1808 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1809 type = BGP_ATTR_AS_PATH;
1810
1811 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1812 type = BGP_ATTR_NEXT_HOP;
1813
1814 if (peer_sort (peer) == BGP_PEER_IBGP
1815 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1816 type = BGP_ATTR_LOCAL_PREF;
1817
1818 if (type)
1819 {
1820 zlog (peer->log, LOG_WARNING,
1821 "%s Missing well-known attribute %d.",
1822 peer->host, type);
1823 bgp_notify_send_with_data (peer,
1824 BGP_NOTIFY_UPDATE_ERR,
1825 BGP_NOTIFY_UPDATE_MISS_ATTR,
1826 &type, 1);
1827 return -1;
1828 }
1829 return 0;
1830}
1831
1832int stream_put_prefix (struct stream *, struct prefix *);
1833
1834/* Make attribute packet. */
1835bgp_size_t
1836bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1837 struct stream *s, struct attr *attr, struct prefix *p,
1838 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001839 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001840{
paulfe69a502005-09-10 16:55:02 +00001841 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001842 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001843 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001844 int send_as4_path = 0;
1845 int send_as4_aggregator = 0;
1846 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001847
1848 if (! bgp)
1849 bgp = bgp_get_default ();
1850
1851 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001852 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001853
1854 /* Origin attribute. */
1855 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1856 stream_putc (s, BGP_ATTR_ORIGIN);
1857 stream_putc (s, 1);
1858 stream_putc (s, attr->origin);
1859
1860 /* AS path attribute. */
1861
1862 /* If remote-peer is EBGP */
1863 if (peer_sort (peer) == BGP_PEER_EBGP
1864 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001865 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001866 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001867 {
1868 aspath = aspath_dup (attr->aspath);
1869
1870 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1871 {
1872 /* Strip the confed info, and then stuff our path CONFED_ID
1873 on the front */
1874 aspath = aspath_delete_confed_seq (aspath);
1875 aspath = aspath_add_seq (aspath, bgp->confed_id);
1876 }
1877 else
1878 {
1879 aspath = aspath_add_seq (aspath, peer->local_as);
1880 if (peer->change_local_as)
1881 aspath = aspath_add_seq (aspath, peer->change_local_as);
1882 }
1883 }
1884 else if (peer_sort (peer) == BGP_PEER_CONFED)
1885 {
1886 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1887 aspath = aspath_dup (attr->aspath);
1888 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1889 }
1890 else
1891 aspath = attr->aspath;
1892
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001893 /* If peer is not AS4 capable, then:
1894 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1895 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1896 * types are in it (i.e. exclude them if they are there)
1897 * AND do this only if there is at least one asnum > 65535 in the path!
1898 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1899 * all ASnums > 65535 to BGP_AS_TRANS
1900 */
paul718e3742002-12-13 20:15:29 +00001901
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001902 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1903 stream_putc (s, BGP_ATTR_AS_PATH);
1904 aspath_sizep = stream_get_endp (s);
1905 stream_putw (s, 0);
1906 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1907
1908 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1909 * in the path
1910 */
1911 if (!use32bit && aspath_has_as4 (aspath))
1912 send_as4_path = 1; /* we'll do this later, at the correct place */
1913
paul718e3742002-12-13 20:15:29 +00001914 /* Nexthop attribute. */
1915 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1916 {
1917 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1918 stream_putc (s, BGP_ATTR_NEXT_HOP);
1919 stream_putc (s, 4);
1920 if (safi == SAFI_MPLS_VPN)
1921 {
1922 if (attr->nexthop.s_addr == 0)
1923 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1924 else
1925 stream_put_ipv4 (s, attr->nexthop.s_addr);
1926 }
1927 else
1928 stream_put_ipv4 (s, attr->nexthop.s_addr);
1929 }
1930
1931 /* MED attribute. */
1932 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1933 {
1934 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1935 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1936 stream_putc (s, 4);
1937 stream_putl (s, attr->med);
1938 }
1939
1940 /* Local preference. */
1941 if (peer_sort (peer) == BGP_PEER_IBGP ||
1942 peer_sort (peer) == BGP_PEER_CONFED)
1943 {
1944 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1945 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1946 stream_putc (s, 4);
1947 stream_putl (s, attr->local_pref);
1948 }
1949
1950 /* Atomic aggregate. */
1951 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1952 {
1953 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1954 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1955 stream_putc (s, 0);
1956 }
1957
1958 /* Aggregator. */
1959 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1960 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001961 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001962
1963 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001964 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1965 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001966
1967 if (use32bit)
1968 {
1969 /* AS4 capable peer */
1970 stream_putc (s, 8);
1971 stream_putl (s, attr->extra->aggregator_as);
1972 }
1973 else
1974 {
1975 /* 2-byte AS peer */
1976 stream_putc (s, 6);
1977
1978 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1979 if ( attr->extra->aggregator_as > 65535 )
1980 {
1981 stream_putw (s, BGP_AS_TRANS);
1982
1983 /* we have to send AS4_AGGREGATOR, too.
1984 * we'll do that later in order to send attributes in ascending
1985 * order.
1986 */
1987 send_as4_aggregator = 1;
1988 }
1989 else
1990 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1991 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001992 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001993 }
1994
1995 /* Community attribute. */
1996 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1997 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1998 {
1999 if (attr->community->size * 4 > 255)
2000 {
2001 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2002 stream_putc (s, BGP_ATTR_COMMUNITIES);
2003 stream_putw (s, attr->community->size * 4);
2004 }
2005 else
2006 {
2007 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2008 stream_putc (s, BGP_ATTR_COMMUNITIES);
2009 stream_putc (s, attr->community->size * 4);
2010 }
2011 stream_put (s, attr->community->val, attr->community->size * 4);
2012 }
2013
2014 /* Route Reflector. */
2015 if (peer_sort (peer) == BGP_PEER_IBGP
2016 && from
2017 && peer_sort (from) == BGP_PEER_IBGP)
2018 {
2019 /* Originator ID. */
2020 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2021 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2022 stream_putc (s, 4);
2023
2024 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002025 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002026 else
2027 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002028
2029 /* Cluster list. */
2030 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2031 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2032
Paul Jakma9eda90c2007-08-30 13:36:17 +00002033 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002034 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002035 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002036 /* If this peer configuration's parent BGP has cluster_id. */
2037 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2038 stream_put_in_addr (s, &bgp->cluster_id);
2039 else
2040 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002041 stream_put (s, attr->extra->cluster->list,
2042 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002043 }
2044 else
2045 {
2046 stream_putc (s, 4);
2047 /* 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);
2052 }
2053 }
2054
2055#ifdef HAVE_IPV6
2056 /* If p is IPv6 address put it into attribute. */
2057 if (p->family == AF_INET6)
2058 {
2059 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002060 struct attr_extra *attre = attr->extra;
2061
2062 assert (attr->extra);
2063
paul718e3742002-12-13 20:15:29 +00002064 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2065 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002066 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002067 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002068 stream_putw (s, AFI_IP6); /* AFI */
2069 stream_putc (s, safi); /* SAFI */
2070
Paul Jakmafb982c22007-05-04 20:15:47 +00002071 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002072
Paul Jakmafb982c22007-05-04 20:15:47 +00002073 if (attre->mp_nexthop_len == 16)
2074 stream_put (s, &attre->mp_nexthop_global, 16);
2075 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002076 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002077 stream_put (s, &attre->mp_nexthop_global, 16);
2078 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002079 }
2080
2081 /* SNPA */
2082 stream_putc (s, 0);
2083
paul718e3742002-12-13 20:15:29 +00002084 /* Prefix write. */
2085 stream_put_prefix (s, p);
2086
2087 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002088 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002089 }
2090#endif /* HAVE_IPV6 */
2091
2092 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2093 {
2094 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002095
2096 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2097 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002098 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002099 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002100 stream_putw (s, AFI_IP); /* AFI */
2101 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2102
2103 stream_putc (s, 4);
2104 stream_put_ipv4 (s, attr->nexthop.s_addr);
2105
2106 /* SNPA */
2107 stream_putc (s, 0);
2108
paul718e3742002-12-13 20:15:29 +00002109 /* Prefix write. */
2110 stream_put_prefix (s, p);
2111
2112 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002113 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002114 }
2115
2116 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2117 {
2118 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002119
2120 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2121 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002122 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002123 stream_putc (s, 0); /* Length of this attribute. */
2124 stream_putw (s, AFI_IP); /* AFI */
2125 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2126
2127 stream_putc (s, 12);
2128 stream_putl (s, 0);
2129 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002130 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002131
2132 /* SNPA */
2133 stream_putc (s, 0);
2134
paul718e3742002-12-13 20:15:29 +00002135 /* Tag, RD, Prefix write. */
2136 stream_putc (s, p->prefixlen + 88);
2137 stream_put (s, tag, 3);
2138 stream_put (s, prd->val, 8);
2139 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2140
2141 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002142 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002143 }
2144
2145 /* Extended Communities attribute. */
2146 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2147 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2148 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002149 struct attr_extra *attre = attr->extra;
2150
2151 assert (attre);
2152
2153 if (peer_sort (peer) == BGP_PEER_IBGP
2154 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002155 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002156 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002157 {
2158 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2159 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002160 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002161 }
2162 else
2163 {
2164 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2165 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002166 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002167 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002168 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002169 }
2170 else
2171 {
paul5228ad22004-06-04 17:58:18 +00002172 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002173 int tbit;
2174 int ecom_tr_size = 0;
2175 int i;
2176
Paul Jakmafb982c22007-05-04 20:15:47 +00002177 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002178 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002179 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002180 tbit = *pnt;
2181
2182 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2183 continue;
2184
2185 ecom_tr_size++;
2186 }
2187
2188 if (ecom_tr_size)
2189 {
2190 if (ecom_tr_size * 8 > 255)
2191 {
2192 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2193 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2194 stream_putw (s, ecom_tr_size * 8);
2195 }
2196 else
2197 {
2198 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2199 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2200 stream_putc (s, ecom_tr_size * 8);
2201 }
2202
Paul Jakmafb982c22007-05-04 20:15:47 +00002203 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002204 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002205 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002206 tbit = *pnt;
2207
2208 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2209 continue;
2210
2211 stream_put (s, pnt, 8);
2212 }
2213 }
paul718e3742002-12-13 20:15:29 +00002214 }
paul718e3742002-12-13 20:15:29 +00002215 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002216
2217 if ( send_as4_path )
2218 {
2219 /* If the peer is NOT As4 capable, AND */
2220 /* there are ASnums > 65535 in path THEN
2221 * give out AS4_PATH */
2222
2223 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2224 * path segments!
2225 * Hm, I wonder... confederation things *should* only be at
2226 * the beginning of an aspath, right? Then we should use
2227 * aspath_delete_confed_seq for this, because it is already
2228 * there! (JK)
2229 * Folks, talk to me: what is reasonable here!?
2230 */
2231 aspath = aspath_delete_confed_seq (aspath);
2232
2233 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2234 stream_putc (s, BGP_ATTR_AS4_PATH);
2235 aspath_sizep = stream_get_endp (s);
2236 stream_putw (s, 0);
2237 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2238 }
2239
2240 if (aspath != attr->aspath)
2241 aspath_free (aspath);
2242
2243 if ( send_as4_aggregator )
2244 {
2245 assert (attr->extra);
2246
2247 /* send AS4_AGGREGATOR, at this place */
2248 /* this section of code moved here in order to ensure the correct
2249 * *ascending* order of attributes
2250 */
2251 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2252 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2253 stream_putc (s, 8);
2254 stream_putl (s, attr->extra->aggregator_as);
2255 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2256 }
Paul Jakma41367172007-08-06 15:24:51 +00002257
2258 /* AS-Pathlimit */
2259 if (attr->pathlimit.ttl)
2260 {
2261 u_int32_t as = attr->pathlimit.as;
2262
2263 /* should already have been done in announce_check(),
2264 * but just in case..
2265 */
2266 if (!as)
2267 as = peer->local_as;
2268
2269 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2270 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2271 stream_putc (s, 5);
2272 stream_putc (s, attr->pathlimit.ttl);
2273 stream_putl (s, as);
2274 }
2275
paul718e3742002-12-13 20:15:29 +00002276 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002277 if (attr->extra && attr->extra->transit)
2278 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002279
2280 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002281 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002282}
2283
2284bgp_size_t
2285bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2286 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002287 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002288{
2289 unsigned long cp;
2290 unsigned long attrlen_pnt;
2291 bgp_size_t size;
2292
paul9985f832005-02-09 15:51:56 +00002293 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002294
2295 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2296 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2297
paul9985f832005-02-09 15:51:56 +00002298 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002299 stream_putc (s, 0); /* Length of this attribute. */
2300
2301 stream_putw (s, family2afi (p->family));
2302
2303 if (safi == SAFI_MPLS_VPN)
2304 {
2305 /* SAFI */
2306 stream_putc (s, BGP_SAFI_VPNV4);
2307
2308 /* prefix. */
2309 stream_putc (s, p->prefixlen + 88);
2310 stream_put (s, tag, 3);
2311 stream_put (s, prd->val, 8);
2312 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2313 }
2314 else
2315 {
2316 /* SAFI */
2317 stream_putc (s, safi);
2318
2319 /* prefix */
2320 stream_put_prefix (s, p);
2321 }
2322
2323 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002324 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002325 stream_putc_at (s, attrlen_pnt, size);
2326
paul9985f832005-02-09 15:51:56 +00002327 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002328}
2329
2330/* Initialization of attribute. */
2331void
paulfe69a502005-09-10 16:55:02 +00002332bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002333{
paul718e3742002-12-13 20:15:29 +00002334 aspath_init ();
2335 attrhash_init ();
2336 community_init ();
2337 ecommunity_init ();
2338 cluster_init ();
2339 transit_init ();
2340}
2341
Chris Caputo228da422009-07-18 05:44:03 +00002342void
2343bgp_attr_finish (void)
2344{
2345 aspath_finish ();
2346 attrhash_finish ();
2347 community_finish ();
2348 ecommunity_finish ();
2349 cluster_finish ();
2350 transit_finish ();
2351}
2352
paul718e3742002-12-13 20:15:29 +00002353/* Make attribute packet. */
2354void
paula3845922003-10-18 01:30:50 +00002355bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2356 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002357{
2358 unsigned long cp;
2359 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002360 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002361 struct aspath *aspath;
2362
2363 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002364 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002365
2366 /* Place holder of length. */
2367 stream_putw (s, 0);
2368
2369 /* Origin attribute. */
2370 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2371 stream_putc (s, BGP_ATTR_ORIGIN);
2372 stream_putc (s, 1);
2373 stream_putc (s, attr->origin);
2374
2375 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002376
2377 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2378 stream_putc (s, BGP_ATTR_AS_PATH);
2379 aspath_lenp = stream_get_endp (s);
2380 stream_putw (s, 0);
2381
2382 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002383
2384 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002385 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2386 if(prefix != NULL
2387#ifdef HAVE_IPV6
2388 && prefix->family != AF_INET6
2389#endif /* HAVE_IPV6 */
2390 )
2391 {
2392 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2393 stream_putc (s, BGP_ATTR_NEXT_HOP);
2394 stream_putc (s, 4);
2395 stream_put_ipv4 (s, attr->nexthop.s_addr);
2396 }
paul718e3742002-12-13 20:15:29 +00002397
2398 /* MED attribute. */
2399 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2400 {
2401 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2402 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2403 stream_putc (s, 4);
2404 stream_putl (s, attr->med);
2405 }
2406
2407 /* Local preference. */
2408 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2409 {
2410 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2411 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2412 stream_putc (s, 4);
2413 stream_putl (s, attr->local_pref);
2414 }
2415
2416 /* Atomic aggregate. */
2417 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2418 {
2419 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2420 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2421 stream_putc (s, 0);
2422 }
2423
2424 /* Aggregator. */
2425 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2426 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002427 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002428 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2429 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002430 stream_putc (s, 8);
2431 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002432 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002433 }
2434
2435 /* Community attribute. */
2436 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2437 {
2438 if (attr->community->size * 4 > 255)
2439 {
2440 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2441 stream_putc (s, BGP_ATTR_COMMUNITIES);
2442 stream_putw (s, attr->community->size * 4);
2443 }
2444 else
2445 {
2446 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2447 stream_putc (s, BGP_ATTR_COMMUNITIES);
2448 stream_putc (s, attr->community->size * 4);
2449 }
2450 stream_put (s, attr->community->val, attr->community->size * 4);
2451 }
2452
paula3845922003-10-18 01:30:50 +00002453#ifdef HAVE_IPV6
2454 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002455 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2456 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002457 {
2458 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002459 struct attr_extra *attre = attr->extra;
2460
paula3845922003-10-18 01:30:50 +00002461 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2462 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002463 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002464
2465 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002466 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002467 stream_putw(s, AFI_IP6); /* AFI */
2468 stream_putc(s, SAFI_UNICAST); /* SAFI */
2469
2470 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002471 stream_putc(s, attre->mp_nexthop_len);
2472 stream_put(s, &attre->mp_nexthop_global, 16);
2473 if (attre->mp_nexthop_len == 32)
2474 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002475
2476 /* SNPA */
2477 stream_putc(s, 0);
2478
2479 /* Prefix */
2480 stream_put_prefix(s, prefix);
2481
2482 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002483 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002484 }
2485#endif /* HAVE_IPV6 */
2486
Paul Jakma41367172007-08-06 15:24:51 +00002487 /* AS-Pathlimit */
2488 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2489 {
2490 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2491 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2492 stream_putc (s, 5);
2493 stream_putc (s, attr->pathlimit.ttl);
2494 stream_putl (s, attr->pathlimit.as);
2495 }
2496
paul718e3742002-12-13 20:15:29 +00002497 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002498 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002499 stream_putw_at (s, cp, len);
2500}