blob: b463b3c0fc36a3b6b29c984a5b752791caeb97d5 [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 Jakma0b2aa3a2007-10-14 22:32:21 +0000895 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
paul718e3742002-12-13 20:15:29 +0000896
897 return 0;
898}
899
900/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000901static int
paul718e3742002-12-13 20:15:29 +0000902bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
903 struct attr *attr, u_char flag, u_char *startp)
904{
905 bgp_size_t total;
906
907 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
908
909 /* Flag check. */
910 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
911 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
912 {
913 zlog (peer->log, LOG_ERR,
914 "Origin attribute flag isn't transitive %d", flag);
915 bgp_notify_send_with_data (peer,
916 BGP_NOTIFY_UPDATE_ERR,
917 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
918 startp, total);
919 return -1;
920 }
921
922 /* Check nexthop attribute length. */
923 if (length != 4)
924 {
925 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
926 length);
927
928 bgp_notify_send_with_data (peer,
929 BGP_NOTIFY_UPDATE_ERR,
930 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
931 startp, total);
932 return -1;
933 }
934
935 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
936 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
937
938 return 0;
939}
940
941/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000942static int
paul718e3742002-12-13 20:15:29 +0000943bgp_attr_med (struct peer *peer, bgp_size_t length,
944 struct attr *attr, u_char flag, u_char *startp)
945{
946 bgp_size_t total;
947
948 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
949
950 /* Length check. */
951 if (length != 4)
952 {
953 zlog (peer->log, LOG_ERR,
954 "MED attribute length isn't four [%d]", length);
955
956 bgp_notify_send_with_data (peer,
957 BGP_NOTIFY_UPDATE_ERR,
958 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
959 startp, total);
960 return -1;
961 }
962
963 attr->med = stream_getl (peer->ibuf);
964
965 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
966
967 return 0;
968}
969
970/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000971static int
paul718e3742002-12-13 20:15:29 +0000972bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
973 struct attr *attr, u_char flag)
974{
975 /* If it is contained in an UPDATE message that is received from an
976 external peer, then this attribute MUST be ignored by the
977 receiving speaker. */
978 if (peer_sort (peer) == BGP_PEER_EBGP)
979 {
paul9985f832005-02-09 15:51:56 +0000980 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000981 return 0;
982 }
983
984 if (length == 4)
985 attr->local_pref = stream_getl (peer->ibuf);
986 else
987 attr->local_pref = 0;
988
989 /* Set atomic aggregate flag. */
990 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
991
992 return 0;
993}
994
995/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000996static int
paul718e3742002-12-13 20:15:29 +0000997bgp_attr_atomic (struct peer *peer, bgp_size_t length,
998 struct attr *attr, u_char flag)
999{
1000 if (length != 0)
1001 {
1002 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1003
1004 bgp_notify_send (peer,
1005 BGP_NOTIFY_UPDATE_ERR,
1006 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1007 return -1;
1008 }
1009
1010 /* Set atomic aggregate flag. */
1011 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1012
1013 return 0;
1014}
1015
1016/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001017static int
paul718e3742002-12-13 20:15:29 +00001018bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1019 struct attr *attr, u_char flag)
1020{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001021 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001022 struct attr_extra *attre = bgp_attr_extra_get (attr);
1023
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001024 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1025 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1026 wantedlen = 8;
1027
1028 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001029 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001030 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001031
1032 bgp_notify_send (peer,
1033 BGP_NOTIFY_UPDATE_ERR,
1034 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1035 return -1;
1036 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001037
1038 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1039 attre->aggregator_as = stream_getl (peer->ibuf);
1040 else
1041 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001042 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001043
1044 /* Set atomic aggregate flag. */
1045 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1046
1047 return 0;
1048}
1049
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001050/* New Aggregator attribute */
1051static int
1052bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1053 struct attr *attr, as_t *as4_aggregator_as,
1054 struct in_addr *as4_aggregator_addr)
1055{
1056 if (length != 8)
1057 {
1058 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1059
1060 bgp_notify_send (peer,
1061 BGP_NOTIFY_UPDATE_ERR,
1062 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1063 return -1;
1064 }
1065 *as4_aggregator_as = stream_getl (peer->ibuf);
1066 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1067
1068 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1069
1070 return 0;
1071}
1072
1073/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1074 */
1075static int
1076bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1077 struct aspath *as4_path, as_t as4_aggregator,
1078 struct in_addr *as4_aggregator_addr)
1079{
1080 int ignore_as4_path = 0;
1081 struct aspath *newpath;
1082 struct attr_extra *attre = attr->extra;
1083
1084 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1085 {
1086 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1087 * if given.
1088 * It is worth a warning though, because the peer really
1089 * should not send them
1090 */
1091 if (BGP_DEBUG(as4, AS4))
1092 {
1093 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1094 zlog_debug ("[AS4] %s %s AS4_PATH",
1095 peer->host, "AS4 capable peer, yet it sent");
1096
1097 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1098 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1099 peer->host, "AS4 capable peer, yet it sent");
1100 }
1101
1102 return 0;
1103 }
1104
1105 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1106 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1107 {
1108 /* Hu? This is not supposed to happen at all!
1109 * got as4_path and no aspath,
1110 * This should already
1111 * have been handled by 'well known attributes missing'
1112 * But... yeah, paranoia
1113 * Take this as a "malformed attribute"
1114 */
1115 zlog (peer->log, LOG_ERR,
1116 "%s BGP not AS4 capable peer sent AS4_PATH but"
1117 " no AS_PATH, cant do anything here", peer->host);
1118 bgp_notify_send (peer,
1119 BGP_NOTIFY_UPDATE_ERR,
1120 BGP_NOTIFY_UPDATE_MAL_ATTR);
1121 return -1;
1122 }
1123
1124 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1125 * because that may override AS4_PATH
1126 */
1127 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1128 {
1129 assert (attre);
1130
1131 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1132 {
1133 /* received both.
1134 * if the as_number in aggregator is not AS_TRANS,
1135 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1136 * and the Aggregator shall be taken as
1137 * info on the aggregating node, and the AS_PATH
1138 * shall be taken as the AS_PATH
1139 * otherwise
1140 * the Aggregator shall be ignored and the
1141 * AS4_AGGREGATOR shall be taken as the
1142 * Aggregating node and the AS_PATH is to be
1143 * constructed "as in all other cases"
1144 */
1145 if ( attre->aggregator_as != BGP_AS_TRANS )
1146 {
1147 /* ignore */
1148 if ( BGP_DEBUG(as4, AS4))
1149 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1150 " send AGGREGATOR != AS_TRANS and"
1151 " AS4_AGGREGATOR, so ignore"
1152 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1153 ignore_as4_path = 1;
1154 }
1155 else
1156 {
1157 /* "New_aggregator shall be taken as aggregator" */
1158 attre->aggregator_as = as4_aggregator;
1159 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1160 }
1161 }
1162 else
1163 {
1164 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1165 * That is bogus - but reading the conditions
1166 * we have to handle AS4_AGGREGATOR as if it were
1167 * AGGREGATOR in that case
1168 */
1169 if ( BGP_DEBUG(as4, AS4))
1170 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1171 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1172 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
1173 attre->aggregator_as = as4_aggregator;
1174 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1175 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1176 }
1177 }
1178
1179 /* need to reconcile NEW_AS_PATH and AS_PATH */
1180 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1181 {
1182 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1183 aspath_unintern (attr->aspath);
1184 attr->aspath = aspath_intern (newpath);
1185 }
1186 return 0;
1187}
1188
paul718e3742002-12-13 20:15:29 +00001189/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001190static int
paul718e3742002-12-13 20:15:29 +00001191bgp_attr_community (struct peer *peer, bgp_size_t length,
1192 struct attr *attr, u_char flag)
1193{
1194 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001195 {
1196 attr->community = NULL;
1197 return 0;
1198 }
paul718e3742002-12-13 20:15:29 +00001199 else
1200 {
paul5228ad22004-06-04 17:58:18 +00001201 attr->community =
1202 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001203 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001204 }
1205
1206 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1207
1208 return 0;
1209}
1210
1211/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001212static int
paul718e3742002-12-13 20:15:29 +00001213bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1214 struct attr *attr, u_char flag)
1215{
1216 if (length != 4)
1217 {
1218 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1219
1220 bgp_notify_send (peer,
1221 BGP_NOTIFY_UPDATE_ERR,
1222 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1223 return -1;
1224 }
1225
Paul Jakmafb982c22007-05-04 20:15:47 +00001226 (bgp_attr_extra_get (attr))->originator_id.s_addr
1227 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001228
1229 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1230
1231 return 0;
1232}
1233
1234/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001235static int
paul718e3742002-12-13 20:15:29 +00001236bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1237 struct attr *attr, u_char flag)
1238{
1239 /* Check length. */
1240 if (length % 4)
1241 {
1242 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1243
1244 bgp_notify_send (peer,
1245 BGP_NOTIFY_UPDATE_ERR,
1246 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1247 return -1;
1248 }
1249
Paul Jakmafb982c22007-05-04 20:15:47 +00001250 (bgp_attr_extra_get (attr))->cluster
1251 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001252
paul9985f832005-02-09 15:51:56 +00001253 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001254
1255 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1256
1257 return 0;
1258}
1259
1260/* Multiprotocol reachability information parse. */
paul94f2b392005-06-28 12:44:16 +00001261static int
paul718e3742002-12-13 20:15:29 +00001262bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1263 struct bgp_nlri *mp_update)
1264{
1265 u_int16_t afi;
1266 u_char safi;
paul718e3742002-12-13 20:15:29 +00001267 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001268 size_t start;
paul718e3742002-12-13 20:15:29 +00001269 int ret;
1270 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001271 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001272
1273 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001274 s = BGP_INPUT(peer);
1275 start = stream_get_getp(s);
1276
1277 /* safe to read statically sized header? */
1278#define BGP_MP_REACH_MIN_SIZE 5
1279 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
1280 return -1;
1281
paul718e3742002-12-13 20:15:29 +00001282 /* Load AFI, SAFI. */
1283 afi = stream_getw (s);
1284 safi = stream_getc (s);
1285
1286 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001287 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001288
Paul Jakmafb982c22007-05-04 20:15:47 +00001289 if (STREAM_READABLE(s) < attre->mp_nexthop_len)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001290 return -1;
1291
paul718e3742002-12-13 20:15:29 +00001292 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001293 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001294 {
1295 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001296 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001297 break;
1298 case 12:
1299 {
1300 u_int32_t rd_high;
1301 u_int32_t rd_low;
1302
1303 rd_high = stream_getl (s);
1304 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001305 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001306 }
1307 break;
1308#ifdef HAVE_IPV6
1309 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001310 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001311 break;
1312 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001313 stream_get (&attre->mp_nexthop_global, s, 16);
1314 stream_get (&attre->mp_nexthop_local, s, 16);
1315 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001316 {
1317 char buf1[INET6_ADDRSTRLEN];
1318 char buf2[INET6_ADDRSTRLEN];
1319
1320 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001321 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 +00001322 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001323 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001324 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001325 buf2, INET6_ADDRSTRLEN));
1326
Paul Jakmafb982c22007-05-04 20:15:47 +00001327 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001328 }
1329 break;
1330#endif /* HAVE_IPV6 */
1331 default:
1332 zlog_info ("Wrong multiprotocol next hop length: %d",
Paul Jakmafb982c22007-05-04 20:15:47 +00001333 attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001334 return -1;
paul718e3742002-12-13 20:15:29 +00001335 }
1336
Paul Jakma6e4ab122007-04-10 19:36:48 +00001337 if (!STREAM_READABLE(s))
1338 return -1;
paul718e3742002-12-13 20:15:29 +00001339
Paul Jakma6e4ab122007-04-10 19:36:48 +00001340 {
1341 u_char val;
1342 if ((val = stream_getc (s)))
1343 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1344 peer->host, val);
1345 }
1346
1347 /* must have nrli_len, what is left of the attribute */
1348 nlri_len = length - (stream_get_getp(s) - start);
1349 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
1350 return -1;
paul718e3742002-12-13 20:15:29 +00001351
1352 if (safi != BGP_SAFI_VPNV4)
1353 {
1354 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1355 if (ret < 0)
1356 return -1;
1357 }
1358
1359 mp_update->afi = afi;
1360 mp_update->safi = safi;
1361 mp_update->nlri = stream_pnt (s);
1362 mp_update->length = nlri_len;
1363
paul9985f832005-02-09 15:51:56 +00001364 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001365
1366 return 0;
1367}
1368
1369/* Multiprotocol unreachable parse */
paul94f2b392005-06-28 12:44:16 +00001370static int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001371bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001372 struct bgp_nlri *mp_withdraw)
1373{
1374 struct stream *s;
1375 u_int16_t afi;
1376 u_char safi;
paul718e3742002-12-13 20:15:29 +00001377 u_int16_t withdraw_len;
1378 int ret;
1379
1380 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001381
1382#define BGP_MP_UNREACH_MIN_SIZE 3
1383 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1384 return -1;
1385
paul718e3742002-12-13 20:15:29 +00001386 afi = stream_getw (s);
1387 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001388
1389 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001390
1391 if (safi != BGP_SAFI_VPNV4)
1392 {
1393 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1394 if (ret < 0)
1395 return -1;
1396 }
1397
1398 mp_withdraw->afi = afi;
1399 mp_withdraw->safi = safi;
1400 mp_withdraw->nlri = stream_pnt (s);
1401 mp_withdraw->length = withdraw_len;
1402
paul9985f832005-02-09 15:51:56 +00001403 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001404
1405 return 0;
1406}
1407
1408/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001409static int
paul718e3742002-12-13 20:15:29 +00001410bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1411 struct attr *attr, u_char flag)
1412{
1413 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001414 {
1415 if (attr->extra)
1416 attr->extra->ecommunity = NULL;
1417 }
paul718e3742002-12-13 20:15:29 +00001418 else
1419 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001420 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001421 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001422 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001423 }
1424 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1425
1426 return 0;
1427}
1428
1429/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001430static int
paul718e3742002-12-13 20:15:29 +00001431bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1432 u_char type, bgp_size_t length, u_char *startp)
1433{
1434 bgp_size_t total;
1435 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001436 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001437
hassof4184462005-02-01 20:13:16 +00001438 if (BGP_DEBUG (normal, NORMAL))
1439 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1440 peer->host, type, length);
1441
paul718e3742002-12-13 20:15:29 +00001442 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001443 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001444 "Unknown attribute type %d length %d is received", type, length);
1445
1446 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001447 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001448
1449 /* Adjest total length to include type and length. */
1450 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1451
1452 /* If any of the mandatory well-known attributes are not recognized,
1453 then the Error Subcode is set to Unrecognized Well-known
1454 Attribute. The Data field contains the unrecognized attribute
1455 (type, length and value). */
1456 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1457 {
1458 /* Adjust startp to do not include flag value. */
1459 bgp_notify_send_with_data (peer,
1460 BGP_NOTIFY_UPDATE_ERR,
1461 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1462 startp, total);
1463 return -1;
1464 }
1465
1466 /* Unrecognized non-transitive optional attributes must be quietly
1467 ignored and not passed along to other BGP peers. */
1468 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1469 return 0;
1470
1471 /* If a path with recognized transitive optional attribute is
1472 accepted and passed along to other BGP peers and the Partial bit
1473 in the Attribute Flags octet is set to 1 by some previous AS, it
1474 is not set back to 0 by the current AS. */
1475 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1476
1477 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001478 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
paul718e3742002-12-13 20:15:29 +00001479 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001480 attre->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1481 memset (attre->transit, 0, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001482 }
1483
Paul Jakmafb982c22007-05-04 20:15:47 +00001484 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001485
1486 if (transit->val)
1487 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1488 transit->length + total);
1489 else
1490 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1491
1492 memcpy (transit->val + transit->length, startp, total);
1493 transit->length += total;
1494
1495 return 0;
1496}
1497
1498/* Read attribute of update packet. This function is called from
1499 bgp_update() in bgpd.c. */
1500int
1501bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1502 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1503{
1504 int ret;
1505 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001506 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001507 bgp_size_t length;
1508 u_char *startp, *endp;
1509 u_char *attr_endp;
1510 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001511 /* we need the as4_path only until we have synthesized the as_path with it */
1512 /* same goes for as4_aggregator */
1513 struct aspath *as4_path = NULL;
1514 as_t as4_aggregator = 0;
1515 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001516
1517 /* Initialize bitmap. */
1518 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1519
1520 /* End pointer of BGP attribute. */
1521 endp = BGP_INPUT_PNT (peer) + size;
1522
1523 /* Get attributes to the end of attribute length. */
1524 while (BGP_INPUT_PNT (peer) < endp)
1525 {
1526 /* Check remaining length check.*/
1527 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1528 {
gdtc29fdba2004-12-09 14:46:46 +00001529 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001530 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001531 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001532 peer->host,
1533 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001534
1535 bgp_notify_send (peer,
1536 BGP_NOTIFY_UPDATE_ERR,
1537 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1538 return -1;
1539 }
1540
1541 /* Fetch attribute flag and type. */
1542 startp = BGP_INPUT_PNT (peer);
1543 flag = stream_getc (BGP_INPUT (peer));
1544 type = stream_getc (BGP_INPUT (peer));
1545
1546 /* Check extended attribue length bit. */
1547 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1548 length = stream_getw (BGP_INPUT (peer));
1549 else
1550 length = stream_getc (BGP_INPUT (peer));
1551
1552 /* If any attribute appears more than once in the UPDATE
1553 message, then the Error Subcode is set to Malformed Attribute
1554 List. */
1555
1556 if (CHECK_BITMAP (seen, type))
1557 {
1558 zlog (peer->log, LOG_WARNING,
1559 "%s error BGP attribute type %d appears twice in a message",
1560 peer->host, type);
1561
1562 bgp_notify_send (peer,
1563 BGP_NOTIFY_UPDATE_ERR,
1564 BGP_NOTIFY_UPDATE_MAL_ATTR);
1565 return -1;
1566 }
1567
1568 /* Set type to bitmap to check duplicate attribute. `type' is
1569 unsigned char so it never overflow bitmap range. */
1570
1571 SET_BITMAP (seen, type);
1572
1573 /* Overflow check. */
1574 attr_endp = BGP_INPUT_PNT (peer) + length;
1575
1576 if (attr_endp > endp)
1577 {
1578 zlog (peer->log, LOG_WARNING,
1579 "%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);
1580 bgp_notify_send (peer,
1581 BGP_NOTIFY_UPDATE_ERR,
1582 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1583 return -1;
1584 }
1585
1586 /* OK check attribute and store it's value. */
1587 switch (type)
1588 {
1589 case BGP_ATTR_ORIGIN:
1590 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1591 break;
1592 case BGP_ATTR_AS_PATH:
1593 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1594 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001595 case BGP_ATTR_AS4_PATH:
1596 ret = bgp_attr_as4_path (peer, length, attr, &as4_path );
1597 break;
paul718e3742002-12-13 20:15:29 +00001598 case BGP_ATTR_NEXT_HOP:
1599 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1600 break;
1601 case BGP_ATTR_MULTI_EXIT_DISC:
1602 ret = bgp_attr_med (peer, length, attr, flag, startp);
1603 break;
1604 case BGP_ATTR_LOCAL_PREF:
1605 ret = bgp_attr_local_pref (peer, length, attr, flag);
1606 break;
1607 case BGP_ATTR_ATOMIC_AGGREGATE:
1608 ret = bgp_attr_atomic (peer, length, attr, flag);
1609 break;
1610 case BGP_ATTR_AGGREGATOR:
1611 ret = bgp_attr_aggregator (peer, length, attr, flag);
1612 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001613 case BGP_ATTR_AS4_AGGREGATOR:
1614 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1615 break;
paul718e3742002-12-13 20:15:29 +00001616 case BGP_ATTR_COMMUNITIES:
1617 ret = bgp_attr_community (peer, length, attr, flag);
1618 break;
1619 case BGP_ATTR_ORIGINATOR_ID:
1620 ret = bgp_attr_originator_id (peer, length, attr, flag);
1621 break;
1622 case BGP_ATTR_CLUSTER_LIST:
1623 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1624 break;
1625 case BGP_ATTR_MP_REACH_NLRI:
1626 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1627 break;
1628 case BGP_ATTR_MP_UNREACH_NLRI:
1629 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1630 break;
1631 case BGP_ATTR_EXT_COMMUNITIES:
1632 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1633 break;
Paul Jakma41367172007-08-06 15:24:51 +00001634 case BGP_ATTR_AS_PATHLIMIT:
1635 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1636 break;
paul718e3742002-12-13 20:15:29 +00001637 default:
1638 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1639 break;
1640 }
1641
1642 /* If error occured immediately return to the caller. */
1643 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001644 {
1645 zlog (peer->log, LOG_WARNING,
1646 "%s: Attribute %s, parse error",
1647 peer->host,
1648 LOOKUP (attr_str, type));
1649 bgp_notify_send (peer,
1650 BGP_NOTIFY_UPDATE_ERR,
1651 BGP_NOTIFY_UPDATE_MAL_ATTR);
1652 return ret;
1653 }
paul718e3742002-12-13 20:15:29 +00001654
1655 /* Check the fetched length. */
1656 if (BGP_INPUT_PNT (peer) != attr_endp)
1657 {
1658 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001659 "%s: BGP attribute %s, fetch error",
1660 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001661 bgp_notify_send (peer,
1662 BGP_NOTIFY_UPDATE_ERR,
1663 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1664 return -1;
1665 }
1666 }
1667
1668 /* Check final read pointer is same as end pointer. */
1669 if (BGP_INPUT_PNT (peer) != endp)
1670 {
1671 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001672 "%s BGP attribute %s, length mismatch",
1673 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001674 bgp_notify_send (peer,
1675 BGP_NOTIFY_UPDATE_ERR,
1676 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1677 return -1;
1678 }
1679
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001680 /*
1681 * At this place we can see whether we got AS4_PATH and/or
1682 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1683 * We can not do this before we've read all attributes because
1684 * the as4 handling does not say whether AS4_PATH has to be sent
1685 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1686 * in relationship to AGGREGATOR.
1687 * So, to be defensive, we are not relying on any order and read
1688 * all attributes first, including these 32bit ones, and now,
1689 * afterwards, we look what and if something is to be done for as4.
1690 */
1691 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1692 as4_aggregator, &as4_aggregator_addr))
1693 return -1;
1694
1695 /* At this stage, we have done all fiddling with as4, and the
1696 * resulting info is in attr->aggregator resp. attr->aspath
1697 * so we can chuck as4_aggregator and as4_path alltogether in
1698 * order to save memory
1699 */
1700 if ( as4_path )
1701 {
1702 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1703 as4_path = NULL;
1704 /* The flag that we got this is still there, but that does not
1705 * do any trouble
1706 */
1707 }
1708 /*
1709 * The "rest" of the code does nothing with as4_aggregator.
1710 * there is no memory attached specifically which is not part
1711 * of the attr.
1712 * so ignoring just means do nothing.
1713 */
1714 /*
1715 * Finally do the checks on the aspath we did not do yet
1716 * because we waited for a potentially synthesized aspath.
1717 */
1718 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1719 {
1720 ret = bgp_attr_aspath_check( peer, attr );
1721 if ( ret < 0 )
1722 return ret;
1723 }
1724
paul718e3742002-12-13 20:15:29 +00001725 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001726 if (attr->extra && attr->extra->transit)
1727 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001728
1729 return 0;
1730}
1731
1732/* Well-known attribute check. */
1733int
1734bgp_attr_check (struct peer *peer, struct attr *attr)
1735{
1736 u_char type = 0;
1737
1738 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1739 type = BGP_ATTR_ORIGIN;
1740
1741 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1742 type = BGP_ATTR_AS_PATH;
1743
1744 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1745 type = BGP_ATTR_NEXT_HOP;
1746
1747 if (peer_sort (peer) == BGP_PEER_IBGP
1748 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1749 type = BGP_ATTR_LOCAL_PREF;
1750
1751 if (type)
1752 {
1753 zlog (peer->log, LOG_WARNING,
1754 "%s Missing well-known attribute %d.",
1755 peer->host, type);
1756 bgp_notify_send_with_data (peer,
1757 BGP_NOTIFY_UPDATE_ERR,
1758 BGP_NOTIFY_UPDATE_MISS_ATTR,
1759 &type, 1);
1760 return -1;
1761 }
1762 return 0;
1763}
1764
1765int stream_put_prefix (struct stream *, struct prefix *);
1766
1767/* Make attribute packet. */
1768bgp_size_t
1769bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1770 struct stream *s, struct attr *attr, struct prefix *p,
1771 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001772 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001773{
paulfe69a502005-09-10 16:55:02 +00001774 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001775 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001776 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001777 int send_as4_path = 0;
1778 int send_as4_aggregator = 0;
1779 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001780
1781 if (! bgp)
1782 bgp = bgp_get_default ();
1783
1784 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001785 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001786
1787 /* Origin attribute. */
1788 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1789 stream_putc (s, BGP_ATTR_ORIGIN);
1790 stream_putc (s, 1);
1791 stream_putc (s, attr->origin);
1792
1793 /* AS path attribute. */
1794
1795 /* If remote-peer is EBGP */
1796 if (peer_sort (peer) == BGP_PEER_EBGP
1797 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001798 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001799 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001800 {
1801 aspath = aspath_dup (attr->aspath);
1802
1803 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1804 {
1805 /* Strip the confed info, and then stuff our path CONFED_ID
1806 on the front */
1807 aspath = aspath_delete_confed_seq (aspath);
1808 aspath = aspath_add_seq (aspath, bgp->confed_id);
1809 }
1810 else
1811 {
1812 aspath = aspath_add_seq (aspath, peer->local_as);
1813 if (peer->change_local_as)
1814 aspath = aspath_add_seq (aspath, peer->change_local_as);
1815 }
1816 }
1817 else if (peer_sort (peer) == BGP_PEER_CONFED)
1818 {
1819 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1820 aspath = aspath_dup (attr->aspath);
1821 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1822 }
1823 else
1824 aspath = attr->aspath;
1825
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001826 /* If peer is not AS4 capable, then:
1827 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1828 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1829 * types are in it (i.e. exclude them if they are there)
1830 * AND do this only if there is at least one asnum > 65535 in the path!
1831 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1832 * all ASnums > 65535 to BGP_AS_TRANS
1833 */
paul718e3742002-12-13 20:15:29 +00001834
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001835 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1836 stream_putc (s, BGP_ATTR_AS_PATH);
1837 aspath_sizep = stream_get_endp (s);
1838 stream_putw (s, 0);
1839 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1840
1841 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1842 * in the path
1843 */
1844 if (!use32bit && aspath_has_as4 (aspath))
1845 send_as4_path = 1; /* we'll do this later, at the correct place */
1846
paul718e3742002-12-13 20:15:29 +00001847 /* Nexthop attribute. */
1848 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1849 {
1850 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1851 stream_putc (s, BGP_ATTR_NEXT_HOP);
1852 stream_putc (s, 4);
1853 if (safi == SAFI_MPLS_VPN)
1854 {
1855 if (attr->nexthop.s_addr == 0)
1856 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1857 else
1858 stream_put_ipv4 (s, attr->nexthop.s_addr);
1859 }
1860 else
1861 stream_put_ipv4 (s, attr->nexthop.s_addr);
1862 }
1863
1864 /* MED attribute. */
1865 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1866 {
1867 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1868 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1869 stream_putc (s, 4);
1870 stream_putl (s, attr->med);
1871 }
1872
1873 /* Local preference. */
1874 if (peer_sort (peer) == BGP_PEER_IBGP ||
1875 peer_sort (peer) == BGP_PEER_CONFED)
1876 {
1877 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1878 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1879 stream_putc (s, 4);
1880 stream_putl (s, attr->local_pref);
1881 }
1882
1883 /* Atomic aggregate. */
1884 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1885 {
1886 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1887 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1888 stream_putc (s, 0);
1889 }
1890
1891 /* Aggregator. */
1892 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1893 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001894 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001895
1896 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001897 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1898 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001899
1900 if (use32bit)
1901 {
1902 /* AS4 capable peer */
1903 stream_putc (s, 8);
1904 stream_putl (s, attr->extra->aggregator_as);
1905 }
1906 else
1907 {
1908 /* 2-byte AS peer */
1909 stream_putc (s, 6);
1910
1911 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1912 if ( attr->extra->aggregator_as > 65535 )
1913 {
1914 stream_putw (s, BGP_AS_TRANS);
1915
1916 /* we have to send AS4_AGGREGATOR, too.
1917 * we'll do that later in order to send attributes in ascending
1918 * order.
1919 */
1920 send_as4_aggregator = 1;
1921 }
1922 else
1923 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1924 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001925 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001926 }
1927
1928 /* Community attribute. */
1929 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1930 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1931 {
1932 if (attr->community->size * 4 > 255)
1933 {
1934 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1935 stream_putc (s, BGP_ATTR_COMMUNITIES);
1936 stream_putw (s, attr->community->size * 4);
1937 }
1938 else
1939 {
1940 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1941 stream_putc (s, BGP_ATTR_COMMUNITIES);
1942 stream_putc (s, attr->community->size * 4);
1943 }
1944 stream_put (s, attr->community->val, attr->community->size * 4);
1945 }
1946
1947 /* Route Reflector. */
1948 if (peer_sort (peer) == BGP_PEER_IBGP
1949 && from
1950 && peer_sort (from) == BGP_PEER_IBGP)
1951 {
1952 /* Originator ID. */
1953 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1954 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1955 stream_putc (s, 4);
1956
1957 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00001958 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001959 else
1960 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001961
1962 /* Cluster list. */
1963 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1964 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1965
Paul Jakma9eda90c2007-08-30 13:36:17 +00001966 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00001967 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001968 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00001969 /* If this peer configuration's parent BGP has cluster_id. */
1970 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1971 stream_put_in_addr (s, &bgp->cluster_id);
1972 else
1973 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00001974 stream_put (s, attr->extra->cluster->list,
1975 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00001976 }
1977 else
1978 {
1979 stream_putc (s, 4);
1980 /* If this peer configuration's parent BGP has cluster_id. */
1981 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1982 stream_put_in_addr (s, &bgp->cluster_id);
1983 else
1984 stream_put_in_addr (s, &bgp->router_id);
1985 }
1986 }
1987
1988#ifdef HAVE_IPV6
1989 /* If p is IPv6 address put it into attribute. */
1990 if (p->family == AF_INET6)
1991 {
1992 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00001993 struct attr_extra *attre = attr->extra;
1994
1995 assert (attr->extra);
1996
paul718e3742002-12-13 20:15:29 +00001997 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1998 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001999 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002000 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002001 stream_putw (s, AFI_IP6); /* AFI */
2002 stream_putc (s, safi); /* SAFI */
2003
Paul Jakmafb982c22007-05-04 20:15:47 +00002004 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002005
Paul Jakmafb982c22007-05-04 20:15:47 +00002006 if (attre->mp_nexthop_len == 16)
2007 stream_put (s, &attre->mp_nexthop_global, 16);
2008 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002009 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002010 stream_put (s, &attre->mp_nexthop_global, 16);
2011 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002012 }
2013
2014 /* SNPA */
2015 stream_putc (s, 0);
2016
paul718e3742002-12-13 20:15:29 +00002017 /* Prefix write. */
2018 stream_put_prefix (s, p);
2019
2020 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002021 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002022 }
2023#endif /* HAVE_IPV6 */
2024
2025 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2026 {
2027 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002028
2029 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2030 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002031 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002032 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002033 stream_putw (s, AFI_IP); /* AFI */
2034 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2035
2036 stream_putc (s, 4);
2037 stream_put_ipv4 (s, attr->nexthop.s_addr);
2038
2039 /* SNPA */
2040 stream_putc (s, 0);
2041
paul718e3742002-12-13 20:15:29 +00002042 /* Prefix write. */
2043 stream_put_prefix (s, p);
2044
2045 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002046 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002047 }
2048
2049 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2050 {
2051 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002052
2053 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2054 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002055 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002056 stream_putc (s, 0); /* Length of this attribute. */
2057 stream_putw (s, AFI_IP); /* AFI */
2058 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2059
2060 stream_putc (s, 12);
2061 stream_putl (s, 0);
2062 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002063 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002064
2065 /* SNPA */
2066 stream_putc (s, 0);
2067
paul718e3742002-12-13 20:15:29 +00002068 /* Tag, RD, Prefix write. */
2069 stream_putc (s, p->prefixlen + 88);
2070 stream_put (s, tag, 3);
2071 stream_put (s, prd->val, 8);
2072 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2073
2074 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002075 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002076 }
2077
2078 /* Extended Communities attribute. */
2079 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2080 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2081 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002082 struct attr_extra *attre = attr->extra;
2083
2084 assert (attre);
2085
2086 if (peer_sort (peer) == BGP_PEER_IBGP
2087 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002088 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002089 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002090 {
2091 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2092 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002093 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002094 }
2095 else
2096 {
2097 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2098 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002099 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002100 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002101 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002102 }
2103 else
2104 {
paul5228ad22004-06-04 17:58:18 +00002105 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002106 int tbit;
2107 int ecom_tr_size = 0;
2108 int i;
2109
Paul Jakmafb982c22007-05-04 20:15:47 +00002110 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002111 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002112 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002113 tbit = *pnt;
2114
2115 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2116 continue;
2117
2118 ecom_tr_size++;
2119 }
2120
2121 if (ecom_tr_size)
2122 {
2123 if (ecom_tr_size * 8 > 255)
2124 {
2125 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2126 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2127 stream_putw (s, ecom_tr_size * 8);
2128 }
2129 else
2130 {
2131 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2132 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2133 stream_putc (s, ecom_tr_size * 8);
2134 }
2135
Paul Jakmafb982c22007-05-04 20:15:47 +00002136 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002137 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002138 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002139 tbit = *pnt;
2140
2141 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2142 continue;
2143
2144 stream_put (s, pnt, 8);
2145 }
2146 }
paul718e3742002-12-13 20:15:29 +00002147 }
paul718e3742002-12-13 20:15:29 +00002148 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002149
2150 if ( send_as4_path )
2151 {
2152 /* If the peer is NOT As4 capable, AND */
2153 /* there are ASnums > 65535 in path THEN
2154 * give out AS4_PATH */
2155
2156 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2157 * path segments!
2158 * Hm, I wonder... confederation things *should* only be at
2159 * the beginning of an aspath, right? Then we should use
2160 * aspath_delete_confed_seq for this, because it is already
2161 * there! (JK)
2162 * Folks, talk to me: what is reasonable here!?
2163 */
2164 aspath = aspath_delete_confed_seq (aspath);
2165
2166 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2167 stream_putc (s, BGP_ATTR_AS4_PATH);
2168 aspath_sizep = stream_get_endp (s);
2169 stream_putw (s, 0);
2170 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2171 }
2172
2173 if (aspath != attr->aspath)
2174 aspath_free (aspath);
2175
2176 if ( send_as4_aggregator )
2177 {
2178 assert (attr->extra);
2179
2180 /* send AS4_AGGREGATOR, at this place */
2181 /* this section of code moved here in order to ensure the correct
2182 * *ascending* order of attributes
2183 */
2184 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2185 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2186 stream_putc (s, 8);
2187 stream_putl (s, attr->extra->aggregator_as);
2188 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2189 }
Paul Jakma41367172007-08-06 15:24:51 +00002190
2191 /* AS-Pathlimit */
2192 if (attr->pathlimit.ttl)
2193 {
2194 u_int32_t as = attr->pathlimit.as;
2195
2196 /* should already have been done in announce_check(),
2197 * but just in case..
2198 */
2199 if (!as)
2200 as = peer->local_as;
2201
2202 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2203 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2204 stream_putc (s, 5);
2205 stream_putc (s, attr->pathlimit.ttl);
2206 stream_putl (s, as);
2207 }
2208
paul718e3742002-12-13 20:15:29 +00002209 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002210 if (attr->extra && attr->extra->transit)
2211 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002212
2213 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002214 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002215}
2216
2217bgp_size_t
2218bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2219 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002220 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002221{
2222 unsigned long cp;
2223 unsigned long attrlen_pnt;
2224 bgp_size_t size;
2225
paul9985f832005-02-09 15:51:56 +00002226 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002227
2228 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2229 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2230
paul9985f832005-02-09 15:51:56 +00002231 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002232 stream_putc (s, 0); /* Length of this attribute. */
2233
2234 stream_putw (s, family2afi (p->family));
2235
2236 if (safi == SAFI_MPLS_VPN)
2237 {
2238 /* SAFI */
2239 stream_putc (s, BGP_SAFI_VPNV4);
2240
2241 /* prefix. */
2242 stream_putc (s, p->prefixlen + 88);
2243 stream_put (s, tag, 3);
2244 stream_put (s, prd->val, 8);
2245 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2246 }
2247 else
2248 {
2249 /* SAFI */
2250 stream_putc (s, safi);
2251
2252 /* prefix */
2253 stream_put_prefix (s, p);
2254 }
2255
2256 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002257 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002258 stream_putc_at (s, attrlen_pnt, size);
2259
paul9985f832005-02-09 15:51:56 +00002260 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002261}
2262
2263/* Initialization of attribute. */
2264void
paulfe69a502005-09-10 16:55:02 +00002265bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002266{
2267 void attrhash_init ();
2268
2269 aspath_init ();
2270 attrhash_init ();
2271 community_init ();
2272 ecommunity_init ();
2273 cluster_init ();
2274 transit_init ();
2275}
2276
2277/* Make attribute packet. */
2278void
paula3845922003-10-18 01:30:50 +00002279bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2280 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002281{
2282 unsigned long cp;
2283 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002284 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002285 struct aspath *aspath;
2286
2287 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002288 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002289
2290 /* Place holder of length. */
2291 stream_putw (s, 0);
2292
2293 /* Origin attribute. */
2294 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2295 stream_putc (s, BGP_ATTR_ORIGIN);
2296 stream_putc (s, 1);
2297 stream_putc (s, attr->origin);
2298
2299 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002300
2301 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2302 stream_putc (s, BGP_ATTR_AS_PATH);
2303 aspath_lenp = stream_get_endp (s);
2304 stream_putw (s, 0);
2305
2306 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002307
2308 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002309 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2310 if(prefix != NULL
2311#ifdef HAVE_IPV6
2312 && prefix->family != AF_INET6
2313#endif /* HAVE_IPV6 */
2314 )
2315 {
2316 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2317 stream_putc (s, BGP_ATTR_NEXT_HOP);
2318 stream_putc (s, 4);
2319 stream_put_ipv4 (s, attr->nexthop.s_addr);
2320 }
paul718e3742002-12-13 20:15:29 +00002321
2322 /* MED attribute. */
2323 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2324 {
2325 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2326 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2327 stream_putc (s, 4);
2328 stream_putl (s, attr->med);
2329 }
2330
2331 /* Local preference. */
2332 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2333 {
2334 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2335 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2336 stream_putc (s, 4);
2337 stream_putl (s, attr->local_pref);
2338 }
2339
2340 /* Atomic aggregate. */
2341 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2342 {
2343 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2344 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2345 stream_putc (s, 0);
2346 }
2347
2348 /* Aggregator. */
2349 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2350 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002351 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002352 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2353 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002354 stream_putc (s, 8);
2355 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002356 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002357 }
2358
2359 /* Community attribute. */
2360 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2361 {
2362 if (attr->community->size * 4 > 255)
2363 {
2364 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2365 stream_putc (s, BGP_ATTR_COMMUNITIES);
2366 stream_putw (s, attr->community->size * 4);
2367 }
2368 else
2369 {
2370 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2371 stream_putc (s, BGP_ATTR_COMMUNITIES);
2372 stream_putc (s, attr->community->size * 4);
2373 }
2374 stream_put (s, attr->community->val, attr->community->size * 4);
2375 }
2376
paula3845922003-10-18 01:30:50 +00002377#ifdef HAVE_IPV6
2378 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002379 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2380 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002381 {
2382 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002383 struct attr_extra *attre = attr->extra;
2384
paula3845922003-10-18 01:30:50 +00002385 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2386 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002387 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002388
2389 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002390 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002391 stream_putw(s, AFI_IP6); /* AFI */
2392 stream_putc(s, SAFI_UNICAST); /* SAFI */
2393
2394 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002395 stream_putc(s, attre->mp_nexthop_len);
2396 stream_put(s, &attre->mp_nexthop_global, 16);
2397 if (attre->mp_nexthop_len == 32)
2398 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002399
2400 /* SNPA */
2401 stream_putc(s, 0);
2402
2403 /* Prefix */
2404 stream_put_prefix(s, prefix);
2405
2406 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002407 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002408 }
2409#endif /* HAVE_IPV6 */
2410
Paul Jakma41367172007-08-06 15:24:51 +00002411 /* AS-Pathlimit */
2412 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2413 {
2414 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2415 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2416 stream_putc (s, 5);
2417 stream_putc (s, attr->pathlimit.ttl);
2418 stream_putl (s, attr->pathlimit.as);
2419 }
2420
paul718e3742002-12-13 20:15:29 +00002421 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002422 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002423 stream_putw_at (s, cp, len);
2424}