blob: 35473651cb41df7a46718580c7d07b953e967e14 [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 }
paul718e3742002-12-13 20:15:29 +00001217 else
1218 {
paul5228ad22004-06-04 17:58:18 +00001219 attr->community =
1220 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001221 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001222 }
1223
1224 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1225
1226 return 0;
1227}
1228
1229/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001230static int
paul718e3742002-12-13 20:15:29 +00001231bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1232 struct attr *attr, u_char flag)
1233{
1234 if (length != 4)
1235 {
1236 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1237
1238 bgp_notify_send (peer,
1239 BGP_NOTIFY_UPDATE_ERR,
1240 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1241 return -1;
1242 }
1243
Paul Jakmafb982c22007-05-04 20:15:47 +00001244 (bgp_attr_extra_get (attr))->originator_id.s_addr
1245 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001246
1247 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1248
1249 return 0;
1250}
1251
1252/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001253static int
paul718e3742002-12-13 20:15:29 +00001254bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1255 struct attr *attr, u_char flag)
1256{
1257 /* Check length. */
1258 if (length % 4)
1259 {
1260 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1261
1262 bgp_notify_send (peer,
1263 BGP_NOTIFY_UPDATE_ERR,
1264 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1265 return -1;
1266 }
1267
Paul Jakmafb982c22007-05-04 20:15:47 +00001268 (bgp_attr_extra_get (attr))->cluster
1269 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001270
paul9985f832005-02-09 15:51:56 +00001271 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001272
1273 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1274
1275 return 0;
1276}
1277
1278/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001279int
paul718e3742002-12-13 20:15:29 +00001280bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1281 struct bgp_nlri *mp_update)
1282{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001283 afi_t afi;
1284 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001285 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001286 size_t start;
paul718e3742002-12-13 20:15:29 +00001287 int ret;
1288 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001289 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001290
1291 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001292 s = BGP_INPUT(peer);
1293 start = stream_get_getp(s);
1294
1295 /* safe to read statically sized header? */
1296#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001297#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001298 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001299 {
1300 zlog_info ("%s: %s sent invalid length, %lu",
1301 __func__, peer->host, (unsigned long)length);
1302 return -1;
1303 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001304
paul718e3742002-12-13 20:15:29 +00001305 /* Load AFI, SAFI. */
1306 afi = stream_getw (s);
1307 safi = stream_getc (s);
1308
1309 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001310 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001311
Paul Jakma03292802008-06-07 20:37:10 +00001312 if (LEN_LEFT < attre->mp_nexthop_len)
1313 {
1314 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1315 __func__, peer->host, attre->mp_nexthop_len);
1316 return -1;
1317 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001318
paul718e3742002-12-13 20:15:29 +00001319 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001320 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001321 {
1322 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001323 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001324 /* Probably needed for RFC 2283 */
1325 if (attr->nexthop.s_addr == 0)
1326 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001327 break;
1328 case 12:
1329 {
1330 u_int32_t rd_high;
1331 u_int32_t rd_low;
1332
1333 rd_high = stream_getl (s);
1334 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001335 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001336 }
1337 break;
1338#ifdef HAVE_IPV6
1339 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001340 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001341 break;
1342 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001343 stream_get (&attre->mp_nexthop_global, s, 16);
1344 stream_get (&attre->mp_nexthop_local, s, 16);
1345 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001346 {
1347 char buf1[INET6_ADDRSTRLEN];
1348 char buf2[INET6_ADDRSTRLEN];
1349
1350 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001351 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 +00001352 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001353 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001354 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001355 buf2, INET6_ADDRSTRLEN));
1356
Paul Jakmafb982c22007-05-04 20:15:47 +00001357 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001358 }
1359 break;
1360#endif /* HAVE_IPV6 */
1361 default:
Paul Jakma03292802008-06-07 20:37:10 +00001362 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1363 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001364 return -1;
paul718e3742002-12-13 20:15:29 +00001365 }
1366
Paul Jakma03292802008-06-07 20:37:10 +00001367 if (!LEN_LEFT)
1368 {
1369 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1370 __func__, peer->host);
1371 return -1;
1372 }
paul718e3742002-12-13 20:15:29 +00001373
Paul Jakma6e4ab122007-04-10 19:36:48 +00001374 {
1375 u_char val;
1376 if ((val = stream_getc (s)))
1377 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1378 peer->host, val);
1379 }
1380
1381 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001382 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001383 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001384 {
1385 zlog_info ("%s: (%s) Failed to read NLRI",
1386 __func__, peer->host);
1387 return -1;
1388 }
paul718e3742002-12-13 20:15:29 +00001389
1390 if (safi != BGP_SAFI_VPNV4)
1391 {
1392 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001393 if (ret < 0)
1394 {
1395 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1396 __func__, peer->host);
1397 return -1;
1398 }
paul718e3742002-12-13 20:15:29 +00001399 }
1400
1401 mp_update->afi = afi;
1402 mp_update->safi = safi;
1403 mp_update->nlri = stream_pnt (s);
1404 mp_update->length = nlri_len;
1405
paul9985f832005-02-09 15:51:56 +00001406 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001407
1408 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001409#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001410}
1411
1412/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001413int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001414bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001415 struct bgp_nlri *mp_withdraw)
1416{
1417 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001418 afi_t afi;
1419 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001420 u_int16_t withdraw_len;
1421 int ret;
1422
1423 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001424
1425#define BGP_MP_UNREACH_MIN_SIZE 3
1426 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1427 return -1;
1428
paul718e3742002-12-13 20:15:29 +00001429 afi = stream_getw (s);
1430 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001431
1432 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001433
1434 if (safi != BGP_SAFI_VPNV4)
1435 {
1436 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1437 if (ret < 0)
1438 return -1;
1439 }
1440
1441 mp_withdraw->afi = afi;
1442 mp_withdraw->safi = safi;
1443 mp_withdraw->nlri = stream_pnt (s);
1444 mp_withdraw->length = withdraw_len;
1445
paul9985f832005-02-09 15:51:56 +00001446 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001447
1448 return 0;
1449}
1450
1451/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001452static int
paul718e3742002-12-13 20:15:29 +00001453bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1454 struct attr *attr, u_char flag)
1455{
1456 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001457 {
1458 if (attr->extra)
1459 attr->extra->ecommunity = NULL;
1460 }
paul718e3742002-12-13 20:15:29 +00001461 else
1462 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001463 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001464 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001465 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001466 }
1467 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1468
1469 return 0;
1470}
1471
1472/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001473static int
paul718e3742002-12-13 20:15:29 +00001474bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1475 u_char type, bgp_size_t length, u_char *startp)
1476{
1477 bgp_size_t total;
1478 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001479 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001480
hassof4184462005-02-01 20:13:16 +00001481 if (BGP_DEBUG (normal, NORMAL))
1482 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1483 peer->host, type, length);
1484
paul718e3742002-12-13 20:15:29 +00001485 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001486 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001487 "Unknown attribute type %d length %d is received", type, length);
1488
1489 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001490 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001491
1492 /* Adjest total length to include type and length. */
1493 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1494
1495 /* If any of the mandatory well-known attributes are not recognized,
1496 then the Error Subcode is set to Unrecognized Well-known
1497 Attribute. The Data field contains the unrecognized attribute
1498 (type, length and value). */
1499 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1500 {
1501 /* Adjust startp to do not include flag value. */
1502 bgp_notify_send_with_data (peer,
1503 BGP_NOTIFY_UPDATE_ERR,
1504 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1505 startp, total);
1506 return -1;
1507 }
1508
1509 /* Unrecognized non-transitive optional attributes must be quietly
1510 ignored and not passed along to other BGP peers. */
1511 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1512 return 0;
1513
1514 /* If a path with recognized transitive optional attribute is
1515 accepted and passed along to other BGP peers and the Partial bit
1516 in the Attribute Flags octet is set to 1 by some previous AS, it
1517 is not set back to 0 by the current AS. */
1518 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1519
1520 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001521 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001522 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001523
Paul Jakmafb982c22007-05-04 20:15:47 +00001524 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001525
1526 if (transit->val)
1527 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1528 transit->length + total);
1529 else
1530 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1531
1532 memcpy (transit->val + transit->length, startp, total);
1533 transit->length += total;
1534
1535 return 0;
1536}
1537
1538/* Read attribute of update packet. This function is called from
1539 bgp_update() in bgpd.c. */
1540int
1541bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1542 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1543{
1544 int ret;
1545 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001546 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001547 bgp_size_t length;
1548 u_char *startp, *endp;
1549 u_char *attr_endp;
1550 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001551 /* we need the as4_path only until we have synthesized the as_path with it */
1552 /* same goes for as4_aggregator */
1553 struct aspath *as4_path = NULL;
1554 as_t as4_aggregator = 0;
1555 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001556
1557 /* Initialize bitmap. */
1558 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1559
1560 /* End pointer of BGP attribute. */
1561 endp = BGP_INPUT_PNT (peer) + size;
1562
1563 /* Get attributes to the end of attribute length. */
1564 while (BGP_INPUT_PNT (peer) < endp)
1565 {
1566 /* Check remaining length check.*/
1567 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1568 {
gdtc29fdba2004-12-09 14:46:46 +00001569 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001570 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001571 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001572 peer->host,
1573 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001574
1575 bgp_notify_send (peer,
1576 BGP_NOTIFY_UPDATE_ERR,
1577 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1578 return -1;
1579 }
1580
1581 /* Fetch attribute flag and type. */
1582 startp = BGP_INPUT_PNT (peer);
1583 flag = stream_getc (BGP_INPUT (peer));
1584 type = stream_getc (BGP_INPUT (peer));
1585
Paul Jakma370b64a2007-12-22 16:49:52 +00001586 /* Check whether Extended-Length applies and is in bounds */
1587 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1588 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1589 {
1590 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001591 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001592 peer->host,
1593 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1594
1595 bgp_notify_send (peer,
1596 BGP_NOTIFY_UPDATE_ERR,
1597 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1598 return -1;
1599 }
1600
paul718e3742002-12-13 20:15:29 +00001601 /* Check extended attribue length bit. */
1602 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1603 length = stream_getw (BGP_INPUT (peer));
1604 else
1605 length = stream_getc (BGP_INPUT (peer));
1606
1607 /* If any attribute appears more than once in the UPDATE
1608 message, then the Error Subcode is set to Malformed Attribute
1609 List. */
1610
1611 if (CHECK_BITMAP (seen, type))
1612 {
1613 zlog (peer->log, LOG_WARNING,
1614 "%s error BGP attribute type %d appears twice in a message",
1615 peer->host, type);
1616
1617 bgp_notify_send (peer,
1618 BGP_NOTIFY_UPDATE_ERR,
1619 BGP_NOTIFY_UPDATE_MAL_ATTR);
1620 return -1;
1621 }
1622
1623 /* Set type to bitmap to check duplicate attribute. `type' is
1624 unsigned char so it never overflow bitmap range. */
1625
1626 SET_BITMAP (seen, type);
1627
1628 /* Overflow check. */
1629 attr_endp = BGP_INPUT_PNT (peer) + length;
1630
1631 if (attr_endp > endp)
1632 {
1633 zlog (peer->log, LOG_WARNING,
1634 "%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);
1635 bgp_notify_send (peer,
1636 BGP_NOTIFY_UPDATE_ERR,
1637 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1638 return -1;
1639 }
1640
1641 /* OK check attribute and store it's value. */
1642 switch (type)
1643 {
1644 case BGP_ATTR_ORIGIN:
1645 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1646 break;
1647 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001648 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1649 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001650 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001651 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001652 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1653 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001654 break;
paul718e3742002-12-13 20:15:29 +00001655 case BGP_ATTR_NEXT_HOP:
1656 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1657 break;
1658 case BGP_ATTR_MULTI_EXIT_DISC:
1659 ret = bgp_attr_med (peer, length, attr, flag, startp);
1660 break;
1661 case BGP_ATTR_LOCAL_PREF:
1662 ret = bgp_attr_local_pref (peer, length, attr, flag);
1663 break;
1664 case BGP_ATTR_ATOMIC_AGGREGATE:
1665 ret = bgp_attr_atomic (peer, length, attr, flag);
1666 break;
1667 case BGP_ATTR_AGGREGATOR:
1668 ret = bgp_attr_aggregator (peer, length, attr, flag);
1669 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001670 case BGP_ATTR_AS4_AGGREGATOR:
1671 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1672 break;
paul718e3742002-12-13 20:15:29 +00001673 case BGP_ATTR_COMMUNITIES:
1674 ret = bgp_attr_community (peer, length, attr, flag);
1675 break;
1676 case BGP_ATTR_ORIGINATOR_ID:
1677 ret = bgp_attr_originator_id (peer, length, attr, flag);
1678 break;
1679 case BGP_ATTR_CLUSTER_LIST:
1680 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1681 break;
1682 case BGP_ATTR_MP_REACH_NLRI:
1683 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1684 break;
1685 case BGP_ATTR_MP_UNREACH_NLRI:
1686 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1687 break;
1688 case BGP_ATTR_EXT_COMMUNITIES:
1689 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1690 break;
Paul Jakma41367172007-08-06 15:24:51 +00001691 case BGP_ATTR_AS_PATHLIMIT:
1692 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1693 break;
paul718e3742002-12-13 20:15:29 +00001694 default:
1695 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1696 break;
1697 }
1698
1699 /* If error occured immediately return to the caller. */
1700 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001701 {
1702 zlog (peer->log, LOG_WARNING,
1703 "%s: Attribute %s, parse error",
1704 peer->host,
1705 LOOKUP (attr_str, type));
1706 bgp_notify_send (peer,
1707 BGP_NOTIFY_UPDATE_ERR,
1708 BGP_NOTIFY_UPDATE_MAL_ATTR);
1709 return ret;
1710 }
paul718e3742002-12-13 20:15:29 +00001711
1712 /* Check the fetched length. */
1713 if (BGP_INPUT_PNT (peer) != attr_endp)
1714 {
1715 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001716 "%s: BGP attribute %s, fetch error",
1717 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001718 bgp_notify_send (peer,
1719 BGP_NOTIFY_UPDATE_ERR,
1720 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1721 return -1;
1722 }
1723 }
1724
1725 /* Check final read pointer is same as end pointer. */
1726 if (BGP_INPUT_PNT (peer) != endp)
1727 {
1728 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001729 "%s BGP attribute %s, length mismatch",
1730 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001731 bgp_notify_send (peer,
1732 BGP_NOTIFY_UPDATE_ERR,
1733 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1734 return -1;
1735 }
1736
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001737 /*
1738 * At this place we can see whether we got AS4_PATH and/or
1739 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1740 * We can not do this before we've read all attributes because
1741 * the as4 handling does not say whether AS4_PATH has to be sent
1742 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1743 * in relationship to AGGREGATOR.
1744 * So, to be defensive, we are not relying on any order and read
1745 * all attributes first, including these 32bit ones, and now,
1746 * afterwards, we look what and if something is to be done for as4.
1747 */
1748 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1749 as4_aggregator, &as4_aggregator_addr))
1750 return -1;
1751
1752 /* At this stage, we have done all fiddling with as4, and the
1753 * resulting info is in attr->aggregator resp. attr->aspath
1754 * so we can chuck as4_aggregator and as4_path alltogether in
1755 * order to save memory
1756 */
1757 if ( as4_path )
1758 {
1759 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1760 as4_path = NULL;
1761 /* The flag that we got this is still there, but that does not
1762 * do any trouble
1763 */
1764 }
1765 /*
1766 * The "rest" of the code does nothing with as4_aggregator.
1767 * there is no memory attached specifically which is not part
1768 * of the attr.
1769 * so ignoring just means do nothing.
1770 */
1771 /*
1772 * Finally do the checks on the aspath we did not do yet
1773 * because we waited for a potentially synthesized aspath.
1774 */
1775 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1776 {
1777 ret = bgp_attr_aspath_check( peer, attr );
1778 if ( ret < 0 )
1779 return ret;
1780 }
1781
paul718e3742002-12-13 20:15:29 +00001782 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001783 if (attr->extra && attr->extra->transit)
1784 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001785
1786 return 0;
1787}
1788
1789/* Well-known attribute check. */
1790int
1791bgp_attr_check (struct peer *peer, struct attr *attr)
1792{
1793 u_char type = 0;
1794
1795 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1796 type = BGP_ATTR_ORIGIN;
1797
1798 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1799 type = BGP_ATTR_AS_PATH;
1800
1801 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1802 type = BGP_ATTR_NEXT_HOP;
1803
1804 if (peer_sort (peer) == BGP_PEER_IBGP
1805 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1806 type = BGP_ATTR_LOCAL_PREF;
1807
1808 if (type)
1809 {
1810 zlog (peer->log, LOG_WARNING,
1811 "%s Missing well-known attribute %d.",
1812 peer->host, type);
1813 bgp_notify_send_with_data (peer,
1814 BGP_NOTIFY_UPDATE_ERR,
1815 BGP_NOTIFY_UPDATE_MISS_ATTR,
1816 &type, 1);
1817 return -1;
1818 }
1819 return 0;
1820}
1821
1822int stream_put_prefix (struct stream *, struct prefix *);
1823
1824/* Make attribute packet. */
1825bgp_size_t
1826bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1827 struct stream *s, struct attr *attr, struct prefix *p,
1828 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001829 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001830{
paulfe69a502005-09-10 16:55:02 +00001831 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001832 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001833 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001834 int send_as4_path = 0;
1835 int send_as4_aggregator = 0;
1836 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001837
1838 if (! bgp)
1839 bgp = bgp_get_default ();
1840
1841 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001842 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001843
1844 /* Origin attribute. */
1845 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1846 stream_putc (s, BGP_ATTR_ORIGIN);
1847 stream_putc (s, 1);
1848 stream_putc (s, attr->origin);
1849
1850 /* AS path attribute. */
1851
1852 /* If remote-peer is EBGP */
1853 if (peer_sort (peer) == BGP_PEER_EBGP
1854 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001855 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001856 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001857 {
1858 aspath = aspath_dup (attr->aspath);
1859
1860 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1861 {
1862 /* Strip the confed info, and then stuff our path CONFED_ID
1863 on the front */
1864 aspath = aspath_delete_confed_seq (aspath);
1865 aspath = aspath_add_seq (aspath, bgp->confed_id);
1866 }
1867 else
1868 {
1869 aspath = aspath_add_seq (aspath, peer->local_as);
1870 if (peer->change_local_as)
1871 aspath = aspath_add_seq (aspath, peer->change_local_as);
1872 }
1873 }
1874 else if (peer_sort (peer) == BGP_PEER_CONFED)
1875 {
1876 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1877 aspath = aspath_dup (attr->aspath);
1878 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1879 }
1880 else
1881 aspath = attr->aspath;
1882
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001883 /* If peer is not AS4 capable, then:
1884 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1885 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1886 * types are in it (i.e. exclude them if they are there)
1887 * AND do this only if there is at least one asnum > 65535 in the path!
1888 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1889 * all ASnums > 65535 to BGP_AS_TRANS
1890 */
paul718e3742002-12-13 20:15:29 +00001891
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001892 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1893 stream_putc (s, BGP_ATTR_AS_PATH);
1894 aspath_sizep = stream_get_endp (s);
1895 stream_putw (s, 0);
1896 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1897
1898 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1899 * in the path
1900 */
1901 if (!use32bit && aspath_has_as4 (aspath))
1902 send_as4_path = 1; /* we'll do this later, at the correct place */
1903
paul718e3742002-12-13 20:15:29 +00001904 /* Nexthop attribute. */
1905 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1906 {
1907 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1908 stream_putc (s, BGP_ATTR_NEXT_HOP);
1909 stream_putc (s, 4);
1910 if (safi == SAFI_MPLS_VPN)
1911 {
1912 if (attr->nexthop.s_addr == 0)
1913 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1914 else
1915 stream_put_ipv4 (s, attr->nexthop.s_addr);
1916 }
1917 else
1918 stream_put_ipv4 (s, attr->nexthop.s_addr);
1919 }
1920
1921 /* MED attribute. */
1922 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1923 {
1924 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1925 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1926 stream_putc (s, 4);
1927 stream_putl (s, attr->med);
1928 }
1929
1930 /* Local preference. */
1931 if (peer_sort (peer) == BGP_PEER_IBGP ||
1932 peer_sort (peer) == BGP_PEER_CONFED)
1933 {
1934 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1935 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1936 stream_putc (s, 4);
1937 stream_putl (s, attr->local_pref);
1938 }
1939
1940 /* Atomic aggregate. */
1941 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1942 {
1943 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1944 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1945 stream_putc (s, 0);
1946 }
1947
1948 /* Aggregator. */
1949 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1950 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001951 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001952
1953 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001954 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1955 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001956
1957 if (use32bit)
1958 {
1959 /* AS4 capable peer */
1960 stream_putc (s, 8);
1961 stream_putl (s, attr->extra->aggregator_as);
1962 }
1963 else
1964 {
1965 /* 2-byte AS peer */
1966 stream_putc (s, 6);
1967
1968 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1969 if ( attr->extra->aggregator_as > 65535 )
1970 {
1971 stream_putw (s, BGP_AS_TRANS);
1972
1973 /* we have to send AS4_AGGREGATOR, too.
1974 * we'll do that later in order to send attributes in ascending
1975 * order.
1976 */
1977 send_as4_aggregator = 1;
1978 }
1979 else
1980 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1981 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001982 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001983 }
1984
1985 /* Community attribute. */
1986 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1987 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1988 {
1989 if (attr->community->size * 4 > 255)
1990 {
1991 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1992 stream_putc (s, BGP_ATTR_COMMUNITIES);
1993 stream_putw (s, attr->community->size * 4);
1994 }
1995 else
1996 {
1997 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1998 stream_putc (s, BGP_ATTR_COMMUNITIES);
1999 stream_putc (s, attr->community->size * 4);
2000 }
2001 stream_put (s, attr->community->val, attr->community->size * 4);
2002 }
2003
2004 /* Route Reflector. */
2005 if (peer_sort (peer) == BGP_PEER_IBGP
2006 && from
2007 && peer_sort (from) == BGP_PEER_IBGP)
2008 {
2009 /* Originator ID. */
2010 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2011 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2012 stream_putc (s, 4);
2013
2014 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002015 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002016 else
2017 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002018
2019 /* Cluster list. */
2020 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2021 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2022
Paul Jakma9eda90c2007-08-30 13:36:17 +00002023 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002024 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002025 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002026 /* If this peer configuration's parent BGP has cluster_id. */
2027 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2028 stream_put_in_addr (s, &bgp->cluster_id);
2029 else
2030 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002031 stream_put (s, attr->extra->cluster->list,
2032 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002033 }
2034 else
2035 {
2036 stream_putc (s, 4);
2037 /* If this peer configuration's parent BGP has cluster_id. */
2038 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2039 stream_put_in_addr (s, &bgp->cluster_id);
2040 else
2041 stream_put_in_addr (s, &bgp->router_id);
2042 }
2043 }
2044
2045#ifdef HAVE_IPV6
2046 /* If p is IPv6 address put it into attribute. */
2047 if (p->family == AF_INET6)
2048 {
2049 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002050 struct attr_extra *attre = attr->extra;
2051
2052 assert (attr->extra);
2053
paul718e3742002-12-13 20:15:29 +00002054 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2055 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002056 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002057 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002058 stream_putw (s, AFI_IP6); /* AFI */
2059 stream_putc (s, safi); /* SAFI */
2060
Paul Jakmafb982c22007-05-04 20:15:47 +00002061 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002062
Paul Jakmafb982c22007-05-04 20:15:47 +00002063 if (attre->mp_nexthop_len == 16)
2064 stream_put (s, &attre->mp_nexthop_global, 16);
2065 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002066 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002067 stream_put (s, &attre->mp_nexthop_global, 16);
2068 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002069 }
2070
2071 /* SNPA */
2072 stream_putc (s, 0);
2073
paul718e3742002-12-13 20:15:29 +00002074 /* Prefix write. */
2075 stream_put_prefix (s, p);
2076
2077 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002078 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002079 }
2080#endif /* HAVE_IPV6 */
2081
2082 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2083 {
2084 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002085
2086 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2087 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002088 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002089 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002090 stream_putw (s, AFI_IP); /* AFI */
2091 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2092
2093 stream_putc (s, 4);
2094 stream_put_ipv4 (s, attr->nexthop.s_addr);
2095
2096 /* SNPA */
2097 stream_putc (s, 0);
2098
paul718e3742002-12-13 20:15:29 +00002099 /* Prefix write. */
2100 stream_put_prefix (s, p);
2101
2102 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002103 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002104 }
2105
2106 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2107 {
2108 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002109
2110 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2111 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002112 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002113 stream_putc (s, 0); /* Length of this attribute. */
2114 stream_putw (s, AFI_IP); /* AFI */
2115 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2116
2117 stream_putc (s, 12);
2118 stream_putl (s, 0);
2119 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002120 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002121
2122 /* SNPA */
2123 stream_putc (s, 0);
2124
paul718e3742002-12-13 20:15:29 +00002125 /* Tag, RD, Prefix write. */
2126 stream_putc (s, p->prefixlen + 88);
2127 stream_put (s, tag, 3);
2128 stream_put (s, prd->val, 8);
2129 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2130
2131 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002132 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002133 }
2134
2135 /* Extended Communities attribute. */
2136 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2137 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2138 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002139 struct attr_extra *attre = attr->extra;
2140
2141 assert (attre);
2142
2143 if (peer_sort (peer) == BGP_PEER_IBGP
2144 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002145 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002146 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002147 {
2148 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2149 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002150 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002151 }
2152 else
2153 {
2154 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2155 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002156 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002157 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002158 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002159 }
2160 else
2161 {
paul5228ad22004-06-04 17:58:18 +00002162 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002163 int tbit;
2164 int ecom_tr_size = 0;
2165 int i;
2166
Paul Jakmafb982c22007-05-04 20:15:47 +00002167 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002168 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002169 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002170 tbit = *pnt;
2171
2172 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2173 continue;
2174
2175 ecom_tr_size++;
2176 }
2177
2178 if (ecom_tr_size)
2179 {
2180 if (ecom_tr_size * 8 > 255)
2181 {
2182 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2183 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2184 stream_putw (s, ecom_tr_size * 8);
2185 }
2186 else
2187 {
2188 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2189 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2190 stream_putc (s, ecom_tr_size * 8);
2191 }
2192
Paul Jakmafb982c22007-05-04 20:15:47 +00002193 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002194 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002195 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002196 tbit = *pnt;
2197
2198 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2199 continue;
2200
2201 stream_put (s, pnt, 8);
2202 }
2203 }
paul718e3742002-12-13 20:15:29 +00002204 }
paul718e3742002-12-13 20:15:29 +00002205 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002206
2207 if ( send_as4_path )
2208 {
2209 /* If the peer is NOT As4 capable, AND */
2210 /* there are ASnums > 65535 in path THEN
2211 * give out AS4_PATH */
2212
2213 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2214 * path segments!
2215 * Hm, I wonder... confederation things *should* only be at
2216 * the beginning of an aspath, right? Then we should use
2217 * aspath_delete_confed_seq for this, because it is already
2218 * there! (JK)
2219 * Folks, talk to me: what is reasonable here!?
2220 */
2221 aspath = aspath_delete_confed_seq (aspath);
2222
2223 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2224 stream_putc (s, BGP_ATTR_AS4_PATH);
2225 aspath_sizep = stream_get_endp (s);
2226 stream_putw (s, 0);
2227 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2228 }
2229
2230 if (aspath != attr->aspath)
2231 aspath_free (aspath);
2232
2233 if ( send_as4_aggregator )
2234 {
2235 assert (attr->extra);
2236
2237 /* send AS4_AGGREGATOR, at this place */
2238 /* this section of code moved here in order to ensure the correct
2239 * *ascending* order of attributes
2240 */
2241 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2242 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2243 stream_putc (s, 8);
2244 stream_putl (s, attr->extra->aggregator_as);
2245 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2246 }
Paul Jakma41367172007-08-06 15:24:51 +00002247
2248 /* AS-Pathlimit */
2249 if (attr->pathlimit.ttl)
2250 {
2251 u_int32_t as = attr->pathlimit.as;
2252
2253 /* should already have been done in announce_check(),
2254 * but just in case..
2255 */
2256 if (!as)
2257 as = peer->local_as;
2258
2259 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2260 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2261 stream_putc (s, 5);
2262 stream_putc (s, attr->pathlimit.ttl);
2263 stream_putl (s, as);
2264 }
2265
paul718e3742002-12-13 20:15:29 +00002266 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002267 if (attr->extra && attr->extra->transit)
2268 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002269
2270 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002271 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002272}
2273
2274bgp_size_t
2275bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2276 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002277 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002278{
2279 unsigned long cp;
2280 unsigned long attrlen_pnt;
2281 bgp_size_t size;
2282
paul9985f832005-02-09 15:51:56 +00002283 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002284
2285 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2286 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2287
paul9985f832005-02-09 15:51:56 +00002288 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002289 stream_putc (s, 0); /* Length of this attribute. */
2290
2291 stream_putw (s, family2afi (p->family));
2292
2293 if (safi == SAFI_MPLS_VPN)
2294 {
2295 /* SAFI */
2296 stream_putc (s, BGP_SAFI_VPNV4);
2297
2298 /* prefix. */
2299 stream_putc (s, p->prefixlen + 88);
2300 stream_put (s, tag, 3);
2301 stream_put (s, prd->val, 8);
2302 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2303 }
2304 else
2305 {
2306 /* SAFI */
2307 stream_putc (s, safi);
2308
2309 /* prefix */
2310 stream_put_prefix (s, p);
2311 }
2312
2313 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002314 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002315 stream_putc_at (s, attrlen_pnt, size);
2316
paul9985f832005-02-09 15:51:56 +00002317 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002318}
2319
2320/* Initialization of attribute. */
2321void
paulfe69a502005-09-10 16:55:02 +00002322bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002323{
paul718e3742002-12-13 20:15:29 +00002324 aspath_init ();
2325 attrhash_init ();
2326 community_init ();
2327 ecommunity_init ();
2328 cluster_init ();
2329 transit_init ();
2330}
2331
Chris Caputo228da422009-07-18 05:44:03 +00002332void
2333bgp_attr_finish (void)
2334{
2335 aspath_finish ();
2336 attrhash_finish ();
2337 community_finish ();
2338 ecommunity_finish ();
2339 cluster_finish ();
2340 transit_finish ();
2341}
2342
paul718e3742002-12-13 20:15:29 +00002343/* Make attribute packet. */
2344void
paula3845922003-10-18 01:30:50 +00002345bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2346 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002347{
2348 unsigned long cp;
2349 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002350 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002351 struct aspath *aspath;
2352
2353 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002354 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002355
2356 /* Place holder of length. */
2357 stream_putw (s, 0);
2358
2359 /* Origin attribute. */
2360 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2361 stream_putc (s, BGP_ATTR_ORIGIN);
2362 stream_putc (s, 1);
2363 stream_putc (s, attr->origin);
2364
2365 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002366
2367 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2368 stream_putc (s, BGP_ATTR_AS_PATH);
2369 aspath_lenp = stream_get_endp (s);
2370 stream_putw (s, 0);
2371
2372 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002373
2374 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002375 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2376 if(prefix != NULL
2377#ifdef HAVE_IPV6
2378 && prefix->family != AF_INET6
2379#endif /* HAVE_IPV6 */
2380 )
2381 {
2382 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2383 stream_putc (s, BGP_ATTR_NEXT_HOP);
2384 stream_putc (s, 4);
2385 stream_put_ipv4 (s, attr->nexthop.s_addr);
2386 }
paul718e3742002-12-13 20:15:29 +00002387
2388 /* MED attribute. */
2389 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2390 {
2391 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2392 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2393 stream_putc (s, 4);
2394 stream_putl (s, attr->med);
2395 }
2396
2397 /* Local preference. */
2398 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2399 {
2400 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2401 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2402 stream_putc (s, 4);
2403 stream_putl (s, attr->local_pref);
2404 }
2405
2406 /* Atomic aggregate. */
2407 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2408 {
2409 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2410 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2411 stream_putc (s, 0);
2412 }
2413
2414 /* Aggregator. */
2415 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2416 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002417 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002418 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2419 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002420 stream_putc (s, 8);
2421 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002422 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002423 }
2424
2425 /* Community attribute. */
2426 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2427 {
2428 if (attr->community->size * 4 > 255)
2429 {
2430 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2431 stream_putc (s, BGP_ATTR_COMMUNITIES);
2432 stream_putw (s, attr->community->size * 4);
2433 }
2434 else
2435 {
2436 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2437 stream_putc (s, BGP_ATTR_COMMUNITIES);
2438 stream_putc (s, attr->community->size * 4);
2439 }
2440 stream_put (s, attr->community->val, attr->community->size * 4);
2441 }
2442
paula3845922003-10-18 01:30:50 +00002443#ifdef HAVE_IPV6
2444 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002445 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2446 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002447 {
2448 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002449 struct attr_extra *attre = attr->extra;
2450
paula3845922003-10-18 01:30:50 +00002451 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2452 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002453 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002454
2455 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002456 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002457 stream_putw(s, AFI_IP6); /* AFI */
2458 stream_putc(s, SAFI_UNICAST); /* SAFI */
2459
2460 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002461 stream_putc(s, attre->mp_nexthop_len);
2462 stream_put(s, &attre->mp_nexthop_global, 16);
2463 if (attre->mp_nexthop_len == 32)
2464 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002465
2466 /* SNPA */
2467 stream_putc(s, 0);
2468
2469 /* Prefix */
2470 stream_put_prefix(s, prefix);
2471
2472 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002473 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002474 }
2475#endif /* HAVE_IPV6 */
2476
Paul Jakma41367172007-08-06 15:24:51 +00002477 /* AS-Pathlimit */
2478 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2479 {
2480 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2481 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2482 stream_putc (s, 5);
2483 stream_putc (s, attr->pathlimit.ttl);
2484 stream_putl (s, attr->pathlimit.as);
2485 }
2486
paul718e3742002-12-13 20:15:29 +00002487 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002488 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002489 stream_putw_at (s, cp, len);
2490}