blob: a2d4f4ba556420db77149869daf84963e03184fe [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{
paul718e3742002-12-13 20:15:29 +0000178 if (cluster->refcnt)
179 cluster->refcnt--;
180
181 if (cluster->refcnt == 0)
182 {
Stephen Hemminger9206f9e2011-12-18 19:43:40 +0400183 hash_release (cluster_hash, cluster);
paul718e3742002-12-13 20:15:29 +0000184 cluster_free (cluster);
185 }
186}
187
paul94f2b392005-06-28 12:44:16 +0000188static void
189cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000190{
191 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
192}
Chris Caputo228da422009-07-18 05:44:03 +0000193
194static void
195cluster_finish (void)
196{
197 hash_free (cluster_hash);
198 cluster_hash = NULL;
199}
paul718e3742002-12-13 20:15:29 +0000200
201/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700202static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000203
paul94f2b392005-06-28 12:44:16 +0000204static void
paul718e3742002-12-13 20:15:29 +0000205transit_free (struct transit *transit)
206{
207 if (transit->val)
208 XFREE (MTYPE_TRANSIT_VAL, transit->val);
209 XFREE (MTYPE_TRANSIT, transit);
210}
211
Paul Jakma923de652007-04-29 18:25:17 +0000212
paul94f2b392005-06-28 12:44:16 +0000213static void *
Paul Jakma923de652007-04-29 18:25:17 +0000214transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000215{
216 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000217 return p;
paul718e3742002-12-13 20:15:29 +0000218}
219
paul94f2b392005-06-28 12:44:16 +0000220static struct transit *
paul718e3742002-12-13 20:15:29 +0000221transit_intern (struct transit *transit)
222{
223 struct transit *find;
224
225 find = hash_get (transit_hash, transit, transit_hash_alloc);
226 if (find != transit)
227 transit_free (transit);
228 find->refcnt++;
229
230 return find;
231}
232
233void
234transit_unintern (struct transit *transit)
235{
paul718e3742002-12-13 20:15:29 +0000236 if (transit->refcnt)
237 transit->refcnt--;
238
239 if (transit->refcnt == 0)
240 {
Stephen Hemminger9206f9e2011-12-18 19:43:40 +0400241 hash_release (transit_hash, transit);
paul718e3742002-12-13 20:15:29 +0000242 transit_free (transit);
243 }
244}
245
paul94f2b392005-06-28 12:44:16 +0000246static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000247transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000248{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700249 const struct transit * transit = p;
paul718e3742002-12-13 20:15:29 +0000250
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700251 return jhash(transit->val, transit->length, 0);
paul718e3742002-12-13 20:15:29 +0000252}
253
paul94f2b392005-06-28 12:44:16 +0000254static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100255transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000256{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100257 const struct transit * transit1 = p1;
258 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000259
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100260 return (transit1->length == transit2->length &&
261 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000262}
263
paul94f2b392005-06-28 12:44:16 +0000264static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800265transit_init (void)
paul718e3742002-12-13 20:15:29 +0000266{
267 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
268}
Chris Caputo228da422009-07-18 05:44:03 +0000269
270static void
271transit_finish (void)
272{
273 hash_free (transit_hash);
274 transit_hash = NULL;
275}
paul718e3742002-12-13 20:15:29 +0000276
277/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700278static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000279
Paul Jakmafb982c22007-05-04 20:15:47 +0000280static struct attr_extra *
281bgp_attr_extra_new (void)
282{
283 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
284}
285
286void
287bgp_attr_extra_free (struct attr *attr)
288{
289 if (attr->extra)
290 {
291 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
292 attr->extra = NULL;
293 }
294}
295
296struct attr_extra *
297bgp_attr_extra_get (struct attr *attr)
298{
299 if (!attr->extra)
300 attr->extra = bgp_attr_extra_new();
301 return attr->extra;
302}
303
304/* Shallow copy of an attribute
305 * Though, not so shallow that it doesn't copy the contents
306 * of the attr_extra pointed to by 'extra'
307 */
308void
309bgp_attr_dup (struct attr *new, struct attr *orig)
310{
311 *new = *orig;
312 if (orig->extra)
313 {
314 new->extra = bgp_attr_extra_new();
315 *new->extra = *orig->extra;
316 }
317}
318
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000319unsigned long int
320attr_count (void)
321{
322 return attrhash->count;
323}
324
325unsigned long int
326attr_unknown_count (void)
327{
328 return transit_hash->count;
329}
330
paul718e3742002-12-13 20:15:29 +0000331unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000332attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000333{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700334 const struct attr * attr = (struct attr *) p;
335 uint32_t key = 0;
336#define MIX(val) key = jhash_1word(val, key)
paul718e3742002-12-13 20:15:29 +0000337
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700338 MIX(attr->origin);
339 MIX(attr->nexthop.s_addr);
340 MIX(attr->med);
341 MIX(attr->local_pref);
342
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000343 key += attr->origin;
344 key += attr->nexthop.s_addr;
345 key += attr->med;
346 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000347
348 if (attr->extra)
349 {
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700350 MIX(attr->extra->aggregator_as);
351 MIX(attr->extra->aggregator_addr.s_addr);
352 MIX(attr->extra->weight);
353 MIX(attr->extra->mp_nexthop_global_in.s_addr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000354 }
355
paul718e3742002-12-13 20:15:29 +0000356 if (attr->aspath)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700357 MIX(aspath_key_make (attr->aspath));
paul718e3742002-12-13 20:15:29 +0000358 if (attr->community)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700359 MIX(community_hash_make (attr->community));
Paul Jakmafb982c22007-05-04 20:15:47 +0000360
361 if (attr->extra)
362 {
363 if (attr->extra->ecommunity)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700364 MIX(ecommunity_hash_make (attr->extra->ecommunity));
Paul Jakmafb982c22007-05-04 20:15:47 +0000365 if (attr->extra->cluster)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700366 MIX(cluster_hash_key_make (attr->extra->cluster));
Paul Jakmafb982c22007-05-04 20:15:47 +0000367 if (attr->extra->transit)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700368 MIX(transit_hash_key_make (attr->extra->transit));
paul718e3742002-12-13 20:15:29 +0000369
370#ifdef HAVE_IPV6
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700371 MIX(attr->extra->mp_nexthop_len);
Paul Jakma31d0f1b2011-03-29 14:18:49 +0100372 key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key);
373 key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key);
paul718e3742002-12-13 20:15:29 +0000374#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000375 }
paul718e3742002-12-13 20:15:29 +0000376
377 return key;
378}
379
380int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100381attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000382{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100383 const struct attr * attr1 = p1;
384 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000385
paul718e3742002-12-13 20:15:29 +0000386 if (attr1->flag == attr2->flag
387 && attr1->origin == attr2->origin
388 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000389 && attr1->aspath == attr2->aspath
390 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000391 && attr1->med == attr2->med
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000392 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000393 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100394 const struct attr_extra *ae1 = attr1->extra;
395 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000396
397 if (ae1 && ae2
398 && ae1->aggregator_as == ae2->aggregator_as
399 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
400 && ae1->weight == ae2->weight
401#ifdef HAVE_IPV6
402 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
403 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
404 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
405#endif /* HAVE_IPV6 */
406 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
407 && ae1->ecommunity == ae2->ecommunity
408 && ae1->cluster == ae2->cluster
409 && ae1->transit == ae2->transit)
410 return 1;
411 else if (ae1 || ae2)
412 return 0;
413 /* neither attribute has extra attributes, so they're same */
414 return 1;
415 }
paul718e3742002-12-13 20:15:29 +0000416 else
417 return 0;
418}
419
paul94f2b392005-06-28 12:44:16 +0000420static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100421attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000422{
423 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
424}
425
paul94f2b392005-06-28 12:44:16 +0000426static void
Chris Caputo228da422009-07-18 05:44:03 +0000427attrhash_finish (void)
428{
429 hash_free (attrhash);
430 attrhash = NULL;
431}
432
433static void
paul718e3742002-12-13 20:15:29 +0000434attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
435{
436 struct attr *attr = backet->data;
437
438 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
439 inet_ntoa (attr->nexthop), VTY_NEWLINE);
440}
441
442void
443attr_show_all (struct vty *vty)
444{
445 hash_iterate (attrhash,
446 (void (*)(struct hash_backet *, void *))
447 attr_show_all_iterator,
448 vty);
449}
450
paul94f2b392005-06-28 12:44:16 +0000451static void *
Paul Jakma923de652007-04-29 18:25:17 +0000452bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000453{
Paul Jakma923de652007-04-29 18:25:17 +0000454 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000455 struct attr *attr;
456
457 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
458 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000459 if (val->extra)
460 {
461 attr->extra = bgp_attr_extra_new ();
462 *attr->extra = *val->extra;
463 }
paul718e3742002-12-13 20:15:29 +0000464 attr->refcnt = 0;
465 return attr;
466}
467
468/* Internet argument attribute. */
469struct attr *
470bgp_attr_intern (struct attr *attr)
471{
472 struct attr *find;
473
474 /* Intern referenced strucutre. */
475 if (attr->aspath)
476 {
477 if (! attr->aspath->refcnt)
478 attr->aspath = aspath_intern (attr->aspath);
479 else
480 attr->aspath->refcnt++;
481 }
482 if (attr->community)
483 {
484 if (! attr->community->refcnt)
485 attr->community = community_intern (attr->community);
486 else
487 attr->community->refcnt++;
488 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000489 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000490 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000491 struct attr_extra *attre = attr->extra;
492
493 if (attre->ecommunity)
494 {
495 if (! attre->ecommunity->refcnt)
496 attre->ecommunity = ecommunity_intern (attre->ecommunity);
497 else
498 attre->ecommunity->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000499
Paul Jakmafb982c22007-05-04 20:15:47 +0000500 }
501 if (attre->cluster)
502 {
503 if (! attre->cluster->refcnt)
504 attre->cluster = cluster_intern (attre->cluster);
505 else
506 attre->cluster->refcnt++;
507 }
508 if (attre->transit)
509 {
510 if (! attre->transit->refcnt)
511 attre->transit = transit_intern (attre->transit);
512 else
513 attre->transit->refcnt++;
514 }
paul718e3742002-12-13 20:15:29 +0000515 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000516
paul718e3742002-12-13 20:15:29 +0000517 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
518 find->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000519
paul718e3742002-12-13 20:15:29 +0000520 return find;
521}
522
Paul Jakma03e214c2007-04-29 18:31:07 +0000523
paul718e3742002-12-13 20:15:29 +0000524/* Make network statement's attribute. */
525struct attr *
526bgp_attr_default_set (struct attr *attr, u_char origin)
527{
528 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000529 bgp_attr_extra_get (attr);
530
paul718e3742002-12-13 20:15:29 +0000531 attr->origin = origin;
532 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
533 attr->aspath = aspath_empty ();
534 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000535 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000536 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
537#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000538 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000539#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000540
paul718e3742002-12-13 20:15:29 +0000541 return attr;
542}
543
Paul Jakma03e214c2007-04-29 18:31:07 +0000544
paul718e3742002-12-13 20:15:29 +0000545/* Make network statement's attribute. */
546struct attr *
547bgp_attr_default_intern (u_char origin)
548{
549 struct attr attr;
550 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000551
552 memset (&attr, 0, sizeof (struct attr));
Stephen Hemminger9206f9e2011-12-18 19:43:40 +0400553 bgp_attr_extra_get (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000554
Paul Jakma03e214c2007-04-29 18:31:07 +0000555 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000556
557 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000558 bgp_attr_extra_free (&attr);
559
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000560 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000561 return new;
562}
563
564struct attr *
565bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
566 struct aspath *aspath,
567 struct community *community, int as_set)
568{
569 struct attr attr;
570 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000571 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000572
573 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000574 attre = bgp_attr_extra_get (&attr);
575
paul718e3742002-12-13 20:15:29 +0000576 /* Origin attribute. */
577 attr.origin = origin;
578 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
579
580 /* AS path attribute. */
581 if (aspath)
582 attr.aspath = aspath_intern (aspath);
583 else
584 attr.aspath = aspath_empty ();
585 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
586
587 /* Next hop attribute. */
588 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
589
590 if (community)
591 {
592 attr.community = community;
593 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
594 }
595
Paul Jakmafb982c22007-05-04 20:15:47 +0000596 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000597#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000598 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000599#endif
600 if (! as_set)
601 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
602 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
603 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000604 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000605 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000606 attre->aggregator_as = bgp->as;
607 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000608
609 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000610 bgp_attr_extra_free (&attr);
611
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000612 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000613 return new;
614}
615
Paul Jakmab881c702010-11-23 16:35:42 +0000616/* Unintern just the sub-components of the attr, but not the attr */
617void
618bgp_attr_unintern_sub (struct attr *attr)
619{
620 /* aspath refcount shoud be decrement. */
621 if (attr->aspath)
622 aspath_unintern (&attr->aspath);
623 UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
624
625 if (attr->community)
626 community_unintern (&attr->community);
627 UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
628
629 if (attr->extra)
630 {
631 if (attr->extra->ecommunity)
632 ecommunity_unintern (&attr->extra->ecommunity);
633 UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
634
635 if (attr->extra->cluster)
636 cluster_unintern (attr->extra->cluster);
637 UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
638
639 if (attr->extra->transit)
640 transit_unintern (attr->extra->transit);
641 }
642}
643
paul718e3742002-12-13 20:15:29 +0000644/* Free bgp attribute and aspath. */
645void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000646bgp_attr_unintern (struct attr **attr)
paul718e3742002-12-13 20:15:29 +0000647{
648 struct attr *ret;
Paul Jakmab881c702010-11-23 16:35:42 +0000649 struct attr tmp;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000650
paul718e3742002-12-13 20:15:29 +0000651 /* Decrement attribute reference. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000652 (*attr)->refcnt--;
Paul Jakmab881c702010-11-23 16:35:42 +0000653
654 tmp = *(*attr);
655
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000656 if ((*attr)->extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000657 {
Paul Jakmab881c702010-11-23 16:35:42 +0000658 tmp.extra = bgp_attr_extra_new ();
659 memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra));
Paul Jakmafb982c22007-05-04 20:15:47 +0000660 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000661
paul718e3742002-12-13 20:15:29 +0000662 /* If reference becomes zero then free attribute object. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000663 if ((*attr)->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000664 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000665 ret = hash_release (attrhash, *attr);
paul718e3742002-12-13 20:15:29 +0000666 assert (ret != NULL);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000667 bgp_attr_extra_free (*attr);
668 XFREE (MTYPE_ATTR, *attr);
669 *attr = NULL;
paul718e3742002-12-13 20:15:29 +0000670 }
671
Paul Jakmab881c702010-11-23 16:35:42 +0000672 bgp_attr_unintern_sub (&tmp);
Oleg A. Arkhangelskyce0af6f2011-12-03 15:18:19 +0400673 bgp_attr_extra_free (&tmp);
paul718e3742002-12-13 20:15:29 +0000674}
675
676void
677bgp_attr_flush (struct attr *attr)
678{
679 if (attr->aspath && ! attr->aspath->refcnt)
680 aspath_free (attr->aspath);
681 if (attr->community && ! attr->community->refcnt)
682 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000683 if (attr->extra)
684 {
685 struct attr_extra *attre = attr->extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000686
Paul Jakmafb982c22007-05-04 20:15:47 +0000687 if (attre->ecommunity && ! attre->ecommunity->refcnt)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000688 ecommunity_free (&attre->ecommunity);
Paul Jakmafb982c22007-05-04 20:15:47 +0000689 if (attre->cluster && ! attre->cluster->refcnt)
690 cluster_free (attre->cluster);
691 if (attre->transit && ! attre->transit->refcnt)
692 transit_free (attre->transit);
693 }
paul718e3742002-12-13 20:15:29 +0000694}
695
Paul Jakmab881c702010-11-23 16:35:42 +0000696/* Implement draft-scudder-idr-optional-transitive behaviour and
697 * avoid resetting sessions for malformed attributes which are
698 * are partial/optional and hence where the error likely was not
699 * introduced by the sending neighbour.
700 */
701static bgp_attr_parse_ret_t
702bgp_attr_malformed (struct peer *peer, u_char type, u_char flag,
703 u_char subcode, u_char *startp, bgp_size_t length)
704{
705 /* Only relax error handling for eBGP peers */
706 if (peer_sort (peer) != BGP_PEER_EBGP)
707 {
708 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
709 startp, length);
710 return BGP_ATTR_PARSE_ERROR;
711
712 }
713
714 switch (type) {
715 /* where an optional attribute is inconsequential, e.g. it does not affect
716 * route selection, and can be safely ignored then any such attributes
717 * which are malformed should just be ignored and the route processed as
718 * normal.
719 */
720 case BGP_ATTR_AS4_AGGREGATOR:
721 case BGP_ATTR_AGGREGATOR:
722 case BGP_ATTR_ATOMIC_AGGREGATE:
723 return BGP_ATTR_PARSE_PROCEED;
724
725 /* Core attributes, particularly ones which may influence route
726 * selection should always cause session resets
727 */
728 case BGP_ATTR_ORIGIN:
729 case BGP_ATTR_AS_PATH:
730 case BGP_ATTR_NEXT_HOP:
731 case BGP_ATTR_MULTI_EXIT_DISC:
732 case BGP_ATTR_LOCAL_PREF:
733 case BGP_ATTR_COMMUNITIES:
734 case BGP_ATTR_ORIGINATOR_ID:
735 case BGP_ATTR_CLUSTER_LIST:
736 case BGP_ATTR_MP_REACH_NLRI:
737 case BGP_ATTR_MP_UNREACH_NLRI:
738 case BGP_ATTR_EXT_COMMUNITIES:
739 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
740 startp, length);
741 return BGP_ATTR_PARSE_ERROR;
742 }
743
744 /* Partial optional attributes that are malformed should not cause
745 * the whole session to be reset. Instead treat it as a withdrawal
746 * of the routes, if possible.
747 */
748 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)
749 && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
750 && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
751 return BGP_ATTR_PARSE_WITHDRAW;
752
753 /* default to reset */
754 return BGP_ATTR_PARSE_ERROR;
755}
756
paul718e3742002-12-13 20:15:29 +0000757/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000758static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000759bgp_attr_origin (struct peer *peer, bgp_size_t length,
760 struct attr *attr, u_char flag, u_char *startp)
761{
762 bgp_size_t total;
763
764 /* total is entire attribute length include Attribute Flags (1),
765 Attribute Type code (1) and Attribute length (1 or 2). */
766 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
767
768 /* If any recognized attribute has Attribute Flags that conflict
769 with the Attribute Type Code, then the Error Subcode is set to
770 Attribute Flags Error. The Data field contains the erroneous
771 attribute (type, length and value). */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +0400772 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +0400773 {
774 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
775 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag);
776 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
777 zlog (peer->log, LOG_ERR, "ORIGIN attribute must be flagged as \"transitive\" (%u)", flag);
778 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
779 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"partial\" (%u)", flag);
780 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
781 }
paul718e3742002-12-13 20:15:29 +0000782
783 /* If any recognized attribute has Attribute Length that conflicts
784 with the expected length (based on the attribute type code), then
785 the Error Subcode is set to Attribute Length Error. The Data
786 field contains the erroneous attribute (type, length and
787 value). */
788 if (length != 1)
789 {
790 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
791 length);
Paul Jakmab881c702010-11-23 16:35:42 +0000792 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
793 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
794 startp, total);
paul718e3742002-12-13 20:15:29 +0000795 }
796
797 /* Fetch origin attribute. */
798 attr->origin = stream_getc (BGP_INPUT (peer));
799
800 /* If the ORIGIN attribute has an undefined value, then the Error
801 Subcode is set to Invalid Origin Attribute. The Data field
802 contains the unrecognized attribute (type, length and value). */
803 if ((attr->origin != BGP_ORIGIN_IGP)
804 && (attr->origin != BGP_ORIGIN_EGP)
805 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
806 {
807 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
808 attr->origin);
Paul Jakmab881c702010-11-23 16:35:42 +0000809 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
810 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
811 startp, total);
paul718e3742002-12-13 20:15:29 +0000812 }
813
814 /* Set oring attribute flag. */
815 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
816
817 return 0;
818}
Paul Jakmaab005292010-11-27 22:48:34 +0000819
820/* Parse AS path information. This function is wrapper of
821 aspath_parse. */
822static int
paul718e3742002-12-13 20:15:29 +0000823bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Paul Jakmaab005292010-11-27 22:48:34 +0000824 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +0000825{
Paul Jakmaab005292010-11-27 22:48:34 +0000826 bgp_size_t total;
paul718e3742002-12-13 20:15:29 +0000827
Paul Jakmaab005292010-11-27 22:48:34 +0000828 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000829
Paul Jakmaab005292010-11-27 22:48:34 +0000830 /* Flag check. */
Denis Ovsienko214bcaa2011-09-24 13:20:43 +0400831 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
832 {
833 zlog (peer->log, LOG_ERR,
834 "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag);
835 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
836 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
837 startp, total);
838 }
839
Paul Jakmaab005292010-11-27 22:48:34 +0000840 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
841 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000842 {
843 zlog (peer->log, LOG_ERR,
Paul Jakmaab005292010-11-27 22:48:34 +0000844 "As-Path attribute flag isn't transitive %d", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000845 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
846 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
847 startp, total);
Chris Hallcddb8112010-08-09 22:31:37 +0400848 }
Paul Jakmaab005292010-11-27 22:48:34 +0000849
850 /*
851 * peer with AS4 => will get 4Byte ASnums
852 * otherwise, will get 16 Bit
853 */
854 attr->aspath = aspath_parse (peer->ibuf, length,
855 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
856
857 /* In case of IBGP, length will be zero. */
858 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000859 {
Paul Jakmab881c702010-11-23 16:35:42 +0000860 zlog (peer->log, LOG_ERR,
861 "Malformed AS path from %s, length is %d",
862 peer->host, length);
863 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
864 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
865 NULL, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000866 }
Chris Hallcddb8112010-08-09 22:31:37 +0400867
Paul Jakmaab005292010-11-27 22:48:34 +0000868 /* Set aspath attribute flag. */
869 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000870
Paul Jakmab881c702010-11-23 16:35:42 +0000871 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000872}
873
Paul Jakmab881c702010-11-23 16:35:42 +0000874static bgp_attr_parse_ret_t
875bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000876{
877 /* These checks were part of bgp_attr_aspath, but with
878 * as4 we should to check aspath things when
879 * aspath synthesizing with as4_path has already taken place.
880 * Otherwise we check ASPATH and use the synthesized thing, and that is
881 * not right.
882 * So do the checks later, i.e. here
883 */
884 struct bgp *bgp = peer->bgp;
885 struct aspath *aspath;
886
paul718e3742002-12-13 20:15:29 +0000887 bgp = peer->bgp;
888
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300889 /* Confederation sanity check. */
890 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
891 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
892 {
893 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +0000894 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
895 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
896 NULL, 0);
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300897 }
898
paul718e3742002-12-13 20:15:29 +0000899 /* First AS check for EBGP. */
900 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
901 {
902 if (peer_sort (peer) == BGP_PEER_EBGP
903 && ! aspath_firstas_check (attr->aspath, peer->as))
904 {
905 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400906 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakmab881c702010-11-23 16:35:42 +0000907 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
908 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
909 NULL, 0);
paul718e3742002-12-13 20:15:29 +0000910 }
911 }
912
913 /* local-as prepend */
914 if (peer->change_local_as &&
915 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
916 {
917 aspath = aspath_dup (attr->aspath);
918 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000919 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +0000920 attr->aspath = aspath_intern (aspath);
921 }
922
Paul Jakmab881c702010-11-23 16:35:42 +0000923 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000924}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000925
Paul Jakmaab005292010-11-27 22:48:34 +0000926/* Parse AS4 path information. This function is another wrapper of
927 aspath_parse. */
928static int
Paul Jakmab881c702010-11-23 16:35:42 +0000929bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
930 struct attr *attr, u_char flag, u_char *startp,
931 struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +0000932{
Paul Jakmab881c702010-11-23 16:35:42 +0000933 bgp_size_t total;
934
935 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
936
937 /* Flag check. */
938 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
939 || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
940 {
941 zlog (peer->log, LOG_ERR,
942 "As4-Path attribute flag isn't optional/transitive %d", flag);
943 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
944 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
945 startp, total);
946 }
947
Paul Jakmaab005292010-11-27 22:48:34 +0000948 *as4_path = aspath_parse (peer->ibuf, length, 1);
949
Paul Jakmab881c702010-11-23 16:35:42 +0000950 /* In case of IBGP, length will be zero. */
951 if (!*as4_path)
952 {
953 zlog (peer->log, LOG_ERR,
954 "Malformed AS4 path from %s, length is %d",
955 peer->host, length);
956 return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
957 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
958 NULL, 0);
959 }
960
Paul Jakmaab005292010-11-27 22:48:34 +0000961 /* Set aspath attribute flag. */
962 if (as4_path)
963 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
964
Paul Jakmab881c702010-11-23 16:35:42 +0000965 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000966}
967
paul718e3742002-12-13 20:15:29 +0000968/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +0000969static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000970bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
971 struct attr *attr, u_char flag, u_char *startp)
972{
973 bgp_size_t total;
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400974 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +0000975
976 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
977
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400978 /* Flags check. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +0400979 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +0400980 {
981 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
982 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag);
983 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
984 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag);
985 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
986 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag);
987 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
988 }
paul718e3742002-12-13 20:15:29 +0000989
990 /* Check nexthop attribute length. */
991 if (length != 4)
992 {
993 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
994 length);
995
Paul Jakmab881c702010-11-23 16:35:42 +0000996 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
997 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
998 startp, total);
paul718e3742002-12-13 20:15:29 +0000999 }
1000
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001001 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1002 attribute must result in a NOTIFICATION message (this is implemented below).
1003 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1004 logged locally (this is implemented somewhere else). The UPDATE message
1005 gets ignored in any of these cases. */
1006 nexthop_n = stream_get_ipv4 (peer->ibuf);
1007 nexthop_h = ntohl (nexthop_n);
1008 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1009 {
1010 char buf[INET_ADDRSTRLEN];
1011 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1012 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
1013 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1014 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
1015 startp, total);
1016 }
1017
1018 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001019 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1020
Paul Jakmab881c702010-11-23 16:35:42 +00001021 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001022}
1023
1024/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001025static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001026bgp_attr_med (struct peer *peer, bgp_size_t length,
1027 struct attr *attr, u_char flag, u_char *startp)
1028{
1029 bgp_size_t total;
1030
1031 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1032
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001033 /* Flag checks. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001034 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001035 {
1036 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1037 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
1038 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1039 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
1040 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1041 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001042 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1043 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1044 startp, total);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001045 }
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001046
paul718e3742002-12-13 20:15:29 +00001047 /* Length check. */
1048 if (length != 4)
1049 {
1050 zlog (peer->log, LOG_ERR,
1051 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001052
1053 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1054 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1055 startp, total);
paul718e3742002-12-13 20:15:29 +00001056 }
1057
1058 attr->med = stream_getl (peer->ibuf);
1059
1060 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1061
Paul Jakmab881c702010-11-23 16:35:42 +00001062 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001063}
1064
1065/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001066static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001067bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001068 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001069{
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001070 bgp_size_t total;
1071
1072 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1073 /* Flag checks. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001074 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001075 {
1076 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1077 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"optional\" (%u)", flag);
1078 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1079 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1080 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1081 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001082 return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag,
1083 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1084 startp, total);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001085 }
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001086 /* Length check. */
1087 if (length != 4)
1088 {
1089 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001090 return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001091 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1092 startp, total);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001093 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001094
paul718e3742002-12-13 20:15:29 +00001095 /* If it is contained in an UPDATE message that is received from an
1096 external peer, then this attribute MUST be ignored by the
1097 receiving speaker. */
1098 if (peer_sort (peer) == BGP_PEER_EBGP)
1099 {
paul9985f832005-02-09 15:51:56 +00001100 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001101 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001102 }
1103
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001104 attr->local_pref = stream_getl (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001105
1106 /* Set atomic aggregate flag. */
1107 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1108
Paul Jakmab881c702010-11-23 16:35:42 +00001109 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001110}
1111
1112/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001113static int
paul718e3742002-12-13 20:15:29 +00001114bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001115 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001116{
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001117 bgp_size_t total;
1118
1119 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1120 /* Flag checks. */
Denis Ovsienkoa5b228b2011-10-12 13:54:21 +04001121 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001122 {
1123 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1124 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
1125 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1126 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
1127 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1128 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001129 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1130 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1131 startp, total);
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001132 }
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001133
1134 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001135 if (length != 0)
1136 {
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001137 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001138 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1139 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001140 startp, total);
paul718e3742002-12-13 20:15:29 +00001141 }
1142
1143 /* Set atomic aggregate flag. */
1144 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1145
Paul Jakmab881c702010-11-23 16:35:42 +00001146 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001147}
1148
1149/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001150static int
paul718e3742002-12-13 20:15:29 +00001151bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001152 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001153{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001154 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001155 struct attr_extra *attre = bgp_attr_extra_get (attr);
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001156 bgp_size_t total;
Paul Jakmafb982c22007-05-04 20:15:47 +00001157
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001158 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
Denis Ovsienkob4cd2422011-10-22 22:32:26 +04001159 /* Flags check. */
1160 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1161 {
1162 zlog (peer->log, LOG_ERR,
1163 "AGGREGATOR attribute must be flagged as \"optional\" (%u)", flag);
1164 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1165 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1166 startp, total);
1167 }
1168 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1169 {
1170 zlog (peer->log, LOG_ERR,
1171 "AGGREGATOR attribute must be flagged as \"transitive\" (%u)", flag);
1172 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1173 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1174 startp, total);
1175 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001176 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001177 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001178 wantedlen = 8;
1179
1180 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001181 {
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001182 zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", wantedlen, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001183 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1184 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001185 startp, total);
paul718e3742002-12-13 20:15:29 +00001186 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001187
1188 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1189 attre->aggregator_as = stream_getl (peer->ibuf);
1190 else
1191 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001192 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001193
1194 /* Set atomic aggregate flag. */
1195 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1196
Paul Jakmab881c702010-11-23 16:35:42 +00001197 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001198}
1199
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001200/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001201static bgp_attr_parse_ret_t
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001202bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001203 struct attr *attr, u_char flag,
1204 as_t *as4_aggregator_as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001205 struct in_addr *as4_aggregator_addr)
1206{
1207 if (length != 8)
1208 {
1209 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001210 return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
1211 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1212 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001213 }
1214 *as4_aggregator_as = stream_getl (peer->ibuf);
1215 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1216
1217 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1218
Paul Jakmab881c702010-11-23 16:35:42 +00001219 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001220}
1221
1222/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1223 */
Paul Jakmab881c702010-11-23 16:35:42 +00001224static bgp_attr_parse_ret_t
1225bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001226 struct aspath *as4_path, as_t as4_aggregator,
1227 struct in_addr *as4_aggregator_addr)
1228{
1229 int ignore_as4_path = 0;
1230 struct aspath *newpath;
1231 struct attr_extra *attre = attr->extra;
1232
Paul Jakmab881c702010-11-23 16:35:42 +00001233 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001234 {
1235 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1236 * if given.
1237 * It is worth a warning though, because the peer really
1238 * should not send them
1239 */
1240 if (BGP_DEBUG(as4, AS4))
1241 {
1242 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1243 zlog_debug ("[AS4] %s %s AS4_PATH",
1244 peer->host, "AS4 capable peer, yet it sent");
1245
1246 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1247 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1248 peer->host, "AS4 capable peer, yet it sent");
1249 }
1250
Paul Jakmab881c702010-11-23 16:35:42 +00001251 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001252 }
1253
Paul Jakmab881c702010-11-23 16:35:42 +00001254 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
1255 && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001256 {
1257 /* Hu? This is not supposed to happen at all!
1258 * got as4_path and no aspath,
1259 * This should already
1260 * have been handled by 'well known attributes missing'
1261 * But... yeah, paranoia
1262 * Take this as a "malformed attribute"
1263 */
1264 zlog (peer->log, LOG_ERR,
1265 "%s BGP not AS4 capable peer sent AS4_PATH but"
1266 " no AS_PATH, cant do anything here", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001267 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1268 BGP_NOTIFY_UPDATE_MAL_ATTR,
1269 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001270 }
1271
1272 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1273 * because that may override AS4_PATH
1274 */
1275 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1276 {
Paul Jakmab881c702010-11-23 16:35:42 +00001277 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001278 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001279 assert (attre);
1280
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001281 /* received both.
1282 * if the as_number in aggregator is not AS_TRANS,
1283 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1284 * and the Aggregator shall be taken as
1285 * info on the aggregating node, and the AS_PATH
1286 * shall be taken as the AS_PATH
1287 * otherwise
1288 * the Aggregator shall be ignored and the
1289 * AS4_AGGREGATOR shall be taken as the
1290 * Aggregating node and the AS_PATH is to be
1291 * constructed "as in all other cases"
1292 */
Paul Jakmab881c702010-11-23 16:35:42 +00001293 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001294 {
1295 /* ignore */
1296 if ( BGP_DEBUG(as4, AS4))
1297 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1298 " send AGGREGATOR != AS_TRANS and"
1299 " AS4_AGGREGATOR, so ignore"
1300 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1301 ignore_as4_path = 1;
1302 }
1303 else
1304 {
1305 /* "New_aggregator shall be taken as aggregator" */
1306 attre->aggregator_as = as4_aggregator;
1307 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1308 }
1309 }
1310 else
1311 {
1312 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1313 * That is bogus - but reading the conditions
1314 * we have to handle AS4_AGGREGATOR as if it were
1315 * AGGREGATOR in that case
1316 */
1317 if ( BGP_DEBUG(as4, AS4))
1318 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1319 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1320 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001321 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001322 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1323 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1324 }
1325 }
1326
1327 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001328 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001329 {
1330 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001331 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001332 attr->aspath = aspath_intern (newpath);
1333 }
Paul Jakmab881c702010-11-23 16:35:42 +00001334 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001335}
1336
paul718e3742002-12-13 20:15:29 +00001337/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001338static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001339bgp_attr_community (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001340 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001341{
Paul Jakmab881c702010-11-23 16:35:42 +00001342 bgp_size_t total
1343 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1344
paul718e3742002-12-13 20:15:29 +00001345 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001346 {
1347 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001348 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001349 }
Paul Jakma0c466382010-12-05 17:17:26 +00001350
1351 attr->community =
1352 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1353
1354 /* XXX: fix community_parse to use stream API and remove this */
1355 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001356
Paul Jakma0c466382010-12-05 17:17:26 +00001357 if (!attr->community)
Paul Jakmab881c702010-11-23 16:35:42 +00001358 return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
1359 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1360 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001361
paul718e3742002-12-13 20:15:29 +00001362 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1363
Paul Jakmab881c702010-11-23 16:35:42 +00001364 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001365}
1366
1367/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001368static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001369bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
Denis Ovsienkod595b562011-09-30 15:08:54 +04001370 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001371{
Denis Ovsienkod595b562011-09-30 15:08:54 +04001372 bgp_size_t total;
1373
1374 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1375 /* Flag checks. */
Denis Ovsienkobbb04bf2011-10-18 14:20:04 +04001376 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienkod595b562011-09-30 15:08:54 +04001377 {
1378 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1379 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must be flagged as \"optional\" (%u)", flag);
1380 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1381 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"transitive\" (%u)", flag);
1382 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1383 zlog (peer->log, LOG_ERR, "ORIGINATOR_ID attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001384 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1385 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1386 startp, total);
Denis Ovsienkod595b562011-09-30 15:08:54 +04001387 }
1388 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001389 if (length != 4)
1390 {
1391 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1392
Paul Jakmab881c702010-11-23 16:35:42 +00001393 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1394 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienko26755182011-10-26 19:34:30 +04001395 startp, total);
paul718e3742002-12-13 20:15:29 +00001396 }
1397
Paul Jakmafb982c22007-05-04 20:15:47 +00001398 (bgp_attr_extra_get (attr))->originator_id.s_addr
1399 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001400
1401 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1402
Paul Jakmab881c702010-11-23 16:35:42 +00001403 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001404}
1405
1406/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001407static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001408bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
Denis Ovsienko0b830442011-09-30 15:12:17 +04001409 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001410{
Denis Ovsienko0b830442011-09-30 15:12:17 +04001411 bgp_size_t total;
1412
1413 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1414 /* Flag checks. */
Denis Ovsienkobbb04bf2011-10-18 14:20:04 +04001415 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko0b830442011-09-30 15:12:17 +04001416 {
1417 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1418 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must be flagged as \"optional\" (%u)", flag);
1419 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1420 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"transitive\" (%u)", flag);
1421 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1422 zlog (peer->log, LOG_ERR, "CLUSTER_LIST attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001423 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1424 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1425 startp, total);
Denis Ovsienko0b830442011-09-30 15:12:17 +04001426 }
paul718e3742002-12-13 20:15:29 +00001427 /* Check length. */
1428 if (length % 4)
1429 {
1430 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1431
Paul Jakmab881c702010-11-23 16:35:42 +00001432 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1433 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
Denis Ovsienko26755182011-10-26 19:34:30 +04001434 startp, total);
paul718e3742002-12-13 20:15:29 +00001435 }
1436
Paul Jakmafb982c22007-05-04 20:15:47 +00001437 (bgp_attr_extra_get (attr))->cluster
1438 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001439
1440 /* XXX: Fix cluster_parse to use stream API and then remove this */
1441 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001442
1443 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1444
Paul Jakmab881c702010-11-23 16:35:42 +00001445 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001446}
1447
1448/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001449int
Denis Ovsienko565b8282011-10-10 21:08:33 +04001450bgp_mp_reach_parse (struct peer *peer, const bgp_size_t length,
1451 struct attr *attr, const u_char flag, u_char *startp, struct bgp_nlri *mp_update)
paul718e3742002-12-13 20:15:29 +00001452{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001453 afi_t afi;
1454 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001455 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001456 size_t start;
paul718e3742002-12-13 20:15:29 +00001457 int ret;
1458 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001459 struct attr_extra *attre = bgp_attr_extra_get(attr);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001460 bgp_size_t total;
1461
1462 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1463 /* Flag checks. */
Denis Ovsienkobbb04bf2011-10-18 14:20:04 +04001464 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko565b8282011-10-10 21:08:33 +04001465 {
1466 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1467 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must be flagged as \"optional\" (%u)", flag);
1468 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1469 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag);
1470 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1471 zlog (peer->log, LOG_ERR, "MP_REACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001472 return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag,
1473 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1474 startp, total);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001475 }
paul718e3742002-12-13 20:15:29 +00001476 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001477 s = BGP_INPUT(peer);
1478 start = stream_get_getp(s);
1479
1480 /* safe to read statically sized header? */
1481#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001482#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001483 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001484 {
1485 zlog_info ("%s: %s sent invalid length, %lu",
1486 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001487 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001488 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001489
paul718e3742002-12-13 20:15:29 +00001490 /* Load AFI, SAFI. */
1491 afi = stream_getw (s);
1492 safi = stream_getc (s);
1493
1494 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001495 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001496
Paul Jakma03292802008-06-07 20:37:10 +00001497 if (LEN_LEFT < attre->mp_nexthop_len)
1498 {
1499 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1500 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001501 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001502 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001503
paul718e3742002-12-13 20:15:29 +00001504 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001505 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001506 {
1507 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001508 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001509 /* Probably needed for RFC 2283 */
1510 if (attr->nexthop.s_addr == 0)
1511 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001512 break;
1513 case 12:
Stephen Hemminger9206f9e2011-12-18 19:43:40 +04001514 stream_getl (s); /* RD high */
1515 stream_getl (s); /* RD low */
1516 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001517 break;
1518#ifdef HAVE_IPV6
1519 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001520 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001521 break;
1522 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001523 stream_get (&attre->mp_nexthop_global, s, 16);
1524 stream_get (&attre->mp_nexthop_local, s, 16);
1525 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001526 {
1527 char buf1[INET6_ADDRSTRLEN];
1528 char buf2[INET6_ADDRSTRLEN];
1529
1530 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001531 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 +00001532 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001533 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001534 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001535 buf2, INET6_ADDRSTRLEN));
1536
Paul Jakmafb982c22007-05-04 20:15:47 +00001537 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001538 }
1539 break;
1540#endif /* HAVE_IPV6 */
1541 default:
Paul Jakma03292802008-06-07 20:37:10 +00001542 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1543 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001544 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001545 }
1546
Paul Jakma03292802008-06-07 20:37:10 +00001547 if (!LEN_LEFT)
1548 {
1549 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1550 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001551 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001552 }
paul718e3742002-12-13 20:15:29 +00001553
Paul Jakma6e4ab122007-04-10 19:36:48 +00001554 {
1555 u_char val;
1556 if ((val = stream_getc (s)))
1557 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1558 peer->host, val);
1559 }
1560
1561 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001562 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001563 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001564 {
1565 zlog_info ("%s: (%s) Failed to read NLRI",
1566 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001567 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001568 }
paul718e3742002-12-13 20:15:29 +00001569
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001570 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001571 {
1572 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001573 if (ret < 0)
1574 {
1575 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
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 }
1580
1581 mp_update->afi = afi;
1582 mp_update->safi = safi;
1583 mp_update->nlri = stream_pnt (s);
1584 mp_update->length = nlri_len;
1585
paul9985f832005-02-09 15:51:56 +00001586 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001587
Paul Jakmab881c702010-11-23 16:35:42 +00001588 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001589#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001590}
1591
1592/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001593int
Denis Ovsienko565b8282011-10-10 21:08:33 +04001594bgp_mp_unreach_parse (struct peer *peer, const bgp_size_t length,
1595 const u_char flag, u_char *startp,
paul718e3742002-12-13 20:15:29 +00001596 struct bgp_nlri *mp_withdraw)
1597{
1598 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001599 afi_t afi;
1600 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001601 u_int16_t withdraw_len;
1602 int ret;
Denis Ovsienko565b8282011-10-10 21:08:33 +04001603 bgp_size_t total;
1604
1605 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1606 /* Flag checks. */
Denis Ovsienkobbb04bf2011-10-18 14:20:04 +04001607 if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
Denis Ovsienko565b8282011-10-10 21:08:33 +04001608 {
1609 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1610 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must be flagged as \"optional\" (%u)", flag);
1611 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1612 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"transitive\" (%u)", flag);
1613 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1614 zlog (peer->log, LOG_ERR, "MP_UNREACH_NLRI attribute must not be flagged as \"partial\" (%u)", flag);
Denis Ovsienkoabc384f2011-10-18 13:55:07 +04001615 return bgp_attr_malformed (peer, BGP_ATTR_MP_UNREACH_NLRI, flag,
1616 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1617 startp, total);
Denis Ovsienko565b8282011-10-10 21:08:33 +04001618 }
paul718e3742002-12-13 20:15:29 +00001619
1620 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001621
1622#define BGP_MP_UNREACH_MIN_SIZE 3
1623 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001624 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001625
paul718e3742002-12-13 20:15:29 +00001626 afi = stream_getw (s);
1627 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001628
1629 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001630
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001631 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001632 {
1633 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1634 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001635 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001636 }
1637
1638 mp_withdraw->afi = afi;
1639 mp_withdraw->safi = safi;
1640 mp_withdraw->nlri = stream_pnt (s);
1641 mp_withdraw->length = withdraw_len;
1642
paul9985f832005-02-09 15:51:56 +00001643 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001644
Paul Jakmab881c702010-11-23 16:35:42 +00001645 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001646}
1647
1648/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001649static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001650bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001651 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001652{
Paul Jakmab881c702010-11-23 16:35:42 +00001653 bgp_size_t total
1654 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1655
paul718e3742002-12-13 20:15:29 +00001656 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001657 {
1658 if (attr->extra)
1659 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001660 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001661 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001662 }
Paul Jakma0c466382010-12-05 17:17:26 +00001663
1664 (bgp_attr_extra_get (attr))->ecommunity =
1665 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1666 /* XXX: fix ecommunity_parse to use stream API */
1667 stream_forward_getp (peer->ibuf, length);
1668
1669 if (!attr->extra->ecommunity)
Paul Jakmab881c702010-11-23 16:35:42 +00001670 return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
1671 flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1672 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001673
paul718e3742002-12-13 20:15:29 +00001674 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1675
Paul Jakmab881c702010-11-23 16:35:42 +00001676 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001677}
1678
1679/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001680static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001681bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1682 u_char type, bgp_size_t length, u_char *startp)
1683{
1684 bgp_size_t total;
1685 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001686 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001687
hassof4184462005-02-01 20:13:16 +00001688 if (BGP_DEBUG (normal, NORMAL))
1689 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1690 peer->host, type, length);
1691
paul718e3742002-12-13 20:15:29 +00001692 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001693 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001694 "Unknown attribute type %d length %d is received", type, length);
1695
1696 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001697 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001698
1699 /* Adjest total length to include type and length. */
1700 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1701
1702 /* If any of the mandatory well-known attributes are not recognized,
1703 then the Error Subcode is set to Unrecognized Well-known
1704 Attribute. The Data field contains the unrecognized attribute
1705 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001706 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001707 {
Paul Jakmab881c702010-11-23 16:35:42 +00001708 return bgp_attr_malformed (peer, type, flag,
1709 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1710 startp, total);
paul718e3742002-12-13 20:15:29 +00001711 }
1712
1713 /* Unrecognized non-transitive optional attributes must be quietly
1714 ignored and not passed along to other BGP peers. */
1715 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001716 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001717
1718 /* If a path with recognized transitive optional attribute is
1719 accepted and passed along to other BGP peers and the Partial bit
1720 in the Attribute Flags octet is set to 1 by some previous AS, it
1721 is not set back to 0 by the current AS. */
1722 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1723
1724 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001725 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001726 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001727
Paul Jakmafb982c22007-05-04 20:15:47 +00001728 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001729
1730 if (transit->val)
1731 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1732 transit->length + total);
1733 else
1734 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1735
1736 memcpy (transit->val + transit->length, startp, total);
1737 transit->length += total;
1738
Paul Jakmab881c702010-11-23 16:35:42 +00001739 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001740}
1741
1742/* Read attribute of update packet. This function is called from
1743 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001744bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001745bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1746 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1747{
1748 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001749 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001750 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001751 bgp_size_t length;
1752 u_char *startp, *endp;
1753 u_char *attr_endp;
1754 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001755 /* we need the as4_path only until we have synthesized the as_path with it */
1756 /* same goes for as4_aggregator */
1757 struct aspath *as4_path = NULL;
1758 as_t as4_aggregator = 0;
1759 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001760
1761 /* Initialize bitmap. */
1762 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1763
1764 /* End pointer of BGP attribute. */
1765 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001766
paul718e3742002-12-13 20:15:29 +00001767 /* Get attributes to the end of attribute length. */
1768 while (BGP_INPUT_PNT (peer) < endp)
1769 {
1770 /* Check remaining length check.*/
1771 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1772 {
gdtc29fdba2004-12-09 14:46:46 +00001773 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001774 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001775 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001776 peer->host,
1777 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001778
1779 bgp_notify_send (peer,
1780 BGP_NOTIFY_UPDATE_ERR,
1781 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001782 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001783 }
1784
1785 /* Fetch attribute flag and type. */
1786 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001787 /* "The lower-order four bits of the Attribute Flags octet are
1788 unused. They MUST be zero when sent and MUST be ignored when
1789 received." */
1790 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001791 type = stream_getc (BGP_INPUT (peer));
1792
Paul Jakma370b64a2007-12-22 16:49:52 +00001793 /* Check whether Extended-Length applies and is in bounds */
1794 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1795 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1796 {
1797 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001798 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001799 peer->host,
1800 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1801
1802 bgp_notify_send (peer,
1803 BGP_NOTIFY_UPDATE_ERR,
1804 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001805 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001806 }
1807
paul718e3742002-12-13 20:15:29 +00001808 /* Check extended attribue length bit. */
1809 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1810 length = stream_getw (BGP_INPUT (peer));
1811 else
1812 length = stream_getc (BGP_INPUT (peer));
1813
1814 /* If any attribute appears more than once in the UPDATE
1815 message, then the Error Subcode is set to Malformed Attribute
1816 List. */
1817
1818 if (CHECK_BITMAP (seen, type))
1819 {
1820 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001821 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001822 peer->host, type);
1823
1824 bgp_notify_send (peer,
1825 BGP_NOTIFY_UPDATE_ERR,
1826 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001827 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001828 }
1829
1830 /* Set type to bitmap to check duplicate attribute. `type' is
1831 unsigned char so it never overflow bitmap range. */
1832
1833 SET_BITMAP (seen, type);
1834
1835 /* Overflow check. */
1836 attr_endp = BGP_INPUT_PNT (peer) + length;
1837
1838 if (attr_endp > endp)
1839 {
1840 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001841 "%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 +00001842 bgp_notify_send (peer,
1843 BGP_NOTIFY_UPDATE_ERR,
1844 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001845 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001846 }
1847
1848 /* OK check attribute and store it's value. */
1849 switch (type)
1850 {
1851 case BGP_ATTR_ORIGIN:
1852 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1853 break;
1854 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001855 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001856 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001857 case BGP_ATTR_AS4_PATH:
Paul Jakmab881c702010-11-23 16:35:42 +00001858 ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001859 break;
paul718e3742002-12-13 20:15:29 +00001860 case BGP_ATTR_NEXT_HOP:
1861 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1862 break;
1863 case BGP_ATTR_MULTI_EXIT_DISC:
1864 ret = bgp_attr_med (peer, length, attr, flag, startp);
1865 break;
1866 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001867 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001868 break;
1869 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001870 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001871 break;
1872 case BGP_ATTR_AGGREGATOR:
Denis Ovsienkoa624cae2011-10-08 13:54:48 +04001873 ret = bgp_attr_aggregator (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001874 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001875 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakmab881c702010-11-23 16:35:42 +00001876 ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
1877 &as4_aggregator,
1878 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001879 break;
paul718e3742002-12-13 20:15:29 +00001880 case BGP_ATTR_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001881 ret = bgp_attr_community (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001882 break;
1883 case BGP_ATTR_ORIGINATOR_ID:
Denis Ovsienkod595b562011-09-30 15:08:54 +04001884 ret = bgp_attr_originator_id (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001885 break;
1886 case BGP_ATTR_CLUSTER_LIST:
Denis Ovsienko0b830442011-09-30 15:12:17 +04001887 ret = bgp_attr_cluster_list (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001888 break;
1889 case BGP_ATTR_MP_REACH_NLRI:
Denis Ovsienko565b8282011-10-10 21:08:33 +04001890 ret = bgp_mp_reach_parse (peer, length, attr, flag, startp, mp_update);
paul718e3742002-12-13 20:15:29 +00001891 break;
1892 case BGP_ATTR_MP_UNREACH_NLRI:
Denis Ovsienko565b8282011-10-10 21:08:33 +04001893 ret = bgp_mp_unreach_parse (peer, length, flag, startp, mp_withdraw);
paul718e3742002-12-13 20:15:29 +00001894 break;
1895 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001896 ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001897 break;
1898 default:
1899 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1900 break;
1901 }
Paul Jakmab881c702010-11-23 16:35:42 +00001902
1903 /* If hard error occured immediately return to the caller. */
1904 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001905 {
1906 zlog (peer->log, LOG_WARNING,
1907 "%s: Attribute %s, parse error",
1908 peer->host,
1909 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001910 bgp_notify_send (peer,
1911 BGP_NOTIFY_UPDATE_ERR,
1912 BGP_NOTIFY_UPDATE_MAL_ATTR);
1913 if (as4_path)
1914 aspath_unintern (&as4_path);
1915 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001916 }
Paul Jakmab881c702010-11-23 16:35:42 +00001917 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1918 {
1919
1920 zlog (peer->log, LOG_WARNING,
1921 "%s: Attribute %s, parse error - treating as withdrawal",
1922 peer->host,
1923 LOOKUP (attr_str, type));
1924 if (as4_path)
1925 aspath_unintern (&as4_path);
1926 return ret;
1927 }
1928
paul718e3742002-12-13 20:15:29 +00001929 /* Check the fetched length. */
1930 if (BGP_INPUT_PNT (peer) != attr_endp)
1931 {
1932 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001933 "%s: BGP attribute %s, fetch error",
1934 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001935 bgp_notify_send (peer,
1936 BGP_NOTIFY_UPDATE_ERR,
1937 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001938 if (as4_path)
1939 aspath_unintern (&as4_path);
1940 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001941 }
1942 }
1943
1944 /* Check final read pointer is same as end pointer. */
1945 if (BGP_INPUT_PNT (peer) != endp)
1946 {
1947 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001948 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001949 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001950 bgp_notify_send (peer,
1951 BGP_NOTIFY_UPDATE_ERR,
1952 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001953 if (as4_path)
1954 aspath_unintern (&as4_path);
1955 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001956 }
1957
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001958 /*
1959 * At this place we can see whether we got AS4_PATH and/or
1960 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1961 * We can not do this before we've read all attributes because
1962 * the as4 handling does not say whether AS4_PATH has to be sent
1963 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1964 * in relationship to AGGREGATOR.
1965 * So, to be defensive, we are not relying on any order and read
1966 * all attributes first, including these 32bit ones, and now,
1967 * afterwards, we look what and if something is to be done for as4.
1968 */
Paul Jakmab881c702010-11-23 16:35:42 +00001969 if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001970 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001971 {
1972 if (as4_path)
1973 aspath_unintern (&as4_path);
1974 return BGP_ATTR_PARSE_ERROR;
1975 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001976
1977 /* At this stage, we have done all fiddling with as4, and the
1978 * resulting info is in attr->aggregator resp. attr->aspath
1979 * so we can chuck as4_aggregator and as4_path alltogether in
1980 * order to save memory
1981 */
Paul Jakmab881c702010-11-23 16:35:42 +00001982 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001983 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001984 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001985 /* The flag that we got this is still there, but that does not
1986 * do any trouble
1987 */
1988 }
1989 /*
1990 * The "rest" of the code does nothing with as4_aggregator.
1991 * there is no memory attached specifically which is not part
1992 * of the attr.
1993 * so ignoring just means do nothing.
1994 */
1995 /*
1996 * Finally do the checks on the aspath we did not do yet
1997 * because we waited for a potentially synthesized aspath.
1998 */
Paul Jakmab881c702010-11-23 16:35:42 +00001999 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002000 {
Paul Jakmab881c702010-11-23 16:35:42 +00002001 ret = bgp_attr_aspath_check (peer, attr, flag);
2002 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002003 return ret;
2004 }
2005
paul718e3742002-12-13 20:15:29 +00002006 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002007 if (attr->extra && attr->extra->transit)
2008 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00002009
Paul Jakmab881c702010-11-23 16:35:42 +00002010 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002011}
2012
2013/* Well-known attribute check. */
2014int
2015bgp_attr_check (struct peer *peer, struct attr *attr)
2016{
2017 u_char type = 0;
2018
2019 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
2020 type = BGP_ATTR_ORIGIN;
2021
2022 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
2023 type = BGP_ATTR_AS_PATH;
2024
2025 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
2026 type = BGP_ATTR_NEXT_HOP;
2027
2028 if (peer_sort (peer) == BGP_PEER_IBGP
2029 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
2030 type = BGP_ATTR_LOCAL_PREF;
2031
2032 if (type)
2033 {
2034 zlog (peer->log, LOG_WARNING,
2035 "%s Missing well-known attribute %d.",
2036 peer->host, type);
2037 bgp_notify_send_with_data (peer,
2038 BGP_NOTIFY_UPDATE_ERR,
2039 BGP_NOTIFY_UPDATE_MISS_ATTR,
2040 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002041 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002042 }
Paul Jakmab881c702010-11-23 16:35:42 +00002043 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002044}
2045
2046int stream_put_prefix (struct stream *, struct prefix *);
2047
2048/* Make attribute packet. */
2049bgp_size_t
2050bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2051 struct stream *s, struct attr *attr, struct prefix *p,
2052 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002053 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002054{
paulfe69a502005-09-10 16:55:02 +00002055 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002056 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002057 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002058 int send_as4_path = 0;
2059 int send_as4_aggregator = 0;
2060 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002061
2062 if (! bgp)
2063 bgp = bgp_get_default ();
2064
2065 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002066 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002067
2068 /* Origin attribute. */
2069 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2070 stream_putc (s, BGP_ATTR_ORIGIN);
2071 stream_putc (s, 1);
2072 stream_putc (s, attr->origin);
2073
2074 /* AS path attribute. */
2075
2076 /* If remote-peer is EBGP */
2077 if (peer_sort (peer) == BGP_PEER_EBGP
2078 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002079 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002080 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002081 {
2082 aspath = aspath_dup (attr->aspath);
2083
2084 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2085 {
2086 /* Strip the confed info, and then stuff our path CONFED_ID
2087 on the front */
2088 aspath = aspath_delete_confed_seq (aspath);
2089 aspath = aspath_add_seq (aspath, bgp->confed_id);
2090 }
2091 else
2092 {
2093 aspath = aspath_add_seq (aspath, peer->local_as);
2094 if (peer->change_local_as)
2095 aspath = aspath_add_seq (aspath, peer->change_local_as);
2096 }
2097 }
2098 else if (peer_sort (peer) == BGP_PEER_CONFED)
2099 {
2100 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2101 aspath = aspath_dup (attr->aspath);
2102 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2103 }
2104 else
2105 aspath = attr->aspath;
2106
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002107 /* If peer is not AS4 capable, then:
2108 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2109 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2110 * types are in it (i.e. exclude them if they are there)
2111 * AND do this only if there is at least one asnum > 65535 in the path!
2112 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2113 * all ASnums > 65535 to BGP_AS_TRANS
2114 */
paul718e3742002-12-13 20:15:29 +00002115
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002116 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2117 stream_putc (s, BGP_ATTR_AS_PATH);
2118 aspath_sizep = stream_get_endp (s);
2119 stream_putw (s, 0);
2120 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2121
2122 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2123 * in the path
2124 */
2125 if (!use32bit && aspath_has_as4 (aspath))
2126 send_as4_path = 1; /* we'll do this later, at the correct place */
2127
paul718e3742002-12-13 20:15:29 +00002128 /* Nexthop attribute. */
2129 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2130 {
2131 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2132 stream_putc (s, BGP_ATTR_NEXT_HOP);
2133 stream_putc (s, 4);
2134 if (safi == SAFI_MPLS_VPN)
2135 {
2136 if (attr->nexthop.s_addr == 0)
2137 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2138 else
2139 stream_put_ipv4 (s, attr->nexthop.s_addr);
2140 }
2141 else
2142 stream_put_ipv4 (s, attr->nexthop.s_addr);
2143 }
2144
2145 /* MED attribute. */
2146 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2147 {
2148 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2149 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2150 stream_putc (s, 4);
2151 stream_putl (s, attr->med);
2152 }
2153
2154 /* Local preference. */
2155 if (peer_sort (peer) == BGP_PEER_IBGP ||
2156 peer_sort (peer) == BGP_PEER_CONFED)
2157 {
2158 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2159 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2160 stream_putc (s, 4);
2161 stream_putl (s, attr->local_pref);
2162 }
2163
2164 /* Atomic aggregate. */
2165 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2166 {
2167 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2168 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2169 stream_putc (s, 0);
2170 }
2171
2172 /* Aggregator. */
2173 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2174 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002175 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002176
2177 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002178 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2179 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002180
2181 if (use32bit)
2182 {
2183 /* AS4 capable peer */
2184 stream_putc (s, 8);
2185 stream_putl (s, attr->extra->aggregator_as);
2186 }
2187 else
2188 {
2189 /* 2-byte AS peer */
2190 stream_putc (s, 6);
2191
2192 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2193 if ( attr->extra->aggregator_as > 65535 )
2194 {
2195 stream_putw (s, BGP_AS_TRANS);
2196
2197 /* we have to send AS4_AGGREGATOR, too.
2198 * we'll do that later in order to send attributes in ascending
2199 * order.
2200 */
2201 send_as4_aggregator = 1;
2202 }
2203 else
2204 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2205 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002206 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002207 }
2208
2209 /* Community attribute. */
2210 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2211 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2212 {
2213 if (attr->community->size * 4 > 255)
2214 {
2215 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2216 stream_putc (s, BGP_ATTR_COMMUNITIES);
2217 stream_putw (s, attr->community->size * 4);
2218 }
2219 else
2220 {
2221 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2222 stream_putc (s, BGP_ATTR_COMMUNITIES);
2223 stream_putc (s, attr->community->size * 4);
2224 }
2225 stream_put (s, attr->community->val, attr->community->size * 4);
2226 }
2227
2228 /* Route Reflector. */
2229 if (peer_sort (peer) == BGP_PEER_IBGP
2230 && from
2231 && peer_sort (from) == BGP_PEER_IBGP)
2232 {
2233 /* Originator ID. */
2234 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2235 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2236 stream_putc (s, 4);
2237
2238 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002239 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002240 else
2241 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002242
2243 /* Cluster list. */
2244 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2245 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2246
Paul Jakma9eda90c2007-08-30 13:36:17 +00002247 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002248 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002249 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002250 /* If this peer configuration's parent BGP has cluster_id. */
2251 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2252 stream_put_in_addr (s, &bgp->cluster_id);
2253 else
2254 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002255 stream_put (s, attr->extra->cluster->list,
2256 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002257 }
2258 else
2259 {
2260 stream_putc (s, 4);
2261 /* If this peer configuration's parent BGP has cluster_id. */
2262 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2263 stream_put_in_addr (s, &bgp->cluster_id);
2264 else
2265 stream_put_in_addr (s, &bgp->router_id);
2266 }
2267 }
2268
2269#ifdef HAVE_IPV6
2270 /* If p is IPv6 address put it into attribute. */
2271 if (p->family == AF_INET6)
2272 {
2273 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002274 struct attr_extra *attre = attr->extra;
2275
2276 assert (attr->extra);
2277
paul718e3742002-12-13 20:15:29 +00002278 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2279 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002280 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002281 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002282 stream_putw (s, AFI_IP6); /* AFI */
2283 stream_putc (s, safi); /* SAFI */
2284
Paul Jakmafb982c22007-05-04 20:15:47 +00002285 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002286
Paul Jakmafb982c22007-05-04 20:15:47 +00002287 if (attre->mp_nexthop_len == 16)
2288 stream_put (s, &attre->mp_nexthop_global, 16);
2289 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002290 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002291 stream_put (s, &attre->mp_nexthop_global, 16);
2292 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002293 }
2294
2295 /* SNPA */
2296 stream_putc (s, 0);
2297
paul718e3742002-12-13 20:15:29 +00002298 /* Prefix write. */
2299 stream_put_prefix (s, p);
2300
2301 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002302 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002303 }
2304#endif /* HAVE_IPV6 */
2305
2306 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2307 {
2308 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002309
2310 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2311 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002312 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002313 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002314 stream_putw (s, AFI_IP); /* AFI */
2315 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2316
2317 stream_putc (s, 4);
2318 stream_put_ipv4 (s, attr->nexthop.s_addr);
2319
2320 /* SNPA */
2321 stream_putc (s, 0);
2322
paul718e3742002-12-13 20:15:29 +00002323 /* Prefix write. */
2324 stream_put_prefix (s, p);
2325
2326 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002327 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002328 }
2329
2330 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2331 {
2332 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002333
2334 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2335 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002336 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002337 stream_putc (s, 0); /* Length of this attribute. */
2338 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002339 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002340
2341 stream_putc (s, 12);
2342 stream_putl (s, 0);
2343 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002344 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002345
2346 /* SNPA */
2347 stream_putc (s, 0);
2348
paul718e3742002-12-13 20:15:29 +00002349 /* Tag, RD, Prefix write. */
2350 stream_putc (s, p->prefixlen + 88);
2351 stream_put (s, tag, 3);
2352 stream_put (s, prd->val, 8);
2353 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2354
2355 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002356 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002357 }
2358
2359 /* Extended Communities attribute. */
2360 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2361 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2362 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002363 struct attr_extra *attre = attr->extra;
2364
2365 assert (attre);
2366
2367 if (peer_sort (peer) == BGP_PEER_IBGP
2368 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002369 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002370 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002371 {
2372 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2373 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002374 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002375 }
2376 else
2377 {
2378 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2379 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002380 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002381 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002382 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002383 }
2384 else
2385 {
paul5228ad22004-06-04 17:58:18 +00002386 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002387 int tbit;
2388 int ecom_tr_size = 0;
2389 int i;
2390
Paul Jakmafb982c22007-05-04 20:15:47 +00002391 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002392 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002393 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002394 tbit = *pnt;
2395
2396 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2397 continue;
2398
2399 ecom_tr_size++;
2400 }
2401
2402 if (ecom_tr_size)
2403 {
2404 if (ecom_tr_size * 8 > 255)
2405 {
2406 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2407 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2408 stream_putw (s, ecom_tr_size * 8);
2409 }
2410 else
2411 {
2412 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2413 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2414 stream_putc (s, ecom_tr_size * 8);
2415 }
2416
Paul Jakmafb982c22007-05-04 20:15:47 +00002417 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002418 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002419 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002420 tbit = *pnt;
2421
2422 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2423 continue;
2424
2425 stream_put (s, pnt, 8);
2426 }
2427 }
paul718e3742002-12-13 20:15:29 +00002428 }
paul718e3742002-12-13 20:15:29 +00002429 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002430
2431 if ( send_as4_path )
2432 {
2433 /* If the peer is NOT As4 capable, AND */
2434 /* there are ASnums > 65535 in path THEN
2435 * give out AS4_PATH */
2436
2437 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2438 * path segments!
2439 * Hm, I wonder... confederation things *should* only be at
2440 * the beginning of an aspath, right? Then we should use
2441 * aspath_delete_confed_seq for this, because it is already
2442 * there! (JK)
2443 * Folks, talk to me: what is reasonable here!?
2444 */
2445 aspath = aspath_delete_confed_seq (aspath);
2446
2447 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2448 stream_putc (s, BGP_ATTR_AS4_PATH);
2449 aspath_sizep = stream_get_endp (s);
2450 stream_putw (s, 0);
2451 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2452 }
2453
2454 if (aspath != attr->aspath)
2455 aspath_free (aspath);
2456
2457 if ( send_as4_aggregator )
2458 {
2459 assert (attr->extra);
2460
2461 /* send AS4_AGGREGATOR, at this place */
2462 /* this section of code moved here in order to ensure the correct
2463 * *ascending* order of attributes
2464 */
2465 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2466 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2467 stream_putc (s, 8);
2468 stream_putl (s, attr->extra->aggregator_as);
2469 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2470 }
Paul Jakma41367172007-08-06 15:24:51 +00002471
paul718e3742002-12-13 20:15:29 +00002472 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002473 if (attr->extra && attr->extra->transit)
2474 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002475
2476 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002477 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002478}
2479
2480bgp_size_t
2481bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2482 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002483 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002484{
2485 unsigned long cp;
2486 unsigned long attrlen_pnt;
2487 bgp_size_t size;
2488
paul9985f832005-02-09 15:51:56 +00002489 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002490
2491 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2492 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2493
paul9985f832005-02-09 15:51:56 +00002494 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002495 stream_putc (s, 0); /* Length of this attribute. */
2496
2497 stream_putw (s, family2afi (p->family));
2498
2499 if (safi == SAFI_MPLS_VPN)
2500 {
2501 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002502 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002503
2504 /* prefix. */
2505 stream_putc (s, p->prefixlen + 88);
2506 stream_put (s, tag, 3);
2507 stream_put (s, prd->val, 8);
2508 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2509 }
2510 else
2511 {
2512 /* SAFI */
2513 stream_putc (s, safi);
2514
2515 /* prefix */
2516 stream_put_prefix (s, p);
2517 }
2518
2519 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002520 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002521 stream_putc_at (s, attrlen_pnt, size);
2522
paul9985f832005-02-09 15:51:56 +00002523 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002524}
2525
2526/* Initialization of attribute. */
2527void
paulfe69a502005-09-10 16:55:02 +00002528bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002529{
paul718e3742002-12-13 20:15:29 +00002530 aspath_init ();
2531 attrhash_init ();
2532 community_init ();
2533 ecommunity_init ();
2534 cluster_init ();
2535 transit_init ();
2536}
2537
Chris Caputo228da422009-07-18 05:44:03 +00002538void
2539bgp_attr_finish (void)
2540{
2541 aspath_finish ();
2542 attrhash_finish ();
2543 community_finish ();
2544 ecommunity_finish ();
2545 cluster_finish ();
2546 transit_finish ();
2547}
2548
paul718e3742002-12-13 20:15:29 +00002549/* Make attribute packet. */
2550void
paula3845922003-10-18 01:30:50 +00002551bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2552 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002553{
2554 unsigned long cp;
2555 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002556 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002557 struct aspath *aspath;
2558
2559 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002560 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002561
2562 /* Place holder of length. */
2563 stream_putw (s, 0);
2564
2565 /* Origin attribute. */
2566 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2567 stream_putc (s, BGP_ATTR_ORIGIN);
2568 stream_putc (s, 1);
2569 stream_putc (s, attr->origin);
2570
2571 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002572
2573 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2574 stream_putc (s, BGP_ATTR_AS_PATH);
2575 aspath_lenp = stream_get_endp (s);
2576 stream_putw (s, 0);
2577
2578 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002579
2580 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002581 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2582 if(prefix != NULL
2583#ifdef HAVE_IPV6
2584 && prefix->family != AF_INET6
2585#endif /* HAVE_IPV6 */
2586 )
2587 {
2588 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2589 stream_putc (s, BGP_ATTR_NEXT_HOP);
2590 stream_putc (s, 4);
2591 stream_put_ipv4 (s, attr->nexthop.s_addr);
2592 }
paul718e3742002-12-13 20:15:29 +00002593
2594 /* MED attribute. */
2595 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2596 {
2597 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2598 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2599 stream_putc (s, 4);
2600 stream_putl (s, attr->med);
2601 }
2602
2603 /* Local preference. */
2604 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2605 {
2606 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2607 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2608 stream_putc (s, 4);
2609 stream_putl (s, attr->local_pref);
2610 }
2611
2612 /* Atomic aggregate. */
2613 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2614 {
2615 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2616 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2617 stream_putc (s, 0);
2618 }
2619
2620 /* Aggregator. */
2621 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2622 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002623 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002624 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2625 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002626 stream_putc (s, 8);
2627 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002628 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002629 }
2630
2631 /* Community attribute. */
2632 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2633 {
2634 if (attr->community->size * 4 > 255)
2635 {
2636 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2637 stream_putc (s, BGP_ATTR_COMMUNITIES);
2638 stream_putw (s, attr->community->size * 4);
2639 }
2640 else
2641 {
2642 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2643 stream_putc (s, BGP_ATTR_COMMUNITIES);
2644 stream_putc (s, attr->community->size * 4);
2645 }
2646 stream_put (s, attr->community->val, attr->community->size * 4);
2647 }
2648
paula3845922003-10-18 01:30:50 +00002649#ifdef HAVE_IPV6
2650 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002651 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2652 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002653 {
2654 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002655 struct attr_extra *attre = attr->extra;
2656
paula3845922003-10-18 01:30:50 +00002657 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2658 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002659 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002660
2661 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002662 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002663 stream_putw(s, AFI_IP6); /* AFI */
2664 stream_putc(s, SAFI_UNICAST); /* SAFI */
2665
2666 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002667 stream_putc(s, attre->mp_nexthop_len);
2668 stream_put(s, &attre->mp_nexthop_global, 16);
2669 if (attre->mp_nexthop_len == 32)
2670 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002671
2672 /* SNPA */
2673 stream_putc(s, 0);
2674
2675 /* Prefix */
2676 stream_put_prefix(s, prefix);
2677
2678 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002679 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002680 }
2681#endif /* HAVE_IPV6 */
2682
paul718e3742002-12-13 20:15:29 +00002683 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002684 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002685 stream_putw_at (s, cp, len);
2686}