blob: a664858c5d700ac3a5010bea4d29ba2f023217f1 [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);
paul718e3742002-12-13 20:15:29 +00001336 break;
1337 case 12:
1338 {
1339 u_int32_t rd_high;
1340 u_int32_t rd_low;
1341
1342 rd_high = stream_getl (s);
1343 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001344 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001345 }
1346 break;
1347#ifdef HAVE_IPV6
1348 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001349 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001350 break;
1351 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001352 stream_get (&attre->mp_nexthop_global, s, 16);
1353 stream_get (&attre->mp_nexthop_local, s, 16);
1354 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001355 {
1356 char buf1[INET6_ADDRSTRLEN];
1357 char buf2[INET6_ADDRSTRLEN];
1358
1359 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001360 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 +00001361 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001362 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001363 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001364 buf2, INET6_ADDRSTRLEN));
1365
Paul Jakmafb982c22007-05-04 20:15:47 +00001366 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001367 }
1368 break;
1369#endif /* HAVE_IPV6 */
1370 default:
Paul Jakma03292802008-06-07 20:37:10 +00001371 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1372 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001373 return -1;
paul718e3742002-12-13 20:15:29 +00001374 }
1375
Paul Jakma03292802008-06-07 20:37:10 +00001376 if (!LEN_LEFT)
1377 {
1378 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1379 __func__, peer->host);
1380 return -1;
1381 }
paul718e3742002-12-13 20:15:29 +00001382
Paul Jakma6e4ab122007-04-10 19:36:48 +00001383 {
1384 u_char val;
1385 if ((val = stream_getc (s)))
1386 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1387 peer->host, val);
1388 }
1389
1390 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001391 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001392 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001393 {
1394 zlog_info ("%s: (%s) Failed to read NLRI",
1395 __func__, peer->host);
1396 return -1;
1397 }
paul718e3742002-12-13 20:15:29 +00001398
1399 if (safi != BGP_SAFI_VPNV4)
1400 {
1401 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001402 if (ret < 0)
1403 {
1404 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1405 __func__, peer->host);
1406 return -1;
1407 }
paul718e3742002-12-13 20:15:29 +00001408 }
1409
1410 mp_update->afi = afi;
1411 mp_update->safi = safi;
1412 mp_update->nlri = stream_pnt (s);
1413 mp_update->length = nlri_len;
1414
paul9985f832005-02-09 15:51:56 +00001415 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001416
1417 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001418#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001419}
1420
1421/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001422int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001423bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001424 struct bgp_nlri *mp_withdraw)
1425{
1426 struct stream *s;
1427 u_int16_t afi;
1428 u_char safi;
paul718e3742002-12-13 20:15:29 +00001429 u_int16_t withdraw_len;
1430 int ret;
1431
1432 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001433
1434#define BGP_MP_UNREACH_MIN_SIZE 3
1435 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1436 return -1;
1437
paul718e3742002-12-13 20:15:29 +00001438 afi = stream_getw (s);
1439 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001440
1441 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001442
1443 if (safi != BGP_SAFI_VPNV4)
1444 {
1445 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1446 if (ret < 0)
1447 return -1;
1448 }
1449
1450 mp_withdraw->afi = afi;
1451 mp_withdraw->safi = safi;
1452 mp_withdraw->nlri = stream_pnt (s);
1453 mp_withdraw->length = withdraw_len;
1454
paul9985f832005-02-09 15:51:56 +00001455 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001456
1457 return 0;
1458}
1459
1460/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001461static int
paul718e3742002-12-13 20:15:29 +00001462bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1463 struct attr *attr, u_char flag)
1464{
1465 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001466 {
1467 if (attr->extra)
1468 attr->extra->ecommunity = NULL;
1469 }
paul718e3742002-12-13 20:15:29 +00001470 else
1471 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001472 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001473 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001474 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001475 }
1476 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1477
1478 return 0;
1479}
1480
1481/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001482static int
paul718e3742002-12-13 20:15:29 +00001483bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1484 u_char type, bgp_size_t length, u_char *startp)
1485{
1486 bgp_size_t total;
1487 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001488 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001489
hassof4184462005-02-01 20:13:16 +00001490 if (BGP_DEBUG (normal, NORMAL))
1491 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1492 peer->host, type, length);
1493
paul718e3742002-12-13 20:15:29 +00001494 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001495 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001496 "Unknown attribute type %d length %d is received", type, length);
1497
1498 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001499 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001500
1501 /* Adjest total length to include type and length. */
1502 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1503
1504 /* If any of the mandatory well-known attributes are not recognized,
1505 then the Error Subcode is set to Unrecognized Well-known
1506 Attribute. The Data field contains the unrecognized attribute
1507 (type, length and value). */
1508 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1509 {
1510 /* Adjust startp to do not include flag value. */
1511 bgp_notify_send_with_data (peer,
1512 BGP_NOTIFY_UPDATE_ERR,
1513 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1514 startp, total);
1515 return -1;
1516 }
1517
1518 /* Unrecognized non-transitive optional attributes must be quietly
1519 ignored and not passed along to other BGP peers. */
1520 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1521 return 0;
1522
1523 /* If a path with recognized transitive optional attribute is
1524 accepted and passed along to other BGP peers and the Partial bit
1525 in the Attribute Flags octet is set to 1 by some previous AS, it
1526 is not set back to 0 by the current AS. */
1527 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1528
1529 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001530 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001531 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001532
Paul Jakmafb982c22007-05-04 20:15:47 +00001533 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001534
1535 if (transit->val)
1536 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1537 transit->length + total);
1538 else
1539 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1540
1541 memcpy (transit->val + transit->length, startp, total);
1542 transit->length += total;
1543
1544 return 0;
1545}
1546
1547/* Read attribute of update packet. This function is called from
1548 bgp_update() in bgpd.c. */
1549int
1550bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1551 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1552{
1553 int ret;
1554 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001555 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001556 bgp_size_t length;
1557 u_char *startp, *endp;
1558 u_char *attr_endp;
1559 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001560 /* we need the as4_path only until we have synthesized the as_path with it */
1561 /* same goes for as4_aggregator */
1562 struct aspath *as4_path = NULL;
1563 as_t as4_aggregator = 0;
1564 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001565
1566 /* Initialize bitmap. */
1567 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1568
1569 /* End pointer of BGP attribute. */
1570 endp = BGP_INPUT_PNT (peer) + size;
1571
1572 /* Get attributes to the end of attribute length. */
1573 while (BGP_INPUT_PNT (peer) < endp)
1574 {
1575 /* Check remaining length check.*/
1576 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1577 {
gdtc29fdba2004-12-09 14:46:46 +00001578 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001579 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001580 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001581 peer->host,
1582 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001583
1584 bgp_notify_send (peer,
1585 BGP_NOTIFY_UPDATE_ERR,
1586 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1587 return -1;
1588 }
1589
1590 /* Fetch attribute flag and type. */
1591 startp = BGP_INPUT_PNT (peer);
1592 flag = stream_getc (BGP_INPUT (peer));
1593 type = stream_getc (BGP_INPUT (peer));
1594
Paul Jakma370b64a2007-12-22 16:49:52 +00001595 /* Check whether Extended-Length applies and is in bounds */
1596 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1597 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1598 {
1599 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001600 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001601 peer->host,
1602 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1603
1604 bgp_notify_send (peer,
1605 BGP_NOTIFY_UPDATE_ERR,
1606 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1607 return -1;
1608 }
1609
paul718e3742002-12-13 20:15:29 +00001610 /* Check extended attribue length bit. */
1611 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1612 length = stream_getw (BGP_INPUT (peer));
1613 else
1614 length = stream_getc (BGP_INPUT (peer));
1615
1616 /* If any attribute appears more than once in the UPDATE
1617 message, then the Error Subcode is set to Malformed Attribute
1618 List. */
1619
1620 if (CHECK_BITMAP (seen, type))
1621 {
1622 zlog (peer->log, LOG_WARNING,
1623 "%s error BGP attribute type %d appears twice in a message",
1624 peer->host, type);
1625
1626 bgp_notify_send (peer,
1627 BGP_NOTIFY_UPDATE_ERR,
1628 BGP_NOTIFY_UPDATE_MAL_ATTR);
1629 return -1;
1630 }
1631
1632 /* Set type to bitmap to check duplicate attribute. `type' is
1633 unsigned char so it never overflow bitmap range. */
1634
1635 SET_BITMAP (seen, type);
1636
1637 /* Overflow check. */
1638 attr_endp = BGP_INPUT_PNT (peer) + length;
1639
1640 if (attr_endp > endp)
1641 {
1642 zlog (peer->log, LOG_WARNING,
1643 "%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);
1644 bgp_notify_send (peer,
1645 BGP_NOTIFY_UPDATE_ERR,
1646 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1647 return -1;
1648 }
1649
1650 /* OK check attribute and store it's value. */
1651 switch (type)
1652 {
1653 case BGP_ATTR_ORIGIN:
1654 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1655 break;
1656 case BGP_ATTR_AS_PATH:
1657 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1658 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001659 case BGP_ATTR_AS4_PATH:
1660 ret = bgp_attr_as4_path (peer, length, attr, &as4_path );
1661 break;
paul718e3742002-12-13 20:15:29 +00001662 case BGP_ATTR_NEXT_HOP:
1663 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1664 break;
1665 case BGP_ATTR_MULTI_EXIT_DISC:
1666 ret = bgp_attr_med (peer, length, attr, flag, startp);
1667 break;
1668 case BGP_ATTR_LOCAL_PREF:
1669 ret = bgp_attr_local_pref (peer, length, attr, flag);
1670 break;
1671 case BGP_ATTR_ATOMIC_AGGREGATE:
1672 ret = bgp_attr_atomic (peer, length, attr, flag);
1673 break;
1674 case BGP_ATTR_AGGREGATOR:
1675 ret = bgp_attr_aggregator (peer, length, attr, flag);
1676 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001677 case BGP_ATTR_AS4_AGGREGATOR:
1678 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1679 break;
paul718e3742002-12-13 20:15:29 +00001680 case BGP_ATTR_COMMUNITIES:
1681 ret = bgp_attr_community (peer, length, attr, flag);
1682 break;
1683 case BGP_ATTR_ORIGINATOR_ID:
1684 ret = bgp_attr_originator_id (peer, length, attr, flag);
1685 break;
1686 case BGP_ATTR_CLUSTER_LIST:
1687 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1688 break;
1689 case BGP_ATTR_MP_REACH_NLRI:
1690 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1691 break;
1692 case BGP_ATTR_MP_UNREACH_NLRI:
1693 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1694 break;
1695 case BGP_ATTR_EXT_COMMUNITIES:
1696 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1697 break;
Paul Jakma41367172007-08-06 15:24:51 +00001698 case BGP_ATTR_AS_PATHLIMIT:
1699 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1700 break;
paul718e3742002-12-13 20:15:29 +00001701 default:
1702 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1703 break;
1704 }
1705
1706 /* If error occured immediately return to the caller. */
1707 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001708 {
1709 zlog (peer->log, LOG_WARNING,
1710 "%s: Attribute %s, parse error",
1711 peer->host,
1712 LOOKUP (attr_str, type));
1713 bgp_notify_send (peer,
1714 BGP_NOTIFY_UPDATE_ERR,
1715 BGP_NOTIFY_UPDATE_MAL_ATTR);
1716 return ret;
1717 }
paul718e3742002-12-13 20:15:29 +00001718
1719 /* Check the fetched length. */
1720 if (BGP_INPUT_PNT (peer) != attr_endp)
1721 {
1722 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001723 "%s: BGP attribute %s, fetch error",
1724 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001725 bgp_notify_send (peer,
1726 BGP_NOTIFY_UPDATE_ERR,
1727 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1728 return -1;
1729 }
1730 }
1731
1732 /* Check final read pointer is same as end pointer. */
1733 if (BGP_INPUT_PNT (peer) != endp)
1734 {
1735 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001736 "%s BGP attribute %s, length mismatch",
1737 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001738 bgp_notify_send (peer,
1739 BGP_NOTIFY_UPDATE_ERR,
1740 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1741 return -1;
1742 }
1743
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001744 /*
1745 * At this place we can see whether we got AS4_PATH and/or
1746 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1747 * We can not do this before we've read all attributes because
1748 * the as4 handling does not say whether AS4_PATH has to be sent
1749 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1750 * in relationship to AGGREGATOR.
1751 * So, to be defensive, we are not relying on any order and read
1752 * all attributes first, including these 32bit ones, and now,
1753 * afterwards, we look what and if something is to be done for as4.
1754 */
1755 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1756 as4_aggregator, &as4_aggregator_addr))
1757 return -1;
1758
1759 /* At this stage, we have done all fiddling with as4, and the
1760 * resulting info is in attr->aggregator resp. attr->aspath
1761 * so we can chuck as4_aggregator and as4_path alltogether in
1762 * order to save memory
1763 */
1764 if ( as4_path )
1765 {
1766 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1767 as4_path = NULL;
1768 /* The flag that we got this is still there, but that does not
1769 * do any trouble
1770 */
1771 }
1772 /*
1773 * The "rest" of the code does nothing with as4_aggregator.
1774 * there is no memory attached specifically which is not part
1775 * of the attr.
1776 * so ignoring just means do nothing.
1777 */
1778 /*
1779 * Finally do the checks on the aspath we did not do yet
1780 * because we waited for a potentially synthesized aspath.
1781 */
1782 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1783 {
1784 ret = bgp_attr_aspath_check( peer, attr );
1785 if ( ret < 0 )
1786 return ret;
1787 }
1788
paul718e3742002-12-13 20:15:29 +00001789 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001790 if (attr->extra && attr->extra->transit)
1791 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001792
1793 return 0;
1794}
1795
1796/* Well-known attribute check. */
1797int
1798bgp_attr_check (struct peer *peer, struct attr *attr)
1799{
1800 u_char type = 0;
1801
1802 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1803 type = BGP_ATTR_ORIGIN;
1804
1805 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1806 type = BGP_ATTR_AS_PATH;
1807
1808 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1809 type = BGP_ATTR_NEXT_HOP;
1810
1811 if (peer_sort (peer) == BGP_PEER_IBGP
1812 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1813 type = BGP_ATTR_LOCAL_PREF;
1814
1815 if (type)
1816 {
1817 zlog (peer->log, LOG_WARNING,
1818 "%s Missing well-known attribute %d.",
1819 peer->host, type);
1820 bgp_notify_send_with_data (peer,
1821 BGP_NOTIFY_UPDATE_ERR,
1822 BGP_NOTIFY_UPDATE_MISS_ATTR,
1823 &type, 1);
1824 return -1;
1825 }
1826 return 0;
1827}
1828
1829int stream_put_prefix (struct stream *, struct prefix *);
1830
1831/* Make attribute packet. */
1832bgp_size_t
1833bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1834 struct stream *s, struct attr *attr, struct prefix *p,
1835 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001836 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001837{
paulfe69a502005-09-10 16:55:02 +00001838 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001839 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001840 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001841 int send_as4_path = 0;
1842 int send_as4_aggregator = 0;
1843 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001844
1845 if (! bgp)
1846 bgp = bgp_get_default ();
1847
1848 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001849 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001850
1851 /* Origin attribute. */
1852 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1853 stream_putc (s, BGP_ATTR_ORIGIN);
1854 stream_putc (s, 1);
1855 stream_putc (s, attr->origin);
1856
1857 /* AS path attribute. */
1858
1859 /* If remote-peer is EBGP */
1860 if (peer_sort (peer) == BGP_PEER_EBGP
1861 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001862 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001863 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001864 {
1865 aspath = aspath_dup (attr->aspath);
1866
1867 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1868 {
1869 /* Strip the confed info, and then stuff our path CONFED_ID
1870 on the front */
1871 aspath = aspath_delete_confed_seq (aspath);
1872 aspath = aspath_add_seq (aspath, bgp->confed_id);
1873 }
1874 else
1875 {
1876 aspath = aspath_add_seq (aspath, peer->local_as);
1877 if (peer->change_local_as)
1878 aspath = aspath_add_seq (aspath, peer->change_local_as);
1879 }
1880 }
1881 else if (peer_sort (peer) == BGP_PEER_CONFED)
1882 {
1883 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1884 aspath = aspath_dup (attr->aspath);
1885 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1886 }
1887 else
1888 aspath = attr->aspath;
1889
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001890 /* If peer is not AS4 capable, then:
1891 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1892 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1893 * types are in it (i.e. exclude them if they are there)
1894 * AND do this only if there is at least one asnum > 65535 in the path!
1895 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1896 * all ASnums > 65535 to BGP_AS_TRANS
1897 */
paul718e3742002-12-13 20:15:29 +00001898
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001899 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1900 stream_putc (s, BGP_ATTR_AS_PATH);
1901 aspath_sizep = stream_get_endp (s);
1902 stream_putw (s, 0);
1903 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1904
1905 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1906 * in the path
1907 */
1908 if (!use32bit && aspath_has_as4 (aspath))
1909 send_as4_path = 1; /* we'll do this later, at the correct place */
1910
paul718e3742002-12-13 20:15:29 +00001911 /* Nexthop attribute. */
1912 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1913 {
1914 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1915 stream_putc (s, BGP_ATTR_NEXT_HOP);
1916 stream_putc (s, 4);
1917 if (safi == SAFI_MPLS_VPN)
1918 {
1919 if (attr->nexthop.s_addr == 0)
1920 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1921 else
1922 stream_put_ipv4 (s, attr->nexthop.s_addr);
1923 }
1924 else
1925 stream_put_ipv4 (s, attr->nexthop.s_addr);
1926 }
1927
1928 /* MED attribute. */
1929 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1930 {
1931 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1932 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1933 stream_putc (s, 4);
1934 stream_putl (s, attr->med);
1935 }
1936
1937 /* Local preference. */
1938 if (peer_sort (peer) == BGP_PEER_IBGP ||
1939 peer_sort (peer) == BGP_PEER_CONFED)
1940 {
1941 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1942 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1943 stream_putc (s, 4);
1944 stream_putl (s, attr->local_pref);
1945 }
1946
1947 /* Atomic aggregate. */
1948 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1949 {
1950 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1951 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1952 stream_putc (s, 0);
1953 }
1954
1955 /* Aggregator. */
1956 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1957 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001958 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001959
1960 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001961 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1962 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001963
1964 if (use32bit)
1965 {
1966 /* AS4 capable peer */
1967 stream_putc (s, 8);
1968 stream_putl (s, attr->extra->aggregator_as);
1969 }
1970 else
1971 {
1972 /* 2-byte AS peer */
1973 stream_putc (s, 6);
1974
1975 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1976 if ( attr->extra->aggregator_as > 65535 )
1977 {
1978 stream_putw (s, BGP_AS_TRANS);
1979
1980 /* we have to send AS4_AGGREGATOR, too.
1981 * we'll do that later in order to send attributes in ascending
1982 * order.
1983 */
1984 send_as4_aggregator = 1;
1985 }
1986 else
1987 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1988 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001989 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001990 }
1991
1992 /* Community attribute. */
1993 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1994 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1995 {
1996 if (attr->community->size * 4 > 255)
1997 {
1998 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1999 stream_putc (s, BGP_ATTR_COMMUNITIES);
2000 stream_putw (s, attr->community->size * 4);
2001 }
2002 else
2003 {
2004 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2005 stream_putc (s, BGP_ATTR_COMMUNITIES);
2006 stream_putc (s, attr->community->size * 4);
2007 }
2008 stream_put (s, attr->community->val, attr->community->size * 4);
2009 }
2010
2011 /* Route Reflector. */
2012 if (peer_sort (peer) == BGP_PEER_IBGP
2013 && from
2014 && peer_sort (from) == BGP_PEER_IBGP)
2015 {
2016 /* Originator ID. */
2017 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2018 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2019 stream_putc (s, 4);
2020
2021 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002022 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002023 else
2024 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002025
2026 /* Cluster list. */
2027 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2028 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2029
Paul Jakma9eda90c2007-08-30 13:36:17 +00002030 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002031 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002032 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002033 /* 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);
Paul Jakmafb982c22007-05-04 20:15:47 +00002038 stream_put (s, attr->extra->cluster->list,
2039 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002040 }
2041 else
2042 {
2043 stream_putc (s, 4);
2044 /* If this peer configuration's parent BGP has cluster_id. */
2045 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2046 stream_put_in_addr (s, &bgp->cluster_id);
2047 else
2048 stream_put_in_addr (s, &bgp->router_id);
2049 }
2050 }
2051
2052#ifdef HAVE_IPV6
2053 /* If p is IPv6 address put it into attribute. */
2054 if (p->family == AF_INET6)
2055 {
2056 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002057 struct attr_extra *attre = attr->extra;
2058
2059 assert (attr->extra);
2060
paul718e3742002-12-13 20:15:29 +00002061 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2062 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002063 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002064 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002065 stream_putw (s, AFI_IP6); /* AFI */
2066 stream_putc (s, safi); /* SAFI */
2067
Paul Jakmafb982c22007-05-04 20:15:47 +00002068 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002069
Paul Jakmafb982c22007-05-04 20:15:47 +00002070 if (attre->mp_nexthop_len == 16)
2071 stream_put (s, &attre->mp_nexthop_global, 16);
2072 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002073 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002074 stream_put (s, &attre->mp_nexthop_global, 16);
2075 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002076 }
2077
2078 /* SNPA */
2079 stream_putc (s, 0);
2080
paul718e3742002-12-13 20:15:29 +00002081 /* Prefix write. */
2082 stream_put_prefix (s, p);
2083
2084 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002085 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002086 }
2087#endif /* HAVE_IPV6 */
2088
2089 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2090 {
2091 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002092
2093 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2094 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002095 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002096 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002097 stream_putw (s, AFI_IP); /* AFI */
2098 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2099
2100 stream_putc (s, 4);
2101 stream_put_ipv4 (s, attr->nexthop.s_addr);
2102
2103 /* SNPA */
2104 stream_putc (s, 0);
2105
paul718e3742002-12-13 20:15:29 +00002106 /* Prefix write. */
2107 stream_put_prefix (s, p);
2108
2109 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002110 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002111 }
2112
2113 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2114 {
2115 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002116
2117 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2118 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002119 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002120 stream_putc (s, 0); /* Length of this attribute. */
2121 stream_putw (s, AFI_IP); /* AFI */
2122 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2123
2124 stream_putc (s, 12);
2125 stream_putl (s, 0);
2126 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002127 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002128
2129 /* SNPA */
2130 stream_putc (s, 0);
2131
paul718e3742002-12-13 20:15:29 +00002132 /* Tag, RD, Prefix write. */
2133 stream_putc (s, p->prefixlen + 88);
2134 stream_put (s, tag, 3);
2135 stream_put (s, prd->val, 8);
2136 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2137
2138 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002139 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002140 }
2141
2142 /* Extended Communities attribute. */
2143 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2144 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2145 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002146 struct attr_extra *attre = attr->extra;
2147
2148 assert (attre);
2149
2150 if (peer_sort (peer) == BGP_PEER_IBGP
2151 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002152 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002153 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002154 {
2155 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2156 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002157 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002158 }
2159 else
2160 {
2161 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2162 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002163 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002164 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002165 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002166 }
2167 else
2168 {
paul5228ad22004-06-04 17:58:18 +00002169 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002170 int tbit;
2171 int ecom_tr_size = 0;
2172 int i;
2173
Paul Jakmafb982c22007-05-04 20:15:47 +00002174 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002175 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002176 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002177 tbit = *pnt;
2178
2179 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2180 continue;
2181
2182 ecom_tr_size++;
2183 }
2184
2185 if (ecom_tr_size)
2186 {
2187 if (ecom_tr_size * 8 > 255)
2188 {
2189 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2190 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2191 stream_putw (s, ecom_tr_size * 8);
2192 }
2193 else
2194 {
2195 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2196 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2197 stream_putc (s, ecom_tr_size * 8);
2198 }
2199
Paul Jakmafb982c22007-05-04 20:15:47 +00002200 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002201 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002202 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002203 tbit = *pnt;
2204
2205 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2206 continue;
2207
2208 stream_put (s, pnt, 8);
2209 }
2210 }
paul718e3742002-12-13 20:15:29 +00002211 }
paul718e3742002-12-13 20:15:29 +00002212 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002213
2214 if ( send_as4_path )
2215 {
2216 /* If the peer is NOT As4 capable, AND */
2217 /* there are ASnums > 65535 in path THEN
2218 * give out AS4_PATH */
2219
2220 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2221 * path segments!
2222 * Hm, I wonder... confederation things *should* only be at
2223 * the beginning of an aspath, right? Then we should use
2224 * aspath_delete_confed_seq for this, because it is already
2225 * there! (JK)
2226 * Folks, talk to me: what is reasonable here!?
2227 */
2228 aspath = aspath_delete_confed_seq (aspath);
2229
2230 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2231 stream_putc (s, BGP_ATTR_AS4_PATH);
2232 aspath_sizep = stream_get_endp (s);
2233 stream_putw (s, 0);
2234 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2235 }
2236
2237 if (aspath != attr->aspath)
2238 aspath_free (aspath);
2239
2240 if ( send_as4_aggregator )
2241 {
2242 assert (attr->extra);
2243
2244 /* send AS4_AGGREGATOR, at this place */
2245 /* this section of code moved here in order to ensure the correct
2246 * *ascending* order of attributes
2247 */
2248 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2249 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2250 stream_putc (s, 8);
2251 stream_putl (s, attr->extra->aggregator_as);
2252 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2253 }
Paul Jakma41367172007-08-06 15:24:51 +00002254
2255 /* AS-Pathlimit */
2256 if (attr->pathlimit.ttl)
2257 {
2258 u_int32_t as = attr->pathlimit.as;
2259
2260 /* should already have been done in announce_check(),
2261 * but just in case..
2262 */
2263 if (!as)
2264 as = peer->local_as;
2265
2266 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2267 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2268 stream_putc (s, 5);
2269 stream_putc (s, attr->pathlimit.ttl);
2270 stream_putl (s, as);
2271 }
2272
paul718e3742002-12-13 20:15:29 +00002273 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002274 if (attr->extra && attr->extra->transit)
2275 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002276
2277 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002278 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002279}
2280
2281bgp_size_t
2282bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2283 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002284 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002285{
2286 unsigned long cp;
2287 unsigned long attrlen_pnt;
2288 bgp_size_t size;
2289
paul9985f832005-02-09 15:51:56 +00002290 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002291
2292 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2293 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2294
paul9985f832005-02-09 15:51:56 +00002295 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002296 stream_putc (s, 0); /* Length of this attribute. */
2297
2298 stream_putw (s, family2afi (p->family));
2299
2300 if (safi == SAFI_MPLS_VPN)
2301 {
2302 /* SAFI */
2303 stream_putc (s, BGP_SAFI_VPNV4);
2304
2305 /* prefix. */
2306 stream_putc (s, p->prefixlen + 88);
2307 stream_put (s, tag, 3);
2308 stream_put (s, prd->val, 8);
2309 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2310 }
2311 else
2312 {
2313 /* SAFI */
2314 stream_putc (s, safi);
2315
2316 /* prefix */
2317 stream_put_prefix (s, p);
2318 }
2319
2320 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002321 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002322 stream_putc_at (s, attrlen_pnt, size);
2323
paul9985f832005-02-09 15:51:56 +00002324 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002325}
2326
2327/* Initialization of attribute. */
2328void
paulfe69a502005-09-10 16:55:02 +00002329bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002330{
paul718e3742002-12-13 20:15:29 +00002331 aspath_init ();
2332 attrhash_init ();
2333 community_init ();
2334 ecommunity_init ();
2335 cluster_init ();
2336 transit_init ();
2337}
2338
Chris Caputo228da422009-07-18 05:44:03 +00002339void
2340bgp_attr_finish (void)
2341{
2342 aspath_finish ();
2343 attrhash_finish ();
2344 community_finish ();
2345 ecommunity_finish ();
2346 cluster_finish ();
2347 transit_finish ();
2348}
2349
paul718e3742002-12-13 20:15:29 +00002350/* Make attribute packet. */
2351void
paula3845922003-10-18 01:30:50 +00002352bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2353 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002354{
2355 unsigned long cp;
2356 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002357 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002358 struct aspath *aspath;
2359
2360 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002361 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002362
2363 /* Place holder of length. */
2364 stream_putw (s, 0);
2365
2366 /* Origin attribute. */
2367 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2368 stream_putc (s, BGP_ATTR_ORIGIN);
2369 stream_putc (s, 1);
2370 stream_putc (s, attr->origin);
2371
2372 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002373
2374 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2375 stream_putc (s, BGP_ATTR_AS_PATH);
2376 aspath_lenp = stream_get_endp (s);
2377 stream_putw (s, 0);
2378
2379 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002380
2381 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002382 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2383 if(prefix != NULL
2384#ifdef HAVE_IPV6
2385 && prefix->family != AF_INET6
2386#endif /* HAVE_IPV6 */
2387 )
2388 {
2389 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2390 stream_putc (s, BGP_ATTR_NEXT_HOP);
2391 stream_putc (s, 4);
2392 stream_put_ipv4 (s, attr->nexthop.s_addr);
2393 }
paul718e3742002-12-13 20:15:29 +00002394
2395 /* MED attribute. */
2396 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2397 {
2398 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2399 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2400 stream_putc (s, 4);
2401 stream_putl (s, attr->med);
2402 }
2403
2404 /* Local preference. */
2405 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2406 {
2407 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2408 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2409 stream_putc (s, 4);
2410 stream_putl (s, attr->local_pref);
2411 }
2412
2413 /* Atomic aggregate. */
2414 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2415 {
2416 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2417 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2418 stream_putc (s, 0);
2419 }
2420
2421 /* Aggregator. */
2422 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2423 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002424 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002425 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2426 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002427 stream_putc (s, 8);
2428 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002429 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002430 }
2431
2432 /* Community attribute. */
2433 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2434 {
2435 if (attr->community->size * 4 > 255)
2436 {
2437 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2438 stream_putc (s, BGP_ATTR_COMMUNITIES);
2439 stream_putw (s, attr->community->size * 4);
2440 }
2441 else
2442 {
2443 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2444 stream_putc (s, BGP_ATTR_COMMUNITIES);
2445 stream_putc (s, attr->community->size * 4);
2446 }
2447 stream_put (s, attr->community->val, attr->community->size * 4);
2448 }
2449
paula3845922003-10-18 01:30:50 +00002450#ifdef HAVE_IPV6
2451 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002452 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2453 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002454 {
2455 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002456 struct attr_extra *attre = attr->extra;
2457
paula3845922003-10-18 01:30:50 +00002458 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2459 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002460 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002461
2462 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002463 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002464 stream_putw(s, AFI_IP6); /* AFI */
2465 stream_putc(s, SAFI_UNICAST); /* SAFI */
2466
2467 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002468 stream_putc(s, attre->mp_nexthop_len);
2469 stream_put(s, &attre->mp_nexthop_global, 16);
2470 if (attre->mp_nexthop_len == 32)
2471 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002472
2473 /* SNPA */
2474 stream_putc(s, 0);
2475
2476 /* Prefix */
2477 stream_put_prefix(s, prefix);
2478
2479 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002480 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002481 }
2482#endif /* HAVE_IPV6 */
2483
Paul Jakma41367172007-08-06 15:24:51 +00002484 /* AS-Pathlimit */
2485 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2486 {
2487 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2488 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2489 stream_putc (s, 5);
2490 stream_putc (s, attr->pathlimit.ttl);
2491 stream_putl (s, attr->pathlimit.as);
2492 }
2493
paul718e3742002-12-13 20:15:29 +00002494 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002495 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002496 stream_putw_at (s, cp, len);
2497}