blob: 07c941300fc5edf26ec71fd972f1762ef163c641 [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" },
59 { 0, NULL }
60};
Paul Jakma6e4ab122007-04-10 19:36:48 +000061int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000062
63struct hash *cluster_hash;
64
paul94f2b392005-06-28 12:44:16 +000065static void *
Paul Jakma923de652007-04-29 18:25:17 +000066cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000067{
Paul Jakma923de652007-04-29 18:25:17 +000068 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000069 struct cluster_list *cluster;
70
71 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
72 cluster->length = val->length;
73
74 if (cluster->length)
75 {
76 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
77 memcpy (cluster->list, val->list, val->length);
78 }
79 else
80 cluster->list = NULL;
81
82 cluster->refcnt = 0;
83
84 return cluster;
85}
86
87/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000088static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000089cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000090{
91 struct cluster_list tmp;
92 struct cluster_list *cluster;
93
94 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000095 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +000096
97 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
98 cluster->refcnt++;
99 return cluster;
100}
101
102int
103cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
104{
105 int i;
106
107 for (i = 0; i < cluster->length / 4; i++)
108 if (cluster->list[i].s_addr == originator.s_addr)
109 return 1;
110 return 0;
111}
112
paul94f2b392005-06-28 12:44:16 +0000113static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000114cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000115{
Paul Jakma923de652007-04-29 18:25:17 +0000116 struct cluster_list * cluster = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +0000117 unsigned int key = 0;
118 int length;
119 caddr_t pnt;
120
121 length = cluster->length;
122 pnt = (caddr_t) cluster->list;
123
124 while (length)
125 key += pnt[--length];
126
127 return key;
128}
129
paul94f2b392005-06-28 12:44:16 +0000130static int
Paul Jakma923de652007-04-29 18:25:17 +0000131cluster_hash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000132{
Paul Jakma923de652007-04-29 18:25:17 +0000133 struct cluster_list * cluster1 = (struct cluster_list *) p1;
134 struct cluster_list * cluster2 = (struct cluster_list *) p2;
135
paul718e3742002-12-13 20:15:29 +0000136 if (cluster1->length == cluster2->length &&
137 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0)
138 return 1;
139 return 0;
140}
141
paul94f2b392005-06-28 12:44:16 +0000142static void
paul718e3742002-12-13 20:15:29 +0000143cluster_free (struct cluster_list *cluster)
144{
145 if (cluster->list)
146 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
147 XFREE (MTYPE_CLUSTER, cluster);
148}
149
paul94f2b392005-06-28 12:44:16 +0000150static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000151cluster_dup (struct cluster_list *cluster)
152{
153 struct cluster_list *new;
154
155 new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
156 memset (new, 0, sizeof (struct cluster_list));
157 new->length = cluster->length;
158
159 if (cluster->length)
160 {
161 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
162 memcpy (new->list, cluster->list, cluster->length);
163 }
164 else
165 new->list = NULL;
166
167 return new;
168}
169
paul94f2b392005-06-28 12:44:16 +0000170static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000171cluster_intern (struct cluster_list *cluster)
172{
173 struct cluster_list *find;
174
175 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
176 find->refcnt++;
177
178 return find;
179}
180
181void
182cluster_unintern (struct cluster_list *cluster)
183{
184 struct cluster_list *ret;
185
186 if (cluster->refcnt)
187 cluster->refcnt--;
188
189 if (cluster->refcnt == 0)
190 {
191 ret = hash_release (cluster_hash, cluster);
192 cluster_free (cluster);
193 }
194}
195
paul94f2b392005-06-28 12:44:16 +0000196static void
197cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000198{
199 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
200}
201
202/* Unknown transit attribute. */
203struct hash *transit_hash;
204
paul94f2b392005-06-28 12:44:16 +0000205static void
paul718e3742002-12-13 20:15:29 +0000206transit_free (struct transit *transit)
207{
208 if (transit->val)
209 XFREE (MTYPE_TRANSIT_VAL, transit->val);
210 XFREE (MTYPE_TRANSIT, transit);
211}
212
Paul Jakma923de652007-04-29 18:25:17 +0000213
paul94f2b392005-06-28 12:44:16 +0000214static void *
Paul Jakma923de652007-04-29 18:25:17 +0000215transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000216{
217 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000218 return p;
paul718e3742002-12-13 20:15:29 +0000219}
220
paul94f2b392005-06-28 12:44:16 +0000221static struct transit *
paul718e3742002-12-13 20:15:29 +0000222transit_intern (struct transit *transit)
223{
224 struct transit *find;
225
226 find = hash_get (transit_hash, transit, transit_hash_alloc);
227 if (find != transit)
228 transit_free (transit);
229 find->refcnt++;
230
231 return find;
232}
233
234void
235transit_unintern (struct transit *transit)
236{
237 struct transit *ret;
238
239 if (transit->refcnt)
240 transit->refcnt--;
241
242 if (transit->refcnt == 0)
243 {
244 ret = hash_release (transit_hash, transit);
245 transit_free (transit);
246 }
247}
248
paul94f2b392005-06-28 12:44:16 +0000249static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000250transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000251{
Paul Jakma923de652007-04-29 18:25:17 +0000252 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000253 unsigned int key = 0;
254 int length;
255 caddr_t pnt;
256
257 length = transit->length;
258 pnt = (caddr_t) transit->val;
259
260 while (length)
261 key += pnt[--length];
262
263 return key;
264}
265
paul94f2b392005-06-28 12:44:16 +0000266static int
Paul Jakma923de652007-04-29 18:25:17 +0000267transit_hash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000268{
Paul Jakma923de652007-04-29 18:25:17 +0000269 struct transit * transit1 = (struct transit *) p1;
270 struct transit * transit2 = (struct transit *) p2;
271
paul718e3742002-12-13 20:15:29 +0000272 if (transit1->length == transit2->length &&
273 memcmp (transit1->val, transit2->val, transit1->length) == 0)
274 return 1;
275 return 0;
276}
277
paul94f2b392005-06-28 12:44:16 +0000278static void
paul718e3742002-12-13 20:15:29 +0000279transit_init ()
280{
281 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
282}
283
284/* Attribute hash routines. */
paul718e3742002-12-13 20:15:29 +0000285struct hash *attrhash;
286
Paul Jakmafb982c22007-05-04 20:15:47 +0000287static struct attr_extra *
288bgp_attr_extra_new (void)
289{
290 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
291}
292
293void
294bgp_attr_extra_free (struct attr *attr)
295{
296 if (attr->extra)
297 {
298 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
299 attr->extra = NULL;
300 }
301}
302
303struct attr_extra *
304bgp_attr_extra_get (struct attr *attr)
305{
306 if (!attr->extra)
307 attr->extra = bgp_attr_extra_new();
308 return attr->extra;
309}
310
311/* Shallow copy of an attribute
312 * Though, not so shallow that it doesn't copy the contents
313 * of the attr_extra pointed to by 'extra'
314 */
315void
316bgp_attr_dup (struct attr *new, struct attr *orig)
317{
318 *new = *orig;
319 if (orig->extra)
320 {
321 new->extra = bgp_attr_extra_new();
322 *new->extra = *orig->extra;
323 }
324}
325
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000326unsigned long int
327attr_count (void)
328{
329 return attrhash->count;
330}
331
332unsigned long int
333attr_unknown_count (void)
334{
335 return transit_hash->count;
336}
337
paul718e3742002-12-13 20:15:29 +0000338unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000339attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000340{
Paul Jakma923de652007-04-29 18:25:17 +0000341 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000342 unsigned int key = 0;
343
344 key += attr->origin;
345 key += attr->nexthop.s_addr;
346 key += attr->med;
347 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000348
349 if (attr->extra)
350 {
351 key += attr->extra->aggregator_as;
352 key += attr->extra->aggregator_addr.s_addr;
353 key += attr->extra->weight;
354 key += attr->extra->mp_nexthop_global_in.s_addr;
355 }
356
paul718e3742002-12-13 20:15:29 +0000357 if (attr->aspath)
358 key += aspath_key_make (attr->aspath);
359 if (attr->community)
360 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000361
362 if (attr->extra)
363 {
364 if (attr->extra->ecommunity)
365 key += ecommunity_hash_make (attr->extra->ecommunity);
366 if (attr->extra->cluster)
367 key += cluster_hash_key_make (attr->extra->cluster);
368 if (attr->extra->transit)
369 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000370
371#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000372 {
373 int i;
374
375 key += attr->extra->mp_nexthop_len;
376 for (i = 0; i < 16; i++)
377 key += attr->extra->mp_nexthop_global.s6_addr[i];
378 for (i = 0; i < 16; i++)
379 key += attr->extra->mp_nexthop_local.s6_addr[i];
380 }
paul718e3742002-12-13 20:15:29 +0000381#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000382 }
paul718e3742002-12-13 20:15:29 +0000383
384 return key;
385}
386
387int
Paul Jakma923de652007-04-29 18:25:17 +0000388attrhash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000389{
Paul Jakma923de652007-04-29 18:25:17 +0000390 struct attr * attr1 = (struct attr *) p1;
391 struct attr * attr2 = (struct attr *) p2;
392
paul718e3742002-12-13 20:15:29 +0000393 if (attr1->flag == attr2->flag
394 && attr1->origin == attr2->origin
395 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000396 && attr1->aspath == attr2->aspath
397 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000398 && attr1->med == attr2->med
399 && attr1->local_pref == attr2->local_pref)
400 {
401 struct attr_extra *ae1 = attr1->extra;
402 struct attr_extra *ae2 = attr2->extra;
403
404 if (ae1 && ae2
405 && ae1->aggregator_as == ae2->aggregator_as
406 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
407 && ae1->weight == ae2->weight
408#ifdef HAVE_IPV6
409 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
410 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
411 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
412#endif /* HAVE_IPV6 */
413 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
414 && ae1->ecommunity == ae2->ecommunity
415 && ae1->cluster == ae2->cluster
416 && ae1->transit == ae2->transit)
417 return 1;
418 else if (ae1 || ae2)
419 return 0;
420 /* neither attribute has extra attributes, so they're same */
421 return 1;
422 }
paul718e3742002-12-13 20:15:29 +0000423 else
424 return 0;
425}
426
paul94f2b392005-06-28 12:44:16 +0000427static void
paul718e3742002-12-13 20:15:29 +0000428attrhash_init ()
429{
430 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
431}
432
paul94f2b392005-06-28 12:44:16 +0000433static void
paul718e3742002-12-13 20:15:29 +0000434attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
435{
436 struct attr *attr = backet->data;
437
438 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
439 inet_ntoa (attr->nexthop), VTY_NEWLINE);
440}
441
442void
443attr_show_all (struct vty *vty)
444{
445 hash_iterate (attrhash,
446 (void (*)(struct hash_backet *, void *))
447 attr_show_all_iterator,
448 vty);
449}
450
paul94f2b392005-06-28 12:44:16 +0000451static void *
Paul Jakma923de652007-04-29 18:25:17 +0000452bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000453{
Paul Jakma923de652007-04-29 18:25:17 +0000454 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000455 struct attr *attr;
456
457 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
458 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000459 if (val->extra)
460 {
461 attr->extra = bgp_attr_extra_new ();
462 *attr->extra = *val->extra;
463 }
paul718e3742002-12-13 20:15:29 +0000464 attr->refcnt = 0;
465 return attr;
466}
467
468/* Internet argument attribute. */
469struct attr *
470bgp_attr_intern (struct attr *attr)
471{
472 struct attr *find;
473
474 /* Intern referenced strucutre. */
475 if (attr->aspath)
476 {
477 if (! attr->aspath->refcnt)
478 attr->aspath = aspath_intern (attr->aspath);
479 else
480 attr->aspath->refcnt++;
481 }
482 if (attr->community)
483 {
484 if (! attr->community->refcnt)
485 attr->community = community_intern (attr->community);
486 else
487 attr->community->refcnt++;
488 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000489 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000490 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000491 struct attr_extra *attre = attr->extra;
492
493 if (attre->ecommunity)
494 {
495 if (! attre->ecommunity->refcnt)
496 attre->ecommunity = ecommunity_intern (attre->ecommunity);
497 else
498 attre->ecommunity->refcnt++;
499 }
500 if (attre->cluster)
501 {
502 if (! attre->cluster->refcnt)
503 attre->cluster = cluster_intern (attre->cluster);
504 else
505 attre->cluster->refcnt++;
506 }
507 if (attre->transit)
508 {
509 if (! attre->transit->refcnt)
510 attre->transit = transit_intern (attre->transit);
511 else
512 attre->transit->refcnt++;
513 }
paul718e3742002-12-13 20:15:29 +0000514 }
515
516 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
517 find->refcnt++;
518
519 return find;
520}
521
Paul Jakma03e214c2007-04-29 18:31:07 +0000522
paul718e3742002-12-13 20:15:29 +0000523/* Make network statement's attribute. */
524struct attr *
525bgp_attr_default_set (struct attr *attr, u_char origin)
526{
527 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000528 bgp_attr_extra_get (attr);
529
paul718e3742002-12-13 20:15:29 +0000530 attr->origin = origin;
531 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
532 attr->aspath = aspath_empty ();
533 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000534 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000535 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
536#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000537 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000538#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000539
paul718e3742002-12-13 20:15:29 +0000540 return attr;
541}
542
Paul Jakma03e214c2007-04-29 18:31:07 +0000543
paul718e3742002-12-13 20:15:29 +0000544/* Make network statement's attribute. */
545struct attr *
546bgp_attr_default_intern (u_char origin)
547{
548 struct attr attr;
549 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000550 struct attr_extra *attre;
551
552 memset (&attr, 0, sizeof (struct attr));
553 attre = bgp_attr_extra_get (&attr);
554
Paul Jakma03e214c2007-04-29 18:31:07 +0000555 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000556
557 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000558 bgp_attr_extra_free (&attr);
559
paul718e3742002-12-13 20:15:29 +0000560 aspath_unintern (new->aspath);
561 return new;
562}
563
564struct attr *
565bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
566 struct aspath *aspath,
567 struct community *community, int as_set)
568{
569 struct attr attr;
570 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000571 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000572
573 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000574 attre = bgp_attr_extra_get (&attr);
575
paul718e3742002-12-13 20:15:29 +0000576 /* Origin attribute. */
577 attr.origin = origin;
578 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
579
580 /* AS path attribute. */
581 if (aspath)
582 attr.aspath = aspath_intern (aspath);
583 else
584 attr.aspath = aspath_empty ();
585 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
586
587 /* Next hop attribute. */
588 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
589
590 if (community)
591 {
592 attr.community = community;
593 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
594 }
595
Paul Jakmafb982c22007-05-04 20:15:47 +0000596 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000597#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000598 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000599#endif
600 if (! as_set)
601 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
602 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
603 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000604 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000605 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000606 attre->aggregator_as = bgp->as;
607 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000608
609 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000610 bgp_attr_extra_free (&attr);
611
paul718e3742002-12-13 20:15:29 +0000612 aspath_unintern (new->aspath);
613 return new;
614}
615
616/* Free bgp attribute and aspath. */
617void
618bgp_attr_unintern (struct attr *attr)
619{
620 struct attr *ret;
621 struct aspath *aspath;
622 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000623 struct ecommunity *ecommunity = NULL;
624 struct cluster_list *cluster = NULL;
625 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000626
627 /* Decrement attribute reference. */
628 attr->refcnt--;
629 aspath = attr->aspath;
630 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000631 if (attr->extra)
632 {
633 ecommunity = attr->extra->ecommunity;
634 cluster = attr->extra->cluster;
635 transit = attr->extra->transit;
636 }
paul718e3742002-12-13 20:15:29 +0000637
638 /* If reference becomes zero then free attribute object. */
639 if (attr->refcnt == 0)
640 {
641 ret = hash_release (attrhash, attr);
642 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000643 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000644 XFREE (MTYPE_ATTR, attr);
645 }
646
647 /* aspath refcount shoud be decrement. */
648 if (aspath)
649 aspath_unintern (aspath);
650 if (community)
651 community_unintern (community);
652 if (ecommunity)
653 ecommunity_unintern (ecommunity);
654 if (cluster)
655 cluster_unintern (cluster);
656 if (transit)
657 transit_unintern (transit);
658}
659
660void
661bgp_attr_flush (struct attr *attr)
662{
663 if (attr->aspath && ! attr->aspath->refcnt)
664 aspath_free (attr->aspath);
665 if (attr->community && ! attr->community->refcnt)
666 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000667 if (attr->extra)
668 {
669 struct attr_extra *attre = attr->extra;
670 if (attre->ecommunity && ! attre->ecommunity->refcnt)
671 ecommunity_free (attre->ecommunity);
672 if (attre->cluster && ! attre->cluster->refcnt)
673 cluster_free (attre->cluster);
674 if (attre->transit && ! attre->transit->refcnt)
675 transit_free (attre->transit);
676 }
paul718e3742002-12-13 20:15:29 +0000677}
678
679/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000680static int
paul718e3742002-12-13 20:15:29 +0000681bgp_attr_origin (struct peer *peer, bgp_size_t length,
682 struct attr *attr, u_char flag, u_char *startp)
683{
684 bgp_size_t total;
685
686 /* total is entire attribute length include Attribute Flags (1),
687 Attribute Type code (1) and Attribute length (1 or 2). */
688 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
689
690 /* If any recognized attribute has Attribute Flags that conflict
691 with the Attribute Type Code, then the Error Subcode is set to
692 Attribute Flags Error. The Data field contains the erroneous
693 attribute (type, length and value). */
694 if (flag != BGP_ATTR_FLAG_TRANS)
695 {
696 zlog (peer->log, LOG_ERR,
697 "Origin attribute flag isn't transitive %d", flag);
698 bgp_notify_send_with_data (peer,
699 BGP_NOTIFY_UPDATE_ERR,
700 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
701 startp, total);
702 return -1;
703 }
704
705 /* If any recognized attribute has Attribute Length that conflicts
706 with the expected length (based on the attribute type code), then
707 the Error Subcode is set to Attribute Length Error. The Data
708 field contains the erroneous attribute (type, length and
709 value). */
710 if (length != 1)
711 {
712 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
713 length);
714 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
715 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
716 startp, total);
717 return -1;
718 }
719
720 /* Fetch origin attribute. */
721 attr->origin = stream_getc (BGP_INPUT (peer));
722
723 /* If the ORIGIN attribute has an undefined value, then the Error
724 Subcode is set to Invalid Origin Attribute. The Data field
725 contains the unrecognized attribute (type, length and value). */
726 if ((attr->origin != BGP_ORIGIN_IGP)
727 && (attr->origin != BGP_ORIGIN_EGP)
728 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
729 {
730 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
731 attr->origin);
732
733 bgp_notify_send_with_data (peer,
734 BGP_NOTIFY_UPDATE_ERR,
735 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
736 startp, total);
737 return -1;
738 }
739
740 /* Set oring attribute flag. */
741 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
742
743 return 0;
744}
745
746/* Parse AS path information. This function is wrapper of
747 aspath_parse. */
paul94f2b392005-06-28 12:44:16 +0000748static int
paul718e3742002-12-13 20:15:29 +0000749bgp_attr_aspath (struct peer *peer, bgp_size_t length,
750 struct attr *attr, u_char flag, u_char *startp)
751{
752 struct bgp *bgp;
753 struct aspath *aspath;
754 bgp_size_t total;
755
756 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
757
758 /* Flag check. */
759 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
760 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
761 {
762 zlog (peer->log, LOG_ERR,
763 "Origin attribute flag isn't transitive %d", flag);
764 bgp_notify_send_with_data (peer,
765 BGP_NOTIFY_UPDATE_ERR,
766 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
767 startp, total);
768 return -1;
769 }
770
771 /* In case of IBGP, length will be zero. */
paulfe69a502005-09-10 16:55:02 +0000772 attr->aspath = aspath_parse (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000773 if (! attr->aspath)
774 {
775 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
776 bgp_notify_send (peer,
777 BGP_NOTIFY_UPDATE_ERR,
778 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
779 return -1;
780 }
781
782 bgp = peer->bgp;
783
784 /* First AS check for EBGP. */
785 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
786 {
787 if (peer_sort (peer) == BGP_PEER_EBGP
788 && ! aspath_firstas_check (attr->aspath, peer->as))
789 {
790 zlog (peer->log, LOG_ERR,
791 "%s incorrect first AS (must be %d)", peer->host, peer->as);
792 bgp_notify_send (peer,
793 BGP_NOTIFY_UPDATE_ERR,
794 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
795 return -1;
796 }
797 }
798
799 /* local-as prepend */
800 if (peer->change_local_as &&
801 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
802 {
803 aspath = aspath_dup (attr->aspath);
804 aspath = aspath_add_seq (aspath, peer->change_local_as);
805 aspath_unintern (attr->aspath);
806 attr->aspath = aspath_intern (aspath);
807 }
808
809 /* Forward pointer. */
paulfe69a502005-09-10 16:55:02 +0000810/* stream_forward_getp (peer->ibuf, length);*/
paul718e3742002-12-13 20:15:29 +0000811
812 /* Set aspath attribute flag. */
813 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
814
815 return 0;
816}
817
818/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000819static int
paul718e3742002-12-13 20:15:29 +0000820bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
821 struct attr *attr, u_char flag, u_char *startp)
822{
823 bgp_size_t total;
824
825 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
826
827 /* Flag check. */
828 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
829 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
830 {
831 zlog (peer->log, LOG_ERR,
832 "Origin attribute flag isn't transitive %d", flag);
833 bgp_notify_send_with_data (peer,
834 BGP_NOTIFY_UPDATE_ERR,
835 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
836 startp, total);
837 return -1;
838 }
839
840 /* Check nexthop attribute length. */
841 if (length != 4)
842 {
843 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
844 length);
845
846 bgp_notify_send_with_data (peer,
847 BGP_NOTIFY_UPDATE_ERR,
848 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
849 startp, total);
850 return -1;
851 }
852
853 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
854 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
855
856 return 0;
857}
858
859/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000860static int
paul718e3742002-12-13 20:15:29 +0000861bgp_attr_med (struct peer *peer, bgp_size_t length,
862 struct attr *attr, u_char flag, u_char *startp)
863{
864 bgp_size_t total;
865
866 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
867
868 /* Length check. */
869 if (length != 4)
870 {
871 zlog (peer->log, LOG_ERR,
872 "MED attribute length isn't four [%d]", length);
873
874 bgp_notify_send_with_data (peer,
875 BGP_NOTIFY_UPDATE_ERR,
876 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
877 startp, total);
878 return -1;
879 }
880
881 attr->med = stream_getl (peer->ibuf);
882
883 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
884
885 return 0;
886}
887
888/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000889static int
paul718e3742002-12-13 20:15:29 +0000890bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
891 struct attr *attr, u_char flag)
892{
893 /* If it is contained in an UPDATE message that is received from an
894 external peer, then this attribute MUST be ignored by the
895 receiving speaker. */
896 if (peer_sort (peer) == BGP_PEER_EBGP)
897 {
paul9985f832005-02-09 15:51:56 +0000898 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000899 return 0;
900 }
901
902 if (length == 4)
903 attr->local_pref = stream_getl (peer->ibuf);
904 else
905 attr->local_pref = 0;
906
907 /* Set atomic aggregate flag. */
908 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
909
910 return 0;
911}
912
913/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000914static int
paul718e3742002-12-13 20:15:29 +0000915bgp_attr_atomic (struct peer *peer, bgp_size_t length,
916 struct attr *attr, u_char flag)
917{
918 if (length != 0)
919 {
920 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
921
922 bgp_notify_send (peer,
923 BGP_NOTIFY_UPDATE_ERR,
924 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
925 return -1;
926 }
927
928 /* Set atomic aggregate flag. */
929 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
930
931 return 0;
932}
933
934/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +0000935static int
paul718e3742002-12-13 20:15:29 +0000936bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
937 struct attr *attr, u_char flag)
938{
Paul Jakmafb982c22007-05-04 20:15:47 +0000939 struct attr_extra *attre = bgp_attr_extra_get (attr);
940
paul718e3742002-12-13 20:15:29 +0000941 if (length != 6)
942 {
943 zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length);
944
945 bgp_notify_send (peer,
946 BGP_NOTIFY_UPDATE_ERR,
947 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
948 return -1;
949 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000950 attre->aggregator_as = stream_getw (peer->ibuf);
951 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +0000952
953 /* Set atomic aggregate flag. */
954 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
955
956 return 0;
957}
958
959/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +0000960static int
paul718e3742002-12-13 20:15:29 +0000961bgp_attr_community (struct peer *peer, bgp_size_t length,
962 struct attr *attr, u_char flag)
963{
964 if (length == 0)
965 attr->community = NULL;
966 else
967 {
paul5228ad22004-06-04 17:58:18 +0000968 attr->community =
969 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +0000970 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000971 }
972
973 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
974
975 return 0;
976}
977
978/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +0000979static int
paul718e3742002-12-13 20:15:29 +0000980bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
981 struct attr *attr, u_char flag)
982{
983 if (length != 4)
984 {
985 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
986
987 bgp_notify_send (peer,
988 BGP_NOTIFY_UPDATE_ERR,
989 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
990 return -1;
991 }
992
Paul Jakmafb982c22007-05-04 20:15:47 +0000993 (bgp_attr_extra_get (attr))->originator_id.s_addr
994 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +0000995
996 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
997
998 return 0;
999}
1000
1001/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001002static int
paul718e3742002-12-13 20:15:29 +00001003bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1004 struct attr *attr, u_char flag)
1005{
1006 /* Check length. */
1007 if (length % 4)
1008 {
1009 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1010
1011 bgp_notify_send (peer,
1012 BGP_NOTIFY_UPDATE_ERR,
1013 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1014 return -1;
1015 }
1016
Paul Jakmafb982c22007-05-04 20:15:47 +00001017 (bgp_attr_extra_get (attr))->cluster
1018 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001019
paul9985f832005-02-09 15:51:56 +00001020 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001021
1022 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1023
1024 return 0;
1025}
1026
1027/* Multiprotocol reachability information parse. */
paul94f2b392005-06-28 12:44:16 +00001028static int
paul718e3742002-12-13 20:15:29 +00001029bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1030 struct bgp_nlri *mp_update)
1031{
1032 u_int16_t afi;
1033 u_char safi;
paul718e3742002-12-13 20:15:29 +00001034 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001035 size_t start;
paul718e3742002-12-13 20:15:29 +00001036 int ret;
1037 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001038 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001039
1040 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001041 s = BGP_INPUT(peer);
1042 start = stream_get_getp(s);
1043
1044 /* safe to read statically sized header? */
1045#define BGP_MP_REACH_MIN_SIZE 5
1046 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
1047 return -1;
1048
paul718e3742002-12-13 20:15:29 +00001049 /* Load AFI, SAFI. */
1050 afi = stream_getw (s);
1051 safi = stream_getc (s);
1052
1053 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001054 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001055
Paul Jakmafb982c22007-05-04 20:15:47 +00001056 if (STREAM_READABLE(s) < attre->mp_nexthop_len)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001057 return -1;
1058
paul718e3742002-12-13 20:15:29 +00001059 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001060 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001061 {
1062 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001063 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001064 break;
1065 case 12:
1066 {
1067 u_int32_t rd_high;
1068 u_int32_t rd_low;
1069
1070 rd_high = stream_getl (s);
1071 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001072 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001073 }
1074 break;
1075#ifdef HAVE_IPV6
1076 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001077 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001078 break;
1079 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001080 stream_get (&attre->mp_nexthop_global, s, 16);
1081 stream_get (&attre->mp_nexthop_local, s, 16);
1082 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001083 {
1084 char buf1[INET6_ADDRSTRLEN];
1085 char buf2[INET6_ADDRSTRLEN];
1086
1087 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001088 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 +00001089 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001090 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001091 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001092 buf2, INET6_ADDRSTRLEN));
1093
Paul Jakmafb982c22007-05-04 20:15:47 +00001094 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001095 }
1096 break;
1097#endif /* HAVE_IPV6 */
1098 default:
1099 zlog_info ("Wrong multiprotocol next hop length: %d",
Paul Jakmafb982c22007-05-04 20:15:47 +00001100 attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001101 return -1;
paul718e3742002-12-13 20:15:29 +00001102 }
1103
Paul Jakma6e4ab122007-04-10 19:36:48 +00001104 if (!STREAM_READABLE(s))
1105 return -1;
paul718e3742002-12-13 20:15:29 +00001106
Paul Jakma6e4ab122007-04-10 19:36:48 +00001107 {
1108 u_char val;
1109 if ((val = stream_getc (s)))
1110 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1111 peer->host, val);
1112 }
1113
1114 /* must have nrli_len, what is left of the attribute */
1115 nlri_len = length - (stream_get_getp(s) - start);
1116 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
1117 return -1;
paul718e3742002-12-13 20:15:29 +00001118
1119 if (safi != BGP_SAFI_VPNV4)
1120 {
1121 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1122 if (ret < 0)
1123 return -1;
1124 }
1125
1126 mp_update->afi = afi;
1127 mp_update->safi = safi;
1128 mp_update->nlri = stream_pnt (s);
1129 mp_update->length = nlri_len;
1130
paul9985f832005-02-09 15:51:56 +00001131 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001132
1133 return 0;
1134}
1135
1136/* Multiprotocol unreachable parse */
paul94f2b392005-06-28 12:44:16 +00001137static int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001138bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001139 struct bgp_nlri *mp_withdraw)
1140{
1141 struct stream *s;
1142 u_int16_t afi;
1143 u_char safi;
paul718e3742002-12-13 20:15:29 +00001144 u_int16_t withdraw_len;
1145 int ret;
1146
1147 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001148
1149#define BGP_MP_UNREACH_MIN_SIZE 3
1150 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1151 return -1;
1152
paul718e3742002-12-13 20:15:29 +00001153 afi = stream_getw (s);
1154 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001155
1156 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001157
1158 if (safi != BGP_SAFI_VPNV4)
1159 {
1160 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1161 if (ret < 0)
1162 return -1;
1163 }
1164
1165 mp_withdraw->afi = afi;
1166 mp_withdraw->safi = safi;
1167 mp_withdraw->nlri = stream_pnt (s);
1168 mp_withdraw->length = withdraw_len;
1169
paul9985f832005-02-09 15:51:56 +00001170 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001171
1172 return 0;
1173}
1174
1175/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001176static int
paul718e3742002-12-13 20:15:29 +00001177bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1178 struct attr *attr, u_char flag)
1179{
1180 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001181 {
1182 if (attr->extra)
1183 attr->extra->ecommunity = NULL;
1184 }
paul718e3742002-12-13 20:15:29 +00001185 else
1186 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001187 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001188 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001189 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001190 }
1191 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1192
1193 return 0;
1194}
1195
1196/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001197static int
paul718e3742002-12-13 20:15:29 +00001198bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1199 u_char type, bgp_size_t length, u_char *startp)
1200{
1201 bgp_size_t total;
1202 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001203 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001204
hassof4184462005-02-01 20:13:16 +00001205 if (BGP_DEBUG (normal, NORMAL))
1206 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1207 peer->host, type, length);
1208
paul718e3742002-12-13 20:15:29 +00001209 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001210 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001211 "Unknown attribute type %d length %d is received", type, length);
1212
1213 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001214 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001215
1216 /* Adjest total length to include type and length. */
1217 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1218
1219 /* If any of the mandatory well-known attributes are not recognized,
1220 then the Error Subcode is set to Unrecognized Well-known
1221 Attribute. The Data field contains the unrecognized attribute
1222 (type, length and value). */
1223 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1224 {
1225 /* Adjust startp to do not include flag value. */
1226 bgp_notify_send_with_data (peer,
1227 BGP_NOTIFY_UPDATE_ERR,
1228 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1229 startp, total);
1230 return -1;
1231 }
1232
1233 /* Unrecognized non-transitive optional attributes must be quietly
1234 ignored and not passed along to other BGP peers. */
1235 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1236 return 0;
1237
1238 /* If a path with recognized transitive optional attribute is
1239 accepted and passed along to other BGP peers and the Partial bit
1240 in the Attribute Flags octet is set to 1 by some previous AS, it
1241 is not set back to 0 by the current AS. */
1242 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1243
1244 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001245 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
paul718e3742002-12-13 20:15:29 +00001246 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001247 attre->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1248 memset (attre->transit, 0, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001249 }
1250
Paul Jakmafb982c22007-05-04 20:15:47 +00001251 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001252
1253 if (transit->val)
1254 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1255 transit->length + total);
1256 else
1257 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1258
1259 memcpy (transit->val + transit->length, startp, total);
1260 transit->length += total;
1261
1262 return 0;
1263}
1264
1265/* Read attribute of update packet. This function is called from
1266 bgp_update() in bgpd.c. */
1267int
1268bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1269 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1270{
1271 int ret;
1272 u_char flag;
1273 u_char type;
1274 bgp_size_t length;
1275 u_char *startp, *endp;
1276 u_char *attr_endp;
1277 u_char seen[BGP_ATTR_BITMAP_SIZE];
1278
1279 /* Initialize bitmap. */
1280 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1281
1282 /* End pointer of BGP attribute. */
1283 endp = BGP_INPUT_PNT (peer) + size;
1284
1285 /* Get attributes to the end of attribute length. */
1286 while (BGP_INPUT_PNT (peer) < endp)
1287 {
1288 /* Check remaining length check.*/
1289 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1290 {
gdtc29fdba2004-12-09 14:46:46 +00001291 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001292 zlog (peer->log, LOG_WARNING,
paula2b1ecd2004-10-31 18:58:09 +00001293 "%s error BGP attribute length %ld is smaller than min len",
paul718e3742002-12-13 20:15:29 +00001294 peer->host, endp - STREAM_PNT (BGP_INPUT (peer)));
1295
1296 bgp_notify_send (peer,
1297 BGP_NOTIFY_UPDATE_ERR,
1298 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1299 return -1;
1300 }
1301
1302 /* Fetch attribute flag and type. */
1303 startp = BGP_INPUT_PNT (peer);
1304 flag = stream_getc (BGP_INPUT (peer));
1305 type = stream_getc (BGP_INPUT (peer));
1306
1307 /* Check extended attribue length bit. */
1308 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1309 length = stream_getw (BGP_INPUT (peer));
1310 else
1311 length = stream_getc (BGP_INPUT (peer));
1312
1313 /* If any attribute appears more than once in the UPDATE
1314 message, then the Error Subcode is set to Malformed Attribute
1315 List. */
1316
1317 if (CHECK_BITMAP (seen, type))
1318 {
1319 zlog (peer->log, LOG_WARNING,
1320 "%s error BGP attribute type %d appears twice in a message",
1321 peer->host, type);
1322
1323 bgp_notify_send (peer,
1324 BGP_NOTIFY_UPDATE_ERR,
1325 BGP_NOTIFY_UPDATE_MAL_ATTR);
1326 return -1;
1327 }
1328
1329 /* Set type to bitmap to check duplicate attribute. `type' is
1330 unsigned char so it never overflow bitmap range. */
1331
1332 SET_BITMAP (seen, type);
1333
1334 /* Overflow check. */
1335 attr_endp = BGP_INPUT_PNT (peer) + length;
1336
1337 if (attr_endp > endp)
1338 {
1339 zlog (peer->log, LOG_WARNING,
1340 "%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);
1341 bgp_notify_send (peer,
1342 BGP_NOTIFY_UPDATE_ERR,
1343 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1344 return -1;
1345 }
1346
1347 /* OK check attribute and store it's value. */
1348 switch (type)
1349 {
1350 case BGP_ATTR_ORIGIN:
1351 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1352 break;
1353 case BGP_ATTR_AS_PATH:
1354 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1355 break;
1356 case BGP_ATTR_NEXT_HOP:
1357 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1358 break;
1359 case BGP_ATTR_MULTI_EXIT_DISC:
1360 ret = bgp_attr_med (peer, length, attr, flag, startp);
1361 break;
1362 case BGP_ATTR_LOCAL_PREF:
1363 ret = bgp_attr_local_pref (peer, length, attr, flag);
1364 break;
1365 case BGP_ATTR_ATOMIC_AGGREGATE:
1366 ret = bgp_attr_atomic (peer, length, attr, flag);
1367 break;
1368 case BGP_ATTR_AGGREGATOR:
1369 ret = bgp_attr_aggregator (peer, length, attr, flag);
1370 break;
1371 case BGP_ATTR_COMMUNITIES:
1372 ret = bgp_attr_community (peer, length, attr, flag);
1373 break;
1374 case BGP_ATTR_ORIGINATOR_ID:
1375 ret = bgp_attr_originator_id (peer, length, attr, flag);
1376 break;
1377 case BGP_ATTR_CLUSTER_LIST:
1378 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1379 break;
1380 case BGP_ATTR_MP_REACH_NLRI:
1381 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1382 break;
1383 case BGP_ATTR_MP_UNREACH_NLRI:
1384 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1385 break;
1386 case BGP_ATTR_EXT_COMMUNITIES:
1387 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1388 break;
1389 default:
1390 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1391 break;
1392 }
1393
1394 /* If error occured immediately return to the caller. */
1395 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001396 {
1397 zlog (peer->log, LOG_WARNING,
1398 "%s: Attribute %s, parse error",
1399 peer->host,
1400 LOOKUP (attr_str, type));
1401 bgp_notify_send (peer,
1402 BGP_NOTIFY_UPDATE_ERR,
1403 BGP_NOTIFY_UPDATE_MAL_ATTR);
1404 return ret;
1405 }
paul718e3742002-12-13 20:15:29 +00001406
1407 /* Check the fetched length. */
1408 if (BGP_INPUT_PNT (peer) != attr_endp)
1409 {
1410 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001411 "%s: BGP attribute %s, fetch error",
1412 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001413 bgp_notify_send (peer,
1414 BGP_NOTIFY_UPDATE_ERR,
1415 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1416 return -1;
1417 }
1418 }
1419
1420 /* Check final read pointer is same as end pointer. */
1421 if (BGP_INPUT_PNT (peer) != endp)
1422 {
1423 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001424 "%s BGP attribute %s, length mismatch",
1425 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001426 bgp_notify_send (peer,
1427 BGP_NOTIFY_UPDATE_ERR,
1428 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1429 return -1;
1430 }
1431
1432 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001433 if (attr->extra && attr->extra->transit)
1434 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001435
1436 return 0;
1437}
1438
1439/* Well-known attribute check. */
1440int
1441bgp_attr_check (struct peer *peer, struct attr *attr)
1442{
1443 u_char type = 0;
1444
1445 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1446 type = BGP_ATTR_ORIGIN;
1447
1448 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1449 type = BGP_ATTR_AS_PATH;
1450
1451 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1452 type = BGP_ATTR_NEXT_HOP;
1453
1454 if (peer_sort (peer) == BGP_PEER_IBGP
1455 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1456 type = BGP_ATTR_LOCAL_PREF;
1457
1458 if (type)
1459 {
1460 zlog (peer->log, LOG_WARNING,
1461 "%s Missing well-known attribute %d.",
1462 peer->host, type);
1463 bgp_notify_send_with_data (peer,
1464 BGP_NOTIFY_UPDATE_ERR,
1465 BGP_NOTIFY_UPDATE_MISS_ATTR,
1466 &type, 1);
1467 return -1;
1468 }
1469 return 0;
1470}
1471
1472int stream_put_prefix (struct stream *, struct prefix *);
1473
1474/* Make attribute packet. */
1475bgp_size_t
1476bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1477 struct stream *s, struct attr *attr, struct prefix *p,
1478 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001479 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001480{
paulfe69a502005-09-10 16:55:02 +00001481 size_t cp;
1482 unsigned int aspath_data_size;
paul718e3742002-12-13 20:15:29 +00001483 struct aspath *aspath;
1484
1485 if (! bgp)
1486 bgp = bgp_get_default ();
1487
1488 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001489 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001490
1491 /* Origin attribute. */
1492 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1493 stream_putc (s, BGP_ATTR_ORIGIN);
1494 stream_putc (s, 1);
1495 stream_putc (s, attr->origin);
1496
1497 /* AS path attribute. */
1498
1499 /* If remote-peer is EBGP */
1500 if (peer_sort (peer) == BGP_PEER_EBGP
1501 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001502 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001503 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001504 {
1505 aspath = aspath_dup (attr->aspath);
1506
1507 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1508 {
1509 /* Strip the confed info, and then stuff our path CONFED_ID
1510 on the front */
1511 aspath = aspath_delete_confed_seq (aspath);
1512 aspath = aspath_add_seq (aspath, bgp->confed_id);
1513 }
1514 else
1515 {
1516 aspath = aspath_add_seq (aspath, peer->local_as);
1517 if (peer->change_local_as)
1518 aspath = aspath_add_seq (aspath, peer->change_local_as);
1519 }
1520 }
1521 else if (peer_sort (peer) == BGP_PEER_CONFED)
1522 {
1523 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1524 aspath = aspath_dup (attr->aspath);
1525 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1526 }
1527 else
1528 aspath = attr->aspath;
1529
1530 /* AS path attribute extended length bit check. */
paulfe69a502005-09-10 16:55:02 +00001531 aspath_data_size = aspath_size (aspath);
1532 if (aspath_data_size > 255)
paul718e3742002-12-13 20:15:29 +00001533 {
1534 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1535 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001536 stream_putw (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001537 }
1538 else
1539 {
1540 stream_putc (s, BGP_ATTR_FLAG_TRANS);
paulfe69a502005-09-10 16:55:02 +00001541 stream_putc (s, BGP_ATTR_AS_PATH);
1542 stream_putc (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001543 }
paulfe69a502005-09-10 16:55:02 +00001544 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001545
1546 if (aspath != attr->aspath)
1547 aspath_free (aspath);
1548
1549 /* Nexthop attribute. */
1550 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1551 {
1552 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1553 stream_putc (s, BGP_ATTR_NEXT_HOP);
1554 stream_putc (s, 4);
1555 if (safi == SAFI_MPLS_VPN)
1556 {
1557 if (attr->nexthop.s_addr == 0)
1558 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1559 else
1560 stream_put_ipv4 (s, attr->nexthop.s_addr);
1561 }
1562 else
1563 stream_put_ipv4 (s, attr->nexthop.s_addr);
1564 }
1565
1566 /* MED attribute. */
1567 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1568 {
1569 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1570 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1571 stream_putc (s, 4);
1572 stream_putl (s, attr->med);
1573 }
1574
1575 /* Local preference. */
1576 if (peer_sort (peer) == BGP_PEER_IBGP ||
1577 peer_sort (peer) == BGP_PEER_CONFED)
1578 {
1579 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1580 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1581 stream_putc (s, 4);
1582 stream_putl (s, attr->local_pref);
1583 }
1584
1585 /* Atomic aggregate. */
1586 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1587 {
1588 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1589 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1590 stream_putc (s, 0);
1591 }
1592
1593 /* Aggregator. */
1594 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1595 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001596 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00001597 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1598 stream_putc (s, BGP_ATTR_AGGREGATOR);
1599 stream_putc (s, 6);
Paul Jakmafb982c22007-05-04 20:15:47 +00001600 stream_putw (s, attr->extra->aggregator_as);
1601 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001602 }
1603
1604 /* Community attribute. */
1605 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1606 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1607 {
1608 if (attr->community->size * 4 > 255)
1609 {
1610 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1611 stream_putc (s, BGP_ATTR_COMMUNITIES);
1612 stream_putw (s, attr->community->size * 4);
1613 }
1614 else
1615 {
1616 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1617 stream_putc (s, BGP_ATTR_COMMUNITIES);
1618 stream_putc (s, attr->community->size * 4);
1619 }
1620 stream_put (s, attr->community->val, attr->community->size * 4);
1621 }
1622
1623 /* Route Reflector. */
1624 if (peer_sort (peer) == BGP_PEER_IBGP
1625 && from
1626 && peer_sort (from) == BGP_PEER_IBGP)
1627 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001628 assert (attr->extra);
1629
paul718e3742002-12-13 20:15:29 +00001630 /* Originator ID. */
1631 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1632 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1633 stream_putc (s, 4);
1634
1635 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00001636 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001637 else
1638 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001639
1640 /* Cluster list. */
1641 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1642 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1643
Paul Jakmafb982c22007-05-04 20:15:47 +00001644 if (attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00001645 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001646 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00001647 /* If this peer configuration's parent BGP has cluster_id. */
1648 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1649 stream_put_in_addr (s, &bgp->cluster_id);
1650 else
1651 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00001652 stream_put (s, attr->extra->cluster->list,
1653 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00001654 }
1655 else
1656 {
1657 stream_putc (s, 4);
1658 /* If this peer configuration's parent BGP has cluster_id. */
1659 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1660 stream_put_in_addr (s, &bgp->cluster_id);
1661 else
1662 stream_put_in_addr (s, &bgp->router_id);
1663 }
1664 }
1665
1666#ifdef HAVE_IPV6
1667 /* If p is IPv6 address put it into attribute. */
1668 if (p->family == AF_INET6)
1669 {
1670 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00001671 struct attr_extra *attre = attr->extra;
1672
1673 assert (attr->extra);
1674
paul718e3742002-12-13 20:15:29 +00001675 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1676 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001677 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001678 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00001679 stream_putw (s, AFI_IP6); /* AFI */
1680 stream_putc (s, safi); /* SAFI */
1681
Paul Jakmafb982c22007-05-04 20:15:47 +00001682 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001683
Paul Jakmafb982c22007-05-04 20:15:47 +00001684 if (attre->mp_nexthop_len == 16)
1685 stream_put (s, &attre->mp_nexthop_global, 16);
1686 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00001687 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001688 stream_put (s, &attre->mp_nexthop_global, 16);
1689 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00001690 }
1691
1692 /* SNPA */
1693 stream_putc (s, 0);
1694
paul718e3742002-12-13 20:15:29 +00001695 /* Prefix write. */
1696 stream_put_prefix (s, p);
1697
1698 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001699 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001700 }
1701#endif /* HAVE_IPV6 */
1702
1703 if (p->family == AF_INET && safi == SAFI_MULTICAST)
1704 {
1705 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001706
1707 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1708 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001709 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001710 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00001711 stream_putw (s, AFI_IP); /* AFI */
1712 stream_putc (s, SAFI_MULTICAST); /* SAFI */
1713
1714 stream_putc (s, 4);
1715 stream_put_ipv4 (s, attr->nexthop.s_addr);
1716
1717 /* SNPA */
1718 stream_putc (s, 0);
1719
paul718e3742002-12-13 20:15:29 +00001720 /* Prefix write. */
1721 stream_put_prefix (s, p);
1722
1723 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001724 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001725 }
1726
1727 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
1728 {
1729 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001730
1731 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1732 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001733 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001734 stream_putc (s, 0); /* Length of this attribute. */
1735 stream_putw (s, AFI_IP); /* AFI */
1736 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
1737
1738 stream_putc (s, 12);
1739 stream_putl (s, 0);
1740 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00001741 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001742
1743 /* SNPA */
1744 stream_putc (s, 0);
1745
paul718e3742002-12-13 20:15:29 +00001746 /* Tag, RD, Prefix write. */
1747 stream_putc (s, p->prefixlen + 88);
1748 stream_put (s, tag, 3);
1749 stream_put (s, prd->val, 8);
1750 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1751
1752 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001753 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001754 }
1755
1756 /* Extended Communities attribute. */
1757 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
1758 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
1759 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001760 struct attr_extra *attre = attr->extra;
1761
1762 assert (attre);
1763
1764 if (peer_sort (peer) == BGP_PEER_IBGP
1765 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00001766 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001767 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00001768 {
1769 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1770 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00001771 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00001772 }
1773 else
1774 {
1775 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1776 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00001777 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00001778 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001779 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00001780 }
1781 else
1782 {
paul5228ad22004-06-04 17:58:18 +00001783 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00001784 int tbit;
1785 int ecom_tr_size = 0;
1786 int i;
1787
Paul Jakmafb982c22007-05-04 20:15:47 +00001788 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00001789 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001790 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00001791 tbit = *pnt;
1792
1793 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1794 continue;
1795
1796 ecom_tr_size++;
1797 }
1798
1799 if (ecom_tr_size)
1800 {
1801 if (ecom_tr_size * 8 > 255)
1802 {
1803 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1804 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1805 stream_putw (s, ecom_tr_size * 8);
1806 }
1807 else
1808 {
1809 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1810 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1811 stream_putc (s, ecom_tr_size * 8);
1812 }
1813
Paul Jakmafb982c22007-05-04 20:15:47 +00001814 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00001815 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001816 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00001817 tbit = *pnt;
1818
1819 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1820 continue;
1821
1822 stream_put (s, pnt, 8);
1823 }
1824 }
paul718e3742002-12-13 20:15:29 +00001825 }
paul718e3742002-12-13 20:15:29 +00001826 }
1827
1828 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001829 if (attr->extra && attr->extra->transit)
1830 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00001831
1832 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00001833 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001834}
1835
1836bgp_size_t
1837bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
1838 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001839 u_char *tag)
paul718e3742002-12-13 20:15:29 +00001840{
1841 unsigned long cp;
1842 unsigned long attrlen_pnt;
1843 bgp_size_t size;
1844
paul9985f832005-02-09 15:51:56 +00001845 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001846
1847 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1848 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
1849
paul9985f832005-02-09 15:51:56 +00001850 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001851 stream_putc (s, 0); /* Length of this attribute. */
1852
1853 stream_putw (s, family2afi (p->family));
1854
1855 if (safi == SAFI_MPLS_VPN)
1856 {
1857 /* SAFI */
1858 stream_putc (s, BGP_SAFI_VPNV4);
1859
1860 /* prefix. */
1861 stream_putc (s, p->prefixlen + 88);
1862 stream_put (s, tag, 3);
1863 stream_put (s, prd->val, 8);
1864 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1865 }
1866 else
1867 {
1868 /* SAFI */
1869 stream_putc (s, safi);
1870
1871 /* prefix */
1872 stream_put_prefix (s, p);
1873 }
1874
1875 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001876 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00001877 stream_putc_at (s, attrlen_pnt, size);
1878
paul9985f832005-02-09 15:51:56 +00001879 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001880}
1881
1882/* Initialization of attribute. */
1883void
paulfe69a502005-09-10 16:55:02 +00001884bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00001885{
1886 void attrhash_init ();
1887
1888 aspath_init ();
1889 attrhash_init ();
1890 community_init ();
1891 ecommunity_init ();
1892 cluster_init ();
1893 transit_init ();
1894}
1895
1896/* Make attribute packet. */
1897void
paula3845922003-10-18 01:30:50 +00001898bgp_dump_routes_attr (struct stream *s, struct attr *attr,
1899 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00001900{
1901 unsigned long cp;
1902 unsigned long len;
paulfe69a502005-09-10 16:55:02 +00001903 unsigned int aspathlen;
paul718e3742002-12-13 20:15:29 +00001904 struct aspath *aspath;
1905
1906 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001907 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001908
1909 /* Place holder of length. */
1910 stream_putw (s, 0);
1911
1912 /* Origin attribute. */
1913 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1914 stream_putc (s, BGP_ATTR_ORIGIN);
1915 stream_putc (s, 1);
1916 stream_putc (s, attr->origin);
1917
1918 aspath = attr->aspath;
1919
paulfe69a502005-09-10 16:55:02 +00001920 if ( (aspathlen = aspath_size (aspath)) > 255 )
paul718e3742002-12-13 20:15:29 +00001921 {
1922 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1923 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001924 stream_putw (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001925 }
1926 else
1927 {
1928 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1929 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001930 stream_putc (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001931 }
paulfe69a502005-09-10 16:55:02 +00001932 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001933
1934 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00001935 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
1936 if(prefix != NULL
1937#ifdef HAVE_IPV6
1938 && prefix->family != AF_INET6
1939#endif /* HAVE_IPV6 */
1940 )
1941 {
1942 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1943 stream_putc (s, BGP_ATTR_NEXT_HOP);
1944 stream_putc (s, 4);
1945 stream_put_ipv4 (s, attr->nexthop.s_addr);
1946 }
paul718e3742002-12-13 20:15:29 +00001947
1948 /* MED attribute. */
1949 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1950 {
1951 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1952 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1953 stream_putc (s, 4);
1954 stream_putl (s, attr->med);
1955 }
1956
1957 /* Local preference. */
1958 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
1959 {
1960 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1961 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1962 stream_putc (s, 4);
1963 stream_putl (s, attr->local_pref);
1964 }
1965
1966 /* Atomic aggregate. */
1967 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1968 {
1969 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1970 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1971 stream_putc (s, 0);
1972 }
1973
1974 /* Aggregator. */
1975 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1976 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001977 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00001978 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1979 stream_putc (s, BGP_ATTR_AGGREGATOR);
1980 stream_putc (s, 6);
Paul Jakmafb982c22007-05-04 20:15:47 +00001981 stream_putw (s, attr->extra->aggregator_as);
1982 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001983 }
1984
1985 /* Community attribute. */
1986 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
1987 {
1988 if (attr->community->size * 4 > 255)
1989 {
1990 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1991 stream_putc (s, BGP_ATTR_COMMUNITIES);
1992 stream_putw (s, attr->community->size * 4);
1993 }
1994 else
1995 {
1996 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1997 stream_putc (s, BGP_ATTR_COMMUNITIES);
1998 stream_putc (s, attr->community->size * 4);
1999 }
2000 stream_put (s, attr->community->val, attr->community->size * 4);
2001 }
2002
paula3845922003-10-18 01:30:50 +00002003#ifdef HAVE_IPV6
2004 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002005 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2006 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002007 {
2008 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002009 struct attr_extra *attre = attr->extra;
2010
paula3845922003-10-18 01:30:50 +00002011 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2012 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002013 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002014
2015 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002016 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002017 stream_putw(s, AFI_IP6); /* AFI */
2018 stream_putc(s, SAFI_UNICAST); /* SAFI */
2019
2020 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002021 stream_putc(s, attre->mp_nexthop_len);
2022 stream_put(s, &attre->mp_nexthop_global, 16);
2023 if (attre->mp_nexthop_len == 32)
2024 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002025
2026 /* SNPA */
2027 stream_putc(s, 0);
2028
2029 /* Prefix */
2030 stream_put_prefix(s, prefix);
2031
2032 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002033 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002034 }
2035#endif /* HAVE_IPV6 */
2036
paul718e3742002-12-13 20:15:29 +00002037 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002038 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002039 stream_putw_at (s, cp, len);
2040}