blob: 9416837288b5f47bf69a447dffaf1ac4df81a189 [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
875 /* First AS check for EBGP. */
876 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
877 {
878 if (peer_sort (peer) == BGP_PEER_EBGP
879 && ! aspath_firstas_check (attr->aspath, peer->as))
880 {
881 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400882 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000883 bgp_notify_send (peer,
884 BGP_NOTIFY_UPDATE_ERR,
885 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
886 return -1;
887 }
888 }
889
890 /* local-as prepend */
891 if (peer->change_local_as &&
892 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
893 {
894 aspath = aspath_dup (attr->aspath);
895 aspath = aspath_add_seq (aspath, peer->change_local_as);
896 aspath_unintern (attr->aspath);
897 attr->aspath = aspath_intern (aspath);
898 }
899
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000900 return 0;
901
902}
903
904/* Parse AS4 path information. This function is another wrapper of
905 aspath_parse. */
906static int
907bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
908 struct attr *attr, struct aspath **as4_path)
909{
910 *as4_path = aspath_parse (peer->ibuf, length, 1);
paul718e3742002-12-13 20:15:29 +0000911
912 /* Set aspath attribute flag. */
Paul Jakma370b64a2007-12-22 16:49:52 +0000913 if (as4_path)
914 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
paul718e3742002-12-13 20:15:29 +0000915
916 return 0;
917}
918
919/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000920static int
paul718e3742002-12-13 20:15:29 +0000921bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
922 struct attr *attr, u_char flag, u_char *startp)
923{
924 bgp_size_t total;
925
926 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
927
928 /* Flag check. */
929 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
930 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
931 {
932 zlog (peer->log, LOG_ERR,
933 "Origin attribute flag isn't transitive %d", flag);
934 bgp_notify_send_with_data (peer,
935 BGP_NOTIFY_UPDATE_ERR,
936 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
937 startp, total);
938 return -1;
939 }
940
941 /* Check nexthop attribute length. */
942 if (length != 4)
943 {
944 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
945 length);
946
947 bgp_notify_send_with_data (peer,
948 BGP_NOTIFY_UPDATE_ERR,
949 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
950 startp, total);
951 return -1;
952 }
953
954 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
955 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
956
957 return 0;
958}
959
960/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000961static int
paul718e3742002-12-13 20:15:29 +0000962bgp_attr_med (struct peer *peer, bgp_size_t length,
963 struct attr *attr, u_char flag, u_char *startp)
964{
965 bgp_size_t total;
966
967 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
968
969 /* Length check. */
970 if (length != 4)
971 {
972 zlog (peer->log, LOG_ERR,
973 "MED attribute length isn't four [%d]", length);
974
975 bgp_notify_send_with_data (peer,
976 BGP_NOTIFY_UPDATE_ERR,
977 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
978 startp, total);
979 return -1;
980 }
981
982 attr->med = stream_getl (peer->ibuf);
983
984 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
985
986 return 0;
987}
988
989/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000990static int
paul718e3742002-12-13 20:15:29 +0000991bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
992 struct attr *attr, u_char flag)
993{
994 /* If it is contained in an UPDATE message that is received from an
995 external peer, then this attribute MUST be ignored by the
996 receiving speaker. */
997 if (peer_sort (peer) == BGP_PEER_EBGP)
998 {
paul9985f832005-02-09 15:51:56 +0000999 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001000 return 0;
1001 }
1002
1003 if (length == 4)
1004 attr->local_pref = stream_getl (peer->ibuf);
1005 else
1006 attr->local_pref = 0;
1007
1008 /* Set atomic aggregate flag. */
1009 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1010
1011 return 0;
1012}
1013
1014/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001015static int
paul718e3742002-12-13 20:15:29 +00001016bgp_attr_atomic (struct peer *peer, bgp_size_t length,
1017 struct attr *attr, u_char flag)
1018{
1019 if (length != 0)
1020 {
1021 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1022
1023 bgp_notify_send (peer,
1024 BGP_NOTIFY_UPDATE_ERR,
1025 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1026 return -1;
1027 }
1028
1029 /* Set atomic aggregate flag. */
1030 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1031
1032 return 0;
1033}
1034
1035/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001036static int
paul718e3742002-12-13 20:15:29 +00001037bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1038 struct attr *attr, u_char flag)
1039{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001040 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001041 struct attr_extra *attre = bgp_attr_extra_get (attr);
1042
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001043 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1044 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1045 wantedlen = 8;
1046
1047 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001048 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001049 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001050
1051 bgp_notify_send (peer,
1052 BGP_NOTIFY_UPDATE_ERR,
1053 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1054 return -1;
1055 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001056
1057 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1058 attre->aggregator_as = stream_getl (peer->ibuf);
1059 else
1060 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001061 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001062
1063 /* Set atomic aggregate flag. */
1064 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1065
1066 return 0;
1067}
1068
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001069/* New Aggregator attribute */
1070static int
1071bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1072 struct attr *attr, as_t *as4_aggregator_as,
1073 struct in_addr *as4_aggregator_addr)
1074{
1075 if (length != 8)
1076 {
1077 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1078
1079 bgp_notify_send (peer,
1080 BGP_NOTIFY_UPDATE_ERR,
1081 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1082 return -1;
1083 }
1084 *as4_aggregator_as = stream_getl (peer->ibuf);
1085 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1086
1087 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1088
1089 return 0;
1090}
1091
1092/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1093 */
1094static int
1095bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1096 struct aspath *as4_path, as_t as4_aggregator,
1097 struct in_addr *as4_aggregator_addr)
1098{
1099 int ignore_as4_path = 0;
1100 struct aspath *newpath;
1101 struct attr_extra *attre = attr->extra;
1102
1103 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1104 {
1105 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1106 * if given.
1107 * It is worth a warning though, because the peer really
1108 * should not send them
1109 */
1110 if (BGP_DEBUG(as4, AS4))
1111 {
1112 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1113 zlog_debug ("[AS4] %s %s AS4_PATH",
1114 peer->host, "AS4 capable peer, yet it sent");
1115
1116 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1117 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1118 peer->host, "AS4 capable peer, yet it sent");
1119 }
1120
1121 return 0;
1122 }
1123
1124 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1125 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1126 {
1127 /* Hu? This is not supposed to happen at all!
1128 * got as4_path and no aspath,
1129 * This should already
1130 * have been handled by 'well known attributes missing'
1131 * But... yeah, paranoia
1132 * Take this as a "malformed attribute"
1133 */
1134 zlog (peer->log, LOG_ERR,
1135 "%s BGP not AS4 capable peer sent AS4_PATH but"
1136 " no AS_PATH, cant do anything here", peer->host);
1137 bgp_notify_send (peer,
1138 BGP_NOTIFY_UPDATE_ERR,
1139 BGP_NOTIFY_UPDATE_MAL_ATTR);
1140 return -1;
1141 }
1142
1143 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1144 * because that may override AS4_PATH
1145 */
1146 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1147 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001148 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1149 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001150 assert (attre);
1151
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001152 /* received both.
1153 * if the as_number in aggregator is not AS_TRANS,
1154 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1155 * and the Aggregator shall be taken as
1156 * info on the aggregating node, and the AS_PATH
1157 * shall be taken as the AS_PATH
1158 * otherwise
1159 * the Aggregator shall be ignored and the
1160 * AS4_AGGREGATOR shall be taken as the
1161 * Aggregating node and the AS_PATH is to be
1162 * constructed "as in all other cases"
1163 */
1164 if ( attre->aggregator_as != BGP_AS_TRANS )
1165 {
1166 /* ignore */
1167 if ( BGP_DEBUG(as4, AS4))
1168 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1169 " send AGGREGATOR != AS_TRANS and"
1170 " AS4_AGGREGATOR, so ignore"
1171 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1172 ignore_as4_path = 1;
1173 }
1174 else
1175 {
1176 /* "New_aggregator shall be taken as aggregator" */
1177 attre->aggregator_as = as4_aggregator;
1178 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1179 }
1180 }
1181 else
1182 {
1183 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1184 * That is bogus - but reading the conditions
1185 * we have to handle AS4_AGGREGATOR as if it were
1186 * AGGREGATOR in that case
1187 */
1188 if ( BGP_DEBUG(as4, AS4))
1189 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1190 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1191 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001192 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001193 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1194 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1195 }
1196 }
1197
1198 /* need to reconcile NEW_AS_PATH and AS_PATH */
1199 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1200 {
1201 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1202 aspath_unintern (attr->aspath);
1203 attr->aspath = aspath_intern (newpath);
1204 }
1205 return 0;
1206}
1207
paul718e3742002-12-13 20:15:29 +00001208/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001209static int
paul718e3742002-12-13 20:15:29 +00001210bgp_attr_community (struct peer *peer, bgp_size_t length,
1211 struct attr *attr, u_char flag)
1212{
1213 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001214 {
1215 attr->community = NULL;
1216 return 0;
1217 }
paul718e3742002-12-13 20:15:29 +00001218 else
1219 {
paul5228ad22004-06-04 17:58:18 +00001220 attr->community =
1221 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001222 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001223 }
1224
1225 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1226
1227 return 0;
1228}
1229
1230/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001231static int
paul718e3742002-12-13 20:15:29 +00001232bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1233 struct attr *attr, u_char flag)
1234{
1235 if (length != 4)
1236 {
1237 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1238
1239 bgp_notify_send (peer,
1240 BGP_NOTIFY_UPDATE_ERR,
1241 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1242 return -1;
1243 }
1244
Paul Jakmafb982c22007-05-04 20:15:47 +00001245 (bgp_attr_extra_get (attr))->originator_id.s_addr
1246 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001247
1248 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1249
1250 return 0;
1251}
1252
1253/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001254static int
paul718e3742002-12-13 20:15:29 +00001255bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1256 struct attr *attr, u_char flag)
1257{
1258 /* Check length. */
1259 if (length % 4)
1260 {
1261 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1262
1263 bgp_notify_send (peer,
1264 BGP_NOTIFY_UPDATE_ERR,
1265 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1266 return -1;
1267 }
1268
Paul Jakmafb982c22007-05-04 20:15:47 +00001269 (bgp_attr_extra_get (attr))->cluster
1270 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001271
paul9985f832005-02-09 15:51:56 +00001272 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001273
1274 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1275
1276 return 0;
1277}
1278
1279/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001280int
paul718e3742002-12-13 20:15:29 +00001281bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1282 struct bgp_nlri *mp_update)
1283{
1284 u_int16_t afi;
1285 u_char safi;
paul718e3742002-12-13 20:15:29 +00001286 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001287 size_t start;
paul718e3742002-12-13 20:15:29 +00001288 int ret;
1289 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001290 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001291
1292 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001293 s = BGP_INPUT(peer);
1294 start = stream_get_getp(s);
1295
1296 /* safe to read statically sized header? */
1297#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001298#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001299 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001300 {
1301 zlog_info ("%s: %s sent invalid length, %lu",
1302 __func__, peer->host, (unsigned long)length);
1303 return -1;
1304 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001305
paul718e3742002-12-13 20:15:29 +00001306 /* Load AFI, SAFI. */
1307 afi = stream_getw (s);
1308 safi = stream_getc (s);
1309
1310 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001311 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001312
Paul Jakma03292802008-06-07 20:37:10 +00001313 if (LEN_LEFT < attre->mp_nexthop_len)
1314 {
1315 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1316 __func__, peer->host, attre->mp_nexthop_len);
1317 return -1;
1318 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001319
paul718e3742002-12-13 20:15:29 +00001320 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001321 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001322 {
1323 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001324 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001325 break;
1326 case 12:
1327 {
1328 u_int32_t rd_high;
1329 u_int32_t rd_low;
1330
1331 rd_high = stream_getl (s);
1332 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001333 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001334 }
1335 break;
1336#ifdef HAVE_IPV6
1337 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001338 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001339 break;
1340 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001341 stream_get (&attre->mp_nexthop_global, s, 16);
1342 stream_get (&attre->mp_nexthop_local, s, 16);
1343 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001344 {
1345 char buf1[INET6_ADDRSTRLEN];
1346 char buf2[INET6_ADDRSTRLEN];
1347
1348 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001349 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 +00001350 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001351 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001352 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001353 buf2, INET6_ADDRSTRLEN));
1354
Paul Jakmafb982c22007-05-04 20:15:47 +00001355 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001356 }
1357 break;
1358#endif /* HAVE_IPV6 */
1359 default:
Paul Jakma03292802008-06-07 20:37:10 +00001360 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1361 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001362 return -1;
paul718e3742002-12-13 20:15:29 +00001363 }
1364
Paul Jakma03292802008-06-07 20:37:10 +00001365 if (!LEN_LEFT)
1366 {
1367 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1368 __func__, peer->host);
1369 return -1;
1370 }
paul718e3742002-12-13 20:15:29 +00001371
Paul Jakma6e4ab122007-04-10 19:36:48 +00001372 {
1373 u_char val;
1374 if ((val = stream_getc (s)))
1375 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1376 peer->host, val);
1377 }
1378
1379 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001380 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001381 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001382 {
1383 zlog_info ("%s: (%s) Failed to read NLRI",
1384 __func__, peer->host);
1385 return -1;
1386 }
paul718e3742002-12-13 20:15:29 +00001387
1388 if (safi != BGP_SAFI_VPNV4)
1389 {
1390 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001391 if (ret < 0)
1392 {
1393 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1394 __func__, peer->host);
1395 return -1;
1396 }
paul718e3742002-12-13 20:15:29 +00001397 }
1398
1399 mp_update->afi = afi;
1400 mp_update->safi = safi;
1401 mp_update->nlri = stream_pnt (s);
1402 mp_update->length = nlri_len;
1403
paul9985f832005-02-09 15:51:56 +00001404 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001405
1406 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001407#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001408}
1409
1410/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001411int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001412bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001413 struct bgp_nlri *mp_withdraw)
1414{
1415 struct stream *s;
1416 u_int16_t afi;
1417 u_char safi;
paul718e3742002-12-13 20:15:29 +00001418 u_int16_t withdraw_len;
1419 int ret;
1420
1421 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001422
1423#define BGP_MP_UNREACH_MIN_SIZE 3
1424 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1425 return -1;
1426
paul718e3742002-12-13 20:15:29 +00001427 afi = stream_getw (s);
1428 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001429
1430 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001431
1432 if (safi != BGP_SAFI_VPNV4)
1433 {
1434 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1435 if (ret < 0)
1436 return -1;
1437 }
1438
1439 mp_withdraw->afi = afi;
1440 mp_withdraw->safi = safi;
1441 mp_withdraw->nlri = stream_pnt (s);
1442 mp_withdraw->length = withdraw_len;
1443
paul9985f832005-02-09 15:51:56 +00001444 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001445
1446 return 0;
1447}
1448
1449/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001450static int
paul718e3742002-12-13 20:15:29 +00001451bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1452 struct attr *attr, u_char flag)
1453{
1454 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001455 {
1456 if (attr->extra)
1457 attr->extra->ecommunity = NULL;
1458 }
paul718e3742002-12-13 20:15:29 +00001459 else
1460 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001461 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001462 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001463 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001464 }
1465 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1466
1467 return 0;
1468}
1469
1470/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001471static int
paul718e3742002-12-13 20:15:29 +00001472bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1473 u_char type, bgp_size_t length, u_char *startp)
1474{
1475 bgp_size_t total;
1476 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001477 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001478
hassof4184462005-02-01 20:13:16 +00001479 if (BGP_DEBUG (normal, NORMAL))
1480 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1481 peer->host, type, length);
1482
paul718e3742002-12-13 20:15:29 +00001483 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001484 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001485 "Unknown attribute type %d length %d is received", type, length);
1486
1487 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001488 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001489
1490 /* Adjest total length to include type and length. */
1491 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1492
1493 /* If any of the mandatory well-known attributes are not recognized,
1494 then the Error Subcode is set to Unrecognized Well-known
1495 Attribute. The Data field contains the unrecognized attribute
1496 (type, length and value). */
1497 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1498 {
1499 /* Adjust startp to do not include flag value. */
1500 bgp_notify_send_with_data (peer,
1501 BGP_NOTIFY_UPDATE_ERR,
1502 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1503 startp, total);
1504 return -1;
1505 }
1506
1507 /* Unrecognized non-transitive optional attributes must be quietly
1508 ignored and not passed along to other BGP peers. */
1509 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1510 return 0;
1511
1512 /* If a path with recognized transitive optional attribute is
1513 accepted and passed along to other BGP peers and the Partial bit
1514 in the Attribute Flags octet is set to 1 by some previous AS, it
1515 is not set back to 0 by the current AS. */
1516 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1517
1518 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001519 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001520 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001521
Paul Jakmafb982c22007-05-04 20:15:47 +00001522 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001523
1524 if (transit->val)
1525 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1526 transit->length + total);
1527 else
1528 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1529
1530 memcpy (transit->val + transit->length, startp, total);
1531 transit->length += total;
1532
1533 return 0;
1534}
1535
1536/* Read attribute of update packet. This function is called from
1537 bgp_update() in bgpd.c. */
1538int
1539bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1540 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1541{
1542 int ret;
1543 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001544 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001545 bgp_size_t length;
1546 u_char *startp, *endp;
1547 u_char *attr_endp;
1548 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001549 /* we need the as4_path only until we have synthesized the as_path with it */
1550 /* same goes for as4_aggregator */
1551 struct aspath *as4_path = NULL;
1552 as_t as4_aggregator = 0;
1553 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001554
1555 /* Initialize bitmap. */
1556 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1557
1558 /* End pointer of BGP attribute. */
1559 endp = BGP_INPUT_PNT (peer) + size;
1560
1561 /* Get attributes to the end of attribute length. */
1562 while (BGP_INPUT_PNT (peer) < endp)
1563 {
1564 /* Check remaining length check.*/
1565 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1566 {
gdtc29fdba2004-12-09 14:46:46 +00001567 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001568 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001569 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001570 peer->host,
1571 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001572
1573 bgp_notify_send (peer,
1574 BGP_NOTIFY_UPDATE_ERR,
1575 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1576 return -1;
1577 }
1578
1579 /* Fetch attribute flag and type. */
1580 startp = BGP_INPUT_PNT (peer);
1581 flag = stream_getc (BGP_INPUT (peer));
1582 type = stream_getc (BGP_INPUT (peer));
1583
Paul Jakma370b64a2007-12-22 16:49:52 +00001584 /* Check whether Extended-Length applies and is in bounds */
1585 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1586 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1587 {
1588 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001589 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001590 peer->host,
1591 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1592
1593 bgp_notify_send (peer,
1594 BGP_NOTIFY_UPDATE_ERR,
1595 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1596 return -1;
1597 }
1598
paul718e3742002-12-13 20:15:29 +00001599 /* Check extended attribue length bit. */
1600 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1601 length = stream_getw (BGP_INPUT (peer));
1602 else
1603 length = stream_getc (BGP_INPUT (peer));
1604
1605 /* If any attribute appears more than once in the UPDATE
1606 message, then the Error Subcode is set to Malformed Attribute
1607 List. */
1608
1609 if (CHECK_BITMAP (seen, type))
1610 {
1611 zlog (peer->log, LOG_WARNING,
1612 "%s error BGP attribute type %d appears twice in a message",
1613 peer->host, type);
1614
1615 bgp_notify_send (peer,
1616 BGP_NOTIFY_UPDATE_ERR,
1617 BGP_NOTIFY_UPDATE_MAL_ATTR);
1618 return -1;
1619 }
1620
1621 /* Set type to bitmap to check duplicate attribute. `type' is
1622 unsigned char so it never overflow bitmap range. */
1623
1624 SET_BITMAP (seen, type);
1625
1626 /* Overflow check. */
1627 attr_endp = BGP_INPUT_PNT (peer) + length;
1628
1629 if (attr_endp > endp)
1630 {
1631 zlog (peer->log, LOG_WARNING,
1632 "%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);
1633 bgp_notify_send (peer,
1634 BGP_NOTIFY_UPDATE_ERR,
1635 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1636 return -1;
1637 }
1638
1639 /* OK check attribute and store it's value. */
1640 switch (type)
1641 {
1642 case BGP_ATTR_ORIGIN:
1643 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1644 break;
1645 case BGP_ATTR_AS_PATH:
1646 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1647 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001648 case BGP_ATTR_AS4_PATH:
1649 ret = bgp_attr_as4_path (peer, length, attr, &as4_path );
1650 break;
paul718e3742002-12-13 20:15:29 +00001651 case BGP_ATTR_NEXT_HOP:
1652 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1653 break;
1654 case BGP_ATTR_MULTI_EXIT_DISC:
1655 ret = bgp_attr_med (peer, length, attr, flag, startp);
1656 break;
1657 case BGP_ATTR_LOCAL_PREF:
1658 ret = bgp_attr_local_pref (peer, length, attr, flag);
1659 break;
1660 case BGP_ATTR_ATOMIC_AGGREGATE:
1661 ret = bgp_attr_atomic (peer, length, attr, flag);
1662 break;
1663 case BGP_ATTR_AGGREGATOR:
1664 ret = bgp_attr_aggregator (peer, length, attr, flag);
1665 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001666 case BGP_ATTR_AS4_AGGREGATOR:
1667 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1668 break;
paul718e3742002-12-13 20:15:29 +00001669 case BGP_ATTR_COMMUNITIES:
1670 ret = bgp_attr_community (peer, length, attr, flag);
1671 break;
1672 case BGP_ATTR_ORIGINATOR_ID:
1673 ret = bgp_attr_originator_id (peer, length, attr, flag);
1674 break;
1675 case BGP_ATTR_CLUSTER_LIST:
1676 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1677 break;
1678 case BGP_ATTR_MP_REACH_NLRI:
1679 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1680 break;
1681 case BGP_ATTR_MP_UNREACH_NLRI:
1682 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1683 break;
1684 case BGP_ATTR_EXT_COMMUNITIES:
1685 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1686 break;
Paul Jakma41367172007-08-06 15:24:51 +00001687 case BGP_ATTR_AS_PATHLIMIT:
1688 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1689 break;
paul718e3742002-12-13 20:15:29 +00001690 default:
1691 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1692 break;
1693 }
1694
1695 /* If error occured immediately return to the caller. */
1696 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001697 {
1698 zlog (peer->log, LOG_WARNING,
1699 "%s: Attribute %s, parse error",
1700 peer->host,
1701 LOOKUP (attr_str, type));
1702 bgp_notify_send (peer,
1703 BGP_NOTIFY_UPDATE_ERR,
1704 BGP_NOTIFY_UPDATE_MAL_ATTR);
1705 return ret;
1706 }
paul718e3742002-12-13 20:15:29 +00001707
1708 /* Check the fetched length. */
1709 if (BGP_INPUT_PNT (peer) != attr_endp)
1710 {
1711 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001712 "%s: BGP attribute %s, fetch error",
1713 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001714 bgp_notify_send (peer,
1715 BGP_NOTIFY_UPDATE_ERR,
1716 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1717 return -1;
1718 }
1719 }
1720
1721 /* Check final read pointer is same as end pointer. */
1722 if (BGP_INPUT_PNT (peer) != endp)
1723 {
1724 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001725 "%s BGP attribute %s, length mismatch",
1726 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001727 bgp_notify_send (peer,
1728 BGP_NOTIFY_UPDATE_ERR,
1729 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1730 return -1;
1731 }
1732
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001733 /*
1734 * At this place we can see whether we got AS4_PATH and/or
1735 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1736 * We can not do this before we've read all attributes because
1737 * the as4 handling does not say whether AS4_PATH has to be sent
1738 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1739 * in relationship to AGGREGATOR.
1740 * So, to be defensive, we are not relying on any order and read
1741 * all attributes first, including these 32bit ones, and now,
1742 * afterwards, we look what and if something is to be done for as4.
1743 */
1744 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1745 as4_aggregator, &as4_aggregator_addr))
1746 return -1;
1747
1748 /* At this stage, we have done all fiddling with as4, and the
1749 * resulting info is in attr->aggregator resp. attr->aspath
1750 * so we can chuck as4_aggregator and as4_path alltogether in
1751 * order to save memory
1752 */
1753 if ( as4_path )
1754 {
1755 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1756 as4_path = NULL;
1757 /* The flag that we got this is still there, but that does not
1758 * do any trouble
1759 */
1760 }
1761 /*
1762 * The "rest" of the code does nothing with as4_aggregator.
1763 * there is no memory attached specifically which is not part
1764 * of the attr.
1765 * so ignoring just means do nothing.
1766 */
1767 /*
1768 * Finally do the checks on the aspath we did not do yet
1769 * because we waited for a potentially synthesized aspath.
1770 */
1771 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1772 {
1773 ret = bgp_attr_aspath_check( peer, attr );
1774 if ( ret < 0 )
1775 return ret;
1776 }
1777
paul718e3742002-12-13 20:15:29 +00001778 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001779 if (attr->extra && attr->extra->transit)
1780 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001781
1782 return 0;
1783}
1784
1785/* Well-known attribute check. */
1786int
1787bgp_attr_check (struct peer *peer, struct attr *attr)
1788{
1789 u_char type = 0;
1790
1791 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1792 type = BGP_ATTR_ORIGIN;
1793
1794 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1795 type = BGP_ATTR_AS_PATH;
1796
1797 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1798 type = BGP_ATTR_NEXT_HOP;
1799
1800 if (peer_sort (peer) == BGP_PEER_IBGP
1801 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1802 type = BGP_ATTR_LOCAL_PREF;
1803
1804 if (type)
1805 {
1806 zlog (peer->log, LOG_WARNING,
1807 "%s Missing well-known attribute %d.",
1808 peer->host, type);
1809 bgp_notify_send_with_data (peer,
1810 BGP_NOTIFY_UPDATE_ERR,
1811 BGP_NOTIFY_UPDATE_MISS_ATTR,
1812 &type, 1);
1813 return -1;
1814 }
1815 return 0;
1816}
1817
1818int stream_put_prefix (struct stream *, struct prefix *);
1819
1820/* Make attribute packet. */
1821bgp_size_t
1822bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1823 struct stream *s, struct attr *attr, struct prefix *p,
1824 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001825 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001826{
paulfe69a502005-09-10 16:55:02 +00001827 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001828 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001829 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001830 int send_as4_path = 0;
1831 int send_as4_aggregator = 0;
1832 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001833
1834 if (! bgp)
1835 bgp = bgp_get_default ();
1836
1837 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001838 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001839
1840 /* Origin attribute. */
1841 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1842 stream_putc (s, BGP_ATTR_ORIGIN);
1843 stream_putc (s, 1);
1844 stream_putc (s, attr->origin);
1845
1846 /* AS path attribute. */
1847
1848 /* If remote-peer is EBGP */
1849 if (peer_sort (peer) == BGP_PEER_EBGP
1850 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001851 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001852 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001853 {
1854 aspath = aspath_dup (attr->aspath);
1855
1856 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1857 {
1858 /* Strip the confed info, and then stuff our path CONFED_ID
1859 on the front */
1860 aspath = aspath_delete_confed_seq (aspath);
1861 aspath = aspath_add_seq (aspath, bgp->confed_id);
1862 }
1863 else
1864 {
1865 aspath = aspath_add_seq (aspath, peer->local_as);
1866 if (peer->change_local_as)
1867 aspath = aspath_add_seq (aspath, peer->change_local_as);
1868 }
1869 }
1870 else if (peer_sort (peer) == BGP_PEER_CONFED)
1871 {
1872 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1873 aspath = aspath_dup (attr->aspath);
1874 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1875 }
1876 else
1877 aspath = attr->aspath;
1878
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001879 /* If peer is not AS4 capable, then:
1880 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1881 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1882 * types are in it (i.e. exclude them if they are there)
1883 * AND do this only if there is at least one asnum > 65535 in the path!
1884 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1885 * all ASnums > 65535 to BGP_AS_TRANS
1886 */
paul718e3742002-12-13 20:15:29 +00001887
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001888 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1889 stream_putc (s, BGP_ATTR_AS_PATH);
1890 aspath_sizep = stream_get_endp (s);
1891 stream_putw (s, 0);
1892 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1893
1894 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1895 * in the path
1896 */
1897 if (!use32bit && aspath_has_as4 (aspath))
1898 send_as4_path = 1; /* we'll do this later, at the correct place */
1899
paul718e3742002-12-13 20:15:29 +00001900 /* Nexthop attribute. */
1901 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1902 {
1903 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1904 stream_putc (s, BGP_ATTR_NEXT_HOP);
1905 stream_putc (s, 4);
1906 if (safi == SAFI_MPLS_VPN)
1907 {
1908 if (attr->nexthop.s_addr == 0)
1909 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1910 else
1911 stream_put_ipv4 (s, attr->nexthop.s_addr);
1912 }
1913 else
1914 stream_put_ipv4 (s, attr->nexthop.s_addr);
1915 }
1916
1917 /* MED attribute. */
1918 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1919 {
1920 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1921 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1922 stream_putc (s, 4);
1923 stream_putl (s, attr->med);
1924 }
1925
1926 /* Local preference. */
1927 if (peer_sort (peer) == BGP_PEER_IBGP ||
1928 peer_sort (peer) == BGP_PEER_CONFED)
1929 {
1930 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1931 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1932 stream_putc (s, 4);
1933 stream_putl (s, attr->local_pref);
1934 }
1935
1936 /* Atomic aggregate. */
1937 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1938 {
1939 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1940 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1941 stream_putc (s, 0);
1942 }
1943
1944 /* Aggregator. */
1945 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1946 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001947 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001948
1949 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001950 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1951 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001952
1953 if (use32bit)
1954 {
1955 /* AS4 capable peer */
1956 stream_putc (s, 8);
1957 stream_putl (s, attr->extra->aggregator_as);
1958 }
1959 else
1960 {
1961 /* 2-byte AS peer */
1962 stream_putc (s, 6);
1963
1964 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1965 if ( attr->extra->aggregator_as > 65535 )
1966 {
1967 stream_putw (s, BGP_AS_TRANS);
1968
1969 /* we have to send AS4_AGGREGATOR, too.
1970 * we'll do that later in order to send attributes in ascending
1971 * order.
1972 */
1973 send_as4_aggregator = 1;
1974 }
1975 else
1976 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1977 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001978 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001979 }
1980
1981 /* Community attribute. */
1982 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1983 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1984 {
1985 if (attr->community->size * 4 > 255)
1986 {
1987 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1988 stream_putc (s, BGP_ATTR_COMMUNITIES);
1989 stream_putw (s, attr->community->size * 4);
1990 }
1991 else
1992 {
1993 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1994 stream_putc (s, BGP_ATTR_COMMUNITIES);
1995 stream_putc (s, attr->community->size * 4);
1996 }
1997 stream_put (s, attr->community->val, attr->community->size * 4);
1998 }
1999
2000 /* Route Reflector. */
2001 if (peer_sort (peer) == BGP_PEER_IBGP
2002 && from
2003 && peer_sort (from) == BGP_PEER_IBGP)
2004 {
2005 /* Originator ID. */
2006 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2007 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2008 stream_putc (s, 4);
2009
2010 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002011 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002012 else
2013 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002014
2015 /* Cluster list. */
2016 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2017 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2018
Paul Jakma9eda90c2007-08-30 13:36:17 +00002019 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002020 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002021 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002022 /* If this peer configuration's parent BGP has cluster_id. */
2023 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2024 stream_put_in_addr (s, &bgp->cluster_id);
2025 else
2026 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002027 stream_put (s, attr->extra->cluster->list,
2028 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002029 }
2030 else
2031 {
2032 stream_putc (s, 4);
2033 /* If this peer configuration's parent BGP has cluster_id. */
2034 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2035 stream_put_in_addr (s, &bgp->cluster_id);
2036 else
2037 stream_put_in_addr (s, &bgp->router_id);
2038 }
2039 }
2040
2041#ifdef HAVE_IPV6
2042 /* If p is IPv6 address put it into attribute. */
2043 if (p->family == AF_INET6)
2044 {
2045 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002046 struct attr_extra *attre = attr->extra;
2047
2048 assert (attr->extra);
2049
paul718e3742002-12-13 20:15:29 +00002050 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2051 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002052 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002053 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002054 stream_putw (s, AFI_IP6); /* AFI */
2055 stream_putc (s, safi); /* SAFI */
2056
Paul Jakmafb982c22007-05-04 20:15:47 +00002057 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002058
Paul Jakmafb982c22007-05-04 20:15:47 +00002059 if (attre->mp_nexthop_len == 16)
2060 stream_put (s, &attre->mp_nexthop_global, 16);
2061 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002062 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002063 stream_put (s, &attre->mp_nexthop_global, 16);
2064 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002065 }
2066
2067 /* SNPA */
2068 stream_putc (s, 0);
2069
paul718e3742002-12-13 20:15:29 +00002070 /* Prefix write. */
2071 stream_put_prefix (s, p);
2072
2073 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002074 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002075 }
2076#endif /* HAVE_IPV6 */
2077
2078 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2079 {
2080 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002081
2082 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2083 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002084 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002085 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002086 stream_putw (s, AFI_IP); /* AFI */
2087 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2088
2089 stream_putc (s, 4);
2090 stream_put_ipv4 (s, attr->nexthop.s_addr);
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
2102 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2103 {
2104 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002105
2106 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2107 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002108 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002109 stream_putc (s, 0); /* Length of this attribute. */
2110 stream_putw (s, AFI_IP); /* AFI */
2111 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2112
2113 stream_putc (s, 12);
2114 stream_putl (s, 0);
2115 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002116 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002117
2118 /* SNPA */
2119 stream_putc (s, 0);
2120
paul718e3742002-12-13 20:15:29 +00002121 /* Tag, RD, Prefix write. */
2122 stream_putc (s, p->prefixlen + 88);
2123 stream_put (s, tag, 3);
2124 stream_put (s, prd->val, 8);
2125 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2126
2127 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002128 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002129 }
2130
2131 /* Extended Communities attribute. */
2132 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2133 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2134 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002135 struct attr_extra *attre = attr->extra;
2136
2137 assert (attre);
2138
2139 if (peer_sort (peer) == BGP_PEER_IBGP
2140 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002141 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002142 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002143 {
2144 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2145 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002146 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002147 }
2148 else
2149 {
2150 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2151 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002152 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002153 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002154 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002155 }
2156 else
2157 {
paul5228ad22004-06-04 17:58:18 +00002158 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002159 int tbit;
2160 int ecom_tr_size = 0;
2161 int i;
2162
Paul Jakmafb982c22007-05-04 20:15:47 +00002163 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002164 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002165 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002166 tbit = *pnt;
2167
2168 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2169 continue;
2170
2171 ecom_tr_size++;
2172 }
2173
2174 if (ecom_tr_size)
2175 {
2176 if (ecom_tr_size * 8 > 255)
2177 {
2178 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2179 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2180 stream_putw (s, ecom_tr_size * 8);
2181 }
2182 else
2183 {
2184 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2185 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2186 stream_putc (s, ecom_tr_size * 8);
2187 }
2188
Paul Jakmafb982c22007-05-04 20:15:47 +00002189 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002190 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002191 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002192 tbit = *pnt;
2193
2194 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2195 continue;
2196
2197 stream_put (s, pnt, 8);
2198 }
2199 }
paul718e3742002-12-13 20:15:29 +00002200 }
paul718e3742002-12-13 20:15:29 +00002201 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002202
2203 if ( send_as4_path )
2204 {
2205 /* If the peer is NOT As4 capable, AND */
2206 /* there are ASnums > 65535 in path THEN
2207 * give out AS4_PATH */
2208
2209 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2210 * path segments!
2211 * Hm, I wonder... confederation things *should* only be at
2212 * the beginning of an aspath, right? Then we should use
2213 * aspath_delete_confed_seq for this, because it is already
2214 * there! (JK)
2215 * Folks, talk to me: what is reasonable here!?
2216 */
2217 aspath = aspath_delete_confed_seq (aspath);
2218
2219 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2220 stream_putc (s, BGP_ATTR_AS4_PATH);
2221 aspath_sizep = stream_get_endp (s);
2222 stream_putw (s, 0);
2223 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2224 }
2225
2226 if (aspath != attr->aspath)
2227 aspath_free (aspath);
2228
2229 if ( send_as4_aggregator )
2230 {
2231 assert (attr->extra);
2232
2233 /* send AS4_AGGREGATOR, at this place */
2234 /* this section of code moved here in order to ensure the correct
2235 * *ascending* order of attributes
2236 */
2237 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2238 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2239 stream_putc (s, 8);
2240 stream_putl (s, attr->extra->aggregator_as);
2241 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2242 }
Paul Jakma41367172007-08-06 15:24:51 +00002243
2244 /* AS-Pathlimit */
2245 if (attr->pathlimit.ttl)
2246 {
2247 u_int32_t as = attr->pathlimit.as;
2248
2249 /* should already have been done in announce_check(),
2250 * but just in case..
2251 */
2252 if (!as)
2253 as = peer->local_as;
2254
2255 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2256 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2257 stream_putc (s, 5);
2258 stream_putc (s, attr->pathlimit.ttl);
2259 stream_putl (s, as);
2260 }
2261
paul718e3742002-12-13 20:15:29 +00002262 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002263 if (attr->extra && attr->extra->transit)
2264 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002265
2266 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002267 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002268}
2269
2270bgp_size_t
2271bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2272 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002273 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002274{
2275 unsigned long cp;
2276 unsigned long attrlen_pnt;
2277 bgp_size_t size;
2278
paul9985f832005-02-09 15:51:56 +00002279 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002280
2281 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2282 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2283
paul9985f832005-02-09 15:51:56 +00002284 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002285 stream_putc (s, 0); /* Length of this attribute. */
2286
2287 stream_putw (s, family2afi (p->family));
2288
2289 if (safi == SAFI_MPLS_VPN)
2290 {
2291 /* SAFI */
2292 stream_putc (s, BGP_SAFI_VPNV4);
2293
2294 /* prefix. */
2295 stream_putc (s, p->prefixlen + 88);
2296 stream_put (s, tag, 3);
2297 stream_put (s, prd->val, 8);
2298 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2299 }
2300 else
2301 {
2302 /* SAFI */
2303 stream_putc (s, safi);
2304
2305 /* prefix */
2306 stream_put_prefix (s, p);
2307 }
2308
2309 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002310 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002311 stream_putc_at (s, attrlen_pnt, size);
2312
paul9985f832005-02-09 15:51:56 +00002313 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002314}
2315
2316/* Initialization of attribute. */
2317void
paulfe69a502005-09-10 16:55:02 +00002318bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002319{
paul718e3742002-12-13 20:15:29 +00002320 aspath_init ();
2321 attrhash_init ();
2322 community_init ();
2323 ecommunity_init ();
2324 cluster_init ();
2325 transit_init ();
2326}
2327
Chris Caputo228da422009-07-18 05:44:03 +00002328void
2329bgp_attr_finish (void)
2330{
2331 aspath_finish ();
2332 attrhash_finish ();
2333 community_finish ();
2334 ecommunity_finish ();
2335 cluster_finish ();
2336 transit_finish ();
2337}
2338
paul718e3742002-12-13 20:15:29 +00002339/* Make attribute packet. */
2340void
paula3845922003-10-18 01:30:50 +00002341bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2342 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002343{
2344 unsigned long cp;
2345 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002346 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002347 struct aspath *aspath;
2348
2349 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002350 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002351
2352 /* Place holder of length. */
2353 stream_putw (s, 0);
2354
2355 /* Origin attribute. */
2356 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2357 stream_putc (s, BGP_ATTR_ORIGIN);
2358 stream_putc (s, 1);
2359 stream_putc (s, attr->origin);
2360
2361 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002362
2363 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2364 stream_putc (s, BGP_ATTR_AS_PATH);
2365 aspath_lenp = stream_get_endp (s);
2366 stream_putw (s, 0);
2367
2368 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002369
2370 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002371 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2372 if(prefix != NULL
2373#ifdef HAVE_IPV6
2374 && prefix->family != AF_INET6
2375#endif /* HAVE_IPV6 */
2376 )
2377 {
2378 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2379 stream_putc (s, BGP_ATTR_NEXT_HOP);
2380 stream_putc (s, 4);
2381 stream_put_ipv4 (s, attr->nexthop.s_addr);
2382 }
paul718e3742002-12-13 20:15:29 +00002383
2384 /* MED attribute. */
2385 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2386 {
2387 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2388 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2389 stream_putc (s, 4);
2390 stream_putl (s, attr->med);
2391 }
2392
2393 /* Local preference. */
2394 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2395 {
2396 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2397 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2398 stream_putc (s, 4);
2399 stream_putl (s, attr->local_pref);
2400 }
2401
2402 /* Atomic aggregate. */
2403 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2404 {
2405 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2406 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2407 stream_putc (s, 0);
2408 }
2409
2410 /* Aggregator. */
2411 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2412 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002413 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002414 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2415 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002416 stream_putc (s, 8);
2417 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002418 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002419 }
2420
2421 /* Community attribute. */
2422 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2423 {
2424 if (attr->community->size * 4 > 255)
2425 {
2426 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2427 stream_putc (s, BGP_ATTR_COMMUNITIES);
2428 stream_putw (s, attr->community->size * 4);
2429 }
2430 else
2431 {
2432 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2433 stream_putc (s, BGP_ATTR_COMMUNITIES);
2434 stream_putc (s, attr->community->size * 4);
2435 }
2436 stream_put (s, attr->community->val, attr->community->size * 4);
2437 }
2438
paula3845922003-10-18 01:30:50 +00002439#ifdef HAVE_IPV6
2440 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002441 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2442 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002443 {
2444 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002445 struct attr_extra *attre = attr->extra;
2446
paula3845922003-10-18 01:30:50 +00002447 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2448 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002449 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002450
2451 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002452 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002453 stream_putw(s, AFI_IP6); /* AFI */
2454 stream_putc(s, SAFI_UNICAST); /* SAFI */
2455
2456 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002457 stream_putc(s, attre->mp_nexthop_len);
2458 stream_put(s, &attre->mp_nexthop_global, 16);
2459 if (attre->mp_nexthop_len == 32)
2460 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002461
2462 /* SNPA */
2463 stream_putc(s, 0);
2464
2465 /* Prefix */
2466 stream_put_prefix(s, prefix);
2467
2468 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002469 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002470 }
2471#endif /* HAVE_IPV6 */
2472
Paul Jakma41367172007-08-06 15:24:51 +00002473 /* AS-Pathlimit */
2474 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2475 {
2476 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2477 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2478 stream_putc (s, 5);
2479 stream_putc (s, attr->pathlimit.ttl);
2480 stream_putl (s, attr->pathlimit.as);
2481 }
2482
paul718e3742002-12-13 20:15:29 +00002483 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002484 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002485 stream_putw_at (s, cp, len);
2486}