blob: 4e604b18c6993226cd8324e310280113fbb66b23 [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" },
Denis Ovsienkof8627ff2011-10-10 16:52:20 +040054 { BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST" },
paul718e3742002-12-13 20:15:29 +000055 { 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);
Paul Jakma31d0f1b2011-03-29 14:18:49 +0100376 key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key);
377 key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, 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++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000503
Paul Jakmafb982c22007-05-04 20:15:47 +0000504 }
505 if (attre->cluster)
506 {
507 if (! attre->cluster->refcnt)
508 attre->cluster = cluster_intern (attre->cluster);
509 else
510 attre->cluster->refcnt++;
511 }
512 if (attre->transit)
513 {
514 if (! attre->transit->refcnt)
515 attre->transit = transit_intern (attre->transit);
516 else
517 attre->transit->refcnt++;
518 }
paul718e3742002-12-13 20:15:29 +0000519 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000520
paul718e3742002-12-13 20:15:29 +0000521 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
522 find->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000523
paul718e3742002-12-13 20:15:29 +0000524 return find;
525}
526
Paul Jakma03e214c2007-04-29 18:31:07 +0000527
paul718e3742002-12-13 20:15:29 +0000528/* Make network statement's attribute. */
529struct attr *
530bgp_attr_default_set (struct attr *attr, u_char origin)
531{
532 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000533 bgp_attr_extra_get (attr);
534
paul718e3742002-12-13 20:15:29 +0000535 attr->origin = origin;
536 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
537 attr->aspath = aspath_empty ();
538 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000539 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000540 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
541#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000542 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000543#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000544
paul718e3742002-12-13 20:15:29 +0000545 return attr;
546}
547
Paul Jakma03e214c2007-04-29 18:31:07 +0000548
paul718e3742002-12-13 20:15:29 +0000549/* Make network statement's attribute. */
550struct attr *
551bgp_attr_default_intern (u_char origin)
552{
553 struct attr attr;
554 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000555 struct attr_extra *attre;
556
557 memset (&attr, 0, sizeof (struct attr));
558 attre = bgp_attr_extra_get (&attr);
559
Paul Jakma03e214c2007-04-29 18:31:07 +0000560 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000561
562 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000563 bgp_attr_extra_free (&attr);
564
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000565 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000566 return new;
567}
568
569struct attr *
570bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
571 struct aspath *aspath,
572 struct community *community, int as_set)
573{
574 struct attr attr;
575 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000576 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000577
578 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000579 attre = bgp_attr_extra_get (&attr);
580
paul718e3742002-12-13 20:15:29 +0000581 /* Origin attribute. */
582 attr.origin = origin;
583 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
584
585 /* AS path attribute. */
586 if (aspath)
587 attr.aspath = aspath_intern (aspath);
588 else
589 attr.aspath = aspath_empty ();
590 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
591
592 /* Next hop attribute. */
593 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
594
595 if (community)
596 {
597 attr.community = community;
598 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
599 }
600
Paul Jakmafb982c22007-05-04 20:15:47 +0000601 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000602#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000603 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000604#endif
605 if (! as_set)
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
607 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
608 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000609 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000610 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000611 attre->aggregator_as = bgp->as;
612 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000613
614 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000615 bgp_attr_extra_free (&attr);
616
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000617 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000618 return new;
619}
620
Paul Jakmab881c702010-11-23 16:35:42 +0000621/* Unintern just the sub-components of the attr, but not the attr */
622void
623bgp_attr_unintern_sub (struct attr *attr)
624{
625 /* aspath refcount shoud be decrement. */
626 if (attr->aspath)
627 aspath_unintern (&attr->aspath);
628 UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
629
630 if (attr->community)
631 community_unintern (&attr->community);
632 UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
633
634 if (attr->extra)
635 {
636 if (attr->extra->ecommunity)
637 ecommunity_unintern (&attr->extra->ecommunity);
638 UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
639
640 if (attr->extra->cluster)
641 cluster_unintern (attr->extra->cluster);
642 UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
643
644 if (attr->extra->transit)
645 transit_unintern (attr->extra->transit);
646 }
647}
648
paul718e3742002-12-13 20:15:29 +0000649/* Free bgp attribute and aspath. */
650void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000651bgp_attr_unintern (struct attr **attr)
paul718e3742002-12-13 20:15:29 +0000652{
653 struct attr *ret;
Paul Jakmab881c702010-11-23 16:35:42 +0000654 struct attr tmp;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000655
paul718e3742002-12-13 20:15:29 +0000656 /* Decrement attribute reference. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000657 (*attr)->refcnt--;
Paul Jakmab881c702010-11-23 16:35:42 +0000658
659 tmp = *(*attr);
660
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000661 if ((*attr)->extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000662 {
Paul Jakmab881c702010-11-23 16:35:42 +0000663 tmp.extra = bgp_attr_extra_new ();
664 memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra));
Paul Jakmafb982c22007-05-04 20:15:47 +0000665 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000666
paul718e3742002-12-13 20:15:29 +0000667 /* If reference becomes zero then free attribute object. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000668 if ((*attr)->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000669 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000670 ret = hash_release (attrhash, *attr);
paul718e3742002-12-13 20:15:29 +0000671 assert (ret != NULL);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000672 bgp_attr_extra_free (*attr);
673 XFREE (MTYPE_ATTR, *attr);
674 *attr = NULL;
paul718e3742002-12-13 20:15:29 +0000675 }
676
Paul Jakmab881c702010-11-23 16:35:42 +0000677 bgp_attr_unintern_sub (&tmp);
Oleg A. Arkhangelskyce0af6f2011-12-03 15:18:19 +0400678 bgp_attr_extra_free (&tmp);
paul718e3742002-12-13 20:15:29 +0000679}
680
681void
682bgp_attr_flush (struct attr *attr)
683{
684 if (attr->aspath && ! attr->aspath->refcnt)
685 aspath_free (attr->aspath);
686 if (attr->community && ! attr->community->refcnt)
687 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000688 if (attr->extra)
689 {
690 struct attr_extra *attre = attr->extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000691
Paul Jakmafb982c22007-05-04 20:15:47 +0000692 if (attre->ecommunity && ! attre->ecommunity->refcnt)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000693 ecommunity_free (&attre->ecommunity);
Paul Jakmafb982c22007-05-04 20:15:47 +0000694 if (attre->cluster && ! attre->cluster->refcnt)
695 cluster_free (attre->cluster);
696 if (attre->transit && ! attre->transit->refcnt)
697 transit_free (attre->transit);
698 }
paul718e3742002-12-13 20:15:29 +0000699}
700
Paul Jakmab881c702010-11-23 16:35:42 +0000701/* Implement draft-scudder-idr-optional-transitive behaviour and
702 * avoid resetting sessions for malformed attributes which are
703 * are partial/optional and hence where the error likely was not
704 * introduced by the sending neighbour.
705 */
706static bgp_attr_parse_ret_t
707bgp_attr_malformed (struct peer *peer, u_char type, u_char flag,
708 u_char subcode, u_char *startp, bgp_size_t length)
709{
710 /* Only relax error handling for eBGP peers */
711 if (peer_sort (peer) != BGP_PEER_EBGP)
712 {
713 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
714 startp, length);
715 return BGP_ATTR_PARSE_ERROR;
716
717 }
718
719 switch (type) {
720 /* where an optional attribute is inconsequential, e.g. it does not affect
721 * route selection, and can be safely ignored then any such attributes
722 * which are malformed should just be ignored and the route processed as
723 * normal.
724 */
725 case BGP_ATTR_AS4_AGGREGATOR:
726 case BGP_ATTR_AGGREGATOR:
727 case BGP_ATTR_ATOMIC_AGGREGATE:
728 return BGP_ATTR_PARSE_PROCEED;
729
730 /* Core attributes, particularly ones which may influence route
731 * selection should always cause session resets
732 */
733 case BGP_ATTR_ORIGIN:
734 case BGP_ATTR_AS_PATH:
735 case BGP_ATTR_NEXT_HOP:
736 case BGP_ATTR_MULTI_EXIT_DISC:
737 case BGP_ATTR_LOCAL_PREF:
738 case BGP_ATTR_COMMUNITIES:
739 case BGP_ATTR_ORIGINATOR_ID:
740 case BGP_ATTR_CLUSTER_LIST:
741 case BGP_ATTR_MP_REACH_NLRI:
742 case BGP_ATTR_MP_UNREACH_NLRI:
743 case BGP_ATTR_EXT_COMMUNITIES:
744 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
745 startp, length);
746 return BGP_ATTR_PARSE_ERROR;
747 }
748
749 /* Partial optional attributes that are malformed should not cause
750 * the whole session to be reset. Instead treat it as a withdrawal
751 * of the routes, if possible.
752 */
753 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)
754 && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
755 && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
756 return BGP_ATTR_PARSE_WITHDRAW;
757
758 /* default to reset */
759 return BGP_ATTR_PARSE_ERROR;
760}
761
paul718e3742002-12-13 20:15:29 +0000762/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000763static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000764bgp_attr_origin (struct peer *peer, bgp_size_t length,
765 struct attr *attr, u_char flag, u_char *startp)
766{
767 bgp_size_t total;
768
769 /* total is entire attribute length include Attribute Flags (1),
770 Attribute Type code (1) and Attribute length (1 or 2). */
771 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
772
773 /* If any recognized attribute has Attribute Flags that conflict
774 with the Attribute Type Code, then the Error Subcode is set to
775 Attribute Flags Error. The Data field contains the erroneous
776 attribute (type, length and value). */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +0400777 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +0400778 {
779 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
780 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag);
781 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
782 zlog (peer->log, LOG_ERR, "ORIGIN attribute must be flagged as \"transitive\" (%u)", flag);
783 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
784 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"partial\" (%u)", flag);
785 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
786 }
paul718e3742002-12-13 20:15:29 +0000787
788 /* If any recognized attribute has Attribute Length that conflicts
789 with the expected length (based on the attribute type code), then
790 the Error Subcode is set to Attribute Length Error. The Data
791 field contains the erroneous attribute (type, length and
792 value). */
793 if (length != 1)
794 {
795 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
796 length);
Paul Jakmab881c702010-11-23 16:35:42 +0000797 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
798 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
799 startp, total);
paul718e3742002-12-13 20:15:29 +0000800 }
801
802 /* Fetch origin attribute. */
803 attr->origin = stream_getc (BGP_INPUT (peer));
804
805 /* If the ORIGIN attribute has an undefined value, then the Error
806 Subcode is set to Invalid Origin Attribute. The Data field
807 contains the unrecognized attribute (type, length and value). */
808 if ((attr->origin != BGP_ORIGIN_IGP)
809 && (attr->origin != BGP_ORIGIN_EGP)
810 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
811 {
812 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
813 attr->origin);
Paul Jakmab881c702010-11-23 16:35:42 +0000814 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
815 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
816 startp, total);
paul718e3742002-12-13 20:15:29 +0000817 }
818
819 /* Set oring attribute flag. */
820 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
821
822 return 0;
823}
Paul Jakmaab005292010-11-27 22:48:34 +0000824
825/* Parse AS path information. This function is wrapper of
826 aspath_parse. */
827static int
paul718e3742002-12-13 20:15:29 +0000828bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Paul Jakmaab005292010-11-27 22:48:34 +0000829 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +0000830{
Paul Jakmaab005292010-11-27 22:48:34 +0000831 bgp_size_t total;
paul718e3742002-12-13 20:15:29 +0000832
Paul Jakmaab005292010-11-27 22:48:34 +0000833 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000834
Paul Jakmaab005292010-11-27 22:48:34 +0000835 /* Flag check. */
Denis Ovsienko214bcaa2011-09-24 13:20:43 +0400836 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
837 {
838 zlog (peer->log, LOG_ERR,
839 "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag);
840 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
841 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
842 startp, total);
843 }
844
Paul Jakmaab005292010-11-27 22:48:34 +0000845 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
846 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000847 {
848 zlog (peer->log, LOG_ERR,
Paul Jakmaab005292010-11-27 22:48:34 +0000849 "As-Path attribute flag isn't transitive %d", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000850 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
851 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
852 startp, total);
Chris Hallcddb8112010-08-09 22:31:37 +0400853 }
Paul Jakmaab005292010-11-27 22:48:34 +0000854
855 /*
856 * peer with AS4 => will get 4Byte ASnums
857 * otherwise, will get 16 Bit
858 */
859 attr->aspath = aspath_parse (peer->ibuf, length,
860 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
861
862 /* In case of IBGP, length will be zero. */
863 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000864 {
Paul Jakmab881c702010-11-23 16:35:42 +0000865 zlog (peer->log, LOG_ERR,
866 "Malformed AS path from %s, length is %d",
867 peer->host, length);
868 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
869 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
870 NULL, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000871 }
Chris Hallcddb8112010-08-09 22:31:37 +0400872
Paul Jakmaab005292010-11-27 22:48:34 +0000873 /* Set aspath attribute flag. */
874 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000875
Paul Jakmab881c702010-11-23 16:35:42 +0000876 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000877}
878
Paul Jakmab881c702010-11-23 16:35:42 +0000879static bgp_attr_parse_ret_t
880bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000881{
882 /* These checks were part of bgp_attr_aspath, but with
883 * as4 we should to check aspath things when
884 * aspath synthesizing with as4_path has already taken place.
885 * Otherwise we check ASPATH and use the synthesized thing, and that is
886 * not right.
887 * So do the checks later, i.e. here
888 */
889 struct bgp *bgp = peer->bgp;
890 struct aspath *aspath;
891
paul718e3742002-12-13 20:15:29 +0000892 bgp = peer->bgp;
893
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300894 /* Confederation sanity check. */
895 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
896 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
897 {
898 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +0000899 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
900 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
901 NULL, 0);
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300902 }
903
paul718e3742002-12-13 20:15:29 +0000904 /* First AS check for EBGP. */
905 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
906 {
907 if (peer_sort (peer) == BGP_PEER_EBGP
908 && ! aspath_firstas_check (attr->aspath, peer->as))
909 {
910 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400911 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakmab881c702010-11-23 16:35:42 +0000912 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
913 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
914 NULL, 0);
paul718e3742002-12-13 20:15:29 +0000915 }
916 }
917
918 /* local-as prepend */
919 if (peer->change_local_as &&
920 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
921 {
922 aspath = aspath_dup (attr->aspath);
923 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000924 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +0000925 attr->aspath = aspath_intern (aspath);
926 }
927
Paul Jakmab881c702010-11-23 16:35:42 +0000928 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000929}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000930
Paul Jakmaab005292010-11-27 22:48:34 +0000931/* Parse AS4 path information. This function is another wrapper of
932 aspath_parse. */
933static int
Paul Jakmab881c702010-11-23 16:35:42 +0000934bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
935 struct attr *attr, u_char flag, u_char *startp,
936 struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +0000937{
Paul Jakmab881c702010-11-23 16:35:42 +0000938 bgp_size_t total;
939
940 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
941
942 /* Flag check. */
943 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
944 || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
945 {
946 zlog (peer->log, LOG_ERR,
947 "As4-Path attribute flag isn't optional/transitive %d", flag);
948 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
949 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
950 startp, total);
951 }
952
Paul Jakmaab005292010-11-27 22:48:34 +0000953 *as4_path = aspath_parse (peer->ibuf, length, 1);
954
Paul Jakmab881c702010-11-23 16:35:42 +0000955 /* In case of IBGP, length will be zero. */
956 if (!*as4_path)
957 {
958 zlog (peer->log, LOG_ERR,
959 "Malformed AS4 path from %s, length is %d",
960 peer->host, length);
961 return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
962 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
963 NULL, 0);
964 }
965
Paul Jakmaab005292010-11-27 22:48:34 +0000966 /* Set aspath attribute flag. */
967 if (as4_path)
968 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
969
Paul Jakmab881c702010-11-23 16:35:42 +0000970 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000971}
972
paul718e3742002-12-13 20:15:29 +0000973/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +0000974static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000975bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
976 struct attr *attr, u_char flag, u_char *startp)
977{
978 bgp_size_t total;
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400979 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +0000980
981 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
982
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400983 /* Flags check. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +0400984 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +0400985 {
986 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
987 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag);
988 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
989 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag);
990 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
991 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag);
992 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
993 }
paul718e3742002-12-13 20:15:29 +0000994
995 /* Check nexthop attribute length. */
996 if (length != 4)
997 {
998 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
999 length);
1000
Paul Jakmab881c702010-11-23 16:35:42 +00001001 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1002 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1003 startp, total);
paul718e3742002-12-13 20:15:29 +00001004 }
1005
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001006 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1007 attribute must result in a NOTIFICATION message (this is implemented below).
1008 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1009 logged locally (this is implemented somewhere else). The UPDATE message
1010 gets ignored in any of these cases. */
1011 nexthop_n = stream_get_ipv4 (peer->ibuf);
1012 nexthop_h = ntohl (nexthop_n);
1013 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1014 {
1015 char buf[INET_ADDRSTRLEN];
1016 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1017 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
1018 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1019 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
1020 startp, total);
1021 }
1022
1023 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001024 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1025
Paul Jakmab881c702010-11-23 16:35:42 +00001026 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001027}
1028
1029/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001030static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001031bgp_attr_med (struct peer *peer, bgp_size_t length,
1032 struct attr *attr, u_char flag, u_char *startp)
1033{
1034 bgp_size_t total;
1035
1036 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1037
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001038 /* Flag checks. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001039 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001040 {
1041 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1042 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
1043 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1044 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
1045 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1046 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001047 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1048 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1049 startp, total);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001050 }
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001051
paul718e3742002-12-13 20:15:29 +00001052 /* Length check. */
1053 if (length != 4)
1054 {
1055 zlog (peer->log, LOG_ERR,
1056 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001057
1058 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1059 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1060 startp, total);
paul718e3742002-12-13 20:15:29 +00001061 }
1062
1063 attr->med = stream_getl (peer->ibuf);
1064
1065 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1066
Paul Jakmab881c702010-11-23 16:35:42 +00001067 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001068}
1069
1070/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001071static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001072bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001073 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001074{
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001075 bgp_size_t total;
1076
1077 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1078 /* Flag checks. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001079 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001080 {
1081 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1082 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"optional\" (%u)", flag);
1083 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1084 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1085 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1086 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001087 return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag,
1088 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1089 startp, total);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001090 }
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001091 /* Length check. */
1092 if (length != 4)
1093 {
1094 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001095 return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001096 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1097 startp, total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001098 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001099
paul718e3742002-12-13 20:15:29 +00001100 /* If it is contained in an UPDATE message that is received from an
1101 external peer, then this attribute MUST be ignored by the
1102 receiving speaker. */
1103 if (peer_sort (peer) == BGP_PEER_EBGP)
1104 {
paul9985f832005-02-09 15:51:56 +00001105 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001106 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001107 }
1108
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001109 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001110
1111 /* Set atomic aggregate flag. */
1112 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1113
Paul Jakmab881c702010-11-23 16:35:42 +00001114 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001115}
1116
1117/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001118static int
paul718e3742002-12-13 20:15:29 +00001119bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001120 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001121{
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001122 bgp_size_t total;
1123
1124 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1125 /* Flag checks. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001126 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001127 {
1128 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1129 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
1130 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1131 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
1132 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1133 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001134 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1135 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1136 startp, total);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001137 }
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001138
1139 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001140 if (length != 0)
1141 {
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001142 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001143 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1144 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001145 startp, total);
paul718e3742002-12-13 20:15:29 +00001146 }
1147
1148 /* Set atomic aggregate flag. */
1149 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1150
Paul Jakmab881c702010-11-23 16:35:42 +00001151 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001152}
1153
1154/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001155static int
paul718e3742002-12-13 20:15:29 +00001156bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001157 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001158{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001159 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001160 struct attr_extra *attre = bgp_attr_extra_get (attr);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001161 bgp_size_t total;
Paul Jakmafb982c22007-05-04 20:15:47 +00001162
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001163 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
Denis Ovsienkob4cd2422011-10-22 22:32:26 +04001164 /* Flags check. */
1165 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1166 {
1167 zlog (peer->log, LOG_ERR,
1168 "AGGREGATOR attribute must be flagged as \"optional\" (%u)", flag);
1169 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1170 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1171 startp, total);
1172 }
1173 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1174 {
1175 zlog (peer->log, LOG_ERR,
1176 "AGGREGATOR attribute must be flagged as \"transitive\" (%u)", flag);
1177 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1178 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1179 startp, total);
1180 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001181 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001182 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001183 wantedlen = 8;
1184
1185 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001186 {
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001187 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001188 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1189 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001190 startp, total);
paul718e3742002-12-13 20:15:29 +00001191 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001192
1193 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1194 attre->aggregator_as = stream_getl (peer->ibuf);
1195 else
1196 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001197 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001198
1199 /* Set atomic aggregate flag. */
1200 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1201
Paul Jakmab881c702010-11-23 16:35:42 +00001202 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001203}
1204
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001205/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001206static bgp_attr_parse_ret_t
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001207bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001208 struct attr *attr, u_char flag,
1209 as_t *as4_aggregator_as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001210 struct in_addr *as4_aggregator_addr)
1211{
1212 if (length != 8)
1213 {
1214 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001215 return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
1216 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1217 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001218 }
1219 *as4_aggregator_as = stream_getl (peer->ibuf);
1220 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1221
1222 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1223
Paul Jakmab881c702010-11-23 16:35:42 +00001224 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001225}
1226
1227/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1228 */
Paul Jakmab881c702010-11-23 16:35:42 +00001229static bgp_attr_parse_ret_t
1230bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001231 struct aspath *as4_path, as_t as4_aggregator,
1232 struct in_addr *as4_aggregator_addr)
1233{
1234 int ignore_as4_path = 0;
1235 struct aspath *newpath;
1236 struct attr_extra *attre = attr->extra;
1237
Paul Jakmab881c702010-11-23 16:35:42 +00001238 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001239 {
1240 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1241 * if given.
1242 * It is worth a warning though, because the peer really
1243 * should not send them
1244 */
1245 if (BGP_DEBUG(as4, AS4))
1246 {
1247 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1248 zlog_debug ("[AS4] %s %s AS4_PATH",
1249 peer->host, "AS4 capable peer, yet it sent");
1250
1251 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1252 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1253 peer->host, "AS4 capable peer, yet it sent");
1254 }
1255
Paul Jakmab881c702010-11-23 16:35:42 +00001256 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001257 }
1258
Paul Jakmab881c702010-11-23 16:35:42 +00001259 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
1260 && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001261 {
1262 /* Hu? This is not supposed to happen at all!
1263 * got as4_path and no aspath,
1264 * This should already
1265 * have been handled by 'well known attributes missing'
1266 * But... yeah, paranoia
1267 * Take this as a "malformed attribute"
1268 */
1269 zlog (peer->log, LOG_ERR,
1270 "%s BGP not AS4 capable peer sent AS4_PATH but"
1271 " no AS_PATH, cant do anything here", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001272 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1273 BGP_NOTIFY_UPDATE_MAL_ATTR,
1274 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001275 }
1276
1277 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1278 * because that may override AS4_PATH
1279 */
1280 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1281 {
Paul Jakmab881c702010-11-23 16:35:42 +00001282 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001283 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001284 assert (attre);
1285
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001286 /* received both.
1287 * if the as_number in aggregator is not AS_TRANS,
1288 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1289 * and the Aggregator shall be taken as
1290 * info on the aggregating node, and the AS_PATH
1291 * shall be taken as the AS_PATH
1292 * otherwise
1293 * the Aggregator shall be ignored and the
1294 * AS4_AGGREGATOR shall be taken as the
1295 * Aggregating node and the AS_PATH is to be
1296 * constructed "as in all other cases"
1297 */
Paul Jakmab881c702010-11-23 16:35:42 +00001298 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001299 {
1300 /* ignore */
1301 if ( BGP_DEBUG(as4, AS4))
1302 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1303 " send AGGREGATOR != AS_TRANS and"
1304 " AS4_AGGREGATOR, so ignore"
1305 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1306 ignore_as4_path = 1;
1307 }
1308 else
1309 {
1310 /* "New_aggregator shall be taken as aggregator" */
1311 attre->aggregator_as = as4_aggregator;
1312 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1313 }
1314 }
1315 else
1316 {
1317 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1318 * That is bogus - but reading the conditions
1319 * we have to handle AS4_AGGREGATOR as if it were
1320 * AGGREGATOR in that case
1321 */
1322 if ( BGP_DEBUG(as4, AS4))
1323 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1324 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1325 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001326 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001327 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1328 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1329 }
1330 }
1331
1332 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001333 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001334 {
1335 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001336 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001337 attr->aspath = aspath_intern (newpath);
1338 }
Paul Jakmab881c702010-11-23 16:35:42 +00001339 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001340}
1341
paul718e3742002-12-13 20:15:29 +00001342/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001343static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001344bgp_attr_community (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001345 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001346{
Paul Jakmab881c702010-11-23 16:35:42 +00001347 bgp_size_t total
1348 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1349
paul718e3742002-12-13 20:15:29 +00001350 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001351 {
1352 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001353 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001354 }
Paul Jakma0c466382010-12-05 17:17:26 +00001355
1356 attr->community =
1357 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1358
1359 /* XXX: fix community_parse to use stream API and remove this */
1360 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001361
Paul Jakma0c466382010-12-05 17:17:26 +00001362 if (!attr->community)
Paul Jakmab881c702010-11-23 16:35:42 +00001363 return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
1364 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1365 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001366
paul718e3742002-12-13 20:15:29 +00001367 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1368
Paul Jakmab881c702010-11-23 16:35:42 +00001369 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001370}
1371
1372/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001373static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001374bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
Denis Ovsienkod595b562011-09-30 15:08:54 +04001375 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001376{
Denis Ovsienkod595b562011-09-30 15:08:54 +04001377 bgp_size_t total;
1378
1379 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1380 /* Flag checks. */
Denis Ovsienkobbb04bf2011-10-18 14:20:04 +04001381 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkod595b562011-09-30 15:08:54 +04001382 {
1383 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1384 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must be flagged as \"optional\" (%u)", flag);
1385 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1386 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"transitive\" (%u)", flag);
1387 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1388 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001389 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1390 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1391 startp, total);
Denis Ovsienkod595b562011-09-30 15:08:54 +04001392 }
1393 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001394 if (length != 4)
1395 {
1396 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1397
Paul Jakmab881c702010-11-23 16:35:42 +00001398 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1399 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienko26755182011-10-26 19:34:30 +04001400 startp, total);
paul718e3742002-12-13 20:15:29 +00001401 }
1402
Paul Jakmafb982c22007-05-04 20:15:47 +00001403 (bgp_attr_extra_get (attr))->originator_id.s_addr
1404 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001405
1406 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1407
Paul Jakmab881c702010-11-23 16:35:42 +00001408 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001409}
1410
1411/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001412static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001413bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
Denis Ovsienko0b830442011-09-30 15:12:17 +04001414 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001415{
Denis Ovsienko0b830442011-09-30 15:12:17 +04001416 bgp_size_t total;
1417
1418 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1419 /* Flag checks. */
Denis Ovsienkobbb04bf2011-10-18 14:20:04 +04001420 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko0b830442011-09-30 15:12:17 +04001421 {
1422 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1423 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must be flagged as \"optional\" (%u)", flag);
1424 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1425 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"transitive\" (%u)", flag);
1426 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1427 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001428 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1429 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1430 startp, total);
Denis Ovsienko0b830442011-09-30 15:12:17 +04001431 }
paul718e3742002-12-13 20:15:29 +00001432 /* Check length. */
1433 if (length % 4)
1434 {
1435 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1436
Paul Jakmab881c702010-11-23 16:35:42 +00001437 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1438 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienko26755182011-10-26 19:34:30 +04001439 startp, total);
paul718e3742002-12-13 20:15:29 +00001440 }
1441
Paul Jakmafb982c22007-05-04 20:15:47 +00001442 (bgp_attr_extra_get (attr))->cluster
1443 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001444
1445 /* XXX: Fix cluster_parse to use stream API and then remove this */
1446 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001447
1448 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1449
Paul Jakmab881c702010-11-23 16:35:42 +00001450 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001451}
1452
1453/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001454int
Denis Ovsienko565b8282011-10-10 21:08:33 +04001455bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length,
1456 struct attr *attr, const u_char flag, u_char *startp, struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001457{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001458 afi_t afi;
1459 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001460 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001461 size_t start;
paul718e3742002-12-13 20:15:29 +00001462 int ret;
1463 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001464 struct attr_extra *attre = bgp_attr_extra_get(attr);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001465 bgp_size_t total;
1466
1467 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1468 /* Flag checks. */
Denis Ovsienkobbb04bf2011-10-18 14:20:04 +04001469 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko565b8282011-10-10 21:08:33 +04001470 {
1471 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1472 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must be flagged as \"optional\" (%u)", flag);
1473 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1474 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag);
1475 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1476 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001477 return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag,
1478 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1479 startp, total);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001480 }
paul718e3742002-12-13 20:15:29 +00001481 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001482 s = BGP_INPUT(peer);
1483 start = stream_get_getp(s);
1484
1485 /* safe to read statically sized header? */
1486#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001487#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001488 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001489 {
1490 zlog_info ("%s: %s sent invalid length, %lu",
1491 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001492 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001493 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001494
paul718e3742002-12-13 20:15:29 +00001495 /* Load AFI, SAFI. */
1496 afi = stream_getw (s);
1497 safi = stream_getc (s);
1498
1499 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001500 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001501
Paul Jakma03292802008-06-07 20:37:10 +00001502 if (LEN_LEFT < attre->mp_nexthop_len)
1503 {
1504 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1505 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001506 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001507 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001508
paul718e3742002-12-13 20:15:29 +00001509 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001510 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001511 {
1512 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001513 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001514 /* Probably needed for RFC 2283 */
1515 if (attr->nexthop.s_addr == 0)
1516 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001517 break;
1518 case 12:
1519 {
1520 u_int32_t rd_high;
1521 u_int32_t rd_low;
1522
1523 rd_high = stream_getl (s);
1524 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001525 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001526 }
1527 break;
1528#ifdef HAVE_IPV6
1529 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001530 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001531 break;
1532 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001533 stream_get (&attre->mp_nexthop_global, s, 16);
1534 stream_get (&attre->mp_nexthop_local, s, 16);
1535 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001536 {
1537 char buf1[INET6_ADDRSTRLEN];
1538 char buf2[INET6_ADDRSTRLEN];
1539
1540 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001541 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 +00001542 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001543 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001544 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001545 buf2, INET6_ADDRSTRLEN));
1546
Paul Jakmafb982c22007-05-04 20:15:47 +00001547 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001548 }
1549 break;
1550#endif /* HAVE_IPV6 */
1551 default:
Paul Jakma03292802008-06-07 20:37:10 +00001552 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1553 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001554 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001555 }
1556
Paul Jakma03292802008-06-07 20:37:10 +00001557 if (!LEN_LEFT)
1558 {
1559 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1560 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001561 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001562 }
paul718e3742002-12-13 20:15:29 +00001563
Paul Jakma6e4ab122007-04-10 19:36:48 +00001564 {
1565 u_char val;
1566 if ((val = stream_getc (s)))
1567 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1568 peer->host, val);
1569 }
1570
1571 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001572 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001573 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001574 {
1575 zlog_info ("%s: (%s) Failed to read NLRI",
1576 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001577 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001578 }
paul718e3742002-12-13 20:15:29 +00001579
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001580 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001581 {
1582 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001583 if (ret < 0)
1584 {
1585 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1586 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001587 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001588 }
paul718e3742002-12-13 20:15:29 +00001589 }
1590
1591 mp_update->afi = afi;
1592 mp_update->safi = safi;
1593 mp_update->nlri = stream_pnt (s);
1594 mp_update->length = nlri_len;
1595
paul9985f832005-02-09 15:51:56 +00001596 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001597
Paul Jakmab881c702010-11-23 16:35:42 +00001598 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001599#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001600}
1601
1602/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001603int
Denis Ovsienko565b8282011-10-10 21:08:33 +04001604bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length,
1605 const u_char flag, u_char *startp,
paul718e3742002-12-13 20:15:29 +00001606 struct bgp_nlri *mp_withdraw)
1607{
1608 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001609 afi_t afi;
1610 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001611 u_int16_t withdraw_len;
1612 int ret;
Denis Ovsienko565b8282011-10-10 21:08:33 +04001613 bgp_size_t total;
1614
1615 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1616 /* Flag checks. */
Denis Ovsienkobbb04bf2011-10-18 14:20:04 +04001617 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko565b8282011-10-10 21:08:33 +04001618 {
1619 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1620 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must be flagged as \"optional\" (%u)", flag);
1621 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1622 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag);
1623 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1624 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001625 return bgp_attr_malformed (peer, BGP_ATTR_MP_UNREACH_NLRI, flag,
1626 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1627 startp, total);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001628 }
paul718e3742002-12-13 20:15:29 +00001629
1630 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001631
1632#define BGP_MP_UNREACH_MIN_SIZE 3
1633 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001634 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001635
paul718e3742002-12-13 20:15:29 +00001636 afi = stream_getw (s);
1637 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001638
1639 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001640
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001641 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001642 {
1643 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1644 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001645 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001646 }
1647
1648 mp_withdraw->afi = afi;
1649 mp_withdraw->safi = safi;
1650 mp_withdraw->nlri = stream_pnt (s);
1651 mp_withdraw->length = withdraw_len;
1652
paul9985f832005-02-09 15:51:56 +00001653 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001654
Paul Jakmab881c702010-11-23 16:35:42 +00001655 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001656}
1657
1658/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001659static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001660bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001661 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001662{
Paul Jakmab881c702010-11-23 16:35:42 +00001663 bgp_size_t total
1664 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1665
paul718e3742002-12-13 20:15:29 +00001666 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001667 {
1668 if (attr->extra)
1669 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001670 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001671 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001672 }
Paul Jakma0c466382010-12-05 17:17:26 +00001673
1674 (bgp_attr_extra_get (attr))->ecommunity =
1675 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1676 /* XXX: fix ecommunity_parse to use stream API */
1677 stream_forward_getp (peer->ibuf, length);
1678
1679 if (!attr->extra->ecommunity)
Paul Jakmab881c702010-11-23 16:35:42 +00001680 return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
1681 flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1682 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001683
paul718e3742002-12-13 20:15:29 +00001684 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1685
Paul Jakmab881c702010-11-23 16:35:42 +00001686 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001687}
1688
1689/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001690static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001691bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1692 u_char type, bgp_size_t length, u_char *startp)
1693{
1694 bgp_size_t total;
1695 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001696 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001697
hassof4184462005-02-01 20:13:16 +00001698 if (BGP_DEBUG (normal, NORMAL))
1699 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1700 peer->host, type, length);
1701
paul718e3742002-12-13 20:15:29 +00001702 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001703 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001704 "Unknown attribute type %d length %d is received", type, length);
1705
1706 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001707 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001708
1709 /* Adjest total length to include type and length. */
1710 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1711
1712 /* If any of the mandatory well-known attributes are not recognized,
1713 then the Error Subcode is set to Unrecognized Well-known
1714 Attribute. The Data field contains the unrecognized attribute
1715 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001716 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001717 {
Paul Jakmab881c702010-11-23 16:35:42 +00001718 return bgp_attr_malformed (peer, type, flag,
1719 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1720 startp, total);
paul718e3742002-12-13 20:15:29 +00001721 }
1722
1723 /* Unrecognized non-transitive optional attributes must be quietly
1724 ignored and not passed along to other BGP peers. */
1725 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001726 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001727
1728 /* If a path with recognized transitive optional attribute is
1729 accepted and passed along to other BGP peers and the Partial bit
1730 in the Attribute Flags octet is set to 1 by some previous AS, it
1731 is not set back to 0 by the current AS. */
1732 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1733
1734 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001735 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001736 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001737
Paul Jakmafb982c22007-05-04 20:15:47 +00001738 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001739
1740 if (transit->val)
1741 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1742 transit->length + total);
1743 else
1744 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1745
1746 memcpy (transit->val + transit->length, startp, total);
1747 transit->length += total;
1748
Paul Jakmab881c702010-11-23 16:35:42 +00001749 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001750}
1751
1752/* Read attribute of update packet. This function is called from
1753 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001754bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001755bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1756 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1757{
1758 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001759 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001760 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001761 bgp_size_t length;
1762 u_char *startp, *endp;
1763 u_char *attr_endp;
1764 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001765 /* we need the as4_path only until we have synthesized the as_path with it */
1766 /* same goes for as4_aggregator */
1767 struct aspath *as4_path = NULL;
1768 as_t as4_aggregator = 0;
1769 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001770
1771 /* Initialize bitmap. */
1772 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1773
1774 /* End pointer of BGP attribute. */
1775 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001776
paul718e3742002-12-13 20:15:29 +00001777 /* Get attributes to the end of attribute length. */
1778 while (BGP_INPUT_PNT (peer) < endp)
1779 {
1780 /* Check remaining length check.*/
1781 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1782 {
gdtc29fdba2004-12-09 14:46:46 +00001783 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001784 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001785 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001786 peer->host,
1787 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001788
1789 bgp_notify_send (peer,
1790 BGP_NOTIFY_UPDATE_ERR,
1791 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001792 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001793 }
1794
1795 /* Fetch attribute flag and type. */
1796 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001797 /* "The lower-order four bits of the Attribute Flags octet are
1798 unused. They MUST be zero when sent and MUST be ignored when
1799 received." */
1800 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001801 type = stream_getc (BGP_INPUT (peer));
1802
Paul Jakma370b64a2007-12-22 16:49:52 +00001803 /* Check whether Extended-Length applies and is in bounds */
1804 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1805 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1806 {
1807 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001808 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001809 peer->host,
1810 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1811
1812 bgp_notify_send (peer,
1813 BGP_NOTIFY_UPDATE_ERR,
1814 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001815 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001816 }
1817
paul718e3742002-12-13 20:15:29 +00001818 /* Check extended attribue length bit. */
1819 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1820 length = stream_getw (BGP_INPUT (peer));
1821 else
1822 length = stream_getc (BGP_INPUT (peer));
1823
1824 /* If any attribute appears more than once in the UPDATE
1825 message, then the Error Subcode is set to Malformed Attribute
1826 List. */
1827
1828 if (CHECK_BITMAP (seen, type))
1829 {
1830 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001831 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001832 peer->host, type);
1833
1834 bgp_notify_send (peer,
1835 BGP_NOTIFY_UPDATE_ERR,
1836 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001837 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001838 }
1839
1840 /* Set type to bitmap to check duplicate attribute. `type' is
1841 unsigned char so it never overflow bitmap range. */
1842
1843 SET_BITMAP (seen, type);
1844
1845 /* Overflow check. */
1846 attr_endp = BGP_INPUT_PNT (peer) + length;
1847
1848 if (attr_endp > endp)
1849 {
1850 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001851 "%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);
paul718e3742002-12-13 20:15:29 +00001852 bgp_notify_send (peer,
1853 BGP_NOTIFY_UPDATE_ERR,
1854 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001855 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001856 }
1857
1858 /* OK check attribute and store it's value. */
1859 switch (type)
1860 {
1861 case BGP_ATTR_ORIGIN:
1862 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1863 break;
1864 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001865 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001866 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001867 case BGP_ATTR_AS4_PATH:
Paul Jakmab881c702010-11-23 16:35:42 +00001868 ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001869 break;
paul718e3742002-12-13 20:15:29 +00001870 case BGP_ATTR_NEXT_HOP:
1871 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1872 break;
1873 case BGP_ATTR_MULTI_EXIT_DISC:
1874 ret = bgp_attr_med (peer, length, attr, flag, startp);
1875 break;
1876 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001877 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001878 break;
1879 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001880 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001881 break;
1882 case BGP_ATTR_AGGREGATOR:
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001883 ret = bgp_attr_aggregator (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001884 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001885 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakmab881c702010-11-23 16:35:42 +00001886 ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
1887 &as4_aggregator,
1888 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001889 break;
paul718e3742002-12-13 20:15:29 +00001890 case BGP_ATTR_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001891 ret = bgp_attr_community (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001892 break;
1893 case BGP_ATTR_ORIGINATOR_ID:
Denis Ovsienkod595b562011-09-30 15:08:54 +04001894 ret = bgp_attr_originator_id (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001895 break;
1896 case BGP_ATTR_CLUSTER_LIST:
Denis Ovsienko0b830442011-09-30 15:12:17 +04001897 ret = bgp_attr_cluster_list (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001898 break;
1899 case BGP_ATTR_MP_REACH_NLRI:
Denis Ovsienko565b8282011-10-10 21:08:33 +04001900 ret = bgp_mp_reach_parse (peer, length, attr, flag, startp, mp_update);
paul718e3742002-12-13 20:15:29 +00001901 break;
1902 case BGP_ATTR_MP_UNREACH_NLRI:
Denis Ovsienko565b8282011-10-10 21:08:33 +04001903 ret = bgp_mp_unreach_parse (peer, length, flag, startp, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001904 break;
1905 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001906 ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001907 break;
1908 default:
1909 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1910 break;
1911 }
Paul Jakmab881c702010-11-23 16:35:42 +00001912
1913 /* If hard error occured immediately return to the caller. */
1914 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001915 {
1916 zlog (peer->log, LOG_WARNING,
1917 "%s: Attribute %s, parse error",
1918 peer->host,
1919 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001920 bgp_notify_send (peer,
1921 BGP_NOTIFY_UPDATE_ERR,
1922 BGP_NOTIFY_UPDATE_MAL_ATTR);
1923 if (as4_path)
1924 aspath_unintern (&as4_path);
1925 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001926 }
Paul Jakmab881c702010-11-23 16:35:42 +00001927 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1928 {
1929
1930 zlog (peer->log, LOG_WARNING,
1931 "%s: Attribute %s, parse error - treating as withdrawal",
1932 peer->host,
1933 LOOKUP (attr_str, type));
1934 if (as4_path)
1935 aspath_unintern (&as4_path);
1936 return ret;
1937 }
1938
paul718e3742002-12-13 20:15:29 +00001939 /* Check the fetched length. */
1940 if (BGP_INPUT_PNT (peer) != attr_endp)
1941 {
1942 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001943 "%s: BGP attribute %s, fetch error",
1944 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001945 bgp_notify_send (peer,
1946 BGP_NOTIFY_UPDATE_ERR,
1947 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001948 if (as4_path)
1949 aspath_unintern (&as4_path);
1950 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001951 }
1952 }
1953
1954 /* Check final read pointer is same as end pointer. */
1955 if (BGP_INPUT_PNT (peer) != endp)
1956 {
1957 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001958 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001959 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001960 bgp_notify_send (peer,
1961 BGP_NOTIFY_UPDATE_ERR,
1962 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001963 if (as4_path)
1964 aspath_unintern (&as4_path);
1965 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001966 }
1967
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001968 /*
1969 * At this place we can see whether we got AS4_PATH and/or
1970 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1971 * We can not do this before we've read all attributes because
1972 * the as4 handling does not say whether AS4_PATH has to be sent
1973 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1974 * in relationship to AGGREGATOR.
1975 * So, to be defensive, we are not relying on any order and read
1976 * all attributes first, including these 32bit ones, and now,
1977 * afterwards, we look what and if something is to be done for as4.
1978 */
Paul Jakmab881c702010-11-23 16:35:42 +00001979 if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001980 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001981 {
1982 if (as4_path)
1983 aspath_unintern (&as4_path);
1984 return BGP_ATTR_PARSE_ERROR;
1985 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001986
1987 /* At this stage, we have done all fiddling with as4, and the
1988 * resulting info is in attr->aggregator resp. attr->aspath
1989 * so we can chuck as4_aggregator and as4_path alltogether in
1990 * order to save memory
1991 */
Paul Jakmab881c702010-11-23 16:35:42 +00001992 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001993 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001994 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001995 /* The flag that we got this is still there, but that does not
1996 * do any trouble
1997 */
1998 }
1999 /*
2000 * The "rest" of the code does nothing with as4_aggregator.
2001 * there is no memory attached specifically which is not part
2002 * of the attr.
2003 * so ignoring just means do nothing.
2004 */
2005 /*
2006 * Finally do the checks on the aspath we did not do yet
2007 * because we waited for a potentially synthesized aspath.
2008 */
Paul Jakmab881c702010-11-23 16:35:42 +00002009 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002010 {
Paul Jakmab881c702010-11-23 16:35:42 +00002011 ret = bgp_attr_aspath_check (peer, attr, flag);
2012 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002013 return ret;
2014 }
2015
paul718e3742002-12-13 20:15:29 +00002016 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002017 if (attr->extra && attr->extra->transit)
2018 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002019
Paul Jakmab881c702010-11-23 16:35:42 +00002020 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002021}
2022
2023/* Well-known attribute check. */
2024int
2025bgp_attr_check (struct peer *peer, struct attr *attr)
2026{
2027 u_char type = 0;
2028
2029 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2030 type = BGP_ATTR_ORIGIN;
2031
2032 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2033 type = BGP_ATTR_AS_PATH;
2034
2035 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2036 type = BGP_ATTR_NEXT_HOP;
2037
2038 if (peer_sort (peer) == BGP_PEER_IBGP
2039 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2040 type = BGP_ATTR_LOCAL_PREF;
2041
2042 if (type)
2043 {
2044 zlog (peer->log, LOG_WARNING,
2045 "%s Missing well-known attribute %d.",
2046 peer->host, type);
2047 bgp_notify_send_with_data (peer,
2048 BGP_NOTIFY_UPDATE_ERR,
2049 BGP_NOTIFY_UPDATE_MISS_ATTR,
2050 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002051 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002052 }
Paul Jakmab881c702010-11-23 16:35:42 +00002053 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002054}
2055
2056int stream_put_prefix (struct stream *, struct prefix *);
2057
2058/* Make attribute packet. */
2059bgp_size_t
2060bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2061 struct stream *s, struct attr *attr, struct prefix *p,
2062 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002063 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002064{
paulfe69a502005-09-10 16:55:02 +00002065 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002066 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002067 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002068 int send_as4_path = 0;
2069 int send_as4_aggregator = 0;
2070 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002071
2072 if (! bgp)
2073 bgp = bgp_get_default ();
2074
2075 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002076 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002077
2078 /* Origin attribute. */
2079 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2080 stream_putc (s, BGP_ATTR_ORIGIN);
2081 stream_putc (s, 1);
2082 stream_putc (s, attr->origin);
2083
2084 /* AS path attribute. */
2085
2086 /* If remote-peer is EBGP */
2087 if (peer_sort (peer) == BGP_PEER_EBGP
2088 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002089 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002090 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002091 {
2092 aspath = aspath_dup (attr->aspath);
2093
2094 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2095 {
2096 /* Strip the confed info, and then stuff our path CONFED_ID
2097 on the front */
2098 aspath = aspath_delete_confed_seq (aspath);
2099 aspath = aspath_add_seq (aspath, bgp->confed_id);
2100 }
2101 else
2102 {
2103 aspath = aspath_add_seq (aspath, peer->local_as);
2104 if (peer->change_local_as)
2105 aspath = aspath_add_seq (aspath, peer->change_local_as);
2106 }
2107 }
2108 else if (peer_sort (peer) == BGP_PEER_CONFED)
2109 {
2110 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2111 aspath = aspath_dup (attr->aspath);
2112 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2113 }
2114 else
2115 aspath = attr->aspath;
2116
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002117 /* If peer is not AS4 capable, then:
2118 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2119 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2120 * types are in it (i.e. exclude them if they are there)
2121 * AND do this only if there is at least one asnum > 65535 in the path!
2122 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2123 * all ASnums > 65535 to BGP_AS_TRANS
2124 */
paul718e3742002-12-13 20:15:29 +00002125
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002126 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2127 stream_putc (s, BGP_ATTR_AS_PATH);
2128 aspath_sizep = stream_get_endp (s);
2129 stream_putw (s, 0);
2130 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2131
2132 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2133 * in the path
2134 */
2135 if (!use32bit && aspath_has_as4 (aspath))
2136 send_as4_path = 1; /* we'll do this later, at the correct place */
2137
paul718e3742002-12-13 20:15:29 +00002138 /* Nexthop attribute. */
2139 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2140 {
2141 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2142 stream_putc (s, BGP_ATTR_NEXT_HOP);
2143 stream_putc (s, 4);
2144 if (safi == SAFI_MPLS_VPN)
2145 {
2146 if (attr->nexthop.s_addr == 0)
2147 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2148 else
2149 stream_put_ipv4 (s, attr->nexthop.s_addr);
2150 }
2151 else
2152 stream_put_ipv4 (s, attr->nexthop.s_addr);
2153 }
2154
2155 /* MED attribute. */
2156 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2157 {
2158 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2159 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2160 stream_putc (s, 4);
2161 stream_putl (s, attr->med);
2162 }
2163
2164 /* Local preference. */
2165 if (peer_sort (peer) == BGP_PEER_IBGP ||
2166 peer_sort (peer) == BGP_PEER_CONFED)
2167 {
2168 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2169 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2170 stream_putc (s, 4);
2171 stream_putl (s, attr->local_pref);
2172 }
2173
2174 /* Atomic aggregate. */
2175 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2176 {
2177 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2178 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2179 stream_putc (s, 0);
2180 }
2181
2182 /* Aggregator. */
2183 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2184 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002185 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002186
2187 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002188 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2189 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002190
2191 if (use32bit)
2192 {
2193 /* AS4 capable peer */
2194 stream_putc (s, 8);
2195 stream_putl (s, attr->extra->aggregator_as);
2196 }
2197 else
2198 {
2199 /* 2-byte AS peer */
2200 stream_putc (s, 6);
2201
2202 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2203 if ( attr->extra->aggregator_as > 65535 )
2204 {
2205 stream_putw (s, BGP_AS_TRANS);
2206
2207 /* we have to send AS4_AGGREGATOR, too.
2208 * we'll do that later in order to send attributes in ascending
2209 * order.
2210 */
2211 send_as4_aggregator = 1;
2212 }
2213 else
2214 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2215 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002216 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002217 }
2218
2219 /* Community attribute. */
2220 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2221 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2222 {
2223 if (attr->community->size * 4 > 255)
2224 {
2225 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2226 stream_putc (s, BGP_ATTR_COMMUNITIES);
2227 stream_putw (s, attr->community->size * 4);
2228 }
2229 else
2230 {
2231 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2232 stream_putc (s, BGP_ATTR_COMMUNITIES);
2233 stream_putc (s, attr->community->size * 4);
2234 }
2235 stream_put (s, attr->community->val, attr->community->size * 4);
2236 }
2237
2238 /* Route Reflector. */
2239 if (peer_sort (peer) == BGP_PEER_IBGP
2240 && from
2241 && peer_sort (from) == BGP_PEER_IBGP)
2242 {
2243 /* Originator ID. */
2244 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2245 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2246 stream_putc (s, 4);
2247
2248 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002249 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002250 else
2251 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002252
2253 /* Cluster list. */
2254 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2255 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2256
Paul Jakma9eda90c2007-08-30 13:36:17 +00002257 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002258 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002259 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002260 /* If this peer configuration's parent BGP has cluster_id. */
2261 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2262 stream_put_in_addr (s, &bgp->cluster_id);
2263 else
2264 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002265 stream_put (s, attr->extra->cluster->list,
2266 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002267 }
2268 else
2269 {
2270 stream_putc (s, 4);
2271 /* If this peer configuration's parent BGP has cluster_id. */
2272 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2273 stream_put_in_addr (s, &bgp->cluster_id);
2274 else
2275 stream_put_in_addr (s, &bgp->router_id);
2276 }
2277 }
2278
2279#ifdef HAVE_IPV6
2280 /* If p is IPv6 address put it into attribute. */
2281 if (p->family == AF_INET6)
2282 {
2283 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002284 struct attr_extra *attre = attr->extra;
2285
2286 assert (attr->extra);
2287
paul718e3742002-12-13 20:15:29 +00002288 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2289 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002290 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002291 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002292 stream_putw (s, AFI_IP6); /* AFI */
2293 stream_putc (s, safi); /* SAFI */
2294
Paul Jakmafb982c22007-05-04 20:15:47 +00002295 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002296
Paul Jakmafb982c22007-05-04 20:15:47 +00002297 if (attre->mp_nexthop_len == 16)
2298 stream_put (s, &attre->mp_nexthop_global, 16);
2299 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002300 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002301 stream_put (s, &attre->mp_nexthop_global, 16);
2302 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002303 }
2304
2305 /* SNPA */
2306 stream_putc (s, 0);
2307
paul718e3742002-12-13 20:15:29 +00002308 /* Prefix write. */
2309 stream_put_prefix (s, p);
2310
2311 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002312 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002313 }
2314#endif /* HAVE_IPV6 */
2315
2316 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2317 {
2318 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002319
2320 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2321 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002322 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002323 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002324 stream_putw (s, AFI_IP); /* AFI */
2325 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2326
2327 stream_putc (s, 4);
2328 stream_put_ipv4 (s, attr->nexthop.s_addr);
2329
2330 /* SNPA */
2331 stream_putc (s, 0);
2332
paul718e3742002-12-13 20:15:29 +00002333 /* Prefix write. */
2334 stream_put_prefix (s, p);
2335
2336 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002337 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002338 }
2339
2340 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2341 {
2342 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002343
2344 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2345 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002346 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002347 stream_putc (s, 0); /* Length of this attribute. */
2348 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002349 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002350
2351 stream_putc (s, 12);
2352 stream_putl (s, 0);
2353 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002354 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002355
2356 /* SNPA */
2357 stream_putc (s, 0);
2358
paul718e3742002-12-13 20:15:29 +00002359 /* Tag, RD, Prefix write. */
2360 stream_putc (s, p->prefixlen + 88);
2361 stream_put (s, tag, 3);
2362 stream_put (s, prd->val, 8);
2363 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2364
2365 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002366 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002367 }
2368
2369 /* Extended Communities attribute. */
2370 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2371 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2372 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002373 struct attr_extra *attre = attr->extra;
2374
2375 assert (attre);
2376
2377 if (peer_sort (peer) == BGP_PEER_IBGP
2378 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002379 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002380 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002381 {
2382 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2383 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002384 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002385 }
2386 else
2387 {
2388 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2389 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002390 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002391 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002392 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002393 }
2394 else
2395 {
paul5228ad22004-06-04 17:58:18 +00002396 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002397 int tbit;
2398 int ecom_tr_size = 0;
2399 int i;
2400
Paul Jakmafb982c22007-05-04 20:15:47 +00002401 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002402 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002403 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002404 tbit = *pnt;
2405
2406 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2407 continue;
2408
2409 ecom_tr_size++;
2410 }
2411
2412 if (ecom_tr_size)
2413 {
2414 if (ecom_tr_size * 8 > 255)
2415 {
2416 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2417 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2418 stream_putw (s, ecom_tr_size * 8);
2419 }
2420 else
2421 {
2422 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2423 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2424 stream_putc (s, ecom_tr_size * 8);
2425 }
2426
Paul Jakmafb982c22007-05-04 20:15:47 +00002427 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002428 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002429 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002430 tbit = *pnt;
2431
2432 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2433 continue;
2434
2435 stream_put (s, pnt, 8);
2436 }
2437 }
paul718e3742002-12-13 20:15:29 +00002438 }
paul718e3742002-12-13 20:15:29 +00002439 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002440
2441 if ( send_as4_path )
2442 {
2443 /* If the peer is NOT As4 capable, AND */
2444 /* there are ASnums > 65535 in path THEN
2445 * give out AS4_PATH */
2446
2447 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2448 * path segments!
2449 * Hm, I wonder... confederation things *should* only be at
2450 * the beginning of an aspath, right? Then we should use
2451 * aspath_delete_confed_seq for this, because it is already
2452 * there! (JK)
2453 * Folks, talk to me: what is reasonable here!?
2454 */
2455 aspath = aspath_delete_confed_seq (aspath);
2456
2457 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2458 stream_putc (s, BGP_ATTR_AS4_PATH);
2459 aspath_sizep = stream_get_endp (s);
2460 stream_putw (s, 0);
2461 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2462 }
2463
2464 if (aspath != attr->aspath)
2465 aspath_free (aspath);
2466
2467 if ( send_as4_aggregator )
2468 {
2469 assert (attr->extra);
2470
2471 /* send AS4_AGGREGATOR, at this place */
2472 /* this section of code moved here in order to ensure the correct
2473 * *ascending* order of attributes
2474 */
2475 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2476 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2477 stream_putc (s, 8);
2478 stream_putl (s, attr->extra->aggregator_as);
2479 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2480 }
Paul Jakma41367172007-08-06 15:24:51 +00002481
paul718e3742002-12-13 20:15:29 +00002482 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002483 if (attr->extra && attr->extra->transit)
2484 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002485
2486 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002487 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002488}
2489
2490bgp_size_t
2491bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2492 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002493 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002494{
2495 unsigned long cp;
2496 unsigned long attrlen_pnt;
2497 bgp_size_t size;
2498
paul9985f832005-02-09 15:51:56 +00002499 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002500
2501 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2502 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2503
paul9985f832005-02-09 15:51:56 +00002504 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002505 stream_putc (s, 0); /* Length of this attribute. */
2506
2507 stream_putw (s, family2afi (p->family));
2508
2509 if (safi == SAFI_MPLS_VPN)
2510 {
2511 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002512 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002513
2514 /* prefix. */
2515 stream_putc (s, p->prefixlen + 88);
2516 stream_put (s, tag, 3);
2517 stream_put (s, prd->val, 8);
2518 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2519 }
2520 else
2521 {
2522 /* SAFI */
2523 stream_putc (s, safi);
2524
2525 /* prefix */
2526 stream_put_prefix (s, p);
2527 }
2528
2529 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002530 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002531 stream_putc_at (s, attrlen_pnt, size);
2532
paul9985f832005-02-09 15:51:56 +00002533 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002534}
2535
2536/* Initialization of attribute. */
2537void
paulfe69a502005-09-10 16:55:02 +00002538bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002539{
paul718e3742002-12-13 20:15:29 +00002540 aspath_init ();
2541 attrhash_init ();
2542 community_init ();
2543 ecommunity_init ();
2544 cluster_init ();
2545 transit_init ();
2546}
2547
Chris Caputo228da422009-07-18 05:44:03 +00002548void
2549bgp_attr_finish (void)
2550{
2551 aspath_finish ();
2552 attrhash_finish ();
2553 community_finish ();
2554 ecommunity_finish ();
2555 cluster_finish ();
2556 transit_finish ();
2557}
2558
paul718e3742002-12-13 20:15:29 +00002559/* Make attribute packet. */
2560void
paula3845922003-10-18 01:30:50 +00002561bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2562 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002563{
2564 unsigned long cp;
2565 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002566 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002567 struct aspath *aspath;
2568
2569 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002570 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002571
2572 /* Place holder of length. */
2573 stream_putw (s, 0);
2574
2575 /* Origin attribute. */
2576 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2577 stream_putc (s, BGP_ATTR_ORIGIN);
2578 stream_putc (s, 1);
2579 stream_putc (s, attr->origin);
2580
2581 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002582
2583 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2584 stream_putc (s, BGP_ATTR_AS_PATH);
2585 aspath_lenp = stream_get_endp (s);
2586 stream_putw (s, 0);
2587
2588 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002589
2590 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002591 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2592 if(prefix != NULL
2593#ifdef HAVE_IPV6
2594 && prefix->family != AF_INET6
2595#endif /* HAVE_IPV6 */
2596 )
2597 {
2598 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2599 stream_putc (s, BGP_ATTR_NEXT_HOP);
2600 stream_putc (s, 4);
2601 stream_put_ipv4 (s, attr->nexthop.s_addr);
2602 }
paul718e3742002-12-13 20:15:29 +00002603
2604 /* MED attribute. */
2605 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2606 {
2607 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2608 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2609 stream_putc (s, 4);
2610 stream_putl (s, attr->med);
2611 }
2612
2613 /* Local preference. */
2614 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2615 {
2616 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2617 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2618 stream_putc (s, 4);
2619 stream_putl (s, attr->local_pref);
2620 }
2621
2622 /* Atomic aggregate. */
2623 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2624 {
2625 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2626 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2627 stream_putc (s, 0);
2628 }
2629
2630 /* Aggregator. */
2631 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2632 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002633 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002634 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2635 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002636 stream_putc (s, 8);
2637 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002638 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002639 }
2640
2641 /* Community attribute. */
2642 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2643 {
2644 if (attr->community->size * 4 > 255)
2645 {
2646 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2647 stream_putc (s, BGP_ATTR_COMMUNITIES);
2648 stream_putw (s, attr->community->size * 4);
2649 }
2650 else
2651 {
2652 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2653 stream_putc (s, BGP_ATTR_COMMUNITIES);
2654 stream_putc (s, attr->community->size * 4);
2655 }
2656 stream_put (s, attr->community->val, attr->community->size * 4);
2657 }
2658
paula3845922003-10-18 01:30:50 +00002659#ifdef HAVE_IPV6
2660 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002661 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2662 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002663 {
2664 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002665 struct attr_extra *attre = attr->extra;
2666
paula3845922003-10-18 01:30:50 +00002667 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2668 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002669 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002670
2671 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002672 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002673 stream_putw(s, AFI_IP6); /* AFI */
2674 stream_putc(s, SAFI_UNICAST); /* SAFI */
2675
2676 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002677 stream_putc(s, attre->mp_nexthop_len);
2678 stream_put(s, &attre->mp_nexthop_global, 16);
2679 if (attre->mp_nexthop_len == 32)
2680 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002681
2682 /* SNPA */
2683 stream_putc(s, 0);
2684
2685 /* Prefix */
2686 stream_put_prefix(s, prefix);
2687
2688 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002689 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002690 }
2691#endif /* HAVE_IPV6 */
2692
paul718e3742002-12-13 20:15:29 +00002693 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002694 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002695 stream_putw_at (s, cp, len);
2696}