blob: dd3cc965a907902db2b0d12533afee45e60555cf [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. */
Paul Jakma6e4ab122007-04-10 19:36:48 +000042static 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 { 0, NULL }
64};
Paul Jakma6e4ab122007-04-10 19:36:48 +000065int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000066
67struct hash *cluster_hash;
68
paul94f2b392005-06-28 12:44:16 +000069static void *
Paul Jakma923de652007-04-29 18:25:17 +000070cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000071{
Paul Jakma923de652007-04-29 18:25:17 +000072 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000073 struct cluster_list *cluster;
74
75 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
76 cluster->length = val->length;
77
78 if (cluster->length)
79 {
80 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
81 memcpy (cluster->list, val->list, val->length);
82 }
83 else
84 cluster->list = NULL;
85
86 cluster->refcnt = 0;
87
88 return cluster;
89}
90
91/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000092static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000093cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000094{
95 struct cluster_list tmp;
96 struct cluster_list *cluster;
97
98 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000099 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +0000100
101 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
102 cluster->refcnt++;
103 return cluster;
104}
105
106int
107cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
108{
109 int i;
110
111 for (i = 0; i < cluster->length / 4; i++)
112 if (cluster->list[i].s_addr == originator.s_addr)
113 return 1;
114 return 0;
115}
116
paul94f2b392005-06-28 12:44:16 +0000117static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000118cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000119{
Paul Jakma923de652007-04-29 18:25:17 +0000120 struct cluster_list * cluster = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +0000121 unsigned int key = 0;
122 int length;
123 caddr_t pnt;
124
125 length = cluster->length;
126 pnt = (caddr_t) cluster->list;
127
128 while (length)
129 key += pnt[--length];
130
131 return key;
132}
133
paul94f2b392005-06-28 12:44:16 +0000134static int
Paul Jakma923de652007-04-29 18:25:17 +0000135cluster_hash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000136{
Paul Jakma923de652007-04-29 18:25:17 +0000137 struct cluster_list * cluster1 = (struct cluster_list *) p1;
138 struct cluster_list * cluster2 = (struct cluster_list *) p2;
139
paul718e3742002-12-13 20:15:29 +0000140 if (cluster1->length == cluster2->length &&
141 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0)
142 return 1;
143 return 0;
144}
145
paul94f2b392005-06-28 12:44:16 +0000146static void
paul718e3742002-12-13 20:15:29 +0000147cluster_free (struct cluster_list *cluster)
148{
149 if (cluster->list)
150 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
151 XFREE (MTYPE_CLUSTER, cluster);
152}
153
paul94f2b392005-06-28 12:44:16 +0000154static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000155cluster_dup (struct cluster_list *cluster)
156{
157 struct cluster_list *new;
158
159 new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
160 memset (new, 0, sizeof (struct cluster_list));
161 new->length = cluster->length;
162
163 if (cluster->length)
164 {
165 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
166 memcpy (new->list, cluster->list, cluster->length);
167 }
168 else
169 new->list = NULL;
170
171 return new;
172}
173
paul94f2b392005-06-28 12:44:16 +0000174static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000175cluster_intern (struct cluster_list *cluster)
176{
177 struct cluster_list *find;
178
179 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
180 find->refcnt++;
181
182 return find;
183}
184
185void
186cluster_unintern (struct cluster_list *cluster)
187{
188 struct cluster_list *ret;
189
190 if (cluster->refcnt)
191 cluster->refcnt--;
192
193 if (cluster->refcnt == 0)
194 {
195 ret = hash_release (cluster_hash, cluster);
196 cluster_free (cluster);
197 }
198}
199
paul94f2b392005-06-28 12:44:16 +0000200static void
201cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000202{
203 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
204}
205
206/* Unknown transit attribute. */
207struct hash *transit_hash;
208
paul94f2b392005-06-28 12:44:16 +0000209static void
paul718e3742002-12-13 20:15:29 +0000210transit_free (struct transit *transit)
211{
212 if (transit->val)
213 XFREE (MTYPE_TRANSIT_VAL, transit->val);
214 XFREE (MTYPE_TRANSIT, transit);
215}
216
Paul Jakma923de652007-04-29 18:25:17 +0000217
paul94f2b392005-06-28 12:44:16 +0000218static void *
Paul Jakma923de652007-04-29 18:25:17 +0000219transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000220{
221 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000222 return p;
paul718e3742002-12-13 20:15:29 +0000223}
224
paul94f2b392005-06-28 12:44:16 +0000225static struct transit *
paul718e3742002-12-13 20:15:29 +0000226transit_intern (struct transit *transit)
227{
228 struct transit *find;
229
230 find = hash_get (transit_hash, transit, transit_hash_alloc);
231 if (find != transit)
232 transit_free (transit);
233 find->refcnt++;
234
235 return find;
236}
237
238void
239transit_unintern (struct transit *transit)
240{
241 struct transit *ret;
242
243 if (transit->refcnt)
244 transit->refcnt--;
245
246 if (transit->refcnt == 0)
247 {
248 ret = hash_release (transit_hash, transit);
249 transit_free (transit);
250 }
251}
252
paul94f2b392005-06-28 12:44:16 +0000253static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000254transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000255{
Paul Jakma923de652007-04-29 18:25:17 +0000256 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000257 unsigned int key = 0;
258 int length;
259 caddr_t pnt;
260
261 length = transit->length;
262 pnt = (caddr_t) transit->val;
263
264 while (length)
265 key += pnt[--length];
266
267 return key;
268}
269
paul94f2b392005-06-28 12:44:16 +0000270static int
Paul Jakma923de652007-04-29 18:25:17 +0000271transit_hash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000272{
Paul Jakma923de652007-04-29 18:25:17 +0000273 struct transit * transit1 = (struct transit *) p1;
274 struct transit * transit2 = (struct transit *) p2;
275
paul718e3742002-12-13 20:15:29 +0000276 if (transit1->length == transit2->length &&
277 memcmp (transit1->val, transit2->val, transit1->length) == 0)
278 return 1;
279 return 0;
280}
281
paul94f2b392005-06-28 12:44:16 +0000282static void
paul718e3742002-12-13 20:15:29 +0000283transit_init ()
284{
285 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
286}
287
288/* Attribute hash routines. */
paul718e3742002-12-13 20:15:29 +0000289struct hash *attrhash;
290
Paul Jakmafb982c22007-05-04 20:15:47 +0000291static struct attr_extra *
292bgp_attr_extra_new (void)
293{
294 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
295}
296
297void
298bgp_attr_extra_free (struct attr *attr)
299{
300 if (attr->extra)
301 {
302 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
303 attr->extra = NULL;
304 }
305}
306
307struct attr_extra *
308bgp_attr_extra_get (struct attr *attr)
309{
310 if (!attr->extra)
311 attr->extra = bgp_attr_extra_new();
312 return attr->extra;
313}
314
315/* Shallow copy of an attribute
316 * Though, not so shallow that it doesn't copy the contents
317 * of the attr_extra pointed to by 'extra'
318 */
319void
320bgp_attr_dup (struct attr *new, struct attr *orig)
321{
322 *new = *orig;
323 if (orig->extra)
324 {
325 new->extra = bgp_attr_extra_new();
326 *new->extra = *orig->extra;
327 }
328}
329
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000330unsigned long int
331attr_count (void)
332{
333 return attrhash->count;
334}
335
336unsigned long int
337attr_unknown_count (void)
338{
339 return transit_hash->count;
340}
341
paul718e3742002-12-13 20:15:29 +0000342unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000343attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000344{
Paul Jakma923de652007-04-29 18:25:17 +0000345 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000346 unsigned int key = 0;
347
348 key += attr->origin;
349 key += attr->nexthop.s_addr;
350 key += attr->med;
351 key += attr->local_pref;
Paul Jakma41367172007-08-06 15:24:51 +0000352 if (attr->pathlimit.as)
353 {
354 key += attr->pathlimit.ttl;
355 key += attr->pathlimit.as;
356 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000357
358 if (attr->extra)
359 {
360 key += attr->extra->aggregator_as;
361 key += attr->extra->aggregator_addr.s_addr;
362 key += attr->extra->weight;
363 key += attr->extra->mp_nexthop_global_in.s_addr;
364 }
365
paul718e3742002-12-13 20:15:29 +0000366 if (attr->aspath)
367 key += aspath_key_make (attr->aspath);
368 if (attr->community)
369 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000370
371 if (attr->extra)
372 {
373 if (attr->extra->ecommunity)
374 key += ecommunity_hash_make (attr->extra->ecommunity);
375 if (attr->extra->cluster)
376 key += cluster_hash_key_make (attr->extra->cluster);
377 if (attr->extra->transit)
378 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000379
380#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000381 {
382 int i;
383
384 key += attr->extra->mp_nexthop_len;
385 for (i = 0; i < 16; i++)
386 key += attr->extra->mp_nexthop_global.s6_addr[i];
387 for (i = 0; i < 16; i++)
388 key += attr->extra->mp_nexthop_local.s6_addr[i];
389 }
paul718e3742002-12-13 20:15:29 +0000390#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000391 }
paul718e3742002-12-13 20:15:29 +0000392
393 return key;
394}
395
396int
Paul Jakma923de652007-04-29 18:25:17 +0000397attrhash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000398{
Paul Jakma923de652007-04-29 18:25:17 +0000399 struct attr * attr1 = (struct attr *) p1;
400 struct attr * attr2 = (struct attr *) p2;
401
paul718e3742002-12-13 20:15:29 +0000402 if (attr1->flag == attr2->flag
403 && attr1->origin == attr2->origin
404 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000405 && attr1->aspath == attr2->aspath
406 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000407 && attr1->med == attr2->med
Paul Jakma41367172007-08-06 15:24:51 +0000408 && attr1->local_pref == attr2->local_pref
409 && attr1->pathlimit.ttl == attr2->pathlimit.ttl
410 && attr1->pathlimit.as == attr2->pathlimit.as)
Paul Jakmafb982c22007-05-04 20:15:47 +0000411 {
412 struct attr_extra *ae1 = attr1->extra;
413 struct attr_extra *ae2 = attr2->extra;
414
415 if (ae1 && ae2
416 && ae1->aggregator_as == ae2->aggregator_as
417 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
418 && ae1->weight == ae2->weight
419#ifdef HAVE_IPV6
420 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
421 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
422 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
423#endif /* HAVE_IPV6 */
424 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
425 && ae1->ecommunity == ae2->ecommunity
426 && ae1->cluster == ae2->cluster
427 && ae1->transit == ae2->transit)
428 return 1;
429 else if (ae1 || ae2)
430 return 0;
431 /* neither attribute has extra attributes, so they're same */
432 return 1;
433 }
paul718e3742002-12-13 20:15:29 +0000434 else
435 return 0;
436}
437
paul94f2b392005-06-28 12:44:16 +0000438static void
paul718e3742002-12-13 20:15:29 +0000439attrhash_init ()
440{
441 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
442}
443
paul94f2b392005-06-28 12:44:16 +0000444static void
paul718e3742002-12-13 20:15:29 +0000445attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
446{
447 struct attr *attr = backet->data;
448
449 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
450 inet_ntoa (attr->nexthop), VTY_NEWLINE);
451}
452
453void
454attr_show_all (struct vty *vty)
455{
456 hash_iterate (attrhash,
457 (void (*)(struct hash_backet *, void *))
458 attr_show_all_iterator,
459 vty);
460}
461
paul94f2b392005-06-28 12:44:16 +0000462static void *
Paul Jakma923de652007-04-29 18:25:17 +0000463bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000464{
Paul Jakma923de652007-04-29 18:25:17 +0000465 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000466 struct attr *attr;
467
468 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
469 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000470 if (val->extra)
471 {
472 attr->extra = bgp_attr_extra_new ();
473 *attr->extra = *val->extra;
474 }
paul718e3742002-12-13 20:15:29 +0000475 attr->refcnt = 0;
476 return attr;
477}
478
479/* Internet argument attribute. */
480struct attr *
481bgp_attr_intern (struct attr *attr)
482{
483 struct attr *find;
484
485 /* Intern referenced strucutre. */
486 if (attr->aspath)
487 {
488 if (! attr->aspath->refcnt)
489 attr->aspath = aspath_intern (attr->aspath);
490 else
491 attr->aspath->refcnt++;
492 }
493 if (attr->community)
494 {
495 if (! attr->community->refcnt)
496 attr->community = community_intern (attr->community);
497 else
498 attr->community->refcnt++;
499 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000500 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000501 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000502 struct attr_extra *attre = attr->extra;
503
504 if (attre->ecommunity)
505 {
506 if (! attre->ecommunity->refcnt)
507 attre->ecommunity = ecommunity_intern (attre->ecommunity);
508 else
509 attre->ecommunity->refcnt++;
510 }
511 if (attre->cluster)
512 {
513 if (! attre->cluster->refcnt)
514 attre->cluster = cluster_intern (attre->cluster);
515 else
516 attre->cluster->refcnt++;
517 }
518 if (attre->transit)
519 {
520 if (! attre->transit->refcnt)
521 attre->transit = transit_intern (attre->transit);
522 else
523 attre->transit->refcnt++;
524 }
paul718e3742002-12-13 20:15:29 +0000525 }
526
527 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
528 find->refcnt++;
529
530 return find;
531}
532
Paul Jakma03e214c2007-04-29 18:31:07 +0000533
paul718e3742002-12-13 20:15:29 +0000534/* Make network statement's attribute. */
535struct attr *
536bgp_attr_default_set (struct attr *attr, u_char origin)
537{
538 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000539 bgp_attr_extra_get (attr);
540
paul718e3742002-12-13 20:15:29 +0000541 attr->origin = origin;
542 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
543 attr->aspath = aspath_empty ();
544 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000545 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000546 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
547#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000548 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000549#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000550
paul718e3742002-12-13 20:15:29 +0000551 return attr;
552}
553
Paul Jakma03e214c2007-04-29 18:31:07 +0000554
paul718e3742002-12-13 20:15:29 +0000555/* Make network statement's attribute. */
556struct attr *
557bgp_attr_default_intern (u_char origin)
558{
559 struct attr attr;
560 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000561 struct attr_extra *attre;
562
563 memset (&attr, 0, sizeof (struct attr));
564 attre = bgp_attr_extra_get (&attr);
565
Paul Jakma03e214c2007-04-29 18:31:07 +0000566 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000567
568 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000569 bgp_attr_extra_free (&attr);
570
paul718e3742002-12-13 20:15:29 +0000571 aspath_unintern (new->aspath);
572 return new;
573}
574
575struct attr *
576bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
577 struct aspath *aspath,
578 struct community *community, int as_set)
579{
580 struct attr attr;
581 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000582 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000583
584 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000585 attre = bgp_attr_extra_get (&attr);
586
paul718e3742002-12-13 20:15:29 +0000587 /* Origin attribute. */
588 attr.origin = origin;
589 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
590
591 /* AS path attribute. */
592 if (aspath)
593 attr.aspath = aspath_intern (aspath);
594 else
595 attr.aspath = aspath_empty ();
596 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
597
598 /* Next hop attribute. */
599 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
600
601 if (community)
602 {
603 attr.community = community;
604 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
605 }
606
Paul Jakmafb982c22007-05-04 20:15:47 +0000607 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000608#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000609 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000610#endif
611 if (! as_set)
612 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
613 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
614 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000615 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000616 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000617 attre->aggregator_as = bgp->as;
618 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000619
620 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000621 bgp_attr_extra_free (&attr);
622
paul718e3742002-12-13 20:15:29 +0000623 aspath_unintern (new->aspath);
624 return new;
625}
626
627/* Free bgp attribute and aspath. */
628void
629bgp_attr_unintern (struct attr *attr)
630{
631 struct attr *ret;
632 struct aspath *aspath;
633 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000634 struct ecommunity *ecommunity = NULL;
635 struct cluster_list *cluster = NULL;
636 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000637
638 /* Decrement attribute reference. */
639 attr->refcnt--;
640 aspath = attr->aspath;
641 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000642 if (attr->extra)
643 {
644 ecommunity = attr->extra->ecommunity;
645 cluster = attr->extra->cluster;
646 transit = attr->extra->transit;
647 }
paul718e3742002-12-13 20:15:29 +0000648
649 /* If reference becomes zero then free attribute object. */
650 if (attr->refcnt == 0)
651 {
652 ret = hash_release (attrhash, attr);
653 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000654 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000655 XFREE (MTYPE_ATTR, attr);
656 }
657
658 /* aspath refcount shoud be decrement. */
659 if (aspath)
660 aspath_unintern (aspath);
661 if (community)
662 community_unintern (community);
663 if (ecommunity)
664 ecommunity_unintern (ecommunity);
665 if (cluster)
666 cluster_unintern (cluster);
667 if (transit)
668 transit_unintern (transit);
669}
670
671void
672bgp_attr_flush (struct attr *attr)
673{
674 if (attr->aspath && ! attr->aspath->refcnt)
675 aspath_free (attr->aspath);
676 if (attr->community && ! attr->community->refcnt)
677 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000678 if (attr->extra)
679 {
680 struct attr_extra *attre = attr->extra;
681 if (attre->ecommunity && ! attre->ecommunity->refcnt)
682 ecommunity_free (attre->ecommunity);
683 if (attre->cluster && ! attre->cluster->refcnt)
684 cluster_free (attre->cluster);
685 if (attre->transit && ! attre->transit->refcnt)
686 transit_free (attre->transit);
687 }
paul718e3742002-12-13 20:15:29 +0000688}
689
Paul Jakma41367172007-08-06 15:24:51 +0000690/* Parse AS_PATHLIMIT attribute in an UPDATE */
691static int
692bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
693 struct attr *attr, u_char flag, u_char *startp)
694{
695 bgp_size_t total;
696
697 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
698
699 if (flag != (BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL))
700 {
701 zlog (peer->log, LOG_ERR,
702 "AS-Pathlimit attribute flag isn't transitive %d", flag);
703 bgp_notify_send_with_data (peer,
704 BGP_NOTIFY_UPDATE_ERR,
705 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
706 startp, total);
707 return -1;
708 }
709
710 if (length != 5)
711 {
712 zlog (peer->log, LOG_ERR,
713 "AS-Pathlimit length, %u, is not 5", length);
714 bgp_notify_send_with_data (peer,
715 BGP_NOTIFY_UPDATE_ERR,
716 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
717 startp, total);
718 return -1;
719 }
720
721 attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer));
722 attr->pathlimit.as = stream_getl (BGP_INPUT(peer));
723 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
724 return 0;
725}
paul718e3742002-12-13 20:15:29 +0000726/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000727static int
paul718e3742002-12-13 20:15:29 +0000728bgp_attr_origin (struct peer *peer, bgp_size_t length,
729 struct attr *attr, u_char flag, u_char *startp)
730{
731 bgp_size_t total;
732
733 /* total is entire attribute length include Attribute Flags (1),
734 Attribute Type code (1) and Attribute length (1 or 2). */
735 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
736
737 /* If any recognized attribute has Attribute Flags that conflict
738 with the Attribute Type Code, then the Error Subcode is set to
739 Attribute Flags Error. The Data field contains the erroneous
740 attribute (type, length and value). */
741 if (flag != BGP_ATTR_FLAG_TRANS)
742 {
743 zlog (peer->log, LOG_ERR,
744 "Origin attribute flag isn't transitive %d", flag);
745 bgp_notify_send_with_data (peer,
746 BGP_NOTIFY_UPDATE_ERR,
747 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
748 startp, total);
749 return -1;
750 }
751
752 /* If any recognized attribute has Attribute Length that conflicts
753 with the expected length (based on the attribute type code), then
754 the Error Subcode is set to Attribute Length Error. The Data
755 field contains the erroneous attribute (type, length and
756 value). */
757 if (length != 1)
758 {
759 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
760 length);
761 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
762 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
763 startp, total);
764 return -1;
765 }
766
767 /* Fetch origin attribute. */
768 attr->origin = stream_getc (BGP_INPUT (peer));
769
770 /* If the ORIGIN attribute has an undefined value, then the Error
771 Subcode is set to Invalid Origin Attribute. The Data field
772 contains the unrecognized attribute (type, length and value). */
773 if ((attr->origin != BGP_ORIGIN_IGP)
774 && (attr->origin != BGP_ORIGIN_EGP)
775 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
776 {
777 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
778 attr->origin);
779
780 bgp_notify_send_with_data (peer,
781 BGP_NOTIFY_UPDATE_ERR,
782 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
783 startp, total);
784 return -1;
785 }
786
787 /* Set oring attribute flag. */
788 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
789
790 return 0;
791}
792
793/* Parse AS path information. This function is wrapper of
794 aspath_parse. */
paul94f2b392005-06-28 12:44:16 +0000795static int
paul718e3742002-12-13 20:15:29 +0000796bgp_attr_aspath (struct peer *peer, bgp_size_t length,
797 struct attr *attr, u_char flag, u_char *startp)
798{
paul718e3742002-12-13 20:15:29 +0000799 bgp_size_t total;
800
801 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
802
803 /* Flag check. */
804 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
805 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
806 {
807 zlog (peer->log, LOG_ERR,
808 "Origin attribute flag isn't transitive %d", flag);
809 bgp_notify_send_with_data (peer,
810 BGP_NOTIFY_UPDATE_ERR,
811 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
812 startp, total);
813 return -1;
814 }
815
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000816 /*
817 * peer with AS4 => will get 4Byte ASnums
818 * otherwise, will get 16 Bit
819 */
820 attr->aspath = aspath_parse (peer->ibuf, length,
821 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
822
paul718e3742002-12-13 20:15:29 +0000823 /* In case of IBGP, length will be zero. */
paul718e3742002-12-13 20:15:29 +0000824 if (! attr->aspath)
825 {
826 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
827 bgp_notify_send (peer,
828 BGP_NOTIFY_UPDATE_ERR,
829 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
830 return -1;
831 }
832
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000833 /* Forward pointer. */
834/* stream_forward_getp (peer->ibuf, length);*/
835
836 /* Set aspath attribute flag. */
837 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
838
839 return 0;
840}
841
842static int bgp_attr_aspath_check( struct peer *peer,
843 struct attr *attr)
844{
845 /* These checks were part of bgp_attr_aspath, but with
846 * as4 we should to check aspath things when
847 * aspath synthesizing with as4_path has already taken place.
848 * Otherwise we check ASPATH and use the synthesized thing, and that is
849 * not right.
850 * So do the checks later, i.e. here
851 */
852 struct bgp *bgp = peer->bgp;
853 struct aspath *aspath;
854
paul718e3742002-12-13 20:15:29 +0000855 bgp = peer->bgp;
856
857 /* First AS check for EBGP. */
858 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
859 {
860 if (peer_sort (peer) == BGP_PEER_EBGP
861 && ! aspath_firstas_check (attr->aspath, peer->as))
862 {
863 zlog (peer->log, LOG_ERR,
864 "%s incorrect first AS (must be %d)", peer->host, peer->as);
865 bgp_notify_send (peer,
866 BGP_NOTIFY_UPDATE_ERR,
867 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
868 return -1;
869 }
870 }
871
872 /* local-as prepend */
873 if (peer->change_local_as &&
874 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
875 {
876 aspath = aspath_dup (attr->aspath);
877 aspath = aspath_add_seq (aspath, peer->change_local_as);
878 aspath_unintern (attr->aspath);
879 attr->aspath = aspath_intern (aspath);
880 }
881
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000882 return 0;
883
884}
885
886/* Parse AS4 path information. This function is another wrapper of
887 aspath_parse. */
888static int
889bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
890 struct attr *attr, struct aspath **as4_path)
891{
892 *as4_path = aspath_parse (peer->ibuf, length, 1);
paul718e3742002-12-13 20:15:29 +0000893
894 /* Set aspath attribute flag. */
Paul Jakma370b64a2007-12-22 16:49:52 +0000895 if (as4_path)
896 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
paul718e3742002-12-13 20:15:29 +0000897
898 return 0;
899}
900
901/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000902static int
paul718e3742002-12-13 20:15:29 +0000903bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
904 struct attr *attr, u_char flag, u_char *startp)
905{
906 bgp_size_t total;
907
908 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
909
910 /* Flag check. */
911 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
912 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
913 {
914 zlog (peer->log, LOG_ERR,
915 "Origin attribute flag isn't transitive %d", flag);
916 bgp_notify_send_with_data (peer,
917 BGP_NOTIFY_UPDATE_ERR,
918 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
919 startp, total);
920 return -1;
921 }
922
923 /* Check nexthop attribute length. */
924 if (length != 4)
925 {
926 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
927 length);
928
929 bgp_notify_send_with_data (peer,
930 BGP_NOTIFY_UPDATE_ERR,
931 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
932 startp, total);
933 return -1;
934 }
935
936 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
937 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
938
939 return 0;
940}
941
942/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000943static int
paul718e3742002-12-13 20:15:29 +0000944bgp_attr_med (struct peer *peer, bgp_size_t length,
945 struct attr *attr, u_char flag, u_char *startp)
946{
947 bgp_size_t total;
948
949 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
950
951 /* Length check. */
952 if (length != 4)
953 {
954 zlog (peer->log, LOG_ERR,
955 "MED attribute length isn't four [%d]", length);
956
957 bgp_notify_send_with_data (peer,
958 BGP_NOTIFY_UPDATE_ERR,
959 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
960 startp, total);
961 return -1;
962 }
963
964 attr->med = stream_getl (peer->ibuf);
965
966 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
967
968 return 0;
969}
970
971/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000972static int
paul718e3742002-12-13 20:15:29 +0000973bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
974 struct attr *attr, u_char flag)
975{
976 /* If it is contained in an UPDATE message that is received from an
977 external peer, then this attribute MUST be ignored by the
978 receiving speaker. */
979 if (peer_sort (peer) == BGP_PEER_EBGP)
980 {
paul9985f832005-02-09 15:51:56 +0000981 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000982 return 0;
983 }
984
985 if (length == 4)
986 attr->local_pref = stream_getl (peer->ibuf);
987 else
988 attr->local_pref = 0;
989
990 /* Set atomic aggregate flag. */
991 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
992
993 return 0;
994}
995
996/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000997static int
paul718e3742002-12-13 20:15:29 +0000998bgp_attr_atomic (struct peer *peer, bgp_size_t length,
999 struct attr *attr, u_char flag)
1000{
1001 if (length != 0)
1002 {
1003 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1004
1005 bgp_notify_send (peer,
1006 BGP_NOTIFY_UPDATE_ERR,
1007 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1008 return -1;
1009 }
1010
1011 /* Set atomic aggregate flag. */
1012 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1013
1014 return 0;
1015}
1016
1017/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001018static int
paul718e3742002-12-13 20:15:29 +00001019bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1020 struct attr *attr, u_char flag)
1021{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001022 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001023 struct attr_extra *attre = bgp_attr_extra_get (attr);
1024
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001025 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1026 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1027 wantedlen = 8;
1028
1029 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001030 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001031 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001032
1033 bgp_notify_send (peer,
1034 BGP_NOTIFY_UPDATE_ERR,
1035 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1036 return -1;
1037 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001038
1039 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1040 attre->aggregator_as = stream_getl (peer->ibuf);
1041 else
1042 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001043 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001044
1045 /* Set atomic aggregate flag. */
1046 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1047
1048 return 0;
1049}
1050
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001051/* New Aggregator attribute */
1052static int
1053bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1054 struct attr *attr, as_t *as4_aggregator_as,
1055 struct in_addr *as4_aggregator_addr)
1056{
1057 if (length != 8)
1058 {
1059 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1060
1061 bgp_notify_send (peer,
1062 BGP_NOTIFY_UPDATE_ERR,
1063 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1064 return -1;
1065 }
1066 *as4_aggregator_as = stream_getl (peer->ibuf);
1067 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1068
1069 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1070
1071 return 0;
1072}
1073
1074/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1075 */
1076static int
1077bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1078 struct aspath *as4_path, as_t as4_aggregator,
1079 struct in_addr *as4_aggregator_addr)
1080{
1081 int ignore_as4_path = 0;
1082 struct aspath *newpath;
1083 struct attr_extra *attre = attr->extra;
1084
1085 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1086 {
1087 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1088 * if given.
1089 * It is worth a warning though, because the peer really
1090 * should not send them
1091 */
1092 if (BGP_DEBUG(as4, AS4))
1093 {
1094 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1095 zlog_debug ("[AS4] %s %s AS4_PATH",
1096 peer->host, "AS4 capable peer, yet it sent");
1097
1098 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1099 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1100 peer->host, "AS4 capable peer, yet it sent");
1101 }
1102
1103 return 0;
1104 }
1105
1106 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1107 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1108 {
1109 /* Hu? This is not supposed to happen at all!
1110 * got as4_path and no aspath,
1111 * This should already
1112 * have been handled by 'well known attributes missing'
1113 * But... yeah, paranoia
1114 * Take this as a "malformed attribute"
1115 */
1116 zlog (peer->log, LOG_ERR,
1117 "%s BGP not AS4 capable peer sent AS4_PATH but"
1118 " no AS_PATH, cant do anything here", peer->host);
1119 bgp_notify_send (peer,
1120 BGP_NOTIFY_UPDATE_ERR,
1121 BGP_NOTIFY_UPDATE_MAL_ATTR);
1122 return -1;
1123 }
1124
1125 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1126 * because that may override AS4_PATH
1127 */
1128 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1129 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001130 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1131 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001132 assert (attre);
1133
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001134 /* received both.
1135 * if the as_number in aggregator is not AS_TRANS,
1136 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1137 * and the Aggregator shall be taken as
1138 * info on the aggregating node, and the AS_PATH
1139 * shall be taken as the AS_PATH
1140 * otherwise
1141 * the Aggregator shall be ignored and the
1142 * AS4_AGGREGATOR shall be taken as the
1143 * Aggregating node and the AS_PATH is to be
1144 * constructed "as in all other cases"
1145 */
1146 if ( attre->aggregator_as != BGP_AS_TRANS )
1147 {
1148 /* ignore */
1149 if ( BGP_DEBUG(as4, AS4))
1150 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1151 " send AGGREGATOR != AS_TRANS and"
1152 " AS4_AGGREGATOR, so ignore"
1153 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1154 ignore_as4_path = 1;
1155 }
1156 else
1157 {
1158 /* "New_aggregator shall be taken as aggregator" */
1159 attre->aggregator_as = as4_aggregator;
1160 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1161 }
1162 }
1163 else
1164 {
1165 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1166 * That is bogus - but reading the conditions
1167 * we have to handle AS4_AGGREGATOR as if it were
1168 * AGGREGATOR in that case
1169 */
1170 if ( BGP_DEBUG(as4, AS4))
1171 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1172 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1173 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001174 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001175 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1176 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1177 }
1178 }
1179
1180 /* need to reconcile NEW_AS_PATH and AS_PATH */
1181 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1182 {
1183 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1184 aspath_unintern (attr->aspath);
1185 attr->aspath = aspath_intern (newpath);
1186 }
1187 return 0;
1188}
1189
paul718e3742002-12-13 20:15:29 +00001190/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001191static int
paul718e3742002-12-13 20:15:29 +00001192bgp_attr_community (struct peer *peer, bgp_size_t length,
1193 struct attr *attr, u_char flag)
1194{
1195 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001196 {
1197 attr->community = NULL;
1198 return 0;
1199 }
paul718e3742002-12-13 20:15:29 +00001200 else
1201 {
paul5228ad22004-06-04 17:58:18 +00001202 attr->community =
1203 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001204 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001205 }
1206
1207 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1208
1209 return 0;
1210}
1211
1212/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001213static int
paul718e3742002-12-13 20:15:29 +00001214bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1215 struct attr *attr, u_char flag)
1216{
1217 if (length != 4)
1218 {
1219 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1220
1221 bgp_notify_send (peer,
1222 BGP_NOTIFY_UPDATE_ERR,
1223 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1224 return -1;
1225 }
1226
Paul Jakmafb982c22007-05-04 20:15:47 +00001227 (bgp_attr_extra_get (attr))->originator_id.s_addr
1228 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001229
1230 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1231
1232 return 0;
1233}
1234
1235/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001236static int
paul718e3742002-12-13 20:15:29 +00001237bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1238 struct attr *attr, u_char flag)
1239{
1240 /* Check length. */
1241 if (length % 4)
1242 {
1243 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1244
1245 bgp_notify_send (peer,
1246 BGP_NOTIFY_UPDATE_ERR,
1247 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1248 return -1;
1249 }
1250
Paul Jakmafb982c22007-05-04 20:15:47 +00001251 (bgp_attr_extra_get (attr))->cluster
1252 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001253
paul9985f832005-02-09 15:51:56 +00001254 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001255
1256 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1257
1258 return 0;
1259}
1260
1261/* Multiprotocol reachability information parse. */
paul94f2b392005-06-28 12:44:16 +00001262static int
paul718e3742002-12-13 20:15:29 +00001263bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1264 struct bgp_nlri *mp_update)
1265{
1266 u_int16_t afi;
1267 u_char safi;
paul718e3742002-12-13 20:15:29 +00001268 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001269 size_t start;
paul718e3742002-12-13 20:15:29 +00001270 int ret;
1271 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001272 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001273
1274 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001275 s = BGP_INPUT(peer);
1276 start = stream_get_getp(s);
1277
1278 /* safe to read statically sized header? */
1279#define BGP_MP_REACH_MIN_SIZE 5
1280 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
1281 return -1;
1282
paul718e3742002-12-13 20:15:29 +00001283 /* Load AFI, SAFI. */
1284 afi = stream_getw (s);
1285 safi = stream_getc (s);
1286
1287 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001288 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001289
Paul Jakmafb982c22007-05-04 20:15:47 +00001290 if (STREAM_READABLE(s) < attre->mp_nexthop_len)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001291 return -1;
1292
paul718e3742002-12-13 20:15:29 +00001293 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001294 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001295 {
1296 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001297 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001298 break;
1299 case 12:
1300 {
1301 u_int32_t rd_high;
1302 u_int32_t rd_low;
1303
1304 rd_high = stream_getl (s);
1305 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001306 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001307 }
1308 break;
1309#ifdef HAVE_IPV6
1310 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001311 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001312 break;
1313 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001314 stream_get (&attre->mp_nexthop_global, s, 16);
1315 stream_get (&attre->mp_nexthop_local, s, 16);
1316 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001317 {
1318 char buf1[INET6_ADDRSTRLEN];
1319 char buf2[INET6_ADDRSTRLEN];
1320
1321 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001322 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 +00001323 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001324 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001325 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001326 buf2, INET6_ADDRSTRLEN));
1327
Paul Jakmafb982c22007-05-04 20:15:47 +00001328 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001329 }
1330 break;
1331#endif /* HAVE_IPV6 */
1332 default:
1333 zlog_info ("Wrong multiprotocol next hop length: %d",
Paul Jakmafb982c22007-05-04 20:15:47 +00001334 attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001335 return -1;
paul718e3742002-12-13 20:15:29 +00001336 }
1337
Paul Jakma6e4ab122007-04-10 19:36:48 +00001338 if (!STREAM_READABLE(s))
1339 return -1;
paul718e3742002-12-13 20:15:29 +00001340
Paul Jakma6e4ab122007-04-10 19:36:48 +00001341 {
1342 u_char val;
1343 if ((val = stream_getc (s)))
1344 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1345 peer->host, val);
1346 }
1347
1348 /* must have nrli_len, what is left of the attribute */
1349 nlri_len = length - (stream_get_getp(s) - start);
1350 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
1351 return -1;
paul718e3742002-12-13 20:15:29 +00001352
1353 if (safi != BGP_SAFI_VPNV4)
1354 {
1355 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1356 if (ret < 0)
1357 return -1;
1358 }
1359
1360 mp_update->afi = afi;
1361 mp_update->safi = safi;
1362 mp_update->nlri = stream_pnt (s);
1363 mp_update->length = nlri_len;
1364
paul9985f832005-02-09 15:51:56 +00001365 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001366
1367 return 0;
1368}
1369
1370/* Multiprotocol unreachable parse */
paul94f2b392005-06-28 12:44:16 +00001371static int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001372bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001373 struct bgp_nlri *mp_withdraw)
1374{
1375 struct stream *s;
1376 u_int16_t afi;
1377 u_char safi;
paul718e3742002-12-13 20:15:29 +00001378 u_int16_t withdraw_len;
1379 int ret;
1380
1381 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001382
1383#define BGP_MP_UNREACH_MIN_SIZE 3
1384 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1385 return -1;
1386
paul718e3742002-12-13 20:15:29 +00001387 afi = stream_getw (s);
1388 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001389
1390 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001391
1392 if (safi != BGP_SAFI_VPNV4)
1393 {
1394 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1395 if (ret < 0)
1396 return -1;
1397 }
1398
1399 mp_withdraw->afi = afi;
1400 mp_withdraw->safi = safi;
1401 mp_withdraw->nlri = stream_pnt (s);
1402 mp_withdraw->length = withdraw_len;
1403
paul9985f832005-02-09 15:51:56 +00001404 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001405
1406 return 0;
1407}
1408
1409/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001410static int
paul718e3742002-12-13 20:15:29 +00001411bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1412 struct attr *attr, u_char flag)
1413{
1414 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001415 {
1416 if (attr->extra)
1417 attr->extra->ecommunity = NULL;
1418 }
paul718e3742002-12-13 20:15:29 +00001419 else
1420 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001421 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001422 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001423 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001424 }
1425 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1426
1427 return 0;
1428}
1429
1430/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001431static int
paul718e3742002-12-13 20:15:29 +00001432bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1433 u_char type, bgp_size_t length, u_char *startp)
1434{
1435 bgp_size_t total;
1436 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001437 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001438
hassof4184462005-02-01 20:13:16 +00001439 if (BGP_DEBUG (normal, NORMAL))
1440 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1441 peer->host, type, length);
1442
paul718e3742002-12-13 20:15:29 +00001443 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001444 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001445 "Unknown attribute type %d length %d is received", type, length);
1446
1447 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001448 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001449
1450 /* Adjest total length to include type and length. */
1451 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1452
1453 /* If any of the mandatory well-known attributes are not recognized,
1454 then the Error Subcode is set to Unrecognized Well-known
1455 Attribute. The Data field contains the unrecognized attribute
1456 (type, length and value). */
1457 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1458 {
1459 /* Adjust startp to do not include flag value. */
1460 bgp_notify_send_with_data (peer,
1461 BGP_NOTIFY_UPDATE_ERR,
1462 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1463 startp, total);
1464 return -1;
1465 }
1466
1467 /* Unrecognized non-transitive optional attributes must be quietly
1468 ignored and not passed along to other BGP peers. */
1469 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1470 return 0;
1471
1472 /* If a path with recognized transitive optional attribute is
1473 accepted and passed along to other BGP peers and the Partial bit
1474 in the Attribute Flags octet is set to 1 by some previous AS, it
1475 is not set back to 0 by the current AS. */
1476 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1477
1478 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001479 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
paul718e3742002-12-13 20:15:29 +00001480 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001481 attre->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1482 memset (attre->transit, 0, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001483 }
1484
Paul Jakmafb982c22007-05-04 20:15:47 +00001485 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001486
1487 if (transit->val)
1488 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1489 transit->length + total);
1490 else
1491 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1492
1493 memcpy (transit->val + transit->length, startp, total);
1494 transit->length += total;
1495
1496 return 0;
1497}
1498
1499/* Read attribute of update packet. This function is called from
1500 bgp_update() in bgpd.c. */
1501int
1502bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1503 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1504{
1505 int ret;
1506 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001507 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001508 bgp_size_t length;
1509 u_char *startp, *endp;
1510 u_char *attr_endp;
1511 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001512 /* we need the as4_path only until we have synthesized the as_path with it */
1513 /* same goes for as4_aggregator */
1514 struct aspath *as4_path = NULL;
1515 as_t as4_aggregator = 0;
1516 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001517
1518 /* Initialize bitmap. */
1519 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1520
1521 /* End pointer of BGP attribute. */
1522 endp = BGP_INPUT_PNT (peer) + size;
1523
1524 /* Get attributes to the end of attribute length. */
1525 while (BGP_INPUT_PNT (peer) < endp)
1526 {
1527 /* Check remaining length check.*/
1528 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1529 {
gdtc29fdba2004-12-09 14:46:46 +00001530 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001531 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001532 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001533 peer->host,
1534 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001535
1536 bgp_notify_send (peer,
1537 BGP_NOTIFY_UPDATE_ERR,
1538 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1539 return -1;
1540 }
1541
1542 /* Fetch attribute flag and type. */
1543 startp = BGP_INPUT_PNT (peer);
1544 flag = stream_getc (BGP_INPUT (peer));
1545 type = stream_getc (BGP_INPUT (peer));
1546
Paul Jakma370b64a2007-12-22 16:49:52 +00001547 /* Check whether Extended-Length applies and is in bounds */
1548 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1549 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1550 {
1551 zlog (peer->log, LOG_WARNING,
1552 "%s Extended length set, but just %u bytes of attr header",
1553 peer->host,
1554 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1555
1556 bgp_notify_send (peer,
1557 BGP_NOTIFY_UPDATE_ERR,
1558 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1559 return -1;
1560 }
1561
paul718e3742002-12-13 20:15:29 +00001562 /* Check extended attribue length bit. */
1563 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1564 length = stream_getw (BGP_INPUT (peer));
1565 else
1566 length = stream_getc (BGP_INPUT (peer));
1567
1568 /* If any attribute appears more than once in the UPDATE
1569 message, then the Error Subcode is set to Malformed Attribute
1570 List. */
1571
1572 if (CHECK_BITMAP (seen, type))
1573 {
1574 zlog (peer->log, LOG_WARNING,
1575 "%s error BGP attribute type %d appears twice in a message",
1576 peer->host, type);
1577
1578 bgp_notify_send (peer,
1579 BGP_NOTIFY_UPDATE_ERR,
1580 BGP_NOTIFY_UPDATE_MAL_ATTR);
1581 return -1;
1582 }
1583
1584 /* Set type to bitmap to check duplicate attribute. `type' is
1585 unsigned char so it never overflow bitmap range. */
1586
1587 SET_BITMAP (seen, type);
1588
1589 /* Overflow check. */
1590 attr_endp = BGP_INPUT_PNT (peer) + length;
1591
1592 if (attr_endp > endp)
1593 {
1594 zlog (peer->log, LOG_WARNING,
1595 "%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);
1596 bgp_notify_send (peer,
1597 BGP_NOTIFY_UPDATE_ERR,
1598 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1599 return -1;
1600 }
1601
1602 /* OK check attribute and store it's value. */
1603 switch (type)
1604 {
1605 case BGP_ATTR_ORIGIN:
1606 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1607 break;
1608 case BGP_ATTR_AS_PATH:
1609 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1610 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001611 case BGP_ATTR_AS4_PATH:
1612 ret = bgp_attr_as4_path (peer, length, attr, &as4_path );
1613 break;
paul718e3742002-12-13 20:15:29 +00001614 case BGP_ATTR_NEXT_HOP:
1615 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1616 break;
1617 case BGP_ATTR_MULTI_EXIT_DISC:
1618 ret = bgp_attr_med (peer, length, attr, flag, startp);
1619 break;
1620 case BGP_ATTR_LOCAL_PREF:
1621 ret = bgp_attr_local_pref (peer, length, attr, flag);
1622 break;
1623 case BGP_ATTR_ATOMIC_AGGREGATE:
1624 ret = bgp_attr_atomic (peer, length, attr, flag);
1625 break;
1626 case BGP_ATTR_AGGREGATOR:
1627 ret = bgp_attr_aggregator (peer, length, attr, flag);
1628 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001629 case BGP_ATTR_AS4_AGGREGATOR:
1630 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1631 break;
paul718e3742002-12-13 20:15:29 +00001632 case BGP_ATTR_COMMUNITIES:
1633 ret = bgp_attr_community (peer, length, attr, flag);
1634 break;
1635 case BGP_ATTR_ORIGINATOR_ID:
1636 ret = bgp_attr_originator_id (peer, length, attr, flag);
1637 break;
1638 case BGP_ATTR_CLUSTER_LIST:
1639 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1640 break;
1641 case BGP_ATTR_MP_REACH_NLRI:
1642 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1643 break;
1644 case BGP_ATTR_MP_UNREACH_NLRI:
1645 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1646 break;
1647 case BGP_ATTR_EXT_COMMUNITIES:
1648 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1649 break;
Paul Jakma41367172007-08-06 15:24:51 +00001650 case BGP_ATTR_AS_PATHLIMIT:
1651 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1652 break;
paul718e3742002-12-13 20:15:29 +00001653 default:
1654 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1655 break;
1656 }
1657
1658 /* If error occured immediately return to the caller. */
1659 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001660 {
1661 zlog (peer->log, LOG_WARNING,
1662 "%s: Attribute %s, parse error",
1663 peer->host,
1664 LOOKUP (attr_str, type));
1665 bgp_notify_send (peer,
1666 BGP_NOTIFY_UPDATE_ERR,
1667 BGP_NOTIFY_UPDATE_MAL_ATTR);
1668 return ret;
1669 }
paul718e3742002-12-13 20:15:29 +00001670
1671 /* Check the fetched length. */
1672 if (BGP_INPUT_PNT (peer) != attr_endp)
1673 {
1674 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001675 "%s: BGP attribute %s, fetch error",
1676 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001677 bgp_notify_send (peer,
1678 BGP_NOTIFY_UPDATE_ERR,
1679 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1680 return -1;
1681 }
1682 }
1683
1684 /* Check final read pointer is same as end pointer. */
1685 if (BGP_INPUT_PNT (peer) != endp)
1686 {
1687 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001688 "%s BGP attribute %s, length mismatch",
1689 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001690 bgp_notify_send (peer,
1691 BGP_NOTIFY_UPDATE_ERR,
1692 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1693 return -1;
1694 }
1695
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001696 /*
1697 * At this place we can see whether we got AS4_PATH and/or
1698 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1699 * We can not do this before we've read all attributes because
1700 * the as4 handling does not say whether AS4_PATH has to be sent
1701 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1702 * in relationship to AGGREGATOR.
1703 * So, to be defensive, we are not relying on any order and read
1704 * all attributes first, including these 32bit ones, and now,
1705 * afterwards, we look what and if something is to be done for as4.
1706 */
1707 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1708 as4_aggregator, &as4_aggregator_addr))
1709 return -1;
1710
1711 /* At this stage, we have done all fiddling with as4, and the
1712 * resulting info is in attr->aggregator resp. attr->aspath
1713 * so we can chuck as4_aggregator and as4_path alltogether in
1714 * order to save memory
1715 */
1716 if ( as4_path )
1717 {
1718 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1719 as4_path = NULL;
1720 /* The flag that we got this is still there, but that does not
1721 * do any trouble
1722 */
1723 }
1724 /*
1725 * The "rest" of the code does nothing with as4_aggregator.
1726 * there is no memory attached specifically which is not part
1727 * of the attr.
1728 * so ignoring just means do nothing.
1729 */
1730 /*
1731 * Finally do the checks on the aspath we did not do yet
1732 * because we waited for a potentially synthesized aspath.
1733 */
1734 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1735 {
1736 ret = bgp_attr_aspath_check( peer, attr );
1737 if ( ret < 0 )
1738 return ret;
1739 }
1740
paul718e3742002-12-13 20:15:29 +00001741 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001742 if (attr->extra && attr->extra->transit)
1743 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001744
1745 return 0;
1746}
1747
1748/* Well-known attribute check. */
1749int
1750bgp_attr_check (struct peer *peer, struct attr *attr)
1751{
1752 u_char type = 0;
1753
1754 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1755 type = BGP_ATTR_ORIGIN;
1756
1757 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1758 type = BGP_ATTR_AS_PATH;
1759
1760 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1761 type = BGP_ATTR_NEXT_HOP;
1762
1763 if (peer_sort (peer) == BGP_PEER_IBGP
1764 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1765 type = BGP_ATTR_LOCAL_PREF;
1766
1767 if (type)
1768 {
1769 zlog (peer->log, LOG_WARNING,
1770 "%s Missing well-known attribute %d.",
1771 peer->host, type);
1772 bgp_notify_send_with_data (peer,
1773 BGP_NOTIFY_UPDATE_ERR,
1774 BGP_NOTIFY_UPDATE_MISS_ATTR,
1775 &type, 1);
1776 return -1;
1777 }
1778 return 0;
1779}
1780
1781int stream_put_prefix (struct stream *, struct prefix *);
1782
1783/* Make attribute packet. */
1784bgp_size_t
1785bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1786 struct stream *s, struct attr *attr, struct prefix *p,
1787 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001788 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001789{
paulfe69a502005-09-10 16:55:02 +00001790 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001791 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001792 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001793 int send_as4_path = 0;
1794 int send_as4_aggregator = 0;
1795 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001796
1797 if (! bgp)
1798 bgp = bgp_get_default ();
1799
1800 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001801 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001802
1803 /* Origin attribute. */
1804 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1805 stream_putc (s, BGP_ATTR_ORIGIN);
1806 stream_putc (s, 1);
1807 stream_putc (s, attr->origin);
1808
1809 /* AS path attribute. */
1810
1811 /* If remote-peer is EBGP */
1812 if (peer_sort (peer) == BGP_PEER_EBGP
1813 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001814 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001815 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001816 {
1817 aspath = aspath_dup (attr->aspath);
1818
1819 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1820 {
1821 /* Strip the confed info, and then stuff our path CONFED_ID
1822 on the front */
1823 aspath = aspath_delete_confed_seq (aspath);
1824 aspath = aspath_add_seq (aspath, bgp->confed_id);
1825 }
1826 else
1827 {
1828 aspath = aspath_add_seq (aspath, peer->local_as);
1829 if (peer->change_local_as)
1830 aspath = aspath_add_seq (aspath, peer->change_local_as);
1831 }
1832 }
1833 else if (peer_sort (peer) == BGP_PEER_CONFED)
1834 {
1835 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1836 aspath = aspath_dup (attr->aspath);
1837 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1838 }
1839 else
1840 aspath = attr->aspath;
1841
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001842 /* If peer is not AS4 capable, then:
1843 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1844 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1845 * types are in it (i.e. exclude them if they are there)
1846 * AND do this only if there is at least one asnum > 65535 in the path!
1847 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1848 * all ASnums > 65535 to BGP_AS_TRANS
1849 */
paul718e3742002-12-13 20:15:29 +00001850
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001851 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1852 stream_putc (s, BGP_ATTR_AS_PATH);
1853 aspath_sizep = stream_get_endp (s);
1854 stream_putw (s, 0);
1855 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1856
1857 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1858 * in the path
1859 */
1860 if (!use32bit && aspath_has_as4 (aspath))
1861 send_as4_path = 1; /* we'll do this later, at the correct place */
1862
paul718e3742002-12-13 20:15:29 +00001863 /* Nexthop attribute. */
1864 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1865 {
1866 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1867 stream_putc (s, BGP_ATTR_NEXT_HOP);
1868 stream_putc (s, 4);
1869 if (safi == SAFI_MPLS_VPN)
1870 {
1871 if (attr->nexthop.s_addr == 0)
1872 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1873 else
1874 stream_put_ipv4 (s, attr->nexthop.s_addr);
1875 }
1876 else
1877 stream_put_ipv4 (s, attr->nexthop.s_addr);
1878 }
1879
1880 /* MED attribute. */
1881 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1882 {
1883 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1884 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1885 stream_putc (s, 4);
1886 stream_putl (s, attr->med);
1887 }
1888
1889 /* Local preference. */
1890 if (peer_sort (peer) == BGP_PEER_IBGP ||
1891 peer_sort (peer) == BGP_PEER_CONFED)
1892 {
1893 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1894 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1895 stream_putc (s, 4);
1896 stream_putl (s, attr->local_pref);
1897 }
1898
1899 /* Atomic aggregate. */
1900 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1901 {
1902 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1903 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1904 stream_putc (s, 0);
1905 }
1906
1907 /* Aggregator. */
1908 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1909 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001910 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001911
1912 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001913 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1914 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001915
1916 if (use32bit)
1917 {
1918 /* AS4 capable peer */
1919 stream_putc (s, 8);
1920 stream_putl (s, attr->extra->aggregator_as);
1921 }
1922 else
1923 {
1924 /* 2-byte AS peer */
1925 stream_putc (s, 6);
1926
1927 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1928 if ( attr->extra->aggregator_as > 65535 )
1929 {
1930 stream_putw (s, BGP_AS_TRANS);
1931
1932 /* we have to send AS4_AGGREGATOR, too.
1933 * we'll do that later in order to send attributes in ascending
1934 * order.
1935 */
1936 send_as4_aggregator = 1;
1937 }
1938 else
1939 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1940 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001941 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001942 }
1943
1944 /* Community attribute. */
1945 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1946 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1947 {
1948 if (attr->community->size * 4 > 255)
1949 {
1950 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1951 stream_putc (s, BGP_ATTR_COMMUNITIES);
1952 stream_putw (s, attr->community->size * 4);
1953 }
1954 else
1955 {
1956 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1957 stream_putc (s, BGP_ATTR_COMMUNITIES);
1958 stream_putc (s, attr->community->size * 4);
1959 }
1960 stream_put (s, attr->community->val, attr->community->size * 4);
1961 }
1962
1963 /* Route Reflector. */
1964 if (peer_sort (peer) == BGP_PEER_IBGP
1965 && from
1966 && peer_sort (from) == BGP_PEER_IBGP)
1967 {
1968 /* Originator ID. */
1969 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1970 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1971 stream_putc (s, 4);
1972
1973 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00001974 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001975 else
1976 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001977
1978 /* Cluster list. */
1979 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1980 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1981
Paul Jakma9eda90c2007-08-30 13:36:17 +00001982 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00001983 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001984 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00001985 /* If this peer configuration's parent BGP has cluster_id. */
1986 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1987 stream_put_in_addr (s, &bgp->cluster_id);
1988 else
1989 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00001990 stream_put (s, attr->extra->cluster->list,
1991 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00001992 }
1993 else
1994 {
1995 stream_putc (s, 4);
1996 /* If this peer configuration's parent BGP has cluster_id. */
1997 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1998 stream_put_in_addr (s, &bgp->cluster_id);
1999 else
2000 stream_put_in_addr (s, &bgp->router_id);
2001 }
2002 }
2003
2004#ifdef HAVE_IPV6
2005 /* If p is IPv6 address put it into attribute. */
2006 if (p->family == AF_INET6)
2007 {
2008 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002009 struct attr_extra *attre = attr->extra;
2010
2011 assert (attr->extra);
2012
paul718e3742002-12-13 20:15:29 +00002013 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2014 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002015 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002016 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002017 stream_putw (s, AFI_IP6); /* AFI */
2018 stream_putc (s, safi); /* SAFI */
2019
Paul Jakmafb982c22007-05-04 20:15:47 +00002020 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002021
Paul Jakmafb982c22007-05-04 20:15:47 +00002022 if (attre->mp_nexthop_len == 16)
2023 stream_put (s, &attre->mp_nexthop_global, 16);
2024 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002025 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002026 stream_put (s, &attre->mp_nexthop_global, 16);
2027 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002028 }
2029
2030 /* SNPA */
2031 stream_putc (s, 0);
2032
paul718e3742002-12-13 20:15:29 +00002033 /* Prefix write. */
2034 stream_put_prefix (s, p);
2035
2036 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002037 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002038 }
2039#endif /* HAVE_IPV6 */
2040
2041 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2042 {
2043 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002044
2045 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2046 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002047 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002048 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002049 stream_putw (s, AFI_IP); /* AFI */
2050 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2051
2052 stream_putc (s, 4);
2053 stream_put_ipv4 (s, attr->nexthop.s_addr);
2054
2055 /* SNPA */
2056 stream_putc (s, 0);
2057
paul718e3742002-12-13 20:15:29 +00002058 /* Prefix write. */
2059 stream_put_prefix (s, p);
2060
2061 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002062 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002063 }
2064
2065 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2066 {
2067 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002068
2069 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2070 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002071 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002072 stream_putc (s, 0); /* Length of this attribute. */
2073 stream_putw (s, AFI_IP); /* AFI */
2074 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2075
2076 stream_putc (s, 12);
2077 stream_putl (s, 0);
2078 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002079 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002080
2081 /* SNPA */
2082 stream_putc (s, 0);
2083
paul718e3742002-12-13 20:15:29 +00002084 /* Tag, RD, Prefix write. */
2085 stream_putc (s, p->prefixlen + 88);
2086 stream_put (s, tag, 3);
2087 stream_put (s, prd->val, 8);
2088 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2089
2090 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002091 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002092 }
2093
2094 /* Extended Communities attribute. */
2095 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2096 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2097 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002098 struct attr_extra *attre = attr->extra;
2099
2100 assert (attre);
2101
2102 if (peer_sort (peer) == BGP_PEER_IBGP
2103 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002104 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002105 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002106 {
2107 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2108 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002109 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002110 }
2111 else
2112 {
2113 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2114 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002115 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002116 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002117 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002118 }
2119 else
2120 {
paul5228ad22004-06-04 17:58:18 +00002121 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002122 int tbit;
2123 int ecom_tr_size = 0;
2124 int i;
2125
Paul Jakmafb982c22007-05-04 20:15:47 +00002126 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002127 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002128 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002129 tbit = *pnt;
2130
2131 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2132 continue;
2133
2134 ecom_tr_size++;
2135 }
2136
2137 if (ecom_tr_size)
2138 {
2139 if (ecom_tr_size * 8 > 255)
2140 {
2141 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2142 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2143 stream_putw (s, ecom_tr_size * 8);
2144 }
2145 else
2146 {
2147 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2148 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2149 stream_putc (s, ecom_tr_size * 8);
2150 }
2151
Paul Jakmafb982c22007-05-04 20:15:47 +00002152 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002153 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002154 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002155 tbit = *pnt;
2156
2157 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2158 continue;
2159
2160 stream_put (s, pnt, 8);
2161 }
2162 }
paul718e3742002-12-13 20:15:29 +00002163 }
paul718e3742002-12-13 20:15:29 +00002164 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002165
2166 if ( send_as4_path )
2167 {
2168 /* If the peer is NOT As4 capable, AND */
2169 /* there are ASnums > 65535 in path THEN
2170 * give out AS4_PATH */
2171
2172 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2173 * path segments!
2174 * Hm, I wonder... confederation things *should* only be at
2175 * the beginning of an aspath, right? Then we should use
2176 * aspath_delete_confed_seq for this, because it is already
2177 * there! (JK)
2178 * Folks, talk to me: what is reasonable here!?
2179 */
2180 aspath = aspath_delete_confed_seq (aspath);
2181
2182 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2183 stream_putc (s, BGP_ATTR_AS4_PATH);
2184 aspath_sizep = stream_get_endp (s);
2185 stream_putw (s, 0);
2186 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2187 }
2188
2189 if (aspath != attr->aspath)
2190 aspath_free (aspath);
2191
2192 if ( send_as4_aggregator )
2193 {
2194 assert (attr->extra);
2195
2196 /* send AS4_AGGREGATOR, at this place */
2197 /* this section of code moved here in order to ensure the correct
2198 * *ascending* order of attributes
2199 */
2200 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2201 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2202 stream_putc (s, 8);
2203 stream_putl (s, attr->extra->aggregator_as);
2204 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2205 }
Paul Jakma41367172007-08-06 15:24:51 +00002206
2207 /* AS-Pathlimit */
2208 if (attr->pathlimit.ttl)
2209 {
2210 u_int32_t as = attr->pathlimit.as;
2211
2212 /* should already have been done in announce_check(),
2213 * but just in case..
2214 */
2215 if (!as)
2216 as = peer->local_as;
2217
2218 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2219 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2220 stream_putc (s, 5);
2221 stream_putc (s, attr->pathlimit.ttl);
2222 stream_putl (s, as);
2223 }
2224
paul718e3742002-12-13 20:15:29 +00002225 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002226 if (attr->extra && attr->extra->transit)
2227 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002228
2229 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002230 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002231}
2232
2233bgp_size_t
2234bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2235 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002236 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002237{
2238 unsigned long cp;
2239 unsigned long attrlen_pnt;
2240 bgp_size_t size;
2241
paul9985f832005-02-09 15:51:56 +00002242 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002243
2244 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2245 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2246
paul9985f832005-02-09 15:51:56 +00002247 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002248 stream_putc (s, 0); /* Length of this attribute. */
2249
2250 stream_putw (s, family2afi (p->family));
2251
2252 if (safi == SAFI_MPLS_VPN)
2253 {
2254 /* SAFI */
2255 stream_putc (s, BGP_SAFI_VPNV4);
2256
2257 /* prefix. */
2258 stream_putc (s, p->prefixlen + 88);
2259 stream_put (s, tag, 3);
2260 stream_put (s, prd->val, 8);
2261 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2262 }
2263 else
2264 {
2265 /* SAFI */
2266 stream_putc (s, safi);
2267
2268 /* prefix */
2269 stream_put_prefix (s, p);
2270 }
2271
2272 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002273 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002274 stream_putc_at (s, attrlen_pnt, size);
2275
paul9985f832005-02-09 15:51:56 +00002276 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002277}
2278
2279/* Initialization of attribute. */
2280void
paulfe69a502005-09-10 16:55:02 +00002281bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002282{
2283 void attrhash_init ();
2284
2285 aspath_init ();
2286 attrhash_init ();
2287 community_init ();
2288 ecommunity_init ();
2289 cluster_init ();
2290 transit_init ();
2291}
2292
2293/* Make attribute packet. */
2294void
paula3845922003-10-18 01:30:50 +00002295bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2296 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002297{
2298 unsigned long cp;
2299 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002300 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002301 struct aspath *aspath;
2302
2303 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002304 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002305
2306 /* Place holder of length. */
2307 stream_putw (s, 0);
2308
2309 /* Origin attribute. */
2310 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2311 stream_putc (s, BGP_ATTR_ORIGIN);
2312 stream_putc (s, 1);
2313 stream_putc (s, attr->origin);
2314
2315 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002316
2317 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2318 stream_putc (s, BGP_ATTR_AS_PATH);
2319 aspath_lenp = stream_get_endp (s);
2320 stream_putw (s, 0);
2321
2322 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002323
2324 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002325 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2326 if(prefix != NULL
2327#ifdef HAVE_IPV6
2328 && prefix->family != AF_INET6
2329#endif /* HAVE_IPV6 */
2330 )
2331 {
2332 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2333 stream_putc (s, BGP_ATTR_NEXT_HOP);
2334 stream_putc (s, 4);
2335 stream_put_ipv4 (s, attr->nexthop.s_addr);
2336 }
paul718e3742002-12-13 20:15:29 +00002337
2338 /* MED attribute. */
2339 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2340 {
2341 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2342 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2343 stream_putc (s, 4);
2344 stream_putl (s, attr->med);
2345 }
2346
2347 /* Local preference. */
2348 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2349 {
2350 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2351 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2352 stream_putc (s, 4);
2353 stream_putl (s, attr->local_pref);
2354 }
2355
2356 /* Atomic aggregate. */
2357 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2358 {
2359 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2360 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2361 stream_putc (s, 0);
2362 }
2363
2364 /* Aggregator. */
2365 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2366 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002367 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002368 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2369 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002370 stream_putc (s, 8);
2371 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002372 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002373 }
2374
2375 /* Community attribute. */
2376 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2377 {
2378 if (attr->community->size * 4 > 255)
2379 {
2380 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2381 stream_putc (s, BGP_ATTR_COMMUNITIES);
2382 stream_putw (s, attr->community->size * 4);
2383 }
2384 else
2385 {
2386 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2387 stream_putc (s, BGP_ATTR_COMMUNITIES);
2388 stream_putc (s, attr->community->size * 4);
2389 }
2390 stream_put (s, attr->community->val, attr->community->size * 4);
2391 }
2392
paula3845922003-10-18 01:30:50 +00002393#ifdef HAVE_IPV6
2394 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002395 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2396 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002397 {
2398 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002399 struct attr_extra *attre = attr->extra;
2400
paula3845922003-10-18 01:30:50 +00002401 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2402 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002403 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002404
2405 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002406 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002407 stream_putw(s, AFI_IP6); /* AFI */
2408 stream_putc(s, SAFI_UNICAST); /* SAFI */
2409
2410 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002411 stream_putc(s, attre->mp_nexthop_len);
2412 stream_put(s, &attre->mp_nexthop_global, 16);
2413 if (attre->mp_nexthop_len == 32)
2414 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002415
2416 /* SNPA */
2417 stream_putc(s, 0);
2418
2419 /* Prefix */
2420 stream_put_prefix(s, prefix);
2421
2422 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002423 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002424 }
2425#endif /* HAVE_IPV6 */
2426
Paul Jakma41367172007-08-06 15:24:51 +00002427 /* AS-Pathlimit */
2428 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2429 {
2430 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2431 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2432 stream_putc (s, 5);
2433 stream_putc (s, attr->pathlimit.ttl);
2434 stream_putl (s, attr->pathlimit.as);
2435 }
2436
paul718e3742002-12-13 20:15:29 +00002437 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002438 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002439 stream_putw_at (s, cp, len);
2440}