blob: 7a0ab5607a3b605eb3d5953a5203e34ff65a2085 [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 Jakmac8f3fe32010-12-05 20:28:02 +0000347 key += attr->origin;
348 key += attr->nexthop.s_addr;
349 key += attr->med;
350 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000351
352 if (attr->extra)
353 {
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700354 MIX(attr->extra->aggregator_as);
355 MIX(attr->extra->aggregator_addr.s_addr);
356 MIX(attr->extra->weight);
357 MIX(attr->extra->mp_nexthop_global_in.s_addr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000358 }
359
paul718e3742002-12-13 20:15:29 +0000360 if (attr->aspath)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700361 MIX(aspath_key_make (attr->aspath));
paul718e3742002-12-13 20:15:29 +0000362 if (attr->community)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700363 MIX(community_hash_make (attr->community));
Paul Jakmafb982c22007-05-04 20:15:47 +0000364
365 if (attr->extra)
366 {
367 if (attr->extra->ecommunity)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700368 MIX(ecommunity_hash_make (attr->extra->ecommunity));
Paul Jakmafb982c22007-05-04 20:15:47 +0000369 if (attr->extra->cluster)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700370 MIX(cluster_hash_key_make (attr->extra->cluster));
Paul Jakmafb982c22007-05-04 20:15:47 +0000371 if (attr->extra->transit)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700372 MIX(transit_hash_key_make (attr->extra->transit));
paul718e3742002-12-13 20:15:29 +0000373
374#ifdef HAVE_IPV6
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700375 MIX(attr->extra->mp_nexthop_len);
376 key = jhash2(attr->extra->mp_nexthop_global.s6_addr32, 4, key);
377 key = jhash2(attr->extra->mp_nexthop_local.s6_addr32, 4, key);
paul718e3742002-12-13 20:15:29 +0000378#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000379 }
paul718e3742002-12-13 20:15:29 +0000380
381 return key;
382}
383
384int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100385attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000386{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100387 const struct attr * attr1 = p1;
388 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000389
paul718e3742002-12-13 20:15:29 +0000390 if (attr1->flag == attr2->flag
391 && attr1->origin == attr2->origin
392 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000393 && attr1->aspath == attr2->aspath
394 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000395 && attr1->med == attr2->med
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000396 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000397 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100398 const struct attr_extra *ae1 = attr1->extra;
399 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000400
401 if (ae1 && ae2
402 && ae1->aggregator_as == ae2->aggregator_as
403 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
404 && ae1->weight == ae2->weight
405#ifdef HAVE_IPV6
406 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
407 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
408 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
409#endif /* HAVE_IPV6 */
410 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
411 && ae1->ecommunity == ae2->ecommunity
412 && ae1->cluster == ae2->cluster
413 && ae1->transit == ae2->transit)
414 return 1;
415 else if (ae1 || ae2)
416 return 0;
417 /* neither attribute has extra attributes, so they're same */
418 return 1;
419 }
paul718e3742002-12-13 20:15:29 +0000420 else
421 return 0;
422}
423
paul94f2b392005-06-28 12:44:16 +0000424static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100425attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000426{
427 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
428}
429
paul94f2b392005-06-28 12:44:16 +0000430static void
Chris Caputo228da422009-07-18 05:44:03 +0000431attrhash_finish (void)
432{
433 hash_free (attrhash);
434 attrhash = NULL;
435}
436
437static void
paul718e3742002-12-13 20:15:29 +0000438attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
439{
440 struct attr *attr = backet->data;
441
442 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
443 inet_ntoa (attr->nexthop), VTY_NEWLINE);
444}
445
446void
447attr_show_all (struct vty *vty)
448{
449 hash_iterate (attrhash,
450 (void (*)(struct hash_backet *, void *))
451 attr_show_all_iterator,
452 vty);
453}
454
paul94f2b392005-06-28 12:44:16 +0000455static void *
Paul Jakma923de652007-04-29 18:25:17 +0000456bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000457{
Paul Jakma923de652007-04-29 18:25:17 +0000458 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000459 struct attr *attr;
460
461 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
462 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000463 if (val->extra)
464 {
465 attr->extra = bgp_attr_extra_new ();
466 *attr->extra = *val->extra;
467 }
paul718e3742002-12-13 20:15:29 +0000468 attr->refcnt = 0;
469 return attr;
470}
471
472/* Internet argument attribute. */
473struct attr *
474bgp_attr_intern (struct attr *attr)
475{
476 struct attr *find;
477
478 /* Intern referenced strucutre. */
479 if (attr->aspath)
480 {
481 if (! attr->aspath->refcnt)
482 attr->aspath = aspath_intern (attr->aspath);
483 else
484 attr->aspath->refcnt++;
485 }
486 if (attr->community)
487 {
488 if (! attr->community->refcnt)
489 attr->community = community_intern (attr->community);
490 else
491 attr->community->refcnt++;
492 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000493 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000494 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000495 struct attr_extra *attre = attr->extra;
496
497 if (attre->ecommunity)
498 {
499 if (! attre->ecommunity->refcnt)
500 attre->ecommunity = ecommunity_intern (attre->ecommunity);
501 else
502 attre->ecommunity->refcnt++;
503 }
504 if (attre->cluster)
505 {
506 if (! attre->cluster->refcnt)
507 attre->cluster = cluster_intern (attre->cluster);
508 else
509 attre->cluster->refcnt++;
510 }
511 if (attre->transit)
512 {
513 if (! attre->transit->refcnt)
514 attre->transit = transit_intern (attre->transit);
515 else
516 attre->transit->refcnt++;
517 }
paul718e3742002-12-13 20:15:29 +0000518 }
519
520 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
521 find->refcnt++;
522
523 return find;
524}
525
Paul Jakma03e214c2007-04-29 18:31:07 +0000526
paul718e3742002-12-13 20:15:29 +0000527/* Make network statement's attribute. */
528struct attr *
529bgp_attr_default_set (struct attr *attr, u_char origin)
530{
531 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000532 bgp_attr_extra_get (attr);
533
paul718e3742002-12-13 20:15:29 +0000534 attr->origin = origin;
535 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
536 attr->aspath = aspath_empty ();
537 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000538 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000539 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
540#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000541 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000542#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000543
paul718e3742002-12-13 20:15:29 +0000544 return attr;
545}
546
Paul Jakma03e214c2007-04-29 18:31:07 +0000547
paul718e3742002-12-13 20:15:29 +0000548/* Make network statement's attribute. */
549struct attr *
550bgp_attr_default_intern (u_char origin)
551{
552 struct attr attr;
553 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000554 struct attr_extra *attre;
555
556 memset (&attr, 0, sizeof (struct attr));
557 attre = bgp_attr_extra_get (&attr);
558
Paul Jakma03e214c2007-04-29 18:31:07 +0000559 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000560
561 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000562 bgp_attr_extra_free (&attr);
563
paul718e3742002-12-13 20:15:29 +0000564 aspath_unintern (new->aspath);
565 return new;
566}
567
568struct attr *
569bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
570 struct aspath *aspath,
571 struct community *community, int as_set)
572{
573 struct attr attr;
574 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000575 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000576
577 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000578 attre = bgp_attr_extra_get (&attr);
579
paul718e3742002-12-13 20:15:29 +0000580 /* Origin attribute. */
581 attr.origin = origin;
582 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
583
584 /* AS path attribute. */
585 if (aspath)
586 attr.aspath = aspath_intern (aspath);
587 else
588 attr.aspath = aspath_empty ();
589 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
590
591 /* Next hop attribute. */
592 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
593
594 if (community)
595 {
596 attr.community = community;
597 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
598 }
599
Paul Jakmafb982c22007-05-04 20:15:47 +0000600 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000601#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000602 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000603#endif
604 if (! as_set)
605 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
607 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000608 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000609 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000610 attre->aggregator_as = bgp->as;
611 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000612
613 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000614 bgp_attr_extra_free (&attr);
615
paul718e3742002-12-13 20:15:29 +0000616 aspath_unintern (new->aspath);
617 return new;
618}
619
620/* Free bgp attribute and aspath. */
621void
622bgp_attr_unintern (struct attr *attr)
623{
624 struct attr *ret;
625 struct aspath *aspath;
626 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000627 struct ecommunity *ecommunity = NULL;
628 struct cluster_list *cluster = NULL;
629 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000630
631 /* Decrement attribute reference. */
632 attr->refcnt--;
633 aspath = attr->aspath;
634 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000635 if (attr->extra)
636 {
637 ecommunity = attr->extra->ecommunity;
638 cluster = attr->extra->cluster;
639 transit = attr->extra->transit;
640 }
paul718e3742002-12-13 20:15:29 +0000641
642 /* If reference becomes zero then free attribute object. */
643 if (attr->refcnt == 0)
644 {
645 ret = hash_release (attrhash, attr);
646 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000647 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000648 XFREE (MTYPE_ATTR, attr);
649 }
650
651 /* aspath refcount shoud be decrement. */
652 if (aspath)
653 aspath_unintern (aspath);
654 if (community)
655 community_unintern (community);
656 if (ecommunity)
657 ecommunity_unintern (ecommunity);
658 if (cluster)
659 cluster_unintern (cluster);
660 if (transit)
661 transit_unintern (transit);
662}
663
664void
665bgp_attr_flush (struct attr *attr)
666{
667 if (attr->aspath && ! attr->aspath->refcnt)
668 aspath_free (attr->aspath);
669 if (attr->community && ! attr->community->refcnt)
670 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000671 if (attr->extra)
672 {
673 struct attr_extra *attre = attr->extra;
674 if (attre->ecommunity && ! attre->ecommunity->refcnt)
675 ecommunity_free (attre->ecommunity);
676 if (attre->cluster && ! attre->cluster->refcnt)
677 cluster_free (attre->cluster);
678 if (attre->transit && ! attre->transit->refcnt)
679 transit_free (attre->transit);
680 }
paul718e3742002-12-13 20:15:29 +0000681}
682
683/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000684static int
paul718e3742002-12-13 20:15:29 +0000685bgp_attr_origin (struct peer *peer, bgp_size_t length,
686 struct attr *attr, u_char flag, u_char *startp)
687{
688 bgp_size_t total;
689
690 /* total is entire attribute length include Attribute Flags (1),
691 Attribute Type code (1) and Attribute length (1 or 2). */
692 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
693
694 /* If any recognized attribute has Attribute Flags that conflict
695 with the Attribute Type Code, then the Error Subcode is set to
696 Attribute Flags Error. The Data field contains the erroneous
697 attribute (type, length and value). */
698 if (flag != BGP_ATTR_FLAG_TRANS)
699 {
700 zlog (peer->log, LOG_ERR,
701 "Origin attribute flag isn't transitive %d", flag);
702 bgp_notify_send_with_data (peer,
703 BGP_NOTIFY_UPDATE_ERR,
704 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
705 startp, total);
706 return -1;
707 }
708
709 /* If any recognized attribute has Attribute Length that conflicts
710 with the expected length (based on the attribute type code), then
711 the Error Subcode is set to Attribute Length Error. The Data
712 field contains the erroneous attribute (type, length and
713 value). */
714 if (length != 1)
715 {
716 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
717 length);
718 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
719 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
720 startp, total);
721 return -1;
722 }
723
724 /* Fetch origin attribute. */
725 attr->origin = stream_getc (BGP_INPUT (peer));
726
727 /* If the ORIGIN attribute has an undefined value, then the Error
728 Subcode is set to Invalid Origin Attribute. The Data field
729 contains the unrecognized attribute (type, length and value). */
730 if ((attr->origin != BGP_ORIGIN_IGP)
731 && (attr->origin != BGP_ORIGIN_EGP)
732 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
733 {
734 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
735 attr->origin);
736
737 bgp_notify_send_with_data (peer,
738 BGP_NOTIFY_UPDATE_ERR,
739 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
740 startp, total);
741 return -1;
742 }
743
744 /* Set oring attribute flag. */
745 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
746
747 return 0;
748}
Paul Jakmaab005292010-11-27 22:48:34 +0000749
750/* Parse AS path information. This function is wrapper of
751 aspath_parse. */
752static int
paul718e3742002-12-13 20:15:29 +0000753bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Paul Jakmaab005292010-11-27 22:48:34 +0000754 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +0000755{
Paul Jakmaab005292010-11-27 22:48:34 +0000756 bgp_size_t total;
paul718e3742002-12-13 20:15:29 +0000757
Paul Jakmaab005292010-11-27 22:48:34 +0000758 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000759
Paul Jakmaab005292010-11-27 22:48:34 +0000760 /* Flag check. */
761 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
762 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000763 {
764 zlog (peer->log, LOG_ERR,
Paul Jakmaab005292010-11-27 22:48:34 +0000765 "As-Path attribute flag isn't transitive %d", flag);
paul718e3742002-12-13 20:15:29 +0000766 bgp_notify_send_with_data (peer,
767 BGP_NOTIFY_UPDATE_ERR,
768 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
769 startp, total);
Paul Jakmaab005292010-11-27 22:48:34 +0000770 return -1;
Chris Hallcddb8112010-08-09 22:31:37 +0400771 }
Paul Jakmaab005292010-11-27 22:48:34 +0000772
773 /*
774 * peer with AS4 => will get 4Byte ASnums
775 * otherwise, will get 16 Bit
776 */
777 attr->aspath = aspath_parse (peer->ibuf, length,
778 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
779
780 /* In case of IBGP, length will be zero. */
781 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000782 {
783 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
784 bgp_notify_send (peer,
785 BGP_NOTIFY_UPDATE_ERR,
786 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Paul Jakmaab005292010-11-27 22:48:34 +0000787 return -1;
788 }
paul718e3742002-12-13 20:15:29 +0000789
Paul Jakmaab005292010-11-27 22:48:34 +0000790 /* Set aspath attribute flag. */
791 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
792
793 return 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000794}
795
796static int bgp_attr_aspath_check( struct peer *peer,
797 struct attr *attr)
798{
799 /* These checks were part of bgp_attr_aspath, but with
800 * as4 we should to check aspath things when
801 * aspath synthesizing with as4_path has already taken place.
802 * Otherwise we check ASPATH and use the synthesized thing, and that is
803 * not right.
804 * So do the checks later, i.e. here
805 */
806 struct bgp *bgp = peer->bgp;
807 struct aspath *aspath;
808
paul718e3742002-12-13 20:15:29 +0000809 bgp = peer->bgp;
810
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300811 /* Confederation sanity check. */
812 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
813 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
814 {
815 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
816 bgp_notify_send (peer,
817 BGP_NOTIFY_UPDATE_ERR,
818 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
819 return -1;
820 }
821
paul718e3742002-12-13 20:15:29 +0000822 /* First AS check for EBGP. */
823 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
824 {
825 if (peer_sort (peer) == BGP_PEER_EBGP
826 && ! aspath_firstas_check (attr->aspath, peer->as))
827 {
828 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400829 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000830 bgp_notify_send (peer,
831 BGP_NOTIFY_UPDATE_ERR,
832 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
833 return -1;
834 }
835 }
836
837 /* local-as prepend */
838 if (peer->change_local_as &&
839 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
840 {
841 aspath = aspath_dup (attr->aspath);
842 aspath = aspath_add_seq (aspath, peer->change_local_as);
843 aspath_unintern (attr->aspath);
844 attr->aspath = aspath_intern (aspath);
845 }
846
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000847 return 0;
848
849}
850
Paul Jakmaab005292010-11-27 22:48:34 +0000851/* Parse AS4 path information. This function is another wrapper of
852 aspath_parse. */
853static int
854bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
855 struct attr *attr, struct aspath **as4_path)
856{
857 *as4_path = aspath_parse (peer->ibuf, length, 1);
858
859 /* Set aspath attribute flag. */
860 if (as4_path)
861 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
862
863 return 0;
864}
865
paul718e3742002-12-13 20:15:29 +0000866/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000867static int
paul718e3742002-12-13 20:15:29 +0000868bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
869 struct attr *attr, u_char flag, u_char *startp)
870{
871 bgp_size_t total;
872
873 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
874
875 /* Flag check. */
876 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
877 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
878 {
879 zlog (peer->log, LOG_ERR,
880 "Origin attribute flag isn't transitive %d", flag);
881 bgp_notify_send_with_data (peer,
882 BGP_NOTIFY_UPDATE_ERR,
883 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
884 startp, total);
885 return -1;
886 }
887
888 /* Check nexthop attribute length. */
889 if (length != 4)
890 {
891 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
892 length);
893
894 bgp_notify_send_with_data (peer,
895 BGP_NOTIFY_UPDATE_ERR,
896 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
897 startp, total);
898 return -1;
899 }
900
901 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
902 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
903
904 return 0;
905}
906
907/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000908static int
paul718e3742002-12-13 20:15:29 +0000909bgp_attr_med (struct peer *peer, bgp_size_t length,
910 struct attr *attr, u_char flag, u_char *startp)
911{
912 bgp_size_t total;
913
914 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
915
916 /* Length check. */
917 if (length != 4)
918 {
919 zlog (peer->log, LOG_ERR,
920 "MED attribute length isn't four [%d]", length);
921
922 bgp_notify_send_with_data (peer,
923 BGP_NOTIFY_UPDATE_ERR,
924 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
925 startp, total);
926 return -1;
927 }
928
929 attr->med = stream_getl (peer->ibuf);
930
931 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
932
933 return 0;
934}
935
936/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000937static int
paul718e3742002-12-13 20:15:29 +0000938bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
939 struct attr *attr, u_char flag)
940{
941 /* If it is contained in an UPDATE message that is received from an
942 external peer, then this attribute MUST be ignored by the
943 receiving speaker. */
944 if (peer_sort (peer) == BGP_PEER_EBGP)
945 {
paul9985f832005-02-09 15:51:56 +0000946 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000947 return 0;
948 }
949
950 if (length == 4)
951 attr->local_pref = stream_getl (peer->ibuf);
952 else
953 attr->local_pref = 0;
954
955 /* Set atomic aggregate flag. */
956 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
957
958 return 0;
959}
960
961/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000962static int
paul718e3742002-12-13 20:15:29 +0000963bgp_attr_atomic (struct peer *peer, bgp_size_t length,
964 struct attr *attr, u_char flag)
965{
966 if (length != 0)
967 {
968 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
969
970 bgp_notify_send (peer,
971 BGP_NOTIFY_UPDATE_ERR,
972 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
973 return -1;
974 }
975
976 /* Set atomic aggregate flag. */
977 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
978
979 return 0;
980}
981
982/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +0000983static int
paul718e3742002-12-13 20:15:29 +0000984bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
985 struct attr *attr, u_char flag)
986{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000987 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +0000988 struct attr_extra *attre = bgp_attr_extra_get (attr);
989
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000990 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
991 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
992 wantedlen = 8;
993
994 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +0000995 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000996 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +0000997
998 bgp_notify_send (peer,
999 BGP_NOTIFY_UPDATE_ERR,
1000 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1001 return -1;
1002 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001003
1004 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1005 attre->aggregator_as = stream_getl (peer->ibuf);
1006 else
1007 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001008 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001009
1010 /* Set atomic aggregate flag. */
1011 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1012
1013 return 0;
1014}
1015
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001016/* New Aggregator attribute */
1017static int
1018bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1019 struct attr *attr, as_t *as4_aggregator_as,
1020 struct in_addr *as4_aggregator_addr)
1021{
1022 if (length != 8)
1023 {
1024 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1025
1026 bgp_notify_send (peer,
1027 BGP_NOTIFY_UPDATE_ERR,
1028 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1029 return -1;
1030 }
1031 *as4_aggregator_as = stream_getl (peer->ibuf);
1032 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1033
1034 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1035
1036 return 0;
1037}
1038
1039/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1040 */
1041static int
1042bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1043 struct aspath *as4_path, as_t as4_aggregator,
1044 struct in_addr *as4_aggregator_addr)
1045{
1046 int ignore_as4_path = 0;
1047 struct aspath *newpath;
1048 struct attr_extra *attre = attr->extra;
1049
1050 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1051 {
1052 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1053 * if given.
1054 * It is worth a warning though, because the peer really
1055 * should not send them
1056 */
1057 if (BGP_DEBUG(as4, AS4))
1058 {
1059 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1060 zlog_debug ("[AS4] %s %s AS4_PATH",
1061 peer->host, "AS4 capable peer, yet it sent");
1062
1063 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1064 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1065 peer->host, "AS4 capable peer, yet it sent");
1066 }
1067
1068 return 0;
1069 }
1070
1071 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1072 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1073 {
1074 /* Hu? This is not supposed to happen at all!
1075 * got as4_path and no aspath,
1076 * This should already
1077 * have been handled by 'well known attributes missing'
1078 * But... yeah, paranoia
1079 * Take this as a "malformed attribute"
1080 */
1081 zlog (peer->log, LOG_ERR,
1082 "%s BGP not AS4 capable peer sent AS4_PATH but"
1083 " no AS_PATH, cant do anything here", peer->host);
1084 bgp_notify_send (peer,
1085 BGP_NOTIFY_UPDATE_ERR,
1086 BGP_NOTIFY_UPDATE_MAL_ATTR);
1087 return -1;
1088 }
1089
1090 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1091 * because that may override AS4_PATH
1092 */
1093 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1094 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001095 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1096 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001097 assert (attre);
1098
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001099 /* received both.
1100 * if the as_number in aggregator is not AS_TRANS,
1101 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1102 * and the Aggregator shall be taken as
1103 * info on the aggregating node, and the AS_PATH
1104 * shall be taken as the AS_PATH
1105 * otherwise
1106 * the Aggregator shall be ignored and the
1107 * AS4_AGGREGATOR shall be taken as the
1108 * Aggregating node and the AS_PATH is to be
1109 * constructed "as in all other cases"
1110 */
1111 if ( attre->aggregator_as != BGP_AS_TRANS )
1112 {
1113 /* ignore */
1114 if ( BGP_DEBUG(as4, AS4))
1115 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1116 " send AGGREGATOR != AS_TRANS and"
1117 " AS4_AGGREGATOR, so ignore"
1118 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1119 ignore_as4_path = 1;
1120 }
1121 else
1122 {
1123 /* "New_aggregator shall be taken as aggregator" */
1124 attre->aggregator_as = as4_aggregator;
1125 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1126 }
1127 }
1128 else
1129 {
1130 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1131 * That is bogus - but reading the conditions
1132 * we have to handle AS4_AGGREGATOR as if it were
1133 * AGGREGATOR in that case
1134 */
1135 if ( BGP_DEBUG(as4, AS4))
1136 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1137 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1138 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001139 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001140 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1141 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1142 }
1143 }
1144
1145 /* need to reconcile NEW_AS_PATH and AS_PATH */
1146 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1147 {
1148 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1149 aspath_unintern (attr->aspath);
1150 attr->aspath = aspath_intern (newpath);
1151 }
1152 return 0;
1153}
1154
paul718e3742002-12-13 20:15:29 +00001155/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001156static int
paul718e3742002-12-13 20:15:29 +00001157bgp_attr_community (struct peer *peer, bgp_size_t length,
1158 struct attr *attr, u_char flag)
1159{
1160 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001161 {
1162 attr->community = NULL;
1163 return 0;
1164 }
Paul Jakma0c466382010-12-05 17:17:26 +00001165
1166 attr->community =
1167 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1168
1169 /* XXX: fix community_parse to use stream API and remove this */
1170 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001171
Paul Jakma0c466382010-12-05 17:17:26 +00001172 if (!attr->community)
1173 return -1;
1174
paul718e3742002-12-13 20:15:29 +00001175 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1176
1177 return 0;
1178}
1179
1180/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001181static int
paul718e3742002-12-13 20:15:29 +00001182bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1183 struct attr *attr, u_char flag)
1184{
1185 if (length != 4)
1186 {
1187 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1188
1189 bgp_notify_send (peer,
1190 BGP_NOTIFY_UPDATE_ERR,
1191 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1192 return -1;
1193 }
1194
Paul Jakmafb982c22007-05-04 20:15:47 +00001195 (bgp_attr_extra_get (attr))->originator_id.s_addr
1196 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001197
1198 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1199
1200 return 0;
1201}
1202
1203/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001204static int
paul718e3742002-12-13 20:15:29 +00001205bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1206 struct attr *attr, u_char flag)
1207{
1208 /* Check length. */
1209 if (length % 4)
1210 {
1211 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1212
1213 bgp_notify_send (peer,
1214 BGP_NOTIFY_UPDATE_ERR,
1215 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1216 return -1;
1217 }
1218
Paul Jakmafb982c22007-05-04 20:15:47 +00001219 (bgp_attr_extra_get (attr))->cluster
1220 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001221
paul9985f832005-02-09 15:51:56 +00001222 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001223
1224 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1225
1226 return 0;
1227}
1228
1229/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001230int
paul718e3742002-12-13 20:15:29 +00001231bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1232 struct bgp_nlri *mp_update)
1233{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001234 afi_t afi;
1235 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001236 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001237 size_t start;
paul718e3742002-12-13 20:15:29 +00001238 int ret;
1239 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001240 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001241
1242 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001243 s = BGP_INPUT(peer);
1244 start = stream_get_getp(s);
1245
1246 /* safe to read statically sized header? */
1247#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001248#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001249 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001250 {
1251 zlog_info ("%s: %s sent invalid length, %lu",
1252 __func__, peer->host, (unsigned long)length);
1253 return -1;
1254 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001255
paul718e3742002-12-13 20:15:29 +00001256 /* Load AFI, SAFI. */
1257 afi = stream_getw (s);
1258 safi = stream_getc (s);
1259
1260 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001261 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001262
Paul Jakma03292802008-06-07 20:37:10 +00001263 if (LEN_LEFT < attre->mp_nexthop_len)
1264 {
1265 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1266 __func__, peer->host, attre->mp_nexthop_len);
1267 return -1;
1268 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001269
paul718e3742002-12-13 20:15:29 +00001270 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001271 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001272 {
1273 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001274 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001275 /* Probably needed for RFC 2283 */
1276 if (attr->nexthop.s_addr == 0)
1277 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001278 break;
1279 case 12:
1280 {
1281 u_int32_t rd_high;
1282 u_int32_t rd_low;
1283
1284 rd_high = stream_getl (s);
1285 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001286 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001287 }
1288 break;
1289#ifdef HAVE_IPV6
1290 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001291 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001292 break;
1293 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001294 stream_get (&attre->mp_nexthop_global, s, 16);
1295 stream_get (&attre->mp_nexthop_local, s, 16);
1296 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001297 {
1298 char buf1[INET6_ADDRSTRLEN];
1299 char buf2[INET6_ADDRSTRLEN];
1300
1301 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001302 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 +00001303 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001304 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001305 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001306 buf2, INET6_ADDRSTRLEN));
1307
Paul Jakmafb982c22007-05-04 20:15:47 +00001308 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001309 }
1310 break;
1311#endif /* HAVE_IPV6 */
1312 default:
Paul Jakma03292802008-06-07 20:37:10 +00001313 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1314 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001315 return -1;
paul718e3742002-12-13 20:15:29 +00001316 }
1317
Paul Jakma03292802008-06-07 20:37:10 +00001318 if (!LEN_LEFT)
1319 {
1320 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1321 __func__, peer->host);
1322 return -1;
1323 }
paul718e3742002-12-13 20:15:29 +00001324
Paul Jakma6e4ab122007-04-10 19:36:48 +00001325 {
1326 u_char val;
1327 if ((val = stream_getc (s)))
1328 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1329 peer->host, val);
1330 }
1331
1332 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001333 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001334 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001335 {
1336 zlog_info ("%s: (%s) Failed to read NLRI",
1337 __func__, peer->host);
1338 return -1;
1339 }
paul718e3742002-12-13 20:15:29 +00001340
1341 if (safi != BGP_SAFI_VPNV4)
1342 {
1343 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001344 if (ret < 0)
1345 {
1346 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1347 __func__, peer->host);
1348 return -1;
1349 }
paul718e3742002-12-13 20:15:29 +00001350 }
1351
1352 mp_update->afi = afi;
1353 mp_update->safi = safi;
1354 mp_update->nlri = stream_pnt (s);
1355 mp_update->length = nlri_len;
1356
paul9985f832005-02-09 15:51:56 +00001357 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001358
1359 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001360#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001361}
1362
1363/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001364int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001365bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001366 struct bgp_nlri *mp_withdraw)
1367{
1368 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001369 afi_t afi;
1370 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001371 u_int16_t withdraw_len;
1372 int ret;
1373
1374 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001375
1376#define BGP_MP_UNREACH_MIN_SIZE 3
1377 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1378 return -1;
1379
paul718e3742002-12-13 20:15:29 +00001380 afi = stream_getw (s);
1381 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001382
1383 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001384
1385 if (safi != BGP_SAFI_VPNV4)
1386 {
1387 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1388 if (ret < 0)
1389 return -1;
1390 }
1391
1392 mp_withdraw->afi = afi;
1393 mp_withdraw->safi = safi;
1394 mp_withdraw->nlri = stream_pnt (s);
1395 mp_withdraw->length = withdraw_len;
1396
paul9985f832005-02-09 15:51:56 +00001397 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001398
1399 return 0;
1400}
1401
1402/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001403static int
paul718e3742002-12-13 20:15:29 +00001404bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1405 struct attr *attr, u_char flag)
1406{
1407 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001408 {
1409 if (attr->extra)
1410 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001411 /* Empty extcomm doesn't seem to be invalid per se */
1412 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001413 }
Paul Jakma0c466382010-12-05 17:17:26 +00001414
1415 (bgp_attr_extra_get (attr))->ecommunity =
1416 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1417 /* XXX: fix ecommunity_parse to use stream API */
1418 stream_forward_getp (peer->ibuf, length);
1419
1420 if (!attr->extra->ecommunity)
1421 return -1;
1422
paul718e3742002-12-13 20:15:29 +00001423 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1424
1425 return 0;
1426}
1427
1428/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001429static int
paul718e3742002-12-13 20:15:29 +00001430bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1431 u_char type, bgp_size_t length, u_char *startp)
1432{
1433 bgp_size_t total;
1434 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001435 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001436
hassof4184462005-02-01 20:13:16 +00001437 if (BGP_DEBUG (normal, NORMAL))
1438 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1439 peer->host, type, length);
1440
paul718e3742002-12-13 20:15:29 +00001441 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001442 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001443 "Unknown attribute type %d length %d is received", type, length);
1444
1445 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001446 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001447
1448 /* Adjest total length to include type and length. */
1449 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1450
1451 /* If any of the mandatory well-known attributes are not recognized,
1452 then the Error Subcode is set to Unrecognized Well-known
1453 Attribute. The Data field contains the unrecognized attribute
1454 (type, length and value). */
1455 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1456 {
1457 /* Adjust startp to do not include flag value. */
1458 bgp_notify_send_with_data (peer,
1459 BGP_NOTIFY_UPDATE_ERR,
1460 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1461 startp, total);
1462 return -1;
1463 }
1464
1465 /* Unrecognized non-transitive optional attributes must be quietly
1466 ignored and not passed along to other BGP peers. */
1467 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1468 return 0;
1469
1470 /* If a path with recognized transitive optional attribute is
1471 accepted and passed along to other BGP peers and the Partial bit
1472 in the Attribute Flags octet is set to 1 by some previous AS, it
1473 is not set back to 0 by the current AS. */
1474 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1475
1476 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001477 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001478 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001479
Paul Jakmafb982c22007-05-04 20:15:47 +00001480 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001481
1482 if (transit->val)
1483 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1484 transit->length + total);
1485 else
1486 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1487
1488 memcpy (transit->val + transit->length, startp, total);
1489 transit->length += total;
1490
1491 return 0;
1492}
1493
1494/* Read attribute of update packet. This function is called from
1495 bgp_update() in bgpd.c. */
1496int
1497bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1498 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1499{
1500 int ret;
1501 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001502 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001503 bgp_size_t length;
1504 u_char *startp, *endp;
1505 u_char *attr_endp;
1506 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001507 /* we need the as4_path only until we have synthesized the as_path with it */
1508 /* same goes for as4_aggregator */
1509 struct aspath *as4_path = NULL;
1510 as_t as4_aggregator = 0;
1511 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001512
1513 /* Initialize bitmap. */
1514 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1515
1516 /* End pointer of BGP attribute. */
1517 endp = BGP_INPUT_PNT (peer) + size;
1518
1519 /* Get attributes to the end of attribute length. */
1520 while (BGP_INPUT_PNT (peer) < endp)
1521 {
1522 /* Check remaining length check.*/
1523 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1524 {
gdtc29fdba2004-12-09 14:46:46 +00001525 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001526 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001527 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001528 peer->host,
1529 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001530
1531 bgp_notify_send (peer,
1532 BGP_NOTIFY_UPDATE_ERR,
1533 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1534 return -1;
1535 }
1536
1537 /* Fetch attribute flag and type. */
1538 startp = BGP_INPUT_PNT (peer);
1539 flag = stream_getc (BGP_INPUT (peer));
1540 type = stream_getc (BGP_INPUT (peer));
1541
Paul Jakma370b64a2007-12-22 16:49:52 +00001542 /* Check whether Extended-Length applies and is in bounds */
1543 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1544 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1545 {
1546 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001547 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001548 peer->host,
1549 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1550
1551 bgp_notify_send (peer,
1552 BGP_NOTIFY_UPDATE_ERR,
1553 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1554 return -1;
1555 }
1556
paul718e3742002-12-13 20:15:29 +00001557 /* Check extended attribue length bit. */
1558 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1559 length = stream_getw (BGP_INPUT (peer));
1560 else
1561 length = stream_getc (BGP_INPUT (peer));
1562
1563 /* If any attribute appears more than once in the UPDATE
1564 message, then the Error Subcode is set to Malformed Attribute
1565 List. */
1566
1567 if (CHECK_BITMAP (seen, type))
1568 {
1569 zlog (peer->log, LOG_WARNING,
1570 "%s error BGP attribute type %d appears twice in a message",
1571 peer->host, type);
1572
1573 bgp_notify_send (peer,
1574 BGP_NOTIFY_UPDATE_ERR,
1575 BGP_NOTIFY_UPDATE_MAL_ATTR);
1576 return -1;
1577 }
1578
1579 /* Set type to bitmap to check duplicate attribute. `type' is
1580 unsigned char so it never overflow bitmap range. */
1581
1582 SET_BITMAP (seen, type);
1583
1584 /* Overflow check. */
1585 attr_endp = BGP_INPUT_PNT (peer) + length;
1586
1587 if (attr_endp > endp)
1588 {
1589 zlog (peer->log, LOG_WARNING,
1590 "%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);
1591 bgp_notify_send (peer,
1592 BGP_NOTIFY_UPDATE_ERR,
1593 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1594 return -1;
1595 }
1596
1597 /* OK check attribute and store it's value. */
1598 switch (type)
1599 {
1600 case BGP_ATTR_ORIGIN:
1601 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1602 break;
1603 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001604 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001605 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001606 case BGP_ATTR_AS4_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001607 ret = bgp_attr_as4_path (peer, length, attr, &as4_path );
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001608 break;
paul718e3742002-12-13 20:15:29 +00001609 case BGP_ATTR_NEXT_HOP:
1610 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1611 break;
1612 case BGP_ATTR_MULTI_EXIT_DISC:
1613 ret = bgp_attr_med (peer, length, attr, flag, startp);
1614 break;
1615 case BGP_ATTR_LOCAL_PREF:
1616 ret = bgp_attr_local_pref (peer, length, attr, flag);
1617 break;
1618 case BGP_ATTR_ATOMIC_AGGREGATE:
1619 ret = bgp_attr_atomic (peer, length, attr, flag);
1620 break;
1621 case BGP_ATTR_AGGREGATOR:
1622 ret = bgp_attr_aggregator (peer, length, attr, flag);
1623 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001624 case BGP_ATTR_AS4_AGGREGATOR:
1625 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1626 break;
paul718e3742002-12-13 20:15:29 +00001627 case BGP_ATTR_COMMUNITIES:
1628 ret = bgp_attr_community (peer, length, attr, flag);
1629 break;
1630 case BGP_ATTR_ORIGINATOR_ID:
1631 ret = bgp_attr_originator_id (peer, length, attr, flag);
1632 break;
1633 case BGP_ATTR_CLUSTER_LIST:
1634 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1635 break;
1636 case BGP_ATTR_MP_REACH_NLRI:
1637 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1638 break;
1639 case BGP_ATTR_MP_UNREACH_NLRI:
1640 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1641 break;
1642 case BGP_ATTR_EXT_COMMUNITIES:
1643 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1644 break;
1645 default:
1646 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1647 break;
1648 }
1649
1650 /* If error occured immediately return to the caller. */
1651 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001652 {
1653 zlog (peer->log, LOG_WARNING,
1654 "%s: Attribute %s, parse error",
1655 peer->host,
1656 LOOKUP (attr_str, type));
1657 bgp_notify_send (peer,
1658 BGP_NOTIFY_UPDATE_ERR,
1659 BGP_NOTIFY_UPDATE_MAL_ATTR);
1660 return ret;
1661 }
paul718e3742002-12-13 20:15:29 +00001662
1663 /* Check the fetched length. */
1664 if (BGP_INPUT_PNT (peer) != attr_endp)
1665 {
1666 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001667 "%s: BGP attribute %s, fetch error",
1668 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001669 bgp_notify_send (peer,
1670 BGP_NOTIFY_UPDATE_ERR,
1671 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1672 return -1;
1673 }
1674 }
1675
1676 /* Check final read pointer is same as end pointer. */
1677 if (BGP_INPUT_PNT (peer) != endp)
1678 {
1679 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001680 "%s BGP attribute %s, length mismatch",
1681 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001682 bgp_notify_send (peer,
1683 BGP_NOTIFY_UPDATE_ERR,
1684 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1685 return -1;
1686 }
1687
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001688 /*
1689 * At this place we can see whether we got AS4_PATH and/or
1690 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1691 * We can not do this before we've read all attributes because
1692 * the as4 handling does not say whether AS4_PATH has to be sent
1693 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1694 * in relationship to AGGREGATOR.
1695 * So, to be defensive, we are not relying on any order and read
1696 * all attributes first, including these 32bit ones, and now,
1697 * afterwards, we look what and if something is to be done for as4.
1698 */
1699 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1700 as4_aggregator, &as4_aggregator_addr))
1701 return -1;
1702
1703 /* At this stage, we have done all fiddling with as4, and the
1704 * resulting info is in attr->aggregator resp. attr->aspath
1705 * so we can chuck as4_aggregator and as4_path alltogether in
1706 * order to save memory
1707 */
1708 if ( as4_path )
1709 {
1710 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1711 as4_path = NULL;
1712 /* The flag that we got this is still there, but that does not
1713 * do any trouble
1714 */
1715 }
1716 /*
1717 * The "rest" of the code does nothing with as4_aggregator.
1718 * there is no memory attached specifically which is not part
1719 * of the attr.
1720 * so ignoring just means do nothing.
1721 */
1722 /*
1723 * Finally do the checks on the aspath we did not do yet
1724 * because we waited for a potentially synthesized aspath.
1725 */
1726 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1727 {
1728 ret = bgp_attr_aspath_check( peer, attr );
1729 if ( ret < 0 )
1730 return ret;
1731 }
1732
paul718e3742002-12-13 20:15:29 +00001733 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001734 if (attr->extra && attr->extra->transit)
1735 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001736
1737 return 0;
1738}
1739
1740/* Well-known attribute check. */
1741int
1742bgp_attr_check (struct peer *peer, struct attr *attr)
1743{
1744 u_char type = 0;
1745
1746 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1747 type = BGP_ATTR_ORIGIN;
1748
1749 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1750 type = BGP_ATTR_AS_PATH;
1751
1752 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1753 type = BGP_ATTR_NEXT_HOP;
1754
1755 if (peer_sort (peer) == BGP_PEER_IBGP
1756 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1757 type = BGP_ATTR_LOCAL_PREF;
1758
1759 if (type)
1760 {
1761 zlog (peer->log, LOG_WARNING,
1762 "%s Missing well-known attribute %d.",
1763 peer->host, type);
1764 bgp_notify_send_with_data (peer,
1765 BGP_NOTIFY_UPDATE_ERR,
1766 BGP_NOTIFY_UPDATE_MISS_ATTR,
1767 &type, 1);
1768 return -1;
1769 }
1770 return 0;
1771}
1772
1773int stream_put_prefix (struct stream *, struct prefix *);
1774
1775/* Make attribute packet. */
1776bgp_size_t
1777bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1778 struct stream *s, struct attr *attr, struct prefix *p,
1779 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001780 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001781{
paulfe69a502005-09-10 16:55:02 +00001782 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001783 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001784 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001785 int send_as4_path = 0;
1786 int send_as4_aggregator = 0;
1787 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001788
1789 if (! bgp)
1790 bgp = bgp_get_default ();
1791
1792 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001793 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001794
1795 /* Origin attribute. */
1796 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1797 stream_putc (s, BGP_ATTR_ORIGIN);
1798 stream_putc (s, 1);
1799 stream_putc (s, attr->origin);
1800
1801 /* AS path attribute. */
1802
1803 /* If remote-peer is EBGP */
1804 if (peer_sort (peer) == BGP_PEER_EBGP
1805 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001806 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001807 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001808 {
1809 aspath = aspath_dup (attr->aspath);
1810
1811 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1812 {
1813 /* Strip the confed info, and then stuff our path CONFED_ID
1814 on the front */
1815 aspath = aspath_delete_confed_seq (aspath);
1816 aspath = aspath_add_seq (aspath, bgp->confed_id);
1817 }
1818 else
1819 {
1820 aspath = aspath_add_seq (aspath, peer->local_as);
1821 if (peer->change_local_as)
1822 aspath = aspath_add_seq (aspath, peer->change_local_as);
1823 }
1824 }
1825 else if (peer_sort (peer) == BGP_PEER_CONFED)
1826 {
1827 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1828 aspath = aspath_dup (attr->aspath);
1829 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1830 }
1831 else
1832 aspath = attr->aspath;
1833
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001834 /* If peer is not AS4 capable, then:
1835 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1836 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1837 * types are in it (i.e. exclude them if they are there)
1838 * AND do this only if there is at least one asnum > 65535 in the path!
1839 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1840 * all ASnums > 65535 to BGP_AS_TRANS
1841 */
paul718e3742002-12-13 20:15:29 +00001842
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001843 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1844 stream_putc (s, BGP_ATTR_AS_PATH);
1845 aspath_sizep = stream_get_endp (s);
1846 stream_putw (s, 0);
1847 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1848
1849 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1850 * in the path
1851 */
1852 if (!use32bit && aspath_has_as4 (aspath))
1853 send_as4_path = 1; /* we'll do this later, at the correct place */
1854
paul718e3742002-12-13 20:15:29 +00001855 /* Nexthop attribute. */
1856 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1857 {
1858 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1859 stream_putc (s, BGP_ATTR_NEXT_HOP);
1860 stream_putc (s, 4);
1861 if (safi == SAFI_MPLS_VPN)
1862 {
1863 if (attr->nexthop.s_addr == 0)
1864 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1865 else
1866 stream_put_ipv4 (s, attr->nexthop.s_addr);
1867 }
1868 else
1869 stream_put_ipv4 (s, attr->nexthop.s_addr);
1870 }
1871
1872 /* MED attribute. */
1873 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1874 {
1875 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1876 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1877 stream_putc (s, 4);
1878 stream_putl (s, attr->med);
1879 }
1880
1881 /* Local preference. */
1882 if (peer_sort (peer) == BGP_PEER_IBGP ||
1883 peer_sort (peer) == BGP_PEER_CONFED)
1884 {
1885 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1886 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1887 stream_putc (s, 4);
1888 stream_putl (s, attr->local_pref);
1889 }
1890
1891 /* Atomic aggregate. */
1892 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1893 {
1894 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1895 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1896 stream_putc (s, 0);
1897 }
1898
1899 /* Aggregator. */
1900 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1901 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001902 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001903
1904 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001905 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1906 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001907
1908 if (use32bit)
1909 {
1910 /* AS4 capable peer */
1911 stream_putc (s, 8);
1912 stream_putl (s, attr->extra->aggregator_as);
1913 }
1914 else
1915 {
1916 /* 2-byte AS peer */
1917 stream_putc (s, 6);
1918
1919 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1920 if ( attr->extra->aggregator_as > 65535 )
1921 {
1922 stream_putw (s, BGP_AS_TRANS);
1923
1924 /* we have to send AS4_AGGREGATOR, too.
1925 * we'll do that later in order to send attributes in ascending
1926 * order.
1927 */
1928 send_as4_aggregator = 1;
1929 }
1930 else
1931 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1932 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001933 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001934 }
1935
1936 /* Community attribute. */
1937 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1938 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1939 {
1940 if (attr->community->size * 4 > 255)
1941 {
1942 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1943 stream_putc (s, BGP_ATTR_COMMUNITIES);
1944 stream_putw (s, attr->community->size * 4);
1945 }
1946 else
1947 {
1948 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1949 stream_putc (s, BGP_ATTR_COMMUNITIES);
1950 stream_putc (s, attr->community->size * 4);
1951 }
1952 stream_put (s, attr->community->val, attr->community->size * 4);
1953 }
1954
1955 /* Route Reflector. */
1956 if (peer_sort (peer) == BGP_PEER_IBGP
1957 && from
1958 && peer_sort (from) == BGP_PEER_IBGP)
1959 {
1960 /* Originator ID. */
1961 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1962 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1963 stream_putc (s, 4);
1964
1965 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00001966 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001967 else
1968 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001969
1970 /* Cluster list. */
1971 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1972 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1973
Paul Jakma9eda90c2007-08-30 13:36:17 +00001974 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00001975 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001976 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00001977 /* If this peer configuration's parent BGP has cluster_id. */
1978 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1979 stream_put_in_addr (s, &bgp->cluster_id);
1980 else
1981 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00001982 stream_put (s, attr->extra->cluster->list,
1983 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00001984 }
1985 else
1986 {
1987 stream_putc (s, 4);
1988 /* If this peer configuration's parent BGP has cluster_id. */
1989 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1990 stream_put_in_addr (s, &bgp->cluster_id);
1991 else
1992 stream_put_in_addr (s, &bgp->router_id);
1993 }
1994 }
1995
1996#ifdef HAVE_IPV6
1997 /* If p is IPv6 address put it into attribute. */
1998 if (p->family == AF_INET6)
1999 {
2000 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002001 struct attr_extra *attre = attr->extra;
2002
2003 assert (attr->extra);
2004
paul718e3742002-12-13 20:15:29 +00002005 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2006 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002007 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002008 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002009 stream_putw (s, AFI_IP6); /* AFI */
2010 stream_putc (s, safi); /* SAFI */
2011
Paul Jakmafb982c22007-05-04 20:15:47 +00002012 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002013
Paul Jakmafb982c22007-05-04 20:15:47 +00002014 if (attre->mp_nexthop_len == 16)
2015 stream_put (s, &attre->mp_nexthop_global, 16);
2016 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002017 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002018 stream_put (s, &attre->mp_nexthop_global, 16);
2019 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002020 }
2021
2022 /* SNPA */
2023 stream_putc (s, 0);
2024
paul718e3742002-12-13 20:15:29 +00002025 /* Prefix write. */
2026 stream_put_prefix (s, p);
2027
2028 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002029 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002030 }
2031#endif /* HAVE_IPV6 */
2032
2033 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2034 {
2035 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002036
2037 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2038 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002039 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002040 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002041 stream_putw (s, AFI_IP); /* AFI */
2042 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2043
2044 stream_putc (s, 4);
2045 stream_put_ipv4 (s, attr->nexthop.s_addr);
2046
2047 /* SNPA */
2048 stream_putc (s, 0);
2049
paul718e3742002-12-13 20:15:29 +00002050 /* Prefix write. */
2051 stream_put_prefix (s, p);
2052
2053 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002054 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002055 }
2056
2057 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2058 {
2059 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002060
2061 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2062 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002063 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002064 stream_putc (s, 0); /* Length of this attribute. */
2065 stream_putw (s, AFI_IP); /* AFI */
2066 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2067
2068 stream_putc (s, 12);
2069 stream_putl (s, 0);
2070 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002071 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002072
2073 /* SNPA */
2074 stream_putc (s, 0);
2075
paul718e3742002-12-13 20:15:29 +00002076 /* Tag, RD, Prefix write. */
2077 stream_putc (s, p->prefixlen + 88);
2078 stream_put (s, tag, 3);
2079 stream_put (s, prd->val, 8);
2080 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2081
2082 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002083 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002084 }
2085
2086 /* Extended Communities attribute. */
2087 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2088 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2089 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002090 struct attr_extra *attre = attr->extra;
2091
2092 assert (attre);
2093
2094 if (peer_sort (peer) == BGP_PEER_IBGP
2095 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002096 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002097 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002098 {
2099 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2100 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002101 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002102 }
2103 else
2104 {
2105 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2106 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002107 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002108 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002109 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002110 }
2111 else
2112 {
paul5228ad22004-06-04 17:58:18 +00002113 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002114 int tbit;
2115 int ecom_tr_size = 0;
2116 int i;
2117
Paul Jakmafb982c22007-05-04 20:15:47 +00002118 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002119 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002120 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002121 tbit = *pnt;
2122
2123 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2124 continue;
2125
2126 ecom_tr_size++;
2127 }
2128
2129 if (ecom_tr_size)
2130 {
2131 if (ecom_tr_size * 8 > 255)
2132 {
2133 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2134 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2135 stream_putw (s, ecom_tr_size * 8);
2136 }
2137 else
2138 {
2139 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2140 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2141 stream_putc (s, ecom_tr_size * 8);
2142 }
2143
Paul Jakmafb982c22007-05-04 20:15:47 +00002144 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002145 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002146 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002147 tbit = *pnt;
2148
2149 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2150 continue;
2151
2152 stream_put (s, pnt, 8);
2153 }
2154 }
paul718e3742002-12-13 20:15:29 +00002155 }
paul718e3742002-12-13 20:15:29 +00002156 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002157
2158 if ( send_as4_path )
2159 {
2160 /* If the peer is NOT As4 capable, AND */
2161 /* there are ASnums > 65535 in path THEN
2162 * give out AS4_PATH */
2163
2164 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2165 * path segments!
2166 * Hm, I wonder... confederation things *should* only be at
2167 * the beginning of an aspath, right? Then we should use
2168 * aspath_delete_confed_seq for this, because it is already
2169 * there! (JK)
2170 * Folks, talk to me: what is reasonable here!?
2171 */
2172 aspath = aspath_delete_confed_seq (aspath);
2173
2174 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2175 stream_putc (s, BGP_ATTR_AS4_PATH);
2176 aspath_sizep = stream_get_endp (s);
2177 stream_putw (s, 0);
2178 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2179 }
2180
2181 if (aspath != attr->aspath)
2182 aspath_free (aspath);
2183
2184 if ( send_as4_aggregator )
2185 {
2186 assert (attr->extra);
2187
2188 /* send AS4_AGGREGATOR, at this place */
2189 /* this section of code moved here in order to ensure the correct
2190 * *ascending* order of attributes
2191 */
2192 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2193 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2194 stream_putc (s, 8);
2195 stream_putl (s, attr->extra->aggregator_as);
2196 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2197 }
Paul Jakma41367172007-08-06 15:24:51 +00002198
paul718e3742002-12-13 20:15:29 +00002199 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002200 if (attr->extra && attr->extra->transit)
2201 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002202
2203 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002204 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002205}
2206
2207bgp_size_t
2208bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2209 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002210 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002211{
2212 unsigned long cp;
2213 unsigned long attrlen_pnt;
2214 bgp_size_t size;
2215
paul9985f832005-02-09 15:51:56 +00002216 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002217
2218 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2219 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2220
paul9985f832005-02-09 15:51:56 +00002221 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002222 stream_putc (s, 0); /* Length of this attribute. */
2223
2224 stream_putw (s, family2afi (p->family));
2225
2226 if (safi == SAFI_MPLS_VPN)
2227 {
2228 /* SAFI */
2229 stream_putc (s, BGP_SAFI_VPNV4);
2230
2231 /* prefix. */
2232 stream_putc (s, p->prefixlen + 88);
2233 stream_put (s, tag, 3);
2234 stream_put (s, prd->val, 8);
2235 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2236 }
2237 else
2238 {
2239 /* SAFI */
2240 stream_putc (s, safi);
2241
2242 /* prefix */
2243 stream_put_prefix (s, p);
2244 }
2245
2246 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002247 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002248 stream_putc_at (s, attrlen_pnt, size);
2249
paul9985f832005-02-09 15:51:56 +00002250 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002251}
2252
2253/* Initialization of attribute. */
2254void
paulfe69a502005-09-10 16:55:02 +00002255bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002256{
paul718e3742002-12-13 20:15:29 +00002257 aspath_init ();
2258 attrhash_init ();
2259 community_init ();
2260 ecommunity_init ();
2261 cluster_init ();
2262 transit_init ();
2263}
2264
Chris Caputo228da422009-07-18 05:44:03 +00002265void
2266bgp_attr_finish (void)
2267{
2268 aspath_finish ();
2269 attrhash_finish ();
2270 community_finish ();
2271 ecommunity_finish ();
2272 cluster_finish ();
2273 transit_finish ();
2274}
2275
paul718e3742002-12-13 20:15:29 +00002276/* Make attribute packet. */
2277void
paula3845922003-10-18 01:30:50 +00002278bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2279 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002280{
2281 unsigned long cp;
2282 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002283 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002284 struct aspath *aspath;
2285
2286 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002287 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002288
2289 /* Place holder of length. */
2290 stream_putw (s, 0);
2291
2292 /* Origin attribute. */
2293 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2294 stream_putc (s, BGP_ATTR_ORIGIN);
2295 stream_putc (s, 1);
2296 stream_putc (s, attr->origin);
2297
2298 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002299
2300 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2301 stream_putc (s, BGP_ATTR_AS_PATH);
2302 aspath_lenp = stream_get_endp (s);
2303 stream_putw (s, 0);
2304
2305 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002306
2307 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002308 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2309 if(prefix != NULL
2310#ifdef HAVE_IPV6
2311 && prefix->family != AF_INET6
2312#endif /* HAVE_IPV6 */
2313 )
2314 {
2315 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2316 stream_putc (s, BGP_ATTR_NEXT_HOP);
2317 stream_putc (s, 4);
2318 stream_put_ipv4 (s, attr->nexthop.s_addr);
2319 }
paul718e3742002-12-13 20:15:29 +00002320
2321 /* MED attribute. */
2322 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2323 {
2324 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2325 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2326 stream_putc (s, 4);
2327 stream_putl (s, attr->med);
2328 }
2329
2330 /* Local preference. */
2331 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2332 {
2333 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2334 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2335 stream_putc (s, 4);
2336 stream_putl (s, attr->local_pref);
2337 }
2338
2339 /* Atomic aggregate. */
2340 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2341 {
2342 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2343 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2344 stream_putc (s, 0);
2345 }
2346
2347 /* Aggregator. */
2348 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2349 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002350 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002351 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2352 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002353 stream_putc (s, 8);
2354 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002355 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002356 }
2357
2358 /* Community attribute. */
2359 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2360 {
2361 if (attr->community->size * 4 > 255)
2362 {
2363 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2364 stream_putc (s, BGP_ATTR_COMMUNITIES);
2365 stream_putw (s, attr->community->size * 4);
2366 }
2367 else
2368 {
2369 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2370 stream_putc (s, BGP_ATTR_COMMUNITIES);
2371 stream_putc (s, attr->community->size * 4);
2372 }
2373 stream_put (s, attr->community->val, attr->community->size * 4);
2374 }
2375
paula3845922003-10-18 01:30:50 +00002376#ifdef HAVE_IPV6
2377 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002378 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2379 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002380 {
2381 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002382 struct attr_extra *attre = attr->extra;
2383
paula3845922003-10-18 01:30:50 +00002384 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2385 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002386 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002387
2388 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002389 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002390 stream_putw(s, AFI_IP6); /* AFI */
2391 stream_putc(s, SAFI_UNICAST); /* SAFI */
2392
2393 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002394 stream_putc(s, attre->mp_nexthop_len);
2395 stream_put(s, &attre->mp_nexthop_global, 16);
2396 if (attre->mp_nexthop_len == 32)
2397 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002398
2399 /* SNPA */
2400 stream_putc(s, 0);
2401
2402 /* Prefix */
2403 stream_put_prefix(s, prefix);
2404
2405 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002406 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002407 }
2408#endif /* HAVE_IPV6 */
2409
paul718e3742002-12-13 20:15:29 +00002410 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002411 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002412 stream_putw_at (s, cp, len);
2413}