blob: 9c97d6f0394286da33c07bd683f5fe8c6551c44b [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"
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -070031#include "jhash.h"
paul718e3742002-12-13 20:15:29 +000032
33#include "bgpd/bgpd.h"
34#include "bgpd/bgp_attr.h"
35#include "bgpd/bgp_route.h"
36#include "bgpd/bgp_aspath.h"
37#include "bgpd/bgp_community.h"
38#include "bgpd/bgp_debug.h"
39#include "bgpd/bgp_packet.h"
40#include "bgpd/bgp_ecommunity.h"
41
42/* Attribute strings for logging. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -070043static const struct message attr_str [] =
paul718e3742002-12-13 20:15:29 +000044{
45 { BGP_ATTR_ORIGIN, "ORIGIN" },
46 { BGP_ATTR_AS_PATH, "AS_PATH" },
47 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
48 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
49 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
50 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
51 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
52 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
53 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
54 { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" },
55 { BGP_ATTR_DPA, "DPA" },
56 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
57 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
58 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
59 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000060 { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
61 { BGP_ATTR_AS4_PATH, "AS4_PATH" },
62 { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
63 { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
paul718e3742002-12-13 20:15:29 +000064};
Stephen Hemminger9bddac42009-05-15 09:59:51 -070065static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000066
Stephen Hemminger9bddac42009-05-15 09:59:51 -070067static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000068
paul94f2b392005-06-28 12:44:16 +000069static void *
Paul Jakma923de652007-04-29 18:25:17 +000070cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000071{
Paul Jakma923de652007-04-29 18:25:17 +000072 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000073 struct cluster_list *cluster;
74
75 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
76 cluster->length = val->length;
77
78 if (cluster->length)
79 {
80 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
81 memcpy (cluster->list, val->list, val->length);
82 }
83 else
84 cluster->list = NULL;
85
86 cluster->refcnt = 0;
87
88 return cluster;
89}
90
91/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000092static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000093cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000094{
95 struct cluster_list tmp;
96 struct cluster_list *cluster;
97
98 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000099 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +0000100
101 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
102 cluster->refcnt++;
103 return cluster;
104}
105
106int
107cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
108{
109 int i;
110
111 for (i = 0; i < cluster->length / 4; i++)
112 if (cluster->list[i].s_addr == originator.s_addr)
113 return 1;
114 return 0;
115}
116
paul94f2b392005-06-28 12:44:16 +0000117static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000118cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000119{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700120 const struct cluster_list *cluster = p;
paul718e3742002-12-13 20:15:29 +0000121
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700122 return jhash(cluster->list, cluster->length, 0);
paul718e3742002-12-13 20:15:29 +0000123}
124
paul94f2b392005-06-28 12:44:16 +0000125static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100126cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000127{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100128 const struct cluster_list * cluster1 = p1;
129 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000130
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100131 return (cluster1->length == cluster2->length &&
132 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000133}
134
paul94f2b392005-06-28 12:44:16 +0000135static void
paul718e3742002-12-13 20:15:29 +0000136cluster_free (struct cluster_list *cluster)
137{
138 if (cluster->list)
139 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
140 XFREE (MTYPE_CLUSTER, cluster);
141}
142
Chris Caputo228da422009-07-18 05:44:03 +0000143#if 0
paul94f2b392005-06-28 12:44:16 +0000144static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000145cluster_dup (struct cluster_list *cluster)
146{
147 struct cluster_list *new;
148
Stephen Hemminger393deb92008-08-18 14:13:29 -0700149 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000150 new->length = cluster->length;
151
152 if (cluster->length)
153 {
154 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
155 memcpy (new->list, cluster->list, cluster->length);
156 }
157 else
158 new->list = NULL;
159
160 return new;
161}
Chris Caputo228da422009-07-18 05:44:03 +0000162#endif
paul718e3742002-12-13 20:15:29 +0000163
paul94f2b392005-06-28 12:44:16 +0000164static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000165cluster_intern (struct cluster_list *cluster)
166{
167 struct cluster_list *find;
168
169 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
170 find->refcnt++;
171
172 return find;
173}
174
175void
176cluster_unintern (struct cluster_list *cluster)
177{
178 struct cluster_list *ret;
179
180 if (cluster->refcnt)
181 cluster->refcnt--;
182
183 if (cluster->refcnt == 0)
184 {
185 ret = hash_release (cluster_hash, cluster);
186 cluster_free (cluster);
187 }
188}
189
paul94f2b392005-06-28 12:44:16 +0000190static void
191cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000192{
193 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
194}
Chris Caputo228da422009-07-18 05:44:03 +0000195
196static void
197cluster_finish (void)
198{
199 hash_free (cluster_hash);
200 cluster_hash = NULL;
201}
paul718e3742002-12-13 20:15:29 +0000202
203/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700204static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000205
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{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700253 const struct transit * transit = p;
paul718e3742002-12-13 20:15:29 +0000254
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700255 return jhash(transit->val, transit->length, 0);
paul718e3742002-12-13 20:15:29 +0000256}
257
paul94f2b392005-06-28 12:44:16 +0000258static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100259transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000260{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100261 const struct transit * transit1 = p1;
262 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000263
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100264 return (transit1->length == transit2->length &&
265 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000266}
267
paul94f2b392005-06-28 12:44:16 +0000268static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800269transit_init (void)
paul718e3742002-12-13 20:15:29 +0000270{
271 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
272}
Chris Caputo228da422009-07-18 05:44:03 +0000273
274static void
275transit_finish (void)
276{
277 hash_free (transit_hash);
278 transit_hash = NULL;
279}
paul718e3742002-12-13 20:15:29 +0000280
281/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700282static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000283
Paul Jakmafb982c22007-05-04 20:15:47 +0000284static struct attr_extra *
285bgp_attr_extra_new (void)
286{
287 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
288}
289
290void
291bgp_attr_extra_free (struct attr *attr)
292{
293 if (attr->extra)
294 {
295 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
296 attr->extra = NULL;
297 }
298}
299
300struct attr_extra *
301bgp_attr_extra_get (struct attr *attr)
302{
303 if (!attr->extra)
304 attr->extra = bgp_attr_extra_new();
305 return attr->extra;
306}
307
308/* Shallow copy of an attribute
309 * Though, not so shallow that it doesn't copy the contents
310 * of the attr_extra pointed to by 'extra'
311 */
312void
313bgp_attr_dup (struct attr *new, struct attr *orig)
314{
315 *new = *orig;
316 if (orig->extra)
317 {
318 new->extra = bgp_attr_extra_new();
319 *new->extra = *orig->extra;
320 }
321}
322
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000323unsigned long int
324attr_count (void)
325{
326 return attrhash->count;
327}
328
329unsigned long int
330attr_unknown_count (void)
331{
332 return transit_hash->count;
333}
334
paul718e3742002-12-13 20:15:29 +0000335unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000336attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000337{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700338 const struct attr * attr = (struct attr *) p;
339 uint32_t key = 0;
340#define MIX(val) key = jhash_1word(val, key)
paul718e3742002-12-13 20:15:29 +0000341
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700342 MIX(attr->origin);
343 MIX(attr->nexthop.s_addr);
344 MIX(attr->med);
345 MIX(attr->local_pref);
346
Paul Jakma41367172007-08-06 15:24:51 +0000347 if (attr->pathlimit.as)
348 {
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700349 MIX(attr->pathlimit.ttl);
350 MIX(attr->pathlimit.as);
Paul Jakma41367172007-08-06 15:24:51 +0000351 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000352
353 if (attr->extra)
354 {
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700355 MIX(attr->extra->aggregator_as);
356 MIX(attr->extra->aggregator_addr.s_addr);
357 MIX(attr->extra->weight);
358 MIX(attr->extra->mp_nexthop_global_in.s_addr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000359 }
360
paul718e3742002-12-13 20:15:29 +0000361 if (attr->aspath)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700362 MIX(aspath_key_make (attr->aspath));
paul718e3742002-12-13 20:15:29 +0000363 if (attr->community)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700364 MIX(community_hash_make (attr->community));
Paul Jakmafb982c22007-05-04 20:15:47 +0000365
366 if (attr->extra)
367 {
368 if (attr->extra->ecommunity)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700369 MIX(ecommunity_hash_make (attr->extra->ecommunity));
Paul Jakmafb982c22007-05-04 20:15:47 +0000370 if (attr->extra->cluster)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700371 MIX(cluster_hash_key_make (attr->extra->cluster));
Paul Jakmafb982c22007-05-04 20:15:47 +0000372 if (attr->extra->transit)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700373 MIX(transit_hash_key_make (attr->extra->transit));
paul718e3742002-12-13 20:15:29 +0000374
375#ifdef HAVE_IPV6
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700376 MIX(attr->extra->mp_nexthop_len);
377 key = jhash2(attr->extra->mp_nexthop_global.s6_addr32, 4, key);
378 key = jhash2(attr->extra->mp_nexthop_local.s6_addr32, 4, key);
paul718e3742002-12-13 20:15:29 +0000379#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000380 }
paul718e3742002-12-13 20:15:29 +0000381
382 return key;
383}
384
385int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100386attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000387{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100388 const struct attr * attr1 = p1;
389 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000390
paul718e3742002-12-13 20:15:29 +0000391 if (attr1->flag == attr2->flag
392 && attr1->origin == attr2->origin
393 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000394 && attr1->aspath == attr2->aspath
395 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000396 && attr1->med == attr2->med
Paul Jakma41367172007-08-06 15:24:51 +0000397 && attr1->local_pref == attr2->local_pref
398 && attr1->pathlimit.ttl == attr2->pathlimit.ttl
399 && attr1->pathlimit.as == attr2->pathlimit.as)
Paul Jakmafb982c22007-05-04 20:15:47 +0000400 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100401 const struct attr_extra *ae1 = attr1->extra;
402 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000403
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
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100428attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000429{
430 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
431}
432
paul94f2b392005-06-28 12:44:16 +0000433static void
Chris Caputo228da422009-07-18 05:44:03 +0000434attrhash_finish (void)
435{
436 hash_free (attrhash);
437 attrhash = NULL;
438}
439
440static void
paul718e3742002-12-13 20:15:29 +0000441attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
442{
443 struct attr *attr = backet->data;
444
445 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
446 inet_ntoa (attr->nexthop), VTY_NEWLINE);
447}
448
449void
450attr_show_all (struct vty *vty)
451{
452 hash_iterate (attrhash,
453 (void (*)(struct hash_backet *, void *))
454 attr_show_all_iterator,
455 vty);
456}
457
paul94f2b392005-06-28 12:44:16 +0000458static void *
Paul Jakma923de652007-04-29 18:25:17 +0000459bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000460{
Paul Jakma923de652007-04-29 18:25:17 +0000461 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000462 struct attr *attr;
463
464 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
465 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000466 if (val->extra)
467 {
468 attr->extra = bgp_attr_extra_new ();
469 *attr->extra = *val->extra;
470 }
paul718e3742002-12-13 20:15:29 +0000471 attr->refcnt = 0;
472 return attr;
473}
474
475/* Internet argument attribute. */
476struct attr *
477bgp_attr_intern (struct attr *attr)
478{
479 struct attr *find;
480
481 /* Intern referenced strucutre. */
482 if (attr->aspath)
483 {
484 if (! attr->aspath->refcnt)
485 attr->aspath = aspath_intern (attr->aspath);
486 else
487 attr->aspath->refcnt++;
488 }
489 if (attr->community)
490 {
491 if (! attr->community->refcnt)
492 attr->community = community_intern (attr->community);
493 else
494 attr->community->refcnt++;
495 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000496 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000497 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000498 struct attr_extra *attre = attr->extra;
499
500 if (attre->ecommunity)
501 {
502 if (! attre->ecommunity->refcnt)
503 attre->ecommunity = ecommunity_intern (attre->ecommunity);
504 else
505 attre->ecommunity->refcnt++;
506 }
507 if (attre->cluster)
508 {
509 if (! attre->cluster->refcnt)
510 attre->cluster = cluster_intern (attre->cluster);
511 else
512 attre->cluster->refcnt++;
513 }
514 if (attre->transit)
515 {
516 if (! attre->transit->refcnt)
517 attre->transit = transit_intern (attre->transit);
518 else
519 attre->transit->refcnt++;
520 }
paul718e3742002-12-13 20:15:29 +0000521 }
522
523 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
524 find->refcnt++;
525
526 return find;
527}
528
Paul Jakma03e214c2007-04-29 18:31:07 +0000529
paul718e3742002-12-13 20:15:29 +0000530/* Make network statement's attribute. */
531struct attr *
532bgp_attr_default_set (struct attr *attr, u_char origin)
533{
534 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000535 bgp_attr_extra_get (attr);
536
paul718e3742002-12-13 20:15:29 +0000537 attr->origin = origin;
538 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
539 attr->aspath = aspath_empty ();
540 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000541 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000542 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
543#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000544 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000545#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000546
paul718e3742002-12-13 20:15:29 +0000547 return attr;
548}
549
Paul Jakma03e214c2007-04-29 18:31:07 +0000550
paul718e3742002-12-13 20:15:29 +0000551/* Make network statement's attribute. */
552struct attr *
553bgp_attr_default_intern (u_char origin)
554{
555 struct attr attr;
556 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000557 struct attr_extra *attre;
558
559 memset (&attr, 0, sizeof (struct attr));
560 attre = bgp_attr_extra_get (&attr);
561
Paul Jakma03e214c2007-04-29 18:31:07 +0000562 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000563
564 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000565 bgp_attr_extra_free (&attr);
566
paul718e3742002-12-13 20:15:29 +0000567 aspath_unintern (new->aspath);
568 return new;
569}
570
571struct attr *
572bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
573 struct aspath *aspath,
574 struct community *community, int as_set)
575{
576 struct attr attr;
577 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000578 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000579
580 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000581 attre = bgp_attr_extra_get (&attr);
582
paul718e3742002-12-13 20:15:29 +0000583 /* Origin attribute. */
584 attr.origin = origin;
585 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
586
587 /* AS path attribute. */
588 if (aspath)
589 attr.aspath = aspath_intern (aspath);
590 else
591 attr.aspath = aspath_empty ();
592 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
593
594 /* Next hop attribute. */
595 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
596
597 if (community)
598 {
599 attr.community = community;
600 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
601 }
602
Paul Jakmafb982c22007-05-04 20:15:47 +0000603 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000604#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000605 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000606#endif
607 if (! as_set)
608 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
609 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
610 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000611 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000612 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000613 attre->aggregator_as = bgp->as;
614 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000615
616 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000617 bgp_attr_extra_free (&attr);
618
paul718e3742002-12-13 20:15:29 +0000619 aspath_unintern (new->aspath);
620 return new;
621}
622
623/* Free bgp attribute and aspath. */
624void
625bgp_attr_unintern (struct attr *attr)
626{
627 struct attr *ret;
628 struct aspath *aspath;
629 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000630 struct ecommunity *ecommunity = NULL;
631 struct cluster_list *cluster = NULL;
632 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000633
634 /* Decrement attribute reference. */
635 attr->refcnt--;
636 aspath = attr->aspath;
637 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000638 if (attr->extra)
639 {
640 ecommunity = attr->extra->ecommunity;
641 cluster = attr->extra->cluster;
642 transit = attr->extra->transit;
643 }
paul718e3742002-12-13 20:15:29 +0000644
645 /* If reference becomes zero then free attribute object. */
646 if (attr->refcnt == 0)
647 {
648 ret = hash_release (attrhash, attr);
649 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000650 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000651 XFREE (MTYPE_ATTR, attr);
652 }
653
654 /* aspath refcount shoud be decrement. */
655 if (aspath)
656 aspath_unintern (aspath);
657 if (community)
658 community_unintern (community);
659 if (ecommunity)
660 ecommunity_unintern (ecommunity);
661 if (cluster)
662 cluster_unintern (cluster);
663 if (transit)
664 transit_unintern (transit);
665}
666
667void
668bgp_attr_flush (struct attr *attr)
669{
670 if (attr->aspath && ! attr->aspath->refcnt)
671 aspath_free (attr->aspath);
672 if (attr->community && ! attr->community->refcnt)
673 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000674 if (attr->extra)
675 {
676 struct attr_extra *attre = attr->extra;
677 if (attre->ecommunity && ! attre->ecommunity->refcnt)
678 ecommunity_free (attre->ecommunity);
679 if (attre->cluster && ! attre->cluster->refcnt)
680 cluster_free (attre->cluster);
681 if (attre->transit && ! attre->transit->refcnt)
682 transit_free (attre->transit);
683 }
paul718e3742002-12-13 20:15:29 +0000684}
685
Paul Jakma41367172007-08-06 15:24:51 +0000686/* Parse AS_PATHLIMIT attribute in an UPDATE */
687static int
688bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
689 struct attr *attr, u_char flag, u_char *startp)
690{
691 bgp_size_t total;
692
693 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
694
Paul Jakmaa15cfd12008-06-01 14:29:03 +0000695 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
696 || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
Paul Jakma41367172007-08-06 15:24:51 +0000697 {
698 zlog (peer->log, LOG_ERR,
699 "AS-Pathlimit attribute flag isn't transitive %d", flag);
700 bgp_notify_send_with_data (peer,
701 BGP_NOTIFY_UPDATE_ERR,
702 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
703 startp, total);
704 return -1;
705 }
706
707 if (length != 5)
708 {
709 zlog (peer->log, LOG_ERR,
710 "AS-Pathlimit length, %u, is not 5", length);
711 bgp_notify_send_with_data (peer,
712 BGP_NOTIFY_UPDATE_ERR,
713 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
714 startp, total);
715 return -1;
716 }
717
718 attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer));
719 attr->pathlimit.as = stream_getl (BGP_INPUT(peer));
720 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
721 return 0;
722}
paul718e3742002-12-13 20:15:29 +0000723/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000724static int
paul718e3742002-12-13 20:15:29 +0000725bgp_attr_origin (struct peer *peer, bgp_size_t length,
726 struct attr *attr, u_char flag, u_char *startp)
727{
728 bgp_size_t total;
729
730 /* total is entire attribute length include Attribute Flags (1),
731 Attribute Type code (1) and Attribute length (1 or 2). */
732 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
733
734 /* If any recognized attribute has Attribute Flags that conflict
735 with the Attribute Type Code, then the Error Subcode is set to
736 Attribute Flags Error. The Data field contains the erroneous
737 attribute (type, length and value). */
738 if (flag != BGP_ATTR_FLAG_TRANS)
739 {
740 zlog (peer->log, LOG_ERR,
741 "Origin attribute flag isn't transitive %d", flag);
742 bgp_notify_send_with_data (peer,
743 BGP_NOTIFY_UPDATE_ERR,
744 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
745 startp, total);
746 return -1;
747 }
748
749 /* If any recognized attribute has Attribute Length that conflicts
750 with the expected length (based on the attribute type code), then
751 the Error Subcode is set to Attribute Length Error. The Data
752 field contains the erroneous attribute (type, length and
753 value). */
754 if (length != 1)
755 {
756 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
757 length);
758 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
759 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
760 startp, total);
761 return -1;
762 }
763
764 /* Fetch origin attribute. */
765 attr->origin = stream_getc (BGP_INPUT (peer));
766
767 /* If the ORIGIN attribute has an undefined value, then the Error
768 Subcode is set to Invalid Origin Attribute. The Data field
769 contains the unrecognized attribute (type, length and value). */
770 if ((attr->origin != BGP_ORIGIN_IGP)
771 && (attr->origin != BGP_ORIGIN_EGP)
772 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
773 {
774 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
775 attr->origin);
776
777 bgp_notify_send_with_data (peer,
778 BGP_NOTIFY_UPDATE_ERR,
779 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
780 startp, total);
781 return -1;
782 }
783
784 /* Set oring attribute flag. */
785 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
786
787 return 0;
788}
Chris Hallcddb8112010-08-09 22:31:37 +0400789/* Parse AS path information. This function is wrapper of aspath_parse.
790 *
791 * Parses AS_PATH or AS4_PATH.
792 *
793 * Returns: if valid: address of struct aspath in the hash of known aspaths,
794 * with reference count incremented.
795 * else: NULL
796 *
797 * NB: empty AS path (length == 0) is valid. The returned struct aspath will
798 * have segments == NULL and str == zero length string (unique).
799 */
800static struct aspath *
paul718e3742002-12-13 20:15:29 +0000801bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Chris Hallcddb8112010-08-09 22:31:37 +0400802 struct attr *attr, u_char flag, u_char *startp, int as4_path)
paul718e3742002-12-13 20:15:29 +0000803{
Chris Hallcddb8112010-08-09 22:31:37 +0400804 u_char require ;
805 struct aspath *asp ;
paul718e3742002-12-13 20:15:29 +0000806
Chris Hallcddb8112010-08-09 22:31:37 +0400807 /* Check the attribute flags */
808 require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
809 : BGP_ATTR_FLAG_TRANS ;
paul718e3742002-12-13 20:15:29 +0000810
Chris Hallcddb8112010-08-09 22:31:37 +0400811 if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require)
paul718e3742002-12-13 20:15:29 +0000812 {
Chris Hallcddb8112010-08-09 22:31:37 +0400813 const char* path_type ;
814 bgp_size_t total;
815
816 path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
817
818 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000819 zlog (peer->log, LOG_ERR,
Chris Hallcddb8112010-08-09 22:31:37 +0400820 "%s attribute flag isn't transitive %d", path_type, flag) ;
821
822 if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL))
823 zlog (peer->log, LOG_ERR,
824 "%s attribute flag must %sbe optional %d", path_type,
825 (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ;
826
827 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
828
paul718e3742002-12-13 20:15:29 +0000829 bgp_notify_send_with_data (peer,
830 BGP_NOTIFY_UPDATE_ERR,
831 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
832 startp, total);
paul718e3742002-12-13 20:15:29 +0000833
Chris Hallcddb8112010-08-09 22:31:37 +0400834 return NULL ;
835 } ;
836
837 /* Parse the AS_PATH/AS4_PATH body.
838 *
839 * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN
840 * AS4_PATH 4Byte ASN
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000841 */
Chris Hallcddb8112010-08-09 22:31:37 +0400842 asp = aspath_parse (peer->ibuf, length,
843 as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000844
Chris Hallcddb8112010-08-09 22:31:37 +0400845 if (asp != NULL)
846 {
847 attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
848 : BGP_ATTR_AS_PATH) ;
849 }
850 else
paul718e3742002-12-13 20:15:29 +0000851 {
852 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
Chris Hallcddb8112010-08-09 22:31:37 +0400853
854 /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */
paul718e3742002-12-13 20:15:29 +0000855 bgp_notify_send (peer,
856 BGP_NOTIFY_UPDATE_ERR,
857 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Chris Hallcddb8112010-08-09 22:31:37 +0400858 } ;
paul718e3742002-12-13 20:15:29 +0000859
Chris Hallcddb8112010-08-09 22:31:37 +0400860 return asp ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000861}
862
863static int bgp_attr_aspath_check( struct peer *peer,
864 struct attr *attr)
865{
866 /* These checks were part of bgp_attr_aspath, but with
867 * as4 we should to check aspath things when
868 * aspath synthesizing with as4_path has already taken place.
869 * Otherwise we check ASPATH and use the synthesized thing, and that is
870 * not right.
871 * So do the checks later, i.e. here
872 */
873 struct bgp *bgp = peer->bgp;
874 struct aspath *aspath;
875
paul718e3742002-12-13 20:15:29 +0000876 bgp = peer->bgp;
877
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300878 /* Confederation sanity check. */
879 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
880 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
881 {
882 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
883 bgp_notify_send (peer,
884 BGP_NOTIFY_UPDATE_ERR,
885 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
886 return -1;
887 }
888
paul718e3742002-12-13 20:15:29 +0000889 /* First AS check for EBGP. */
890 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
891 {
892 if (peer_sort (peer) == BGP_PEER_EBGP
893 && ! aspath_firstas_check (attr->aspath, peer->as))
894 {
895 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400896 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000897 bgp_notify_send (peer,
898 BGP_NOTIFY_UPDATE_ERR,
899 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
900 return -1;
901 }
902 }
903
904 /* local-as prepend */
905 if (peer->change_local_as &&
906 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
907 {
908 aspath = aspath_dup (attr->aspath);
909 aspath = aspath_add_seq (aspath, peer->change_local_as);
910 aspath_unintern (attr->aspath);
911 attr->aspath = aspath_intern (aspath);
912 }
913
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000914 return 0;
915
916}
917
paul718e3742002-12-13 20:15:29 +0000918/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000919static int
paul718e3742002-12-13 20:15:29 +0000920bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
921 struct attr *attr, u_char flag, u_char *startp)
922{
923 bgp_size_t total;
924
925 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
926
927 /* Flag check. */
928 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
929 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
930 {
931 zlog (peer->log, LOG_ERR,
932 "Origin attribute flag isn't transitive %d", flag);
933 bgp_notify_send_with_data (peer,
934 BGP_NOTIFY_UPDATE_ERR,
935 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
936 startp, total);
937 return -1;
938 }
939
940 /* Check nexthop attribute length. */
941 if (length != 4)
942 {
943 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
944 length);
945
946 bgp_notify_send_with_data (peer,
947 BGP_NOTIFY_UPDATE_ERR,
948 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
949 startp, total);
950 return -1;
951 }
952
953 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
954 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
955
956 return 0;
957}
958
959/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000960static int
paul718e3742002-12-13 20:15:29 +0000961bgp_attr_med (struct peer *peer, bgp_size_t length,
962 struct attr *attr, u_char flag, u_char *startp)
963{
964 bgp_size_t total;
965
966 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
967
968 /* Length check. */
969 if (length != 4)
970 {
971 zlog (peer->log, LOG_ERR,
972 "MED attribute length isn't four [%d]", length);
973
974 bgp_notify_send_with_data (peer,
975 BGP_NOTIFY_UPDATE_ERR,
976 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
977 startp, total);
978 return -1;
979 }
980
981 attr->med = stream_getl (peer->ibuf);
982
983 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
984
985 return 0;
986}
987
988/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000989static int
paul718e3742002-12-13 20:15:29 +0000990bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
991 struct attr *attr, u_char flag)
992{
993 /* If it is contained in an UPDATE message that is received from an
994 external peer, then this attribute MUST be ignored by the
995 receiving speaker. */
996 if (peer_sort (peer) == BGP_PEER_EBGP)
997 {
paul9985f832005-02-09 15:51:56 +0000998 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000999 return 0;
1000 }
1001
1002 if (length == 4)
1003 attr->local_pref = stream_getl (peer->ibuf);
1004 else
1005 attr->local_pref = 0;
1006
1007 /* Set atomic aggregate flag. */
1008 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1009
1010 return 0;
1011}
1012
1013/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001014static int
paul718e3742002-12-13 20:15:29 +00001015bgp_attr_atomic (struct peer *peer, bgp_size_t length,
1016 struct attr *attr, u_char flag)
1017{
1018 if (length != 0)
1019 {
1020 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1021
1022 bgp_notify_send (peer,
1023 BGP_NOTIFY_UPDATE_ERR,
1024 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1025 return -1;
1026 }
1027
1028 /* Set atomic aggregate flag. */
1029 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1030
1031 return 0;
1032}
1033
1034/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001035static int
paul718e3742002-12-13 20:15:29 +00001036bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1037 struct attr *attr, u_char flag)
1038{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001039 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001040 struct attr_extra *attre = bgp_attr_extra_get (attr);
1041
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001042 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1043 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1044 wantedlen = 8;
1045
1046 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001047 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001048 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001049
1050 bgp_notify_send (peer,
1051 BGP_NOTIFY_UPDATE_ERR,
1052 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1053 return -1;
1054 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001055
1056 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1057 attre->aggregator_as = stream_getl (peer->ibuf);
1058 else
1059 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001060 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001061
1062 /* Set atomic aggregate flag. */
1063 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1064
1065 return 0;
1066}
1067
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001068/* New Aggregator attribute */
1069static int
1070bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1071 struct attr *attr, as_t *as4_aggregator_as,
1072 struct in_addr *as4_aggregator_addr)
1073{
1074 if (length != 8)
1075 {
1076 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1077
1078 bgp_notify_send (peer,
1079 BGP_NOTIFY_UPDATE_ERR,
1080 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1081 return -1;
1082 }
1083 *as4_aggregator_as = stream_getl (peer->ibuf);
1084 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1085
1086 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1087
1088 return 0;
1089}
1090
1091/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1092 */
1093static int
1094bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1095 struct aspath *as4_path, as_t as4_aggregator,
1096 struct in_addr *as4_aggregator_addr)
1097{
1098 int ignore_as4_path = 0;
1099 struct aspath *newpath;
1100 struct attr_extra *attre = attr->extra;
1101
1102 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1103 {
1104 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1105 * if given.
1106 * It is worth a warning though, because the peer really
1107 * should not send them
1108 */
1109 if (BGP_DEBUG(as4, AS4))
1110 {
1111 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1112 zlog_debug ("[AS4] %s %s AS4_PATH",
1113 peer->host, "AS4 capable peer, yet it sent");
1114
1115 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1116 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1117 peer->host, "AS4 capable peer, yet it sent");
1118 }
1119
1120 return 0;
1121 }
1122
1123 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1124 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1125 {
1126 /* Hu? This is not supposed to happen at all!
1127 * got as4_path and no aspath,
1128 * This should already
1129 * have been handled by 'well known attributes missing'
1130 * But... yeah, paranoia
1131 * Take this as a "malformed attribute"
1132 */
1133 zlog (peer->log, LOG_ERR,
1134 "%s BGP not AS4 capable peer sent AS4_PATH but"
1135 " no AS_PATH, cant do anything here", peer->host);
1136 bgp_notify_send (peer,
1137 BGP_NOTIFY_UPDATE_ERR,
1138 BGP_NOTIFY_UPDATE_MAL_ATTR);
1139 return -1;
1140 }
1141
1142 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1143 * because that may override AS4_PATH
1144 */
1145 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1146 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001147 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1148 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001149 assert (attre);
1150
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001151 /* received both.
1152 * if the as_number in aggregator is not AS_TRANS,
1153 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1154 * and the Aggregator shall be taken as
1155 * info on the aggregating node, and the AS_PATH
1156 * shall be taken as the AS_PATH
1157 * otherwise
1158 * the Aggregator shall be ignored and the
1159 * AS4_AGGREGATOR shall be taken as the
1160 * Aggregating node and the AS_PATH is to be
1161 * constructed "as in all other cases"
1162 */
1163 if ( attre->aggregator_as != BGP_AS_TRANS )
1164 {
1165 /* ignore */
1166 if ( BGP_DEBUG(as4, AS4))
1167 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1168 " send AGGREGATOR != AS_TRANS and"
1169 " AS4_AGGREGATOR, so ignore"
1170 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1171 ignore_as4_path = 1;
1172 }
1173 else
1174 {
1175 /* "New_aggregator shall be taken as aggregator" */
1176 attre->aggregator_as = as4_aggregator;
1177 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1178 }
1179 }
1180 else
1181 {
1182 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1183 * That is bogus - but reading the conditions
1184 * we have to handle AS4_AGGREGATOR as if it were
1185 * AGGREGATOR in that case
1186 */
1187 if ( BGP_DEBUG(as4, AS4))
1188 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1189 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1190 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001191 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001192 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1193 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1194 }
1195 }
1196
1197 /* need to reconcile NEW_AS_PATH and AS_PATH */
1198 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1199 {
1200 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1201 aspath_unintern (attr->aspath);
1202 attr->aspath = aspath_intern (newpath);
1203 }
1204 return 0;
1205}
1206
paul718e3742002-12-13 20:15:29 +00001207/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001208static int
paul718e3742002-12-13 20:15:29 +00001209bgp_attr_community (struct peer *peer, bgp_size_t length,
1210 struct attr *attr, u_char flag)
1211{
1212 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001213 {
1214 attr->community = NULL;
1215 return 0;
1216 }
Paul Jakma0c466382010-12-05 17:17:26 +00001217
1218 attr->community =
1219 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1220
1221 /* XXX: fix community_parse to use stream API and remove this */
1222 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001223
Paul Jakma0c466382010-12-05 17:17:26 +00001224 if (!attr->community)
1225 return -1;
1226
paul718e3742002-12-13 20:15:29 +00001227 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1228
1229 return 0;
1230}
1231
1232/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001233static int
paul718e3742002-12-13 20:15:29 +00001234bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1235 struct attr *attr, u_char flag)
1236{
1237 if (length != 4)
1238 {
1239 zlog (peer->log, LOG_ERR, "Bad originator ID 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))->originator_id.s_addr
1248 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001249
1250 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1251
1252 return 0;
1253}
1254
1255/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001256static int
paul718e3742002-12-13 20:15:29 +00001257bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1258 struct attr *attr, u_char flag)
1259{
1260 /* Check length. */
1261 if (length % 4)
1262 {
1263 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1264
1265 bgp_notify_send (peer,
1266 BGP_NOTIFY_UPDATE_ERR,
1267 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1268 return -1;
1269 }
1270
Paul Jakmafb982c22007-05-04 20:15:47 +00001271 (bgp_attr_extra_get (attr))->cluster
1272 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001273
paul9985f832005-02-09 15:51:56 +00001274 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001275
1276 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1277
1278 return 0;
1279}
1280
1281/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001282int
paul718e3742002-12-13 20:15:29 +00001283bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1284 struct bgp_nlri *mp_update)
1285{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001286 afi_t afi;
1287 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001288 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001289 size_t start;
paul718e3742002-12-13 20:15:29 +00001290 int ret;
1291 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001292 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001293
1294 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001295 s = BGP_INPUT(peer);
1296 start = stream_get_getp(s);
1297
1298 /* safe to read statically sized header? */
1299#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001300#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001301 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001302 {
1303 zlog_info ("%s: %s sent invalid length, %lu",
1304 __func__, peer->host, (unsigned long)length);
1305 return -1;
1306 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001307
paul718e3742002-12-13 20:15:29 +00001308 /* Load AFI, SAFI. */
1309 afi = stream_getw (s);
1310 safi = stream_getc (s);
1311
1312 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001313 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001314
Paul Jakma03292802008-06-07 20:37:10 +00001315 if (LEN_LEFT < attre->mp_nexthop_len)
1316 {
1317 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1318 __func__, peer->host, attre->mp_nexthop_len);
1319 return -1;
1320 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001321
paul718e3742002-12-13 20:15:29 +00001322 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001323 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001324 {
1325 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001326 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001327 /* Probably needed for RFC 2283 */
1328 if (attr->nexthop.s_addr == 0)
1329 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001330 break;
1331 case 12:
1332 {
1333 u_int32_t rd_high;
1334 u_int32_t rd_low;
1335
1336 rd_high = stream_getl (s);
1337 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001338 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001339 }
1340 break;
1341#ifdef HAVE_IPV6
1342 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001343 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001344 break;
1345 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001346 stream_get (&attre->mp_nexthop_global, s, 16);
1347 stream_get (&attre->mp_nexthop_local, s, 16);
1348 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001349 {
1350 char buf1[INET6_ADDRSTRLEN];
1351 char buf2[INET6_ADDRSTRLEN];
1352
1353 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001354 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 +00001355 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001356 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001357 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001358 buf2, INET6_ADDRSTRLEN));
1359
Paul Jakmafb982c22007-05-04 20:15:47 +00001360 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001361 }
1362 break;
1363#endif /* HAVE_IPV6 */
1364 default:
Paul Jakma03292802008-06-07 20:37:10 +00001365 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1366 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001367 return -1;
paul718e3742002-12-13 20:15:29 +00001368 }
1369
Paul Jakma03292802008-06-07 20:37:10 +00001370 if (!LEN_LEFT)
1371 {
1372 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1373 __func__, peer->host);
1374 return -1;
1375 }
paul718e3742002-12-13 20:15:29 +00001376
Paul Jakma6e4ab122007-04-10 19:36:48 +00001377 {
1378 u_char val;
1379 if ((val = stream_getc (s)))
1380 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1381 peer->host, val);
1382 }
1383
1384 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001385 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001386 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001387 {
1388 zlog_info ("%s: (%s) Failed to read NLRI",
1389 __func__, peer->host);
1390 return -1;
1391 }
paul718e3742002-12-13 20:15:29 +00001392
1393 if (safi != BGP_SAFI_VPNV4)
1394 {
1395 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001396 if (ret < 0)
1397 {
1398 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1399 __func__, peer->host);
1400 return -1;
1401 }
paul718e3742002-12-13 20:15:29 +00001402 }
1403
1404 mp_update->afi = afi;
1405 mp_update->safi = safi;
1406 mp_update->nlri = stream_pnt (s);
1407 mp_update->length = nlri_len;
1408
paul9985f832005-02-09 15:51:56 +00001409 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001410
1411 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001412#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001413}
1414
1415/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001416int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001417bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001418 struct bgp_nlri *mp_withdraw)
1419{
1420 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001421 afi_t afi;
1422 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001423 u_int16_t withdraw_len;
1424 int ret;
1425
1426 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001427
1428#define BGP_MP_UNREACH_MIN_SIZE 3
1429 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1430 return -1;
1431
paul718e3742002-12-13 20:15:29 +00001432 afi = stream_getw (s);
1433 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001434
1435 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001436
1437 if (safi != BGP_SAFI_VPNV4)
1438 {
1439 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1440 if (ret < 0)
1441 return -1;
1442 }
1443
1444 mp_withdraw->afi = afi;
1445 mp_withdraw->safi = safi;
1446 mp_withdraw->nlri = stream_pnt (s);
1447 mp_withdraw->length = withdraw_len;
1448
paul9985f832005-02-09 15:51:56 +00001449 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001450
1451 return 0;
1452}
1453
1454/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001455static int
paul718e3742002-12-13 20:15:29 +00001456bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1457 struct attr *attr, u_char flag)
1458{
1459 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001460 {
1461 if (attr->extra)
1462 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001463 /* Empty extcomm doesn't seem to be invalid per se */
1464 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001465 }
Paul Jakma0c466382010-12-05 17:17:26 +00001466
1467 (bgp_attr_extra_get (attr))->ecommunity =
1468 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1469 /* XXX: fix ecommunity_parse to use stream API */
1470 stream_forward_getp (peer->ibuf, length);
1471
1472 if (!attr->extra->ecommunity)
1473 return -1;
1474
paul718e3742002-12-13 20:15:29 +00001475 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1476
1477 return 0;
1478}
1479
1480/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001481static int
paul718e3742002-12-13 20:15:29 +00001482bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1483 u_char type, bgp_size_t length, u_char *startp)
1484{
1485 bgp_size_t total;
1486 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001487 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001488
hassof4184462005-02-01 20:13:16 +00001489 if (BGP_DEBUG (normal, NORMAL))
1490 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1491 peer->host, type, length);
1492
paul718e3742002-12-13 20:15:29 +00001493 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001494 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001495 "Unknown attribute type %d length %d is received", type, length);
1496
1497 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001498 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001499
1500 /* Adjest total length to include type and length. */
1501 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1502
1503 /* If any of the mandatory well-known attributes are not recognized,
1504 then the Error Subcode is set to Unrecognized Well-known
1505 Attribute. The Data field contains the unrecognized attribute
1506 (type, length and value). */
1507 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1508 {
1509 /* Adjust startp to do not include flag value. */
1510 bgp_notify_send_with_data (peer,
1511 BGP_NOTIFY_UPDATE_ERR,
1512 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1513 startp, total);
1514 return -1;
1515 }
1516
1517 /* Unrecognized non-transitive optional attributes must be quietly
1518 ignored and not passed along to other BGP peers. */
1519 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1520 return 0;
1521
1522 /* If a path with recognized transitive optional attribute is
1523 accepted and passed along to other BGP peers and the Partial bit
1524 in the Attribute Flags octet is set to 1 by some previous AS, it
1525 is not set back to 0 by the current AS. */
1526 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1527
1528 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001529 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001530 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001531
Paul Jakmafb982c22007-05-04 20:15:47 +00001532 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001533
1534 if (transit->val)
1535 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1536 transit->length + total);
1537 else
1538 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1539
1540 memcpy (transit->val + transit->length, startp, total);
1541 transit->length += total;
1542
1543 return 0;
1544}
1545
1546/* Read attribute of update packet. This function is called from
1547 bgp_update() in bgpd.c. */
1548int
1549bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1550 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1551{
1552 int ret;
1553 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001554 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001555 bgp_size_t length;
1556 u_char *startp, *endp;
1557 u_char *attr_endp;
1558 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001559 /* we need the as4_path only until we have synthesized the as_path with it */
1560 /* same goes for as4_aggregator */
1561 struct aspath *as4_path = NULL;
1562 as_t as4_aggregator = 0;
1563 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001564
1565 /* Initialize bitmap. */
1566 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1567
1568 /* End pointer of BGP attribute. */
1569 endp = BGP_INPUT_PNT (peer) + size;
1570
1571 /* Get attributes to the end of attribute length. */
1572 while (BGP_INPUT_PNT (peer) < endp)
1573 {
1574 /* Check remaining length check.*/
1575 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1576 {
gdtc29fdba2004-12-09 14:46:46 +00001577 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001578 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001579 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001580 peer->host,
1581 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001582
1583 bgp_notify_send (peer,
1584 BGP_NOTIFY_UPDATE_ERR,
1585 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1586 return -1;
1587 }
1588
1589 /* Fetch attribute flag and type. */
1590 startp = BGP_INPUT_PNT (peer);
1591 flag = stream_getc (BGP_INPUT (peer));
1592 type = stream_getc (BGP_INPUT (peer));
1593
Paul Jakma370b64a2007-12-22 16:49:52 +00001594 /* Check whether Extended-Length applies and is in bounds */
1595 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1596 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1597 {
1598 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001599 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001600 peer->host,
1601 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1602
1603 bgp_notify_send (peer,
1604 BGP_NOTIFY_UPDATE_ERR,
1605 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1606 return -1;
1607 }
1608
paul718e3742002-12-13 20:15:29 +00001609 /* Check extended attribue length bit. */
1610 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1611 length = stream_getw (BGP_INPUT (peer));
1612 else
1613 length = stream_getc (BGP_INPUT (peer));
1614
1615 /* If any attribute appears more than once in the UPDATE
1616 message, then the Error Subcode is set to Malformed Attribute
1617 List. */
1618
1619 if (CHECK_BITMAP (seen, type))
1620 {
1621 zlog (peer->log, LOG_WARNING,
1622 "%s error BGP attribute type %d appears twice in a message",
1623 peer->host, type);
1624
1625 bgp_notify_send (peer,
1626 BGP_NOTIFY_UPDATE_ERR,
1627 BGP_NOTIFY_UPDATE_MAL_ATTR);
1628 return -1;
1629 }
1630
1631 /* Set type to bitmap to check duplicate attribute. `type' is
1632 unsigned char so it never overflow bitmap range. */
1633
1634 SET_BITMAP (seen, type);
1635
1636 /* Overflow check. */
1637 attr_endp = BGP_INPUT_PNT (peer) + length;
1638
1639 if (attr_endp > endp)
1640 {
1641 zlog (peer->log, LOG_WARNING,
1642 "%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);
1643 bgp_notify_send (peer,
1644 BGP_NOTIFY_UPDATE_ERR,
1645 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1646 return -1;
1647 }
1648
1649 /* OK check attribute and store it's value. */
1650 switch (type)
1651 {
1652 case BGP_ATTR_ORIGIN:
1653 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1654 break;
1655 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001656 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1657 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001658 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001659 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001660 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1661 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001662 break;
paul718e3742002-12-13 20:15:29 +00001663 case BGP_ATTR_NEXT_HOP:
1664 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1665 break;
1666 case BGP_ATTR_MULTI_EXIT_DISC:
1667 ret = bgp_attr_med (peer, length, attr, flag, startp);
1668 break;
1669 case BGP_ATTR_LOCAL_PREF:
1670 ret = bgp_attr_local_pref (peer, length, attr, flag);
1671 break;
1672 case BGP_ATTR_ATOMIC_AGGREGATE:
1673 ret = bgp_attr_atomic (peer, length, attr, flag);
1674 break;
1675 case BGP_ATTR_AGGREGATOR:
1676 ret = bgp_attr_aggregator (peer, length, attr, flag);
1677 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001678 case BGP_ATTR_AS4_AGGREGATOR:
1679 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1680 break;
paul718e3742002-12-13 20:15:29 +00001681 case BGP_ATTR_COMMUNITIES:
1682 ret = bgp_attr_community (peer, length, attr, flag);
1683 break;
1684 case BGP_ATTR_ORIGINATOR_ID:
1685 ret = bgp_attr_originator_id (peer, length, attr, flag);
1686 break;
1687 case BGP_ATTR_CLUSTER_LIST:
1688 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1689 break;
1690 case BGP_ATTR_MP_REACH_NLRI:
1691 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1692 break;
1693 case BGP_ATTR_MP_UNREACH_NLRI:
1694 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1695 break;
1696 case BGP_ATTR_EXT_COMMUNITIES:
1697 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1698 break;
Paul Jakma41367172007-08-06 15:24:51 +00001699 case BGP_ATTR_AS_PATHLIMIT:
1700 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1701 break;
paul718e3742002-12-13 20:15:29 +00001702 default:
1703 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1704 break;
1705 }
1706
1707 /* If error occured immediately return to the caller. */
1708 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001709 {
1710 zlog (peer->log, LOG_WARNING,
1711 "%s: Attribute %s, parse error",
1712 peer->host,
1713 LOOKUP (attr_str, type));
1714 bgp_notify_send (peer,
1715 BGP_NOTIFY_UPDATE_ERR,
1716 BGP_NOTIFY_UPDATE_MAL_ATTR);
1717 return ret;
1718 }
paul718e3742002-12-13 20:15:29 +00001719
1720 /* Check the fetched length. */
1721 if (BGP_INPUT_PNT (peer) != attr_endp)
1722 {
1723 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001724 "%s: BGP attribute %s, fetch error",
1725 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001726 bgp_notify_send (peer,
1727 BGP_NOTIFY_UPDATE_ERR,
1728 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1729 return -1;
1730 }
1731 }
1732
1733 /* Check final read pointer is same as end pointer. */
1734 if (BGP_INPUT_PNT (peer) != endp)
1735 {
1736 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001737 "%s BGP attribute %s, length mismatch",
1738 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001739 bgp_notify_send (peer,
1740 BGP_NOTIFY_UPDATE_ERR,
1741 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1742 return -1;
1743 }
1744
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001745 /*
1746 * At this place we can see whether we got AS4_PATH and/or
1747 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1748 * We can not do this before we've read all attributes because
1749 * the as4 handling does not say whether AS4_PATH has to be sent
1750 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1751 * in relationship to AGGREGATOR.
1752 * So, to be defensive, we are not relying on any order and read
1753 * all attributes first, including these 32bit ones, and now,
1754 * afterwards, we look what and if something is to be done for as4.
1755 */
1756 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1757 as4_aggregator, &as4_aggregator_addr))
1758 return -1;
1759
1760 /* At this stage, we have done all fiddling with as4, and the
1761 * resulting info is in attr->aggregator resp. attr->aspath
1762 * so we can chuck as4_aggregator and as4_path alltogether in
1763 * order to save memory
1764 */
1765 if ( as4_path )
1766 {
1767 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1768 as4_path = NULL;
1769 /* The flag that we got this is still there, but that does not
1770 * do any trouble
1771 */
1772 }
1773 /*
1774 * The "rest" of the code does nothing with as4_aggregator.
1775 * there is no memory attached specifically which is not part
1776 * of the attr.
1777 * so ignoring just means do nothing.
1778 */
1779 /*
1780 * Finally do the checks on the aspath we did not do yet
1781 * because we waited for a potentially synthesized aspath.
1782 */
1783 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1784 {
1785 ret = bgp_attr_aspath_check( peer, attr );
1786 if ( ret < 0 )
1787 return ret;
1788 }
1789
paul718e3742002-12-13 20:15:29 +00001790 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001791 if (attr->extra && attr->extra->transit)
1792 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001793
1794 return 0;
1795}
1796
1797/* Well-known attribute check. */
1798int
1799bgp_attr_check (struct peer *peer, struct attr *attr)
1800{
1801 u_char type = 0;
1802
1803 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1804 type = BGP_ATTR_ORIGIN;
1805
1806 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1807 type = BGP_ATTR_AS_PATH;
1808
1809 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1810 type = BGP_ATTR_NEXT_HOP;
1811
1812 if (peer_sort (peer) == BGP_PEER_IBGP
1813 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1814 type = BGP_ATTR_LOCAL_PREF;
1815
1816 if (type)
1817 {
1818 zlog (peer->log, LOG_WARNING,
1819 "%s Missing well-known attribute %d.",
1820 peer->host, type);
1821 bgp_notify_send_with_data (peer,
1822 BGP_NOTIFY_UPDATE_ERR,
1823 BGP_NOTIFY_UPDATE_MISS_ATTR,
1824 &type, 1);
1825 return -1;
1826 }
1827 return 0;
1828}
1829
1830int stream_put_prefix (struct stream *, struct prefix *);
1831
1832/* Make attribute packet. */
1833bgp_size_t
1834bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1835 struct stream *s, struct attr *attr, struct prefix *p,
1836 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001837 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001838{
paulfe69a502005-09-10 16:55:02 +00001839 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001840 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001841 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001842 int send_as4_path = 0;
1843 int send_as4_aggregator = 0;
1844 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001845
1846 if (! bgp)
1847 bgp = bgp_get_default ();
1848
1849 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001850 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001851
1852 /* Origin attribute. */
1853 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1854 stream_putc (s, BGP_ATTR_ORIGIN);
1855 stream_putc (s, 1);
1856 stream_putc (s, attr->origin);
1857
1858 /* AS path attribute. */
1859
1860 /* If remote-peer is EBGP */
1861 if (peer_sort (peer) == BGP_PEER_EBGP
1862 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001863 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001864 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001865 {
1866 aspath = aspath_dup (attr->aspath);
1867
1868 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1869 {
1870 /* Strip the confed info, and then stuff our path CONFED_ID
1871 on the front */
1872 aspath = aspath_delete_confed_seq (aspath);
1873 aspath = aspath_add_seq (aspath, bgp->confed_id);
1874 }
1875 else
1876 {
1877 aspath = aspath_add_seq (aspath, peer->local_as);
1878 if (peer->change_local_as)
1879 aspath = aspath_add_seq (aspath, peer->change_local_as);
1880 }
1881 }
1882 else if (peer_sort (peer) == BGP_PEER_CONFED)
1883 {
1884 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1885 aspath = aspath_dup (attr->aspath);
1886 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1887 }
1888 else
1889 aspath = attr->aspath;
1890
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001891 /* If peer is not AS4 capable, then:
1892 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1893 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1894 * types are in it (i.e. exclude them if they are there)
1895 * AND do this only if there is at least one asnum > 65535 in the path!
1896 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1897 * all ASnums > 65535 to BGP_AS_TRANS
1898 */
paul718e3742002-12-13 20:15:29 +00001899
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001900 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1901 stream_putc (s, BGP_ATTR_AS_PATH);
1902 aspath_sizep = stream_get_endp (s);
1903 stream_putw (s, 0);
1904 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1905
1906 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1907 * in the path
1908 */
1909 if (!use32bit && aspath_has_as4 (aspath))
1910 send_as4_path = 1; /* we'll do this later, at the correct place */
1911
paul718e3742002-12-13 20:15:29 +00001912 /* Nexthop attribute. */
1913 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1914 {
1915 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1916 stream_putc (s, BGP_ATTR_NEXT_HOP);
1917 stream_putc (s, 4);
1918 if (safi == SAFI_MPLS_VPN)
1919 {
1920 if (attr->nexthop.s_addr == 0)
1921 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1922 else
1923 stream_put_ipv4 (s, attr->nexthop.s_addr);
1924 }
1925 else
1926 stream_put_ipv4 (s, attr->nexthop.s_addr);
1927 }
1928
1929 /* MED attribute. */
1930 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1931 {
1932 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1933 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1934 stream_putc (s, 4);
1935 stream_putl (s, attr->med);
1936 }
1937
1938 /* Local preference. */
1939 if (peer_sort (peer) == BGP_PEER_IBGP ||
1940 peer_sort (peer) == BGP_PEER_CONFED)
1941 {
1942 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1943 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1944 stream_putc (s, 4);
1945 stream_putl (s, attr->local_pref);
1946 }
1947
1948 /* Atomic aggregate. */
1949 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1950 {
1951 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1952 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1953 stream_putc (s, 0);
1954 }
1955
1956 /* Aggregator. */
1957 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1958 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001959 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001960
1961 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001962 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1963 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001964
1965 if (use32bit)
1966 {
1967 /* AS4 capable peer */
1968 stream_putc (s, 8);
1969 stream_putl (s, attr->extra->aggregator_as);
1970 }
1971 else
1972 {
1973 /* 2-byte AS peer */
1974 stream_putc (s, 6);
1975
1976 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1977 if ( attr->extra->aggregator_as > 65535 )
1978 {
1979 stream_putw (s, BGP_AS_TRANS);
1980
1981 /* we have to send AS4_AGGREGATOR, too.
1982 * we'll do that later in order to send attributes in ascending
1983 * order.
1984 */
1985 send_as4_aggregator = 1;
1986 }
1987 else
1988 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1989 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001990 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001991 }
1992
1993 /* Community attribute. */
1994 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1995 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1996 {
1997 if (attr->community->size * 4 > 255)
1998 {
1999 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2000 stream_putc (s, BGP_ATTR_COMMUNITIES);
2001 stream_putw (s, attr->community->size * 4);
2002 }
2003 else
2004 {
2005 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2006 stream_putc (s, BGP_ATTR_COMMUNITIES);
2007 stream_putc (s, attr->community->size * 4);
2008 }
2009 stream_put (s, attr->community->val, attr->community->size * 4);
2010 }
2011
2012 /* Route Reflector. */
2013 if (peer_sort (peer) == BGP_PEER_IBGP
2014 && from
2015 && peer_sort (from) == BGP_PEER_IBGP)
2016 {
2017 /* Originator ID. */
2018 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2019 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2020 stream_putc (s, 4);
2021
2022 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002023 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002024 else
2025 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002026
2027 /* Cluster list. */
2028 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2029 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2030
Paul Jakma9eda90c2007-08-30 13:36:17 +00002031 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002032 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002033 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002034 /* If this peer configuration's parent BGP has cluster_id. */
2035 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2036 stream_put_in_addr (s, &bgp->cluster_id);
2037 else
2038 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002039 stream_put (s, attr->extra->cluster->list,
2040 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002041 }
2042 else
2043 {
2044 stream_putc (s, 4);
2045 /* If this peer configuration's parent BGP has cluster_id. */
2046 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2047 stream_put_in_addr (s, &bgp->cluster_id);
2048 else
2049 stream_put_in_addr (s, &bgp->router_id);
2050 }
2051 }
2052
2053#ifdef HAVE_IPV6
2054 /* If p is IPv6 address put it into attribute. */
2055 if (p->family == AF_INET6)
2056 {
2057 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002058 struct attr_extra *attre = attr->extra;
2059
2060 assert (attr->extra);
2061
paul718e3742002-12-13 20:15:29 +00002062 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2063 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002064 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002065 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002066 stream_putw (s, AFI_IP6); /* AFI */
2067 stream_putc (s, safi); /* SAFI */
2068
Paul Jakmafb982c22007-05-04 20:15:47 +00002069 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002070
Paul Jakmafb982c22007-05-04 20:15:47 +00002071 if (attre->mp_nexthop_len == 16)
2072 stream_put (s, &attre->mp_nexthop_global, 16);
2073 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002074 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002075 stream_put (s, &attre->mp_nexthop_global, 16);
2076 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002077 }
2078
2079 /* SNPA */
2080 stream_putc (s, 0);
2081
paul718e3742002-12-13 20:15:29 +00002082 /* Prefix write. */
2083 stream_put_prefix (s, p);
2084
2085 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002086 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002087 }
2088#endif /* HAVE_IPV6 */
2089
2090 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2091 {
2092 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002093
2094 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2095 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002096 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002097 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002098 stream_putw (s, AFI_IP); /* AFI */
2099 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2100
2101 stream_putc (s, 4);
2102 stream_put_ipv4 (s, attr->nexthop.s_addr);
2103
2104 /* SNPA */
2105 stream_putc (s, 0);
2106
paul718e3742002-12-13 20:15:29 +00002107 /* Prefix write. */
2108 stream_put_prefix (s, p);
2109
2110 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002111 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002112 }
2113
2114 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2115 {
2116 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002117
2118 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2119 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002120 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002121 stream_putc (s, 0); /* Length of this attribute. */
2122 stream_putw (s, AFI_IP); /* AFI */
2123 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2124
2125 stream_putc (s, 12);
2126 stream_putl (s, 0);
2127 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002128 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002129
2130 /* SNPA */
2131 stream_putc (s, 0);
2132
paul718e3742002-12-13 20:15:29 +00002133 /* Tag, RD, Prefix write. */
2134 stream_putc (s, p->prefixlen + 88);
2135 stream_put (s, tag, 3);
2136 stream_put (s, prd->val, 8);
2137 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2138
2139 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002140 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002141 }
2142
2143 /* Extended Communities attribute. */
2144 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2145 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2146 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002147 struct attr_extra *attre = attr->extra;
2148
2149 assert (attre);
2150
2151 if (peer_sort (peer) == BGP_PEER_IBGP
2152 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002153 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002154 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002155 {
2156 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2157 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002158 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002159 }
2160 else
2161 {
2162 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2163 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002164 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002165 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002166 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002167 }
2168 else
2169 {
paul5228ad22004-06-04 17:58:18 +00002170 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002171 int tbit;
2172 int ecom_tr_size = 0;
2173 int i;
2174
Paul Jakmafb982c22007-05-04 20:15:47 +00002175 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002176 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002177 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002178 tbit = *pnt;
2179
2180 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2181 continue;
2182
2183 ecom_tr_size++;
2184 }
2185
2186 if (ecom_tr_size)
2187 {
2188 if (ecom_tr_size * 8 > 255)
2189 {
2190 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2191 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2192 stream_putw (s, ecom_tr_size * 8);
2193 }
2194 else
2195 {
2196 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2197 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2198 stream_putc (s, ecom_tr_size * 8);
2199 }
2200
Paul Jakmafb982c22007-05-04 20:15:47 +00002201 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002202 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002203 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002204 tbit = *pnt;
2205
2206 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2207 continue;
2208
2209 stream_put (s, pnt, 8);
2210 }
2211 }
paul718e3742002-12-13 20:15:29 +00002212 }
paul718e3742002-12-13 20:15:29 +00002213 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002214
2215 if ( send_as4_path )
2216 {
2217 /* If the peer is NOT As4 capable, AND */
2218 /* there are ASnums > 65535 in path THEN
2219 * give out AS4_PATH */
2220
2221 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2222 * path segments!
2223 * Hm, I wonder... confederation things *should* only be at
2224 * the beginning of an aspath, right? Then we should use
2225 * aspath_delete_confed_seq for this, because it is already
2226 * there! (JK)
2227 * Folks, talk to me: what is reasonable here!?
2228 */
2229 aspath = aspath_delete_confed_seq (aspath);
2230
2231 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2232 stream_putc (s, BGP_ATTR_AS4_PATH);
2233 aspath_sizep = stream_get_endp (s);
2234 stream_putw (s, 0);
2235 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2236 }
2237
2238 if (aspath != attr->aspath)
2239 aspath_free (aspath);
2240
2241 if ( send_as4_aggregator )
2242 {
2243 assert (attr->extra);
2244
2245 /* send AS4_AGGREGATOR, at this place */
2246 /* this section of code moved here in order to ensure the correct
2247 * *ascending* order of attributes
2248 */
2249 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2250 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2251 stream_putc (s, 8);
2252 stream_putl (s, attr->extra->aggregator_as);
2253 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2254 }
Paul Jakma41367172007-08-06 15:24:51 +00002255
2256 /* AS-Pathlimit */
2257 if (attr->pathlimit.ttl)
2258 {
2259 u_int32_t as = attr->pathlimit.as;
2260
2261 /* should already have been done in announce_check(),
2262 * but just in case..
2263 */
2264 if (!as)
2265 as = peer->local_as;
2266
2267 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2268 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2269 stream_putc (s, 5);
2270 stream_putc (s, attr->pathlimit.ttl);
2271 stream_putl (s, as);
2272 }
2273
paul718e3742002-12-13 20:15:29 +00002274 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002275 if (attr->extra && attr->extra->transit)
2276 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002277
2278 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002279 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002280}
2281
2282bgp_size_t
2283bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2284 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002285 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002286{
2287 unsigned long cp;
2288 unsigned long attrlen_pnt;
2289 bgp_size_t size;
2290
paul9985f832005-02-09 15:51:56 +00002291 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002292
2293 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2294 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2295
paul9985f832005-02-09 15:51:56 +00002296 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002297 stream_putc (s, 0); /* Length of this attribute. */
2298
2299 stream_putw (s, family2afi (p->family));
2300
2301 if (safi == SAFI_MPLS_VPN)
2302 {
2303 /* SAFI */
2304 stream_putc (s, BGP_SAFI_VPNV4);
2305
2306 /* prefix. */
2307 stream_putc (s, p->prefixlen + 88);
2308 stream_put (s, tag, 3);
2309 stream_put (s, prd->val, 8);
2310 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2311 }
2312 else
2313 {
2314 /* SAFI */
2315 stream_putc (s, safi);
2316
2317 /* prefix */
2318 stream_put_prefix (s, p);
2319 }
2320
2321 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002322 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002323 stream_putc_at (s, attrlen_pnt, size);
2324
paul9985f832005-02-09 15:51:56 +00002325 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002326}
2327
2328/* Initialization of attribute. */
2329void
paulfe69a502005-09-10 16:55:02 +00002330bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002331{
paul718e3742002-12-13 20:15:29 +00002332 aspath_init ();
2333 attrhash_init ();
2334 community_init ();
2335 ecommunity_init ();
2336 cluster_init ();
2337 transit_init ();
2338}
2339
Chris Caputo228da422009-07-18 05:44:03 +00002340void
2341bgp_attr_finish (void)
2342{
2343 aspath_finish ();
2344 attrhash_finish ();
2345 community_finish ();
2346 ecommunity_finish ();
2347 cluster_finish ();
2348 transit_finish ();
2349}
2350
paul718e3742002-12-13 20:15:29 +00002351/* Make attribute packet. */
2352void
paula3845922003-10-18 01:30:50 +00002353bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2354 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002355{
2356 unsigned long cp;
2357 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002358 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002359 struct aspath *aspath;
2360
2361 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002362 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002363
2364 /* Place holder of length. */
2365 stream_putw (s, 0);
2366
2367 /* Origin attribute. */
2368 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2369 stream_putc (s, BGP_ATTR_ORIGIN);
2370 stream_putc (s, 1);
2371 stream_putc (s, attr->origin);
2372
2373 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002374
2375 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2376 stream_putc (s, BGP_ATTR_AS_PATH);
2377 aspath_lenp = stream_get_endp (s);
2378 stream_putw (s, 0);
2379
2380 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002381
2382 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002383 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2384 if(prefix != NULL
2385#ifdef HAVE_IPV6
2386 && prefix->family != AF_INET6
2387#endif /* HAVE_IPV6 */
2388 )
2389 {
2390 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2391 stream_putc (s, BGP_ATTR_NEXT_HOP);
2392 stream_putc (s, 4);
2393 stream_put_ipv4 (s, attr->nexthop.s_addr);
2394 }
paul718e3742002-12-13 20:15:29 +00002395
2396 /* MED attribute. */
2397 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2398 {
2399 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2400 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2401 stream_putc (s, 4);
2402 stream_putl (s, attr->med);
2403 }
2404
2405 /* Local preference. */
2406 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2407 {
2408 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2409 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2410 stream_putc (s, 4);
2411 stream_putl (s, attr->local_pref);
2412 }
2413
2414 /* Atomic aggregate. */
2415 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2416 {
2417 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2418 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2419 stream_putc (s, 0);
2420 }
2421
2422 /* Aggregator. */
2423 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2424 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002425 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002426 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2427 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002428 stream_putc (s, 8);
2429 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002430 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002431 }
2432
2433 /* Community attribute. */
2434 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2435 {
2436 if (attr->community->size * 4 > 255)
2437 {
2438 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2439 stream_putc (s, BGP_ATTR_COMMUNITIES);
2440 stream_putw (s, attr->community->size * 4);
2441 }
2442 else
2443 {
2444 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2445 stream_putc (s, BGP_ATTR_COMMUNITIES);
2446 stream_putc (s, attr->community->size * 4);
2447 }
2448 stream_put (s, attr->community->val, attr->community->size * 4);
2449 }
2450
paula3845922003-10-18 01:30:50 +00002451#ifdef HAVE_IPV6
2452 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002453 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2454 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002455 {
2456 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002457 struct attr_extra *attre = attr->extra;
2458
paula3845922003-10-18 01:30:50 +00002459 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2460 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002461 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002462
2463 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002464 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002465 stream_putw(s, AFI_IP6); /* AFI */
2466 stream_putc(s, SAFI_UNICAST); /* SAFI */
2467
2468 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002469 stream_putc(s, attre->mp_nexthop_len);
2470 stream_put(s, &attre->mp_nexthop_global, 16);
2471 if (attre->mp_nexthop_len == 32)
2472 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002473
2474 /* SNPA */
2475 stream_putc(s, 0);
2476
2477 /* Prefix */
2478 stream_put_prefix(s, prefix);
2479
2480 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002481 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002482 }
2483#endif /* HAVE_IPV6 */
2484
Paul Jakma41367172007-08-06 15:24:51 +00002485 /* AS-Pathlimit */
2486 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2487 {
2488 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2489 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2490 stream_putc (s, 5);
2491 stream_putc (s, attr->pathlimit.ttl);
2492 stream_putl (s, attr->pathlimit.as);
2493 }
2494
paul718e3742002-12-13 20:15:29 +00002495 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002496 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002497 stream_putw_at (s, cp, len);
2498}