blob: f38db4149e57009d833bea2e883743b7dcd23155 [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};
Paul Jakma6e4ab122007-04-10 19:36:48 +000064int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000065
66struct hash *cluster_hash;
67
paul94f2b392005-06-28 12:44:16 +000068static void *
Paul Jakma923de652007-04-29 18:25:17 +000069cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000070{
Paul Jakma923de652007-04-29 18:25:17 +000071 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000072 struct cluster_list *cluster;
73
74 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
75 cluster->length = val->length;
76
77 if (cluster->length)
78 {
79 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
80 memcpy (cluster->list, val->list, val->length);
81 }
82 else
83 cluster->list = NULL;
84
85 cluster->refcnt = 0;
86
87 return cluster;
88}
89
90/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000091static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000092cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000093{
94 struct cluster_list tmp;
95 struct cluster_list *cluster;
96
97 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000098 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +000099
100 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
101 cluster->refcnt++;
102 return cluster;
103}
104
105int
106cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
107{
108 int i;
109
110 for (i = 0; i < cluster->length / 4; i++)
111 if (cluster->list[i].s_addr == originator.s_addr)
112 return 1;
113 return 0;
114}
115
paul94f2b392005-06-28 12:44:16 +0000116static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000117cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000118{
Paul Jakma923de652007-04-29 18:25:17 +0000119 struct cluster_list * cluster = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +0000120 unsigned int key = 0;
121 int length;
122 caddr_t pnt;
123
124 length = cluster->length;
125 pnt = (caddr_t) cluster->list;
126
127 while (length)
128 key += pnt[--length];
129
130 return key;
131}
132
paul94f2b392005-06-28 12:44:16 +0000133static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100134cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000135{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100136 const struct cluster_list * cluster1 = p1;
137 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000138
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100139 return (cluster1->length == cluster2->length &&
140 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000141}
142
paul94f2b392005-06-28 12:44:16 +0000143static void
paul718e3742002-12-13 20:15:29 +0000144cluster_free (struct cluster_list *cluster)
145{
146 if (cluster->list)
147 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
148 XFREE (MTYPE_CLUSTER, cluster);
149}
150
paul94f2b392005-06-28 12:44:16 +0000151static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000152cluster_dup (struct cluster_list *cluster)
153{
154 struct cluster_list *new;
155
156 new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
157 memset (new, 0, sizeof (struct cluster_list));
158 new->length = cluster->length;
159
160 if (cluster->length)
161 {
162 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
163 memcpy (new->list, cluster->list, cluster->length);
164 }
165 else
166 new->list = NULL;
167
168 return new;
169}
170
paul94f2b392005-06-28 12:44:16 +0000171static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000172cluster_intern (struct cluster_list *cluster)
173{
174 struct cluster_list *find;
175
176 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
177 find->refcnt++;
178
179 return find;
180}
181
182void
183cluster_unintern (struct cluster_list *cluster)
184{
185 struct cluster_list *ret;
186
187 if (cluster->refcnt)
188 cluster->refcnt--;
189
190 if (cluster->refcnt == 0)
191 {
192 ret = hash_release (cluster_hash, cluster);
193 cluster_free (cluster);
194 }
195}
196
paul94f2b392005-06-28 12:44:16 +0000197static void
198cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000199{
200 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
201}
202
203/* Unknown transit attribute. */
204struct hash *transit_hash;
205
paul94f2b392005-06-28 12:44:16 +0000206static void
paul718e3742002-12-13 20:15:29 +0000207transit_free (struct transit *transit)
208{
209 if (transit->val)
210 XFREE (MTYPE_TRANSIT_VAL, transit->val);
211 XFREE (MTYPE_TRANSIT, transit);
212}
213
Paul Jakma923de652007-04-29 18:25:17 +0000214
paul94f2b392005-06-28 12:44:16 +0000215static void *
Paul Jakma923de652007-04-29 18:25:17 +0000216transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000217{
218 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000219 return p;
paul718e3742002-12-13 20:15:29 +0000220}
221
paul94f2b392005-06-28 12:44:16 +0000222static struct transit *
paul718e3742002-12-13 20:15:29 +0000223transit_intern (struct transit *transit)
224{
225 struct transit *find;
226
227 find = hash_get (transit_hash, transit, transit_hash_alloc);
228 if (find != transit)
229 transit_free (transit);
230 find->refcnt++;
231
232 return find;
233}
234
235void
236transit_unintern (struct transit *transit)
237{
238 struct transit *ret;
239
240 if (transit->refcnt)
241 transit->refcnt--;
242
243 if (transit->refcnt == 0)
244 {
245 ret = hash_release (transit_hash, transit);
246 transit_free (transit);
247 }
248}
249
paul94f2b392005-06-28 12:44:16 +0000250static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000251transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000252{
Paul Jakma923de652007-04-29 18:25:17 +0000253 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000254 unsigned int key = 0;
255 int length;
256 caddr_t pnt;
257
258 length = transit->length;
259 pnt = (caddr_t) transit->val;
260
261 while (length)
262 key += pnt[--length];
263
264 return key;
265}
266
paul94f2b392005-06-28 12:44:16 +0000267static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100268transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000269{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100270 const struct transit * transit1 = p1;
271 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000272
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100273 return (transit1->length == transit2->length &&
274 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000275}
276
paul94f2b392005-06-28 12:44:16 +0000277static void
paul718e3742002-12-13 20:15:29 +0000278transit_init ()
279{
280 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
281}
282
283/* Attribute hash routines. */
paul718e3742002-12-13 20:15:29 +0000284struct hash *attrhash;
285
Paul Jakmafb982c22007-05-04 20:15:47 +0000286static struct attr_extra *
287bgp_attr_extra_new (void)
288{
289 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
290}
291
292void
293bgp_attr_extra_free (struct attr *attr)
294{
295 if (attr->extra)
296 {
297 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
298 attr->extra = NULL;
299 }
300}
301
302struct attr_extra *
303bgp_attr_extra_get (struct attr *attr)
304{
305 if (!attr->extra)
306 attr->extra = bgp_attr_extra_new();
307 return attr->extra;
308}
309
310/* Shallow copy of an attribute
311 * Though, not so shallow that it doesn't copy the contents
312 * of the attr_extra pointed to by 'extra'
313 */
314void
315bgp_attr_dup (struct attr *new, struct attr *orig)
316{
317 *new = *orig;
318 if (orig->extra)
319 {
320 new->extra = bgp_attr_extra_new();
321 *new->extra = *orig->extra;
322 }
323}
324
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000325unsigned long int
326attr_count (void)
327{
328 return attrhash->count;
329}
330
331unsigned long int
332attr_unknown_count (void)
333{
334 return transit_hash->count;
335}
336
paul718e3742002-12-13 20:15:29 +0000337unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000338attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000339{
Paul Jakma923de652007-04-29 18:25:17 +0000340 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000341 unsigned int key = 0;
342
343 key += attr->origin;
344 key += attr->nexthop.s_addr;
345 key += attr->med;
346 key += attr->local_pref;
Paul Jakma41367172007-08-06 15:24:51 +0000347 if (attr->pathlimit.as)
348 {
349 key += attr->pathlimit.ttl;
350 key += attr->pathlimit.as;
351 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000352
353 if (attr->extra)
354 {
355 key += attr->extra->aggregator_as;
356 key += attr->extra->aggregator_addr.s_addr;
357 key += attr->extra->weight;
358 key += attr->extra->mp_nexthop_global_in.s_addr;
359 }
360
paul718e3742002-12-13 20:15:29 +0000361 if (attr->aspath)
362 key += aspath_key_make (attr->aspath);
363 if (attr->community)
364 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000365
366 if (attr->extra)
367 {
368 if (attr->extra->ecommunity)
369 key += ecommunity_hash_make (attr->extra->ecommunity);
370 if (attr->extra->cluster)
371 key += cluster_hash_key_make (attr->extra->cluster);
372 if (attr->extra->transit)
373 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000374
375#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000376 {
377 int i;
378
379 key += attr->extra->mp_nexthop_len;
380 for (i = 0; i < 16; i++)
381 key += attr->extra->mp_nexthop_global.s6_addr[i];
382 for (i = 0; i < 16; i++)
383 key += attr->extra->mp_nexthop_local.s6_addr[i];
384 }
paul718e3742002-12-13 20:15:29 +0000385#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000386 }
paul718e3742002-12-13 20:15:29 +0000387
388 return key;
389}
390
391int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100392attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000393{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100394 const struct attr * attr1 = p1;
395 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000396
paul718e3742002-12-13 20:15:29 +0000397 if (attr1->flag == attr2->flag
398 && attr1->origin == attr2->origin
399 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000400 && attr1->aspath == attr2->aspath
401 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000402 && attr1->med == attr2->med
Paul Jakma41367172007-08-06 15:24:51 +0000403 && attr1->local_pref == attr2->local_pref
404 && attr1->pathlimit.ttl == attr2->pathlimit.ttl
405 && attr1->pathlimit.as == attr2->pathlimit.as)
Paul Jakmafb982c22007-05-04 20:15:47 +0000406 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100407 const struct attr_extra *ae1 = attr1->extra;
408 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000409
410 if (ae1 && ae2
411 && ae1->aggregator_as == ae2->aggregator_as
412 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
413 && ae1->weight == ae2->weight
414#ifdef HAVE_IPV6
415 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
416 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
417 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
418#endif /* HAVE_IPV6 */
419 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
420 && ae1->ecommunity == ae2->ecommunity
421 && ae1->cluster == ae2->cluster
422 && ae1->transit == ae2->transit)
423 return 1;
424 else if (ae1 || ae2)
425 return 0;
426 /* neither attribute has extra attributes, so they're same */
427 return 1;
428 }
paul718e3742002-12-13 20:15:29 +0000429 else
430 return 0;
431}
432
paul94f2b392005-06-28 12:44:16 +0000433static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100434attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000435{
436 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
437}
438
paul94f2b392005-06-28 12:44:16 +0000439static void
paul718e3742002-12-13 20:15:29 +0000440attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
441{
442 struct attr *attr = backet->data;
443
444 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
445 inet_ntoa (attr->nexthop), VTY_NEWLINE);
446}
447
448void
449attr_show_all (struct vty *vty)
450{
451 hash_iterate (attrhash,
452 (void (*)(struct hash_backet *, void *))
453 attr_show_all_iterator,
454 vty);
455}
456
paul94f2b392005-06-28 12:44:16 +0000457static void *
Paul Jakma923de652007-04-29 18:25:17 +0000458bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000459{
Paul Jakma923de652007-04-29 18:25:17 +0000460 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000461 struct attr *attr;
462
463 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
464 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000465 if (val->extra)
466 {
467 attr->extra = bgp_attr_extra_new ();
468 *attr->extra = *val->extra;
469 }
paul718e3742002-12-13 20:15:29 +0000470 attr->refcnt = 0;
471 return attr;
472}
473
474/* Internet argument attribute. */
475struct attr *
476bgp_attr_intern (struct attr *attr)
477{
478 struct attr *find;
479
480 /* Intern referenced strucutre. */
481 if (attr->aspath)
482 {
483 if (! attr->aspath->refcnt)
484 attr->aspath = aspath_intern (attr->aspath);
485 else
486 attr->aspath->refcnt++;
487 }
488 if (attr->community)
489 {
490 if (! attr->community->refcnt)
491 attr->community = community_intern (attr->community);
492 else
493 attr->community->refcnt++;
494 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000495 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000496 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000497 struct attr_extra *attre = attr->extra;
498
499 if (attre->ecommunity)
500 {
501 if (! attre->ecommunity->refcnt)
502 attre->ecommunity = ecommunity_intern (attre->ecommunity);
503 else
504 attre->ecommunity->refcnt++;
505 }
506 if (attre->cluster)
507 {
508 if (! attre->cluster->refcnt)
509 attre->cluster = cluster_intern (attre->cluster);
510 else
511 attre->cluster->refcnt++;
512 }
513 if (attre->transit)
514 {
515 if (! attre->transit->refcnt)
516 attre->transit = transit_intern (attre->transit);
517 else
518 attre->transit->refcnt++;
519 }
paul718e3742002-12-13 20:15:29 +0000520 }
521
522 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
523 find->refcnt++;
524
525 return find;
526}
527
Paul Jakma03e214c2007-04-29 18:31:07 +0000528
paul718e3742002-12-13 20:15:29 +0000529/* Make network statement's attribute. */
530struct attr *
531bgp_attr_default_set (struct attr *attr, u_char origin)
532{
533 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000534 bgp_attr_extra_get (attr);
535
paul718e3742002-12-13 20:15:29 +0000536 attr->origin = origin;
537 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
538 attr->aspath = aspath_empty ();
539 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000540 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000541 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
542#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000543 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000544#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000545
paul718e3742002-12-13 20:15:29 +0000546 return attr;
547}
548
Paul Jakma03e214c2007-04-29 18:31:07 +0000549
paul718e3742002-12-13 20:15:29 +0000550/* Make network statement's attribute. */
551struct attr *
552bgp_attr_default_intern (u_char origin)
553{
554 struct attr attr;
555 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000556 struct attr_extra *attre;
557
558 memset (&attr, 0, sizeof (struct attr));
559 attre = bgp_attr_extra_get (&attr);
560
Paul Jakma03e214c2007-04-29 18:31:07 +0000561 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000562
563 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000564 bgp_attr_extra_free (&attr);
565
paul718e3742002-12-13 20:15:29 +0000566 aspath_unintern (new->aspath);
567 return new;
568}
569
570struct attr *
571bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
572 struct aspath *aspath,
573 struct community *community, int as_set)
574{
575 struct attr attr;
576 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000577 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000578
579 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000580 attre = bgp_attr_extra_get (&attr);
581
paul718e3742002-12-13 20:15:29 +0000582 /* Origin attribute. */
583 attr.origin = origin;
584 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
585
586 /* AS path attribute. */
587 if (aspath)
588 attr.aspath = aspath_intern (aspath);
589 else
590 attr.aspath = aspath_empty ();
591 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
592
593 /* Next hop attribute. */
594 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
595
596 if (community)
597 {
598 attr.community = community;
599 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
600 }
601
Paul Jakmafb982c22007-05-04 20:15:47 +0000602 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000603#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000604 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000605#endif
606 if (! as_set)
607 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
608 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
609 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000610 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000611 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000612 attre->aggregator_as = bgp->as;
613 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000614
615 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000616 bgp_attr_extra_free (&attr);
617
paul718e3742002-12-13 20:15:29 +0000618 aspath_unintern (new->aspath);
619 return new;
620}
621
622/* Free bgp attribute and aspath. */
623void
624bgp_attr_unintern (struct attr *attr)
625{
626 struct attr *ret;
627 struct aspath *aspath;
628 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000629 struct ecommunity *ecommunity = NULL;
630 struct cluster_list *cluster = NULL;
631 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000632
633 /* Decrement attribute reference. */
634 attr->refcnt--;
635 aspath = attr->aspath;
636 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000637 if (attr->extra)
638 {
639 ecommunity = attr->extra->ecommunity;
640 cluster = attr->extra->cluster;
641 transit = attr->extra->transit;
642 }
paul718e3742002-12-13 20:15:29 +0000643
644 /* If reference becomes zero then free attribute object. */
645 if (attr->refcnt == 0)
646 {
647 ret = hash_release (attrhash, attr);
648 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000649 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000650 XFREE (MTYPE_ATTR, attr);
651 }
652
653 /* aspath refcount shoud be decrement. */
654 if (aspath)
655 aspath_unintern (aspath);
656 if (community)
657 community_unintern (community);
658 if (ecommunity)
659 ecommunity_unintern (ecommunity);
660 if (cluster)
661 cluster_unintern (cluster);
662 if (transit)
663 transit_unintern (transit);
664}
665
666void
667bgp_attr_flush (struct attr *attr)
668{
669 if (attr->aspath && ! attr->aspath->refcnt)
670 aspath_free (attr->aspath);
671 if (attr->community && ! attr->community->refcnt)
672 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000673 if (attr->extra)
674 {
675 struct attr_extra *attre = attr->extra;
676 if (attre->ecommunity && ! attre->ecommunity->refcnt)
677 ecommunity_free (attre->ecommunity);
678 if (attre->cluster && ! attre->cluster->refcnt)
679 cluster_free (attre->cluster);
680 if (attre->transit && ! attre->transit->refcnt)
681 transit_free (attre->transit);
682 }
paul718e3742002-12-13 20:15:29 +0000683}
684
Paul Jakma41367172007-08-06 15:24:51 +0000685/* Parse AS_PATHLIMIT attribute in an UPDATE */
686static int
687bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
688 struct attr *attr, u_char flag, u_char *startp)
689{
690 bgp_size_t total;
691
692 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
693
Paul Jakmaa15cfd12008-06-01 14:29:03 +0000694 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
695 || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
Paul Jakma41367172007-08-06 15:24:51 +0000696 {
697 zlog (peer->log, LOG_ERR,
698 "AS-Pathlimit attribute flag isn't transitive %d", flag);
699 bgp_notify_send_with_data (peer,
700 BGP_NOTIFY_UPDATE_ERR,
701 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
702 startp, total);
703 return -1;
704 }
705
706 if (length != 5)
707 {
708 zlog (peer->log, LOG_ERR,
709 "AS-Pathlimit length, %u, is not 5", length);
710 bgp_notify_send_with_data (peer,
711 BGP_NOTIFY_UPDATE_ERR,
712 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
713 startp, total);
714 return -1;
715 }
716
717 attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer));
718 attr->pathlimit.as = stream_getl (BGP_INPUT(peer));
719 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
720 return 0;
721}
paul718e3742002-12-13 20:15:29 +0000722/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000723static int
paul718e3742002-12-13 20:15:29 +0000724bgp_attr_origin (struct peer *peer, bgp_size_t length,
725 struct attr *attr, u_char flag, u_char *startp)
726{
727 bgp_size_t total;
728
729 /* total is entire attribute length include Attribute Flags (1),
730 Attribute Type code (1) and Attribute length (1 or 2). */
731 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
732
733 /* If any recognized attribute has Attribute Flags that conflict
734 with the Attribute Type Code, then the Error Subcode is set to
735 Attribute Flags Error. The Data field contains the erroneous
736 attribute (type, length and value). */
737 if (flag != BGP_ATTR_FLAG_TRANS)
738 {
739 zlog (peer->log, LOG_ERR,
740 "Origin attribute flag isn't transitive %d", flag);
741 bgp_notify_send_with_data (peer,
742 BGP_NOTIFY_UPDATE_ERR,
743 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
744 startp, total);
745 return -1;
746 }
747
748 /* If any recognized attribute has Attribute Length that conflicts
749 with the expected length (based on the attribute type code), then
750 the Error Subcode is set to Attribute Length Error. The Data
751 field contains the erroneous attribute (type, length and
752 value). */
753 if (length != 1)
754 {
755 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
756 length);
757 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
758 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
759 startp, total);
760 return -1;
761 }
762
763 /* Fetch origin attribute. */
764 attr->origin = stream_getc (BGP_INPUT (peer));
765
766 /* If the ORIGIN attribute has an undefined value, then the Error
767 Subcode is set to Invalid Origin Attribute. The Data field
768 contains the unrecognized attribute (type, length and value). */
769 if ((attr->origin != BGP_ORIGIN_IGP)
770 && (attr->origin != BGP_ORIGIN_EGP)
771 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
772 {
773 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
774 attr->origin);
775
776 bgp_notify_send_with_data (peer,
777 BGP_NOTIFY_UPDATE_ERR,
778 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
779 startp, total);
780 return -1;
781 }
782
783 /* Set oring attribute flag. */
784 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
785
786 return 0;
787}
788
789/* Parse AS path information. This function is wrapper of
790 aspath_parse. */
paul94f2b392005-06-28 12:44:16 +0000791static int
paul718e3742002-12-13 20:15:29 +0000792bgp_attr_aspath (struct peer *peer, bgp_size_t length,
793 struct attr *attr, u_char flag, u_char *startp)
794{
paul718e3742002-12-13 20:15:29 +0000795 bgp_size_t total;
796
797 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
798
799 /* Flag check. */
800 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
801 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
802 {
803 zlog (peer->log, LOG_ERR,
Paul Jakmaa15cfd12008-06-01 14:29:03 +0000804 "As-Path attribute flag isn't transitive %d", flag);
paul718e3742002-12-13 20:15:29 +0000805 bgp_notify_send_with_data (peer,
806 BGP_NOTIFY_UPDATE_ERR,
807 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
808 startp, total);
809 return -1;
810 }
811
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000812 /*
813 * peer with AS4 => will get 4Byte ASnums
814 * otherwise, will get 16 Bit
815 */
816 attr->aspath = aspath_parse (peer->ibuf, length,
817 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
818
paul718e3742002-12-13 20:15:29 +0000819 /* In case of IBGP, length will be zero. */
paul718e3742002-12-13 20:15:29 +0000820 if (! attr->aspath)
821 {
822 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
823 bgp_notify_send (peer,
824 BGP_NOTIFY_UPDATE_ERR,
825 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
826 return -1;
827 }
828
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000829 /* Forward pointer. */
830/* stream_forward_getp (peer->ibuf, length);*/
831
832 /* Set aspath attribute flag. */
833 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
834
835 return 0;
836}
837
838static int bgp_attr_aspath_check( struct peer *peer,
839 struct attr *attr)
840{
841 /* These checks were part of bgp_attr_aspath, but with
842 * as4 we should to check aspath things when
843 * aspath synthesizing with as4_path has already taken place.
844 * Otherwise we check ASPATH and use the synthesized thing, and that is
845 * not right.
846 * So do the checks later, i.e. here
847 */
848 struct bgp *bgp = peer->bgp;
849 struct aspath *aspath;
850
paul718e3742002-12-13 20:15:29 +0000851 bgp = peer->bgp;
852
853 /* First AS check for EBGP. */
854 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
855 {
856 if (peer_sort (peer) == BGP_PEER_EBGP
857 && ! aspath_firstas_check (attr->aspath, peer->as))
858 {
859 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400860 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000861 bgp_notify_send (peer,
862 BGP_NOTIFY_UPDATE_ERR,
863 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
864 return -1;
865 }
866 }
867
868 /* local-as prepend */
869 if (peer->change_local_as &&
870 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
871 {
872 aspath = aspath_dup (attr->aspath);
873 aspath = aspath_add_seq (aspath, peer->change_local_as);
874 aspath_unintern (attr->aspath);
875 attr->aspath = aspath_intern (aspath);
876 }
877
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000878 return 0;
879
880}
881
882/* Parse AS4 path information. This function is another wrapper of
883 aspath_parse. */
884static int
885bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
886 struct attr *attr, struct aspath **as4_path)
887{
888 *as4_path = aspath_parse (peer->ibuf, length, 1);
paul718e3742002-12-13 20:15:29 +0000889
890 /* Set aspath attribute flag. */
Paul Jakma370b64a2007-12-22 16:49:52 +0000891 if (as4_path)
892 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
paul718e3742002-12-13 20:15:29 +0000893
894 return 0;
895}
896
897/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000898static int
paul718e3742002-12-13 20:15:29 +0000899bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
900 struct attr *attr, u_char flag, u_char *startp)
901{
902 bgp_size_t total;
903
904 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
905
906 /* Flag check. */
907 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
908 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
909 {
910 zlog (peer->log, LOG_ERR,
911 "Origin attribute flag isn't transitive %d", flag);
912 bgp_notify_send_with_data (peer,
913 BGP_NOTIFY_UPDATE_ERR,
914 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
915 startp, total);
916 return -1;
917 }
918
919 /* Check nexthop attribute length. */
920 if (length != 4)
921 {
922 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
923 length);
924
925 bgp_notify_send_with_data (peer,
926 BGP_NOTIFY_UPDATE_ERR,
927 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
928 startp, total);
929 return -1;
930 }
931
932 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
933 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
934
935 return 0;
936}
937
938/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000939static int
paul718e3742002-12-13 20:15:29 +0000940bgp_attr_med (struct peer *peer, bgp_size_t length,
941 struct attr *attr, u_char flag, u_char *startp)
942{
943 bgp_size_t total;
944
945 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
946
947 /* Length check. */
948 if (length != 4)
949 {
950 zlog (peer->log, LOG_ERR,
951 "MED attribute length isn't four [%d]", length);
952
953 bgp_notify_send_with_data (peer,
954 BGP_NOTIFY_UPDATE_ERR,
955 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
956 startp, total);
957 return -1;
958 }
959
960 attr->med = stream_getl (peer->ibuf);
961
962 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
963
964 return 0;
965}
966
967/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000968static int
paul718e3742002-12-13 20:15:29 +0000969bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
970 struct attr *attr, u_char flag)
971{
972 /* If it is contained in an UPDATE message that is received from an
973 external peer, then this attribute MUST be ignored by the
974 receiving speaker. */
975 if (peer_sort (peer) == BGP_PEER_EBGP)
976 {
paul9985f832005-02-09 15:51:56 +0000977 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000978 return 0;
979 }
980
981 if (length == 4)
982 attr->local_pref = stream_getl (peer->ibuf);
983 else
984 attr->local_pref = 0;
985
986 /* Set atomic aggregate flag. */
987 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
988
989 return 0;
990}
991
992/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000993static int
paul718e3742002-12-13 20:15:29 +0000994bgp_attr_atomic (struct peer *peer, bgp_size_t length,
995 struct attr *attr, u_char flag)
996{
997 if (length != 0)
998 {
999 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1000
1001 bgp_notify_send (peer,
1002 BGP_NOTIFY_UPDATE_ERR,
1003 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1004 return -1;
1005 }
1006
1007 /* Set atomic aggregate flag. */
1008 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1009
1010 return 0;
1011}
1012
1013/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001014static int
paul718e3742002-12-13 20:15:29 +00001015bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1016 struct attr *attr, u_char flag)
1017{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001018 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001019 struct attr_extra *attre = bgp_attr_extra_get (attr);
1020
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001021 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1022 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1023 wantedlen = 8;
1024
1025 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001026 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001027 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001028
1029 bgp_notify_send (peer,
1030 BGP_NOTIFY_UPDATE_ERR,
1031 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1032 return -1;
1033 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001034
1035 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1036 attre->aggregator_as = stream_getl (peer->ibuf);
1037 else
1038 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001039 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001040
1041 /* Set atomic aggregate flag. */
1042 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1043
1044 return 0;
1045}
1046
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001047/* New Aggregator attribute */
1048static int
1049bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1050 struct attr *attr, as_t *as4_aggregator_as,
1051 struct in_addr *as4_aggregator_addr)
1052{
1053 if (length != 8)
1054 {
1055 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1056
1057 bgp_notify_send (peer,
1058 BGP_NOTIFY_UPDATE_ERR,
1059 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1060 return -1;
1061 }
1062 *as4_aggregator_as = stream_getl (peer->ibuf);
1063 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1064
1065 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1066
1067 return 0;
1068}
1069
1070/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1071 */
1072static int
1073bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1074 struct aspath *as4_path, as_t as4_aggregator,
1075 struct in_addr *as4_aggregator_addr)
1076{
1077 int ignore_as4_path = 0;
1078 struct aspath *newpath;
1079 struct attr_extra *attre = attr->extra;
1080
1081 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1082 {
1083 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1084 * if given.
1085 * It is worth a warning though, because the peer really
1086 * should not send them
1087 */
1088 if (BGP_DEBUG(as4, AS4))
1089 {
1090 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1091 zlog_debug ("[AS4] %s %s AS4_PATH",
1092 peer->host, "AS4 capable peer, yet it sent");
1093
1094 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1095 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1096 peer->host, "AS4 capable peer, yet it sent");
1097 }
1098
1099 return 0;
1100 }
1101
1102 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1103 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1104 {
1105 /* Hu? This is not supposed to happen at all!
1106 * got as4_path and no aspath,
1107 * This should already
1108 * have been handled by 'well known attributes missing'
1109 * But... yeah, paranoia
1110 * Take this as a "malformed attribute"
1111 */
1112 zlog (peer->log, LOG_ERR,
1113 "%s BGP not AS4 capable peer sent AS4_PATH but"
1114 " no AS_PATH, cant do anything here", peer->host);
1115 bgp_notify_send (peer,
1116 BGP_NOTIFY_UPDATE_ERR,
1117 BGP_NOTIFY_UPDATE_MAL_ATTR);
1118 return -1;
1119 }
1120
1121 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1122 * because that may override AS4_PATH
1123 */
1124 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1125 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001126 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1127 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001128 assert (attre);
1129
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001130 /* received both.
1131 * if the as_number in aggregator is not AS_TRANS,
1132 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1133 * and the Aggregator shall be taken as
1134 * info on the aggregating node, and the AS_PATH
1135 * shall be taken as the AS_PATH
1136 * otherwise
1137 * the Aggregator shall be ignored and the
1138 * AS4_AGGREGATOR shall be taken as the
1139 * Aggregating node and the AS_PATH is to be
1140 * constructed "as in all other cases"
1141 */
1142 if ( attre->aggregator_as != BGP_AS_TRANS )
1143 {
1144 /* ignore */
1145 if ( BGP_DEBUG(as4, AS4))
1146 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1147 " send AGGREGATOR != AS_TRANS and"
1148 " AS4_AGGREGATOR, so ignore"
1149 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1150 ignore_as4_path = 1;
1151 }
1152 else
1153 {
1154 /* "New_aggregator shall be taken as aggregator" */
1155 attre->aggregator_as = as4_aggregator;
1156 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1157 }
1158 }
1159 else
1160 {
1161 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1162 * That is bogus - but reading the conditions
1163 * we have to handle AS4_AGGREGATOR as if it were
1164 * AGGREGATOR in that case
1165 */
1166 if ( BGP_DEBUG(as4, AS4))
1167 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1168 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1169 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001170 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001171 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1172 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1173 }
1174 }
1175
1176 /* need to reconcile NEW_AS_PATH and AS_PATH */
1177 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1178 {
1179 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1180 aspath_unintern (attr->aspath);
1181 attr->aspath = aspath_intern (newpath);
1182 }
1183 return 0;
1184}
1185
paul718e3742002-12-13 20:15:29 +00001186/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001187static int
paul718e3742002-12-13 20:15:29 +00001188bgp_attr_community (struct peer *peer, bgp_size_t length,
1189 struct attr *attr, u_char flag)
1190{
1191 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001192 {
1193 attr->community = NULL;
1194 return 0;
1195 }
paul718e3742002-12-13 20:15:29 +00001196 else
1197 {
paul5228ad22004-06-04 17:58:18 +00001198 attr->community =
1199 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001200 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001201 }
1202
1203 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1204
1205 return 0;
1206}
1207
1208/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001209static int
paul718e3742002-12-13 20:15:29 +00001210bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1211 struct attr *attr, u_char flag)
1212{
1213 if (length != 4)
1214 {
1215 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1216
1217 bgp_notify_send (peer,
1218 BGP_NOTIFY_UPDATE_ERR,
1219 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1220 return -1;
1221 }
1222
Paul Jakmafb982c22007-05-04 20:15:47 +00001223 (bgp_attr_extra_get (attr))->originator_id.s_addr
1224 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001225
1226 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1227
1228 return 0;
1229}
1230
1231/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001232static int
paul718e3742002-12-13 20:15:29 +00001233bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1234 struct attr *attr, u_char flag)
1235{
1236 /* Check length. */
1237 if (length % 4)
1238 {
1239 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1240
1241 bgp_notify_send (peer,
1242 BGP_NOTIFY_UPDATE_ERR,
1243 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1244 return -1;
1245 }
1246
Paul Jakmafb982c22007-05-04 20:15:47 +00001247 (bgp_attr_extra_get (attr))->cluster
1248 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001249
paul9985f832005-02-09 15:51:56 +00001250 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001251
1252 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1253
1254 return 0;
1255}
1256
1257/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001258int
paul718e3742002-12-13 20:15:29 +00001259bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1260 struct bgp_nlri *mp_update)
1261{
1262 u_int16_t afi;
1263 u_char safi;
paul718e3742002-12-13 20:15:29 +00001264 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001265 size_t start;
paul718e3742002-12-13 20:15:29 +00001266 int ret;
1267 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001268 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001269
1270 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001271 s = BGP_INPUT(peer);
1272 start = stream_get_getp(s);
1273
1274 /* safe to read statically sized header? */
1275#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001276#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001277 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001278 {
1279 zlog_info ("%s: %s sent invalid length, %lu",
1280 __func__, peer->host, (unsigned long)length);
1281 return -1;
1282 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001283
paul718e3742002-12-13 20:15:29 +00001284 /* Load AFI, SAFI. */
1285 afi = stream_getw (s);
1286 safi = stream_getc (s);
1287
1288 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001289 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001290
Paul Jakma03292802008-06-07 20:37:10 +00001291 if (LEN_LEFT < attre->mp_nexthop_len)
1292 {
1293 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1294 __func__, peer->host, attre->mp_nexthop_len);
1295 return -1;
1296 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001297
paul718e3742002-12-13 20:15:29 +00001298 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001299 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001300 {
1301 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001302 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001303 break;
1304 case 12:
1305 {
1306 u_int32_t rd_high;
1307 u_int32_t rd_low;
1308
1309 rd_high = stream_getl (s);
1310 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001311 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001312 }
1313 break;
1314#ifdef HAVE_IPV6
1315 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001316 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001317 break;
1318 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001319 stream_get (&attre->mp_nexthop_global, s, 16);
1320 stream_get (&attre->mp_nexthop_local, s, 16);
1321 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001322 {
1323 char buf1[INET6_ADDRSTRLEN];
1324 char buf2[INET6_ADDRSTRLEN];
1325
1326 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001327 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 +00001328 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001329 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001330 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001331 buf2, INET6_ADDRSTRLEN));
1332
Paul Jakmafb982c22007-05-04 20:15:47 +00001333 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001334 }
1335 break;
1336#endif /* HAVE_IPV6 */
1337 default:
Paul Jakma03292802008-06-07 20:37:10 +00001338 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1339 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001340 return -1;
paul718e3742002-12-13 20:15:29 +00001341 }
1342
Paul Jakma03292802008-06-07 20:37:10 +00001343 if (!LEN_LEFT)
1344 {
1345 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1346 __func__, peer->host);
1347 return -1;
1348 }
paul718e3742002-12-13 20:15:29 +00001349
Paul Jakma6e4ab122007-04-10 19:36:48 +00001350 {
1351 u_char val;
1352 if ((val = stream_getc (s)))
1353 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1354 peer->host, val);
1355 }
1356
1357 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001358 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001359 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001360 {
1361 zlog_info ("%s: (%s) Failed to read NLRI",
1362 __func__, peer->host);
1363 return -1;
1364 }
paul718e3742002-12-13 20:15:29 +00001365
1366 if (safi != BGP_SAFI_VPNV4)
1367 {
1368 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001369 if (ret < 0)
1370 {
1371 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1372 __func__, peer->host);
1373 return -1;
1374 }
paul718e3742002-12-13 20:15:29 +00001375 }
1376
1377 mp_update->afi = afi;
1378 mp_update->safi = safi;
1379 mp_update->nlri = stream_pnt (s);
1380 mp_update->length = nlri_len;
1381
paul9985f832005-02-09 15:51:56 +00001382 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001383
1384 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001385#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001386}
1387
1388/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001389int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001390bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001391 struct bgp_nlri *mp_withdraw)
1392{
1393 struct stream *s;
1394 u_int16_t afi;
1395 u_char safi;
paul718e3742002-12-13 20:15:29 +00001396 u_int16_t withdraw_len;
1397 int ret;
1398
1399 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001400
1401#define BGP_MP_UNREACH_MIN_SIZE 3
1402 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1403 return -1;
1404
paul718e3742002-12-13 20:15:29 +00001405 afi = stream_getw (s);
1406 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001407
1408 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001409
1410 if (safi != BGP_SAFI_VPNV4)
1411 {
1412 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1413 if (ret < 0)
1414 return -1;
1415 }
1416
1417 mp_withdraw->afi = afi;
1418 mp_withdraw->safi = safi;
1419 mp_withdraw->nlri = stream_pnt (s);
1420 mp_withdraw->length = withdraw_len;
1421
paul9985f832005-02-09 15:51:56 +00001422 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001423
1424 return 0;
1425}
1426
1427/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001428static int
paul718e3742002-12-13 20:15:29 +00001429bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1430 struct attr *attr, u_char flag)
1431{
1432 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001433 {
1434 if (attr->extra)
1435 attr->extra->ecommunity = NULL;
1436 }
paul718e3742002-12-13 20:15:29 +00001437 else
1438 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001439 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001440 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001441 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001442 }
1443 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1444
1445 return 0;
1446}
1447
1448/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001449static int
paul718e3742002-12-13 20:15:29 +00001450bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1451 u_char type, bgp_size_t length, u_char *startp)
1452{
1453 bgp_size_t total;
1454 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001455 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001456
hassof4184462005-02-01 20:13:16 +00001457 if (BGP_DEBUG (normal, NORMAL))
1458 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1459 peer->host, type, length);
1460
paul718e3742002-12-13 20:15:29 +00001461 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001462 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001463 "Unknown attribute type %d length %d is received", type, length);
1464
1465 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001466 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001467
1468 /* Adjest total length to include type and length. */
1469 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1470
1471 /* If any of the mandatory well-known attributes are not recognized,
1472 then the Error Subcode is set to Unrecognized Well-known
1473 Attribute. The Data field contains the unrecognized attribute
1474 (type, length and value). */
1475 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1476 {
1477 /* Adjust startp to do not include flag value. */
1478 bgp_notify_send_with_data (peer,
1479 BGP_NOTIFY_UPDATE_ERR,
1480 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1481 startp, total);
1482 return -1;
1483 }
1484
1485 /* Unrecognized non-transitive optional attributes must be quietly
1486 ignored and not passed along to other BGP peers. */
1487 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1488 return 0;
1489
1490 /* If a path with recognized transitive optional attribute is
1491 accepted and passed along to other BGP peers and the Partial bit
1492 in the Attribute Flags octet is set to 1 by some previous AS, it
1493 is not set back to 0 by the current AS. */
1494 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1495
1496 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001497 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
paul718e3742002-12-13 20:15:29 +00001498 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001499 attre->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1500 memset (attre->transit, 0, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001501 }
1502
Paul Jakmafb982c22007-05-04 20:15:47 +00001503 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001504
1505 if (transit->val)
1506 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1507 transit->length + total);
1508 else
1509 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1510
1511 memcpy (transit->val + transit->length, startp, total);
1512 transit->length += total;
1513
1514 return 0;
1515}
1516
1517/* Read attribute of update packet. This function is called from
1518 bgp_update() in bgpd.c. */
1519int
1520bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1521 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1522{
1523 int ret;
1524 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001525 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001526 bgp_size_t length;
1527 u_char *startp, *endp;
1528 u_char *attr_endp;
1529 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001530 /* we need the as4_path only until we have synthesized the as_path with it */
1531 /* same goes for as4_aggregator */
1532 struct aspath *as4_path = NULL;
1533 as_t as4_aggregator = 0;
1534 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001535
1536 /* Initialize bitmap. */
1537 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1538
1539 /* End pointer of BGP attribute. */
1540 endp = BGP_INPUT_PNT (peer) + size;
1541
1542 /* Get attributes to the end of attribute length. */
1543 while (BGP_INPUT_PNT (peer) < endp)
1544 {
1545 /* Check remaining length check.*/
1546 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1547 {
gdtc29fdba2004-12-09 14:46:46 +00001548 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001549 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001550 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001551 peer->host,
1552 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001553
1554 bgp_notify_send (peer,
1555 BGP_NOTIFY_UPDATE_ERR,
1556 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1557 return -1;
1558 }
1559
1560 /* Fetch attribute flag and type. */
1561 startp = BGP_INPUT_PNT (peer);
1562 flag = stream_getc (BGP_INPUT (peer));
1563 type = stream_getc (BGP_INPUT (peer));
1564
Paul Jakma370b64a2007-12-22 16:49:52 +00001565 /* Check whether Extended-Length applies and is in bounds */
1566 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1567 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1568 {
1569 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001570 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001571 peer->host,
1572 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1573
1574 bgp_notify_send (peer,
1575 BGP_NOTIFY_UPDATE_ERR,
1576 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1577 return -1;
1578 }
1579
paul718e3742002-12-13 20:15:29 +00001580 /* Check extended attribue length bit. */
1581 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1582 length = stream_getw (BGP_INPUT (peer));
1583 else
1584 length = stream_getc (BGP_INPUT (peer));
1585
1586 /* If any attribute appears more than once in the UPDATE
1587 message, then the Error Subcode is set to Malformed Attribute
1588 List. */
1589
1590 if (CHECK_BITMAP (seen, type))
1591 {
1592 zlog (peer->log, LOG_WARNING,
1593 "%s error BGP attribute type %d appears twice in a message",
1594 peer->host, type);
1595
1596 bgp_notify_send (peer,
1597 BGP_NOTIFY_UPDATE_ERR,
1598 BGP_NOTIFY_UPDATE_MAL_ATTR);
1599 return -1;
1600 }
1601
1602 /* Set type to bitmap to check duplicate attribute. `type' is
1603 unsigned char so it never overflow bitmap range. */
1604
1605 SET_BITMAP (seen, type);
1606
1607 /* Overflow check. */
1608 attr_endp = BGP_INPUT_PNT (peer) + length;
1609
1610 if (attr_endp > endp)
1611 {
1612 zlog (peer->log, LOG_WARNING,
1613 "%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);
1614 bgp_notify_send (peer,
1615 BGP_NOTIFY_UPDATE_ERR,
1616 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1617 return -1;
1618 }
1619
1620 /* OK check attribute and store it's value. */
1621 switch (type)
1622 {
1623 case BGP_ATTR_ORIGIN:
1624 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1625 break;
1626 case BGP_ATTR_AS_PATH:
1627 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1628 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001629 case BGP_ATTR_AS4_PATH:
1630 ret = bgp_attr_as4_path (peer, length, attr, &as4_path );
1631 break;
paul718e3742002-12-13 20:15:29 +00001632 case BGP_ATTR_NEXT_HOP:
1633 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1634 break;
1635 case BGP_ATTR_MULTI_EXIT_DISC:
1636 ret = bgp_attr_med (peer, length, attr, flag, startp);
1637 break;
1638 case BGP_ATTR_LOCAL_PREF:
1639 ret = bgp_attr_local_pref (peer, length, attr, flag);
1640 break;
1641 case BGP_ATTR_ATOMIC_AGGREGATE:
1642 ret = bgp_attr_atomic (peer, length, attr, flag);
1643 break;
1644 case BGP_ATTR_AGGREGATOR:
1645 ret = bgp_attr_aggregator (peer, length, attr, flag);
1646 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001647 case BGP_ATTR_AS4_AGGREGATOR:
1648 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1649 break;
paul718e3742002-12-13 20:15:29 +00001650 case BGP_ATTR_COMMUNITIES:
1651 ret = bgp_attr_community (peer, length, attr, flag);
1652 break;
1653 case BGP_ATTR_ORIGINATOR_ID:
1654 ret = bgp_attr_originator_id (peer, length, attr, flag);
1655 break;
1656 case BGP_ATTR_CLUSTER_LIST:
1657 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1658 break;
1659 case BGP_ATTR_MP_REACH_NLRI:
1660 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1661 break;
1662 case BGP_ATTR_MP_UNREACH_NLRI:
1663 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1664 break;
1665 case BGP_ATTR_EXT_COMMUNITIES:
1666 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1667 break;
Paul Jakma41367172007-08-06 15:24:51 +00001668 case BGP_ATTR_AS_PATHLIMIT:
1669 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1670 break;
paul718e3742002-12-13 20:15:29 +00001671 default:
1672 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1673 break;
1674 }
1675
1676 /* If error occured immediately return to the caller. */
1677 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001678 {
1679 zlog (peer->log, LOG_WARNING,
1680 "%s: Attribute %s, parse error",
1681 peer->host,
1682 LOOKUP (attr_str, type));
1683 bgp_notify_send (peer,
1684 BGP_NOTIFY_UPDATE_ERR,
1685 BGP_NOTIFY_UPDATE_MAL_ATTR);
1686 return ret;
1687 }
paul718e3742002-12-13 20:15:29 +00001688
1689 /* Check the fetched length. */
1690 if (BGP_INPUT_PNT (peer) != attr_endp)
1691 {
1692 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001693 "%s: BGP attribute %s, fetch error",
1694 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001695 bgp_notify_send (peer,
1696 BGP_NOTIFY_UPDATE_ERR,
1697 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1698 return -1;
1699 }
1700 }
1701
1702 /* Check final read pointer is same as end pointer. */
1703 if (BGP_INPUT_PNT (peer) != endp)
1704 {
1705 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001706 "%s BGP attribute %s, length mismatch",
1707 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001708 bgp_notify_send (peer,
1709 BGP_NOTIFY_UPDATE_ERR,
1710 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1711 return -1;
1712 }
1713
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001714 /*
1715 * At this place we can see whether we got AS4_PATH and/or
1716 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1717 * We can not do this before we've read all attributes because
1718 * the as4 handling does not say whether AS4_PATH has to be sent
1719 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1720 * in relationship to AGGREGATOR.
1721 * So, to be defensive, we are not relying on any order and read
1722 * all attributes first, including these 32bit ones, and now,
1723 * afterwards, we look what and if something is to be done for as4.
1724 */
1725 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1726 as4_aggregator, &as4_aggregator_addr))
1727 return -1;
1728
1729 /* At this stage, we have done all fiddling with as4, and the
1730 * resulting info is in attr->aggregator resp. attr->aspath
1731 * so we can chuck as4_aggregator and as4_path alltogether in
1732 * order to save memory
1733 */
1734 if ( as4_path )
1735 {
1736 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1737 as4_path = NULL;
1738 /* The flag that we got this is still there, but that does not
1739 * do any trouble
1740 */
1741 }
1742 /*
1743 * The "rest" of the code does nothing with as4_aggregator.
1744 * there is no memory attached specifically which is not part
1745 * of the attr.
1746 * so ignoring just means do nothing.
1747 */
1748 /*
1749 * Finally do the checks on the aspath we did not do yet
1750 * because we waited for a potentially synthesized aspath.
1751 */
1752 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1753 {
1754 ret = bgp_attr_aspath_check( peer, attr );
1755 if ( ret < 0 )
1756 return ret;
1757 }
1758
paul718e3742002-12-13 20:15:29 +00001759 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001760 if (attr->extra && attr->extra->transit)
1761 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001762
1763 return 0;
1764}
1765
1766/* Well-known attribute check. */
1767int
1768bgp_attr_check (struct peer *peer, struct attr *attr)
1769{
1770 u_char type = 0;
1771
1772 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1773 type = BGP_ATTR_ORIGIN;
1774
1775 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1776 type = BGP_ATTR_AS_PATH;
1777
1778 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1779 type = BGP_ATTR_NEXT_HOP;
1780
1781 if (peer_sort (peer) == BGP_PEER_IBGP
1782 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1783 type = BGP_ATTR_LOCAL_PREF;
1784
1785 if (type)
1786 {
1787 zlog (peer->log, LOG_WARNING,
1788 "%s Missing well-known attribute %d.",
1789 peer->host, type);
1790 bgp_notify_send_with_data (peer,
1791 BGP_NOTIFY_UPDATE_ERR,
1792 BGP_NOTIFY_UPDATE_MISS_ATTR,
1793 &type, 1);
1794 return -1;
1795 }
1796 return 0;
1797}
1798
1799int stream_put_prefix (struct stream *, struct prefix *);
1800
1801/* Make attribute packet. */
1802bgp_size_t
1803bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1804 struct stream *s, struct attr *attr, struct prefix *p,
1805 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001806 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001807{
paulfe69a502005-09-10 16:55:02 +00001808 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001809 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001810 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001811 int send_as4_path = 0;
1812 int send_as4_aggregator = 0;
1813 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001814
1815 if (! bgp)
1816 bgp = bgp_get_default ();
1817
1818 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001819 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001820
1821 /* Origin attribute. */
1822 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1823 stream_putc (s, BGP_ATTR_ORIGIN);
1824 stream_putc (s, 1);
1825 stream_putc (s, attr->origin);
1826
1827 /* AS path attribute. */
1828
1829 /* If remote-peer is EBGP */
1830 if (peer_sort (peer) == BGP_PEER_EBGP
1831 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001832 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001833 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001834 {
1835 aspath = aspath_dup (attr->aspath);
1836
1837 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1838 {
1839 /* Strip the confed info, and then stuff our path CONFED_ID
1840 on the front */
1841 aspath = aspath_delete_confed_seq (aspath);
1842 aspath = aspath_add_seq (aspath, bgp->confed_id);
1843 }
1844 else
1845 {
1846 aspath = aspath_add_seq (aspath, peer->local_as);
1847 if (peer->change_local_as)
1848 aspath = aspath_add_seq (aspath, peer->change_local_as);
1849 }
1850 }
1851 else if (peer_sort (peer) == BGP_PEER_CONFED)
1852 {
1853 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1854 aspath = aspath_dup (attr->aspath);
1855 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1856 }
1857 else
1858 aspath = attr->aspath;
1859
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001860 /* If peer is not AS4 capable, then:
1861 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1862 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1863 * types are in it (i.e. exclude them if they are there)
1864 * AND do this only if there is at least one asnum > 65535 in the path!
1865 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1866 * all ASnums > 65535 to BGP_AS_TRANS
1867 */
paul718e3742002-12-13 20:15:29 +00001868
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001869 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1870 stream_putc (s, BGP_ATTR_AS_PATH);
1871 aspath_sizep = stream_get_endp (s);
1872 stream_putw (s, 0);
1873 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1874
1875 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1876 * in the path
1877 */
1878 if (!use32bit && aspath_has_as4 (aspath))
1879 send_as4_path = 1; /* we'll do this later, at the correct place */
1880
paul718e3742002-12-13 20:15:29 +00001881 /* Nexthop attribute. */
1882 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1883 {
1884 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1885 stream_putc (s, BGP_ATTR_NEXT_HOP);
1886 stream_putc (s, 4);
1887 if (safi == SAFI_MPLS_VPN)
1888 {
1889 if (attr->nexthop.s_addr == 0)
1890 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1891 else
1892 stream_put_ipv4 (s, attr->nexthop.s_addr);
1893 }
1894 else
1895 stream_put_ipv4 (s, attr->nexthop.s_addr);
1896 }
1897
1898 /* MED attribute. */
1899 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1900 {
1901 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1902 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1903 stream_putc (s, 4);
1904 stream_putl (s, attr->med);
1905 }
1906
1907 /* Local preference. */
1908 if (peer_sort (peer) == BGP_PEER_IBGP ||
1909 peer_sort (peer) == BGP_PEER_CONFED)
1910 {
1911 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1912 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1913 stream_putc (s, 4);
1914 stream_putl (s, attr->local_pref);
1915 }
1916
1917 /* Atomic aggregate. */
1918 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1919 {
1920 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1921 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1922 stream_putc (s, 0);
1923 }
1924
1925 /* Aggregator. */
1926 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1927 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001928 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001929
1930 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001931 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1932 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001933
1934 if (use32bit)
1935 {
1936 /* AS4 capable peer */
1937 stream_putc (s, 8);
1938 stream_putl (s, attr->extra->aggregator_as);
1939 }
1940 else
1941 {
1942 /* 2-byte AS peer */
1943 stream_putc (s, 6);
1944
1945 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1946 if ( attr->extra->aggregator_as > 65535 )
1947 {
1948 stream_putw (s, BGP_AS_TRANS);
1949
1950 /* we have to send AS4_AGGREGATOR, too.
1951 * we'll do that later in order to send attributes in ascending
1952 * order.
1953 */
1954 send_as4_aggregator = 1;
1955 }
1956 else
1957 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1958 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001959 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001960 }
1961
1962 /* Community attribute. */
1963 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1964 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1965 {
1966 if (attr->community->size * 4 > 255)
1967 {
1968 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1969 stream_putc (s, BGP_ATTR_COMMUNITIES);
1970 stream_putw (s, attr->community->size * 4);
1971 }
1972 else
1973 {
1974 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1975 stream_putc (s, BGP_ATTR_COMMUNITIES);
1976 stream_putc (s, attr->community->size * 4);
1977 }
1978 stream_put (s, attr->community->val, attr->community->size * 4);
1979 }
1980
1981 /* Route Reflector. */
1982 if (peer_sort (peer) == BGP_PEER_IBGP
1983 && from
1984 && peer_sort (from) == BGP_PEER_IBGP)
1985 {
1986 /* Originator ID. */
1987 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1988 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1989 stream_putc (s, 4);
1990
1991 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00001992 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001993 else
1994 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001995
1996 /* Cluster list. */
1997 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1998 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1999
Paul Jakma9eda90c2007-08-30 13:36:17 +00002000 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002001 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002002 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002003 /* If this peer configuration's parent BGP has cluster_id. */
2004 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2005 stream_put_in_addr (s, &bgp->cluster_id);
2006 else
2007 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002008 stream_put (s, attr->extra->cluster->list,
2009 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002010 }
2011 else
2012 {
2013 stream_putc (s, 4);
2014 /* If this peer configuration's parent BGP has cluster_id. */
2015 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2016 stream_put_in_addr (s, &bgp->cluster_id);
2017 else
2018 stream_put_in_addr (s, &bgp->router_id);
2019 }
2020 }
2021
2022#ifdef HAVE_IPV6
2023 /* If p is IPv6 address put it into attribute. */
2024 if (p->family == AF_INET6)
2025 {
2026 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002027 struct attr_extra *attre = attr->extra;
2028
2029 assert (attr->extra);
2030
paul718e3742002-12-13 20:15:29 +00002031 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2032 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002033 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002034 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002035 stream_putw (s, AFI_IP6); /* AFI */
2036 stream_putc (s, safi); /* SAFI */
2037
Paul Jakmafb982c22007-05-04 20:15:47 +00002038 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002039
Paul Jakmafb982c22007-05-04 20:15:47 +00002040 if (attre->mp_nexthop_len == 16)
2041 stream_put (s, &attre->mp_nexthop_global, 16);
2042 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002043 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002044 stream_put (s, &attre->mp_nexthop_global, 16);
2045 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002046 }
2047
2048 /* SNPA */
2049 stream_putc (s, 0);
2050
paul718e3742002-12-13 20:15:29 +00002051 /* Prefix write. */
2052 stream_put_prefix (s, p);
2053
2054 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002055 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002056 }
2057#endif /* HAVE_IPV6 */
2058
2059 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2060 {
2061 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002062
2063 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2064 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002065 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002066 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002067 stream_putw (s, AFI_IP); /* AFI */
2068 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2069
2070 stream_putc (s, 4);
2071 stream_put_ipv4 (s, attr->nexthop.s_addr);
2072
2073 /* SNPA */
2074 stream_putc (s, 0);
2075
paul718e3742002-12-13 20:15:29 +00002076 /* Prefix write. */
2077 stream_put_prefix (s, p);
2078
2079 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002080 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002081 }
2082
2083 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2084 {
2085 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002086
2087 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2088 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002089 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002090 stream_putc (s, 0); /* Length of this attribute. */
2091 stream_putw (s, AFI_IP); /* AFI */
2092 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2093
2094 stream_putc (s, 12);
2095 stream_putl (s, 0);
2096 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002097 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002098
2099 /* SNPA */
2100 stream_putc (s, 0);
2101
paul718e3742002-12-13 20:15:29 +00002102 /* Tag, RD, Prefix write. */
2103 stream_putc (s, p->prefixlen + 88);
2104 stream_put (s, tag, 3);
2105 stream_put (s, prd->val, 8);
2106 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2107
2108 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002109 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002110 }
2111
2112 /* Extended Communities attribute. */
2113 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2114 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2115 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002116 struct attr_extra *attre = attr->extra;
2117
2118 assert (attre);
2119
2120 if (peer_sort (peer) == BGP_PEER_IBGP
2121 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002122 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002123 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002124 {
2125 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2126 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002127 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002128 }
2129 else
2130 {
2131 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2132 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002133 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002134 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002135 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002136 }
2137 else
2138 {
paul5228ad22004-06-04 17:58:18 +00002139 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002140 int tbit;
2141 int ecom_tr_size = 0;
2142 int i;
2143
Paul Jakmafb982c22007-05-04 20:15:47 +00002144 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002145 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002146 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002147 tbit = *pnt;
2148
2149 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2150 continue;
2151
2152 ecom_tr_size++;
2153 }
2154
2155 if (ecom_tr_size)
2156 {
2157 if (ecom_tr_size * 8 > 255)
2158 {
2159 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2160 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2161 stream_putw (s, ecom_tr_size * 8);
2162 }
2163 else
2164 {
2165 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2166 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2167 stream_putc (s, ecom_tr_size * 8);
2168 }
2169
Paul Jakmafb982c22007-05-04 20:15:47 +00002170 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002171 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002172 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002173 tbit = *pnt;
2174
2175 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2176 continue;
2177
2178 stream_put (s, pnt, 8);
2179 }
2180 }
paul718e3742002-12-13 20:15:29 +00002181 }
paul718e3742002-12-13 20:15:29 +00002182 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002183
2184 if ( send_as4_path )
2185 {
2186 /* If the peer is NOT As4 capable, AND */
2187 /* there are ASnums > 65535 in path THEN
2188 * give out AS4_PATH */
2189
2190 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2191 * path segments!
2192 * Hm, I wonder... confederation things *should* only be at
2193 * the beginning of an aspath, right? Then we should use
2194 * aspath_delete_confed_seq for this, because it is already
2195 * there! (JK)
2196 * Folks, talk to me: what is reasonable here!?
2197 */
2198 aspath = aspath_delete_confed_seq (aspath);
2199
2200 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2201 stream_putc (s, BGP_ATTR_AS4_PATH);
2202 aspath_sizep = stream_get_endp (s);
2203 stream_putw (s, 0);
2204 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2205 }
2206
2207 if (aspath != attr->aspath)
2208 aspath_free (aspath);
2209
2210 if ( send_as4_aggregator )
2211 {
2212 assert (attr->extra);
2213
2214 /* send AS4_AGGREGATOR, at this place */
2215 /* this section of code moved here in order to ensure the correct
2216 * *ascending* order of attributes
2217 */
2218 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2219 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2220 stream_putc (s, 8);
2221 stream_putl (s, attr->extra->aggregator_as);
2222 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2223 }
Paul Jakma41367172007-08-06 15:24:51 +00002224
2225 /* AS-Pathlimit */
2226 if (attr->pathlimit.ttl)
2227 {
2228 u_int32_t as = attr->pathlimit.as;
2229
2230 /* should already have been done in announce_check(),
2231 * but just in case..
2232 */
2233 if (!as)
2234 as = peer->local_as;
2235
2236 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2237 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2238 stream_putc (s, 5);
2239 stream_putc (s, attr->pathlimit.ttl);
2240 stream_putl (s, as);
2241 }
2242
paul718e3742002-12-13 20:15:29 +00002243 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002244 if (attr->extra && attr->extra->transit)
2245 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002246
2247 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002248 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002249}
2250
2251bgp_size_t
2252bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2253 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002254 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002255{
2256 unsigned long cp;
2257 unsigned long attrlen_pnt;
2258 bgp_size_t size;
2259
paul9985f832005-02-09 15:51:56 +00002260 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002261
2262 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2263 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2264
paul9985f832005-02-09 15:51:56 +00002265 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002266 stream_putc (s, 0); /* Length of this attribute. */
2267
2268 stream_putw (s, family2afi (p->family));
2269
2270 if (safi == SAFI_MPLS_VPN)
2271 {
2272 /* SAFI */
2273 stream_putc (s, BGP_SAFI_VPNV4);
2274
2275 /* prefix. */
2276 stream_putc (s, p->prefixlen + 88);
2277 stream_put (s, tag, 3);
2278 stream_put (s, prd->val, 8);
2279 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2280 }
2281 else
2282 {
2283 /* SAFI */
2284 stream_putc (s, safi);
2285
2286 /* prefix */
2287 stream_put_prefix (s, p);
2288 }
2289
2290 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002291 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002292 stream_putc_at (s, attrlen_pnt, size);
2293
paul9985f832005-02-09 15:51:56 +00002294 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002295}
2296
2297/* Initialization of attribute. */
2298void
paulfe69a502005-09-10 16:55:02 +00002299bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002300{
paul718e3742002-12-13 20:15:29 +00002301 aspath_init ();
2302 attrhash_init ();
2303 community_init ();
2304 ecommunity_init ();
2305 cluster_init ();
2306 transit_init ();
2307}
2308
2309/* Make attribute packet. */
2310void
paula3845922003-10-18 01:30:50 +00002311bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2312 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002313{
2314 unsigned long cp;
2315 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002316 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002317 struct aspath *aspath;
2318
2319 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002320 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002321
2322 /* Place holder of length. */
2323 stream_putw (s, 0);
2324
2325 /* Origin attribute. */
2326 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2327 stream_putc (s, BGP_ATTR_ORIGIN);
2328 stream_putc (s, 1);
2329 stream_putc (s, attr->origin);
2330
2331 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002332
2333 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2334 stream_putc (s, BGP_ATTR_AS_PATH);
2335 aspath_lenp = stream_get_endp (s);
2336 stream_putw (s, 0);
2337
2338 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002339
2340 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002341 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2342 if(prefix != NULL
2343#ifdef HAVE_IPV6
2344 && prefix->family != AF_INET6
2345#endif /* HAVE_IPV6 */
2346 )
2347 {
2348 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2349 stream_putc (s, BGP_ATTR_NEXT_HOP);
2350 stream_putc (s, 4);
2351 stream_put_ipv4 (s, attr->nexthop.s_addr);
2352 }
paul718e3742002-12-13 20:15:29 +00002353
2354 /* MED attribute. */
2355 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2356 {
2357 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2358 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2359 stream_putc (s, 4);
2360 stream_putl (s, attr->med);
2361 }
2362
2363 /* Local preference. */
2364 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2365 {
2366 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2367 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2368 stream_putc (s, 4);
2369 stream_putl (s, attr->local_pref);
2370 }
2371
2372 /* Atomic aggregate. */
2373 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2374 {
2375 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2376 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2377 stream_putc (s, 0);
2378 }
2379
2380 /* Aggregator. */
2381 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2382 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002383 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002384 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2385 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002386 stream_putc (s, 8);
2387 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002388 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002389 }
2390
2391 /* Community attribute. */
2392 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2393 {
2394 if (attr->community->size * 4 > 255)
2395 {
2396 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2397 stream_putc (s, BGP_ATTR_COMMUNITIES);
2398 stream_putw (s, attr->community->size * 4);
2399 }
2400 else
2401 {
2402 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2403 stream_putc (s, BGP_ATTR_COMMUNITIES);
2404 stream_putc (s, attr->community->size * 4);
2405 }
2406 stream_put (s, attr->community->val, attr->community->size * 4);
2407 }
2408
paula3845922003-10-18 01:30:50 +00002409#ifdef HAVE_IPV6
2410 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002411 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2412 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002413 {
2414 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002415 struct attr_extra *attre = attr->extra;
2416
paula3845922003-10-18 01:30:50 +00002417 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2418 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002419 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002420
2421 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002422 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002423 stream_putw(s, AFI_IP6); /* AFI */
2424 stream_putc(s, SAFI_UNICAST); /* SAFI */
2425
2426 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002427 stream_putc(s, attre->mp_nexthop_len);
2428 stream_put(s, &attre->mp_nexthop_global, 16);
2429 if (attre->mp_nexthop_len == 32)
2430 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002431
2432 /* SNPA */
2433 stream_putc(s, 0);
2434
2435 /* Prefix */
2436 stream_put_prefix(s, prefix);
2437
2438 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002439 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002440 }
2441#endif /* HAVE_IPV6 */
2442
Paul Jakma41367172007-08-06 15:24:51 +00002443 /* AS-Pathlimit */
2444 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2445 {
2446 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2447 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2448 stream_putc (s, 5);
2449 stream_putc (s, attr->pathlimit.ttl);
2450 stream_putl (s, attr->pathlimit.as);
2451 }
2452
paul718e3742002-12-13 20:15:29 +00002453 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002454 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002455 stream_putw_at (s, cp, len);
2456}