blob: daf14bd4fcb0c78183559eaa77f58f7f4b1f4f97 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/* BGP attributes management routines.
2 Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
3
4This file is part of GNU Zebra.
5
6GNU Zebra is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
8Free Software Foundation; either version 2, or (at your option) any
9later version.
10
11GNU Zebra is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Zebra; see the file COPYING. If not, write to the Free
18Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
1902111-1307, USA. */
20
21#include <zebra.h>
22
23#include "linklist.h"
24#include "prefix.h"
25#include "memory.h"
26#include "vector.h"
27#include "vty.h"
28#include "stream.h"
29#include "log.h"
30#include "hash.h"
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -070031#include "jhash.h"
paul718e3742002-12-13 20:15:29 +000032
33#include "bgpd/bgpd.h"
34#include "bgpd/bgp_attr.h"
35#include "bgpd/bgp_route.h"
36#include "bgpd/bgp_aspath.h"
37#include "bgpd/bgp_community.h"
38#include "bgpd/bgp_debug.h"
39#include "bgpd/bgp_packet.h"
40#include "bgpd/bgp_ecommunity.h"
41
42/* Attribute strings for logging. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -070043static const struct message attr_str [] =
paul718e3742002-12-13 20:15:29 +000044{
45 { BGP_ATTR_ORIGIN, "ORIGIN" },
46 { BGP_ATTR_AS_PATH, "AS_PATH" },
47 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
48 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
49 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
50 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
51 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
52 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
53 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
54 { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" },
55 { BGP_ATTR_DPA, "DPA" },
56 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
57 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
58 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
59 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000060 { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
61 { BGP_ATTR_AS4_PATH, "AS4_PATH" },
62 { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
63 { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
paul718e3742002-12-13 20:15:29 +000064};
Stephen Hemminger9bddac42009-05-15 09:59:51 -070065static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000066
Stephen Hemminger9bddac42009-05-15 09:59:51 -070067static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000068
paul94f2b392005-06-28 12:44:16 +000069static void *
Paul Jakma923de652007-04-29 18:25:17 +000070cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000071{
Paul Jakma923de652007-04-29 18:25:17 +000072 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000073 struct cluster_list *cluster;
74
75 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
76 cluster->length = val->length;
77
78 if (cluster->length)
79 {
80 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
81 memcpy (cluster->list, val->list, val->length);
82 }
83 else
84 cluster->list = NULL;
85
86 cluster->refcnt = 0;
87
88 return cluster;
89}
90
91/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000092static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000093cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000094{
95 struct cluster_list tmp;
96 struct cluster_list *cluster;
97
98 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000099 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +0000100
101 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
102 cluster->refcnt++;
103 return cluster;
104}
105
106int
107cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
108{
109 int i;
110
111 for (i = 0; i < cluster->length / 4; i++)
112 if (cluster->list[i].s_addr == originator.s_addr)
113 return 1;
114 return 0;
115}
116
paul94f2b392005-06-28 12:44:16 +0000117static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000118cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000119{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700120 const struct cluster_list *cluster = p;
paul718e3742002-12-13 20:15:29 +0000121
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700122 return jhash(cluster->list, cluster->length, 0);
paul718e3742002-12-13 20:15:29 +0000123}
124
paul94f2b392005-06-28 12:44:16 +0000125static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100126cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000127{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100128 const struct cluster_list * cluster1 = p1;
129 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000130
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100131 return (cluster1->length == cluster2->length &&
132 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000133}
134
paul94f2b392005-06-28 12:44:16 +0000135static void
paul718e3742002-12-13 20:15:29 +0000136cluster_free (struct cluster_list *cluster)
137{
138 if (cluster->list)
139 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
140 XFREE (MTYPE_CLUSTER, cluster);
141}
142
Chris Caputo228da422009-07-18 05:44:03 +0000143#if 0
paul94f2b392005-06-28 12:44:16 +0000144static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000145cluster_dup (struct cluster_list *cluster)
146{
147 struct cluster_list *new;
148
Stephen Hemminger393deb92008-08-18 14:13:29 -0700149 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000150 new->length = cluster->length;
151
152 if (cluster->length)
153 {
154 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
155 memcpy (new->list, cluster->list, cluster->length);
156 }
157 else
158 new->list = NULL;
159
160 return new;
161}
Chris Caputo228da422009-07-18 05:44:03 +0000162#endif
paul718e3742002-12-13 20:15:29 +0000163
paul94f2b392005-06-28 12:44:16 +0000164static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000165cluster_intern (struct cluster_list *cluster)
166{
167 struct cluster_list *find;
168
169 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
170 find->refcnt++;
171
172 return find;
173}
174
175void
176cluster_unintern (struct cluster_list *cluster)
177{
178 struct cluster_list *ret;
179
180 if (cluster->refcnt)
181 cluster->refcnt--;
182
183 if (cluster->refcnt == 0)
184 {
185 ret = hash_release (cluster_hash, cluster);
186 cluster_free (cluster);
187 }
188}
189
paul94f2b392005-06-28 12:44:16 +0000190static void
191cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000192{
193 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
194}
Chris Caputo228da422009-07-18 05:44:03 +0000195
196static void
197cluster_finish (void)
198{
199 hash_free (cluster_hash);
200 cluster_hash = NULL;
201}
paul718e3742002-12-13 20:15:29 +0000202
203/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700204static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000205
paul94f2b392005-06-28 12:44:16 +0000206static void
paul718e3742002-12-13 20:15:29 +0000207transit_free (struct transit *transit)
208{
209 if (transit->val)
210 XFREE (MTYPE_TRANSIT_VAL, transit->val);
211 XFREE (MTYPE_TRANSIT, transit);
212}
213
Paul Jakma923de652007-04-29 18:25:17 +0000214
paul94f2b392005-06-28 12:44:16 +0000215static void *
Paul Jakma923de652007-04-29 18:25:17 +0000216transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000217{
218 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000219 return p;
paul718e3742002-12-13 20:15:29 +0000220}
221
paul94f2b392005-06-28 12:44:16 +0000222static struct transit *
paul718e3742002-12-13 20:15:29 +0000223transit_intern (struct transit *transit)
224{
225 struct transit *find;
226
227 find = hash_get (transit_hash, transit, transit_hash_alloc);
228 if (find != transit)
229 transit_free (transit);
230 find->refcnt++;
231
232 return find;
233}
234
235void
236transit_unintern (struct transit *transit)
237{
238 struct transit *ret;
239
240 if (transit->refcnt)
241 transit->refcnt--;
242
243 if (transit->refcnt == 0)
244 {
245 ret = hash_release (transit_hash, transit);
246 transit_free (transit);
247 }
248}
249
paul94f2b392005-06-28 12:44:16 +0000250static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000251transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000252{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700253 const struct transit * transit = p;
paul718e3742002-12-13 20:15:29 +0000254
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700255 return jhash(transit->val, transit->length, 0);
paul718e3742002-12-13 20:15:29 +0000256}
257
paul94f2b392005-06-28 12:44:16 +0000258static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100259transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000260{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100261 const struct transit * transit1 = p1;
262 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000263
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100264 return (transit1->length == transit2->length &&
265 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000266}
267
paul94f2b392005-06-28 12:44:16 +0000268static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800269transit_init (void)
paul718e3742002-12-13 20:15:29 +0000270{
271 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
272}
Chris Caputo228da422009-07-18 05:44:03 +0000273
274static void
275transit_finish (void)
276{
277 hash_free (transit_hash);
278 transit_hash = NULL;
279}
paul718e3742002-12-13 20:15:29 +0000280
281/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700282static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000283
Paul Jakmafb982c22007-05-04 20:15:47 +0000284static struct attr_extra *
285bgp_attr_extra_new (void)
286{
287 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
288}
289
290void
291bgp_attr_extra_free (struct attr *attr)
292{
293 if (attr->extra)
294 {
295 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
296 attr->extra = NULL;
297 }
298}
299
300struct attr_extra *
301bgp_attr_extra_get (struct attr *attr)
302{
303 if (!attr->extra)
304 attr->extra = bgp_attr_extra_new();
305 return attr->extra;
306}
307
308/* Shallow copy of an attribute
309 * Though, not so shallow that it doesn't copy the contents
310 * of the attr_extra pointed to by 'extra'
311 */
312void
313bgp_attr_dup (struct attr *new, struct attr *orig)
314{
315 *new = *orig;
316 if (orig->extra)
317 {
318 new->extra = bgp_attr_extra_new();
319 *new->extra = *orig->extra;
320 }
321}
322
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000323unsigned long int
324attr_count (void)
325{
326 return attrhash->count;
327}
328
329unsigned long int
330attr_unknown_count (void)
331{
332 return transit_hash->count;
333}
334
paul718e3742002-12-13 20:15:29 +0000335unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000336attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000337{
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700338 const struct attr * attr = (struct attr *) p;
339 uint32_t key = 0;
340#define MIX(val) key = jhash_1word(val, key)
paul718e3742002-12-13 20:15:29 +0000341
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700342 MIX(attr->origin);
343 MIX(attr->nexthop.s_addr);
344 MIX(attr->med);
345 MIX(attr->local_pref);
346
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000347 key += attr->origin;
348 key += attr->nexthop.s_addr;
349 key += attr->med;
350 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000351
352 if (attr->extra)
353 {
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700354 MIX(attr->extra->aggregator_as);
355 MIX(attr->extra->aggregator_addr.s_addr);
356 MIX(attr->extra->weight);
357 MIX(attr->extra->mp_nexthop_global_in.s_addr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000358 }
359
paul718e3742002-12-13 20:15:29 +0000360 if (attr->aspath)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700361 MIX(aspath_key_make (attr->aspath));
paul718e3742002-12-13 20:15:29 +0000362 if (attr->community)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700363 MIX(community_hash_make (attr->community));
Paul Jakmafb982c22007-05-04 20:15:47 +0000364
365 if (attr->extra)
366 {
367 if (attr->extra->ecommunity)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700368 MIX(ecommunity_hash_make (attr->extra->ecommunity));
Paul Jakmafb982c22007-05-04 20:15:47 +0000369 if (attr->extra->cluster)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700370 MIX(cluster_hash_key_make (attr->extra->cluster));
Paul Jakmafb982c22007-05-04 20:15:47 +0000371 if (attr->extra->transit)
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700372 MIX(transit_hash_key_make (attr->extra->transit));
paul718e3742002-12-13 20:15:29 +0000373
374#ifdef HAVE_IPV6
Stephen Hemmingerc8e7b892010-08-27 14:12:54 -0700375 MIX(attr->extra->mp_nexthop_len);
Paul Jakma31d0f1b2011-03-29 14:18:49 +0100376 key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key);
377 key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key);
paul718e3742002-12-13 20:15:29 +0000378#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000379 }
paul718e3742002-12-13 20:15:29 +0000380
381 return key;
382}
383
384int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100385attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000386{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100387 const struct attr * attr1 = p1;
388 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000389
paul718e3742002-12-13 20:15:29 +0000390 if (attr1->flag == attr2->flag
391 && attr1->origin == attr2->origin
392 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000393 && attr1->aspath == attr2->aspath
394 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000395 && attr1->med == attr2->med
Paul Jakmac8f3fe32010-12-05 20:28:02 +0000396 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000397 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100398 const struct attr_extra *ae1 = attr1->extra;
399 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000400
401 if (ae1 && ae2
402 && ae1->aggregator_as == ae2->aggregator_as
403 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
404 && ae1->weight == ae2->weight
405#ifdef HAVE_IPV6
406 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
407 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
408 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
409#endif /* HAVE_IPV6 */
410 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
411 && ae1->ecommunity == ae2->ecommunity
412 && ae1->cluster == ae2->cluster
413 && ae1->transit == ae2->transit)
414 return 1;
415 else if (ae1 || ae2)
416 return 0;
417 /* neither attribute has extra attributes, so they're same */
418 return 1;
419 }
paul718e3742002-12-13 20:15:29 +0000420 else
421 return 0;
422}
423
paul94f2b392005-06-28 12:44:16 +0000424static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100425attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000426{
427 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
428}
429
paul94f2b392005-06-28 12:44:16 +0000430static void
Chris Caputo228da422009-07-18 05:44:03 +0000431attrhash_finish (void)
432{
433 hash_free (attrhash);
434 attrhash = NULL;
435}
436
437static void
paul718e3742002-12-13 20:15:29 +0000438attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
439{
440 struct attr *attr = backet->data;
441
442 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
443 inet_ntoa (attr->nexthop), VTY_NEWLINE);
444}
445
446void
447attr_show_all (struct vty *vty)
448{
449 hash_iterate (attrhash,
450 (void (*)(struct hash_backet *, void *))
451 attr_show_all_iterator,
452 vty);
453}
454
paul94f2b392005-06-28 12:44:16 +0000455static void *
Paul Jakma923de652007-04-29 18:25:17 +0000456bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000457{
Paul Jakma923de652007-04-29 18:25:17 +0000458 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000459 struct attr *attr;
460
461 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
462 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000463 if (val->extra)
464 {
465 attr->extra = bgp_attr_extra_new ();
466 *attr->extra = *val->extra;
467 }
paul718e3742002-12-13 20:15:29 +0000468 attr->refcnt = 0;
469 return attr;
470}
471
472/* Internet argument attribute. */
473struct attr *
474bgp_attr_intern (struct attr *attr)
475{
476 struct attr *find;
477
478 /* Intern referenced strucutre. */
479 if (attr->aspath)
480 {
481 if (! attr->aspath->refcnt)
482 attr->aspath = aspath_intern (attr->aspath);
483 else
484 attr->aspath->refcnt++;
485 }
486 if (attr->community)
487 {
488 if (! attr->community->refcnt)
489 attr->community = community_intern (attr->community);
490 else
491 attr->community->refcnt++;
492 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000493 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000494 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000495 struct attr_extra *attre = attr->extra;
496
497 if (attre->ecommunity)
498 {
499 if (! attre->ecommunity->refcnt)
500 attre->ecommunity = ecommunity_intern (attre->ecommunity);
501 else
502 attre->ecommunity->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000503
Paul Jakmafb982c22007-05-04 20:15:47 +0000504 }
505 if (attre->cluster)
506 {
507 if (! attre->cluster->refcnt)
508 attre->cluster = cluster_intern (attre->cluster);
509 else
510 attre->cluster->refcnt++;
511 }
512 if (attre->transit)
513 {
514 if (! attre->transit->refcnt)
515 attre->transit = transit_intern (attre->transit);
516 else
517 attre->transit->refcnt++;
518 }
paul718e3742002-12-13 20:15:29 +0000519 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000520
paul718e3742002-12-13 20:15:29 +0000521 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
522 find->refcnt++;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000523
paul718e3742002-12-13 20:15:29 +0000524 return find;
525}
526
Paul Jakma03e214c2007-04-29 18:31:07 +0000527
paul718e3742002-12-13 20:15:29 +0000528/* Make network statement's attribute. */
529struct attr *
530bgp_attr_default_set (struct attr *attr, u_char origin)
531{
532 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000533 bgp_attr_extra_get (attr);
534
paul718e3742002-12-13 20:15:29 +0000535 attr->origin = origin;
536 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
537 attr->aspath = aspath_empty ();
538 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000539 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000540 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
541#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000542 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000543#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000544
paul718e3742002-12-13 20:15:29 +0000545 return attr;
546}
547
Paul Jakma03e214c2007-04-29 18:31:07 +0000548
paul718e3742002-12-13 20:15:29 +0000549/* Make network statement's attribute. */
550struct attr *
551bgp_attr_default_intern (u_char origin)
552{
553 struct attr attr;
554 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000555 struct attr_extra *attre;
556
557 memset (&attr, 0, sizeof (struct attr));
558 attre = bgp_attr_extra_get (&attr);
559
Paul Jakma03e214c2007-04-29 18:31:07 +0000560 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000561
562 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000563 bgp_attr_extra_free (&attr);
564
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000565 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000566 return new;
567}
568
569struct attr *
570bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
571 struct aspath *aspath,
572 struct community *community, int as_set)
573{
574 struct attr attr;
575 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000576 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000577
578 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000579 attre = bgp_attr_extra_get (&attr);
580
paul718e3742002-12-13 20:15:29 +0000581 /* Origin attribute. */
582 attr.origin = origin;
583 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
584
585 /* AS path attribute. */
586 if (aspath)
587 attr.aspath = aspath_intern (aspath);
588 else
589 attr.aspath = aspath_empty ();
590 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
591
592 /* Next hop attribute. */
593 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
594
595 if (community)
596 {
597 attr.community = community;
598 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
599 }
600
Paul Jakmafb982c22007-05-04 20:15:47 +0000601 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000602#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000603 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000604#endif
605 if (! as_set)
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
607 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
608 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000609 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000610 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000611 attre->aggregator_as = bgp->as;
612 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000613
614 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000615 bgp_attr_extra_free (&attr);
616
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000617 aspath_unintern (&new->aspath);
paul718e3742002-12-13 20:15:29 +0000618 return new;
619}
620
Paul Jakmab881c702010-11-23 16:35:42 +0000621/* Unintern just the sub-components of the attr, but not the attr */
622void
623bgp_attr_unintern_sub (struct attr *attr)
624{
625 /* aspath refcount shoud be decrement. */
626 if (attr->aspath)
627 aspath_unintern (&attr->aspath);
628 UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
629
630 if (attr->community)
631 community_unintern (&attr->community);
632 UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
633
634 if (attr->extra)
635 {
636 if (attr->extra->ecommunity)
637 ecommunity_unintern (&attr->extra->ecommunity);
638 UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
639
640 if (attr->extra->cluster)
641 cluster_unintern (attr->extra->cluster);
642 UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
643
644 if (attr->extra->transit)
645 transit_unintern (attr->extra->transit);
646 }
647}
648
paul718e3742002-12-13 20:15:29 +0000649/* Free bgp attribute and aspath. */
650void
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000651bgp_attr_unintern (struct attr **attr)
paul718e3742002-12-13 20:15:29 +0000652{
653 struct attr *ret;
Paul Jakmab881c702010-11-23 16:35:42 +0000654 struct attr tmp;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000655
paul718e3742002-12-13 20:15:29 +0000656 /* Decrement attribute reference. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000657 (*attr)->refcnt--;
Paul Jakmab881c702010-11-23 16:35:42 +0000658
659 tmp = *(*attr);
660
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000661 if ((*attr)->extra)
Paul Jakmafb982c22007-05-04 20:15:47 +0000662 {
Paul Jakmab881c702010-11-23 16:35:42 +0000663 tmp.extra = bgp_attr_extra_new ();
664 memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra));
Paul Jakmafb982c22007-05-04 20:15:47 +0000665 }
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000666
paul718e3742002-12-13 20:15:29 +0000667 /* If reference becomes zero then free attribute object. */
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000668 if ((*attr)->refcnt == 0)
paul718e3742002-12-13 20:15:29 +0000669 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000670 ret = hash_release (attrhash, *attr);
paul718e3742002-12-13 20:15:29 +0000671 assert (ret != NULL);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000672 bgp_attr_extra_free (*attr);
673 XFREE (MTYPE_ATTR, *attr);
674 *attr = NULL;
paul718e3742002-12-13 20:15:29 +0000675 }
676
Paul Jakmab881c702010-11-23 16:35:42 +0000677 bgp_attr_unintern_sub (&tmp);
paul718e3742002-12-13 20:15:29 +0000678}
679
680void
681bgp_attr_flush (struct attr *attr)
682{
683 if (attr->aspath && ! attr->aspath->refcnt)
684 aspath_free (attr->aspath);
685 if (attr->community && ! attr->community->refcnt)
686 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000687 if (attr->extra)
688 {
689 struct attr_extra *attre = attr->extra;
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000690
Paul Jakmafb982c22007-05-04 20:15:47 +0000691 if (attre->ecommunity && ! attre->ecommunity->refcnt)
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000692 ecommunity_free (&attre->ecommunity);
Paul Jakmafb982c22007-05-04 20:15:47 +0000693 if (attre->cluster && ! attre->cluster->refcnt)
694 cluster_free (attre->cluster);
695 if (attre->transit && ! attre->transit->refcnt)
696 transit_free (attre->transit);
697 }
paul718e3742002-12-13 20:15:29 +0000698}
699
Paul Jakmab881c702010-11-23 16:35:42 +0000700/* Implement draft-scudder-idr-optional-transitive behaviour and
701 * avoid resetting sessions for malformed attributes which are
702 * are partial/optional and hence where the error likely was not
703 * introduced by the sending neighbour.
704 */
705static bgp_attr_parse_ret_t
706bgp_attr_malformed (struct peer *peer, u_char type, u_char flag,
707 u_char subcode, u_char *startp, bgp_size_t length)
708{
709 /* Only relax error handling for eBGP peers */
710 if (peer_sort (peer) != BGP_PEER_EBGP)
711 {
712 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
713 startp, length);
714 return BGP_ATTR_PARSE_ERROR;
715
716 }
717
718 switch (type) {
719 /* where an optional attribute is inconsequential, e.g. it does not affect
720 * route selection, and can be safely ignored then any such attributes
721 * which are malformed should just be ignored and the route processed as
722 * normal.
723 */
724 case BGP_ATTR_AS4_AGGREGATOR:
725 case BGP_ATTR_AGGREGATOR:
726 case BGP_ATTR_ATOMIC_AGGREGATE:
727 return BGP_ATTR_PARSE_PROCEED;
728
729 /* Core attributes, particularly ones which may influence route
730 * selection should always cause session resets
731 */
732 case BGP_ATTR_ORIGIN:
733 case BGP_ATTR_AS_PATH:
734 case BGP_ATTR_NEXT_HOP:
735 case BGP_ATTR_MULTI_EXIT_DISC:
736 case BGP_ATTR_LOCAL_PREF:
737 case BGP_ATTR_COMMUNITIES:
738 case BGP_ATTR_ORIGINATOR_ID:
739 case BGP_ATTR_CLUSTER_LIST:
740 case BGP_ATTR_MP_REACH_NLRI:
741 case BGP_ATTR_MP_UNREACH_NLRI:
742 case BGP_ATTR_EXT_COMMUNITIES:
743 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
744 startp, length);
745 return BGP_ATTR_PARSE_ERROR;
746 }
747
748 /* Partial optional attributes that are malformed should not cause
749 * the whole session to be reset. Instead treat it as a withdrawal
750 * of the routes, if possible.
751 */
752 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)
753 && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
754 && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
755 return BGP_ATTR_PARSE_WITHDRAW;
756
757 /* default to reset */
758 return BGP_ATTR_PARSE_ERROR;
759}
760
paul718e3742002-12-13 20:15:29 +0000761/* Get origin attribute of the update message. */
Paul Jakmab881c702010-11-23 16:35:42 +0000762static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000763bgp_attr_origin (struct peer *peer, bgp_size_t length,
764 struct attr *attr, u_char flag, u_char *startp)
765{
766 bgp_size_t total;
767
768 /* total is entire attribute length include Attribute Flags (1),
769 Attribute Type code (1) and Attribute length (1 or 2). */
770 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
771
772 /* If any recognized attribute has Attribute Flags that conflict
773 with the Attribute Type Code, then the Error Subcode is set to
774 Attribute Flags Error. The Data field contains the erroneous
775 attribute (type, length and value). */
Denis Ovsienkob84b62d2011-09-27 15:47:25 +0400776 if (flag != BGP_ATTR_FLAG_TRANS)
777 {
778 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
779 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"optional\" (%u)", flag);
780 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
781 zlog (peer->log, LOG_ERR, "ORIGIN attribute must be flagged as \"transitive\" (%u)", flag);
782 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
783 zlog (peer->log, LOG_ERR, "ORIGIN attribute must not be flagged as \"partial\" (%u)", flag);
784 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
785 }
paul718e3742002-12-13 20:15:29 +0000786
787 /* If any recognized attribute has Attribute Length that conflicts
788 with the expected length (based on the attribute type code), then
789 the Error Subcode is set to Attribute Length Error. The Data
790 field contains the erroneous attribute (type, length and
791 value). */
792 if (length != 1)
793 {
794 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
795 length);
Paul Jakmab881c702010-11-23 16:35:42 +0000796 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
797 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
798 startp, total);
paul718e3742002-12-13 20:15:29 +0000799 }
800
801 /* Fetch origin attribute. */
802 attr->origin = stream_getc (BGP_INPUT (peer));
803
804 /* If the ORIGIN attribute has an undefined value, then the Error
805 Subcode is set to Invalid Origin Attribute. The Data field
806 contains the unrecognized attribute (type, length and value). */
807 if ((attr->origin != BGP_ORIGIN_IGP)
808 && (attr->origin != BGP_ORIGIN_EGP)
809 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
810 {
811 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
812 attr->origin);
Paul Jakmab881c702010-11-23 16:35:42 +0000813 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
814 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
815 startp, total);
paul718e3742002-12-13 20:15:29 +0000816 }
817
818 /* Set oring attribute flag. */
819 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
820
821 return 0;
822}
Paul Jakmaab005292010-11-27 22:48:34 +0000823
824/* Parse AS path information. This function is wrapper of
825 aspath_parse. */
826static int
paul718e3742002-12-13 20:15:29 +0000827bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Paul Jakmaab005292010-11-27 22:48:34 +0000828 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +0000829{
Paul Jakmaab005292010-11-27 22:48:34 +0000830 bgp_size_t total;
paul718e3742002-12-13 20:15:29 +0000831
Paul Jakmaab005292010-11-27 22:48:34 +0000832 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000833
Paul Jakmaab005292010-11-27 22:48:34 +0000834 /* Flag check. */
Denis Ovsienko214bcaa2011-09-24 13:20:43 +0400835 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
836 {
837 zlog (peer->log, LOG_ERR,
838 "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag);
839 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
840 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
841 startp, total);
842 }
843
Paul Jakmaab005292010-11-27 22:48:34 +0000844 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
845 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000846 {
847 zlog (peer->log, LOG_ERR,
Paul Jakmaab005292010-11-27 22:48:34 +0000848 "As-Path attribute flag isn't transitive %d", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000849 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
850 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
851 startp, total);
Chris Hallcddb8112010-08-09 22:31:37 +0400852 }
Paul Jakmaab005292010-11-27 22:48:34 +0000853
854 /*
855 * peer with AS4 => will get 4Byte ASnums
856 * otherwise, will get 16 Bit
857 */
858 attr->aspath = aspath_parse (peer->ibuf, length,
859 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
860
861 /* In case of IBGP, length will be zero. */
862 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000863 {
Paul Jakmab881c702010-11-23 16:35:42 +0000864 zlog (peer->log, LOG_ERR,
865 "Malformed AS path from %s, length is %d",
866 peer->host, length);
867 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
868 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
869 NULL, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000870 }
Chris Hallcddb8112010-08-09 22:31:37 +0400871
Paul Jakmaab005292010-11-27 22:48:34 +0000872 /* Set aspath attribute flag. */
873 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000874
Paul Jakmab881c702010-11-23 16:35:42 +0000875 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000876}
877
Paul Jakmab881c702010-11-23 16:35:42 +0000878static bgp_attr_parse_ret_t
879bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000880{
881 /* These checks were part of bgp_attr_aspath, but with
882 * as4 we should to check aspath things when
883 * aspath synthesizing with as4_path has already taken place.
884 * Otherwise we check ASPATH and use the synthesized thing, and that is
885 * not right.
886 * So do the checks later, i.e. here
887 */
888 struct bgp *bgp = peer->bgp;
889 struct aspath *aspath;
890
paul718e3742002-12-13 20:15:29 +0000891 bgp = peer->bgp;
892
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300893 /* Confederation sanity check. */
894 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
895 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
896 {
897 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +0000898 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
899 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
900 NULL, 0);
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300901 }
902
paul718e3742002-12-13 20:15:29 +0000903 /* First AS check for EBGP. */
904 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
905 {
906 if (peer_sort (peer) == BGP_PEER_EBGP
907 && ! aspath_firstas_check (attr->aspath, peer->as))
908 {
909 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400910 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakmab881c702010-11-23 16:35:42 +0000911 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
912 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
913 NULL, 0);
paul718e3742002-12-13 20:15:29 +0000914 }
915 }
916
917 /* local-as prepend */
918 if (peer->change_local_as &&
919 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
920 {
921 aspath = aspath_dup (attr->aspath);
922 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000923 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +0000924 attr->aspath = aspath_intern (aspath);
925 }
926
Paul Jakmab881c702010-11-23 16:35:42 +0000927 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000928}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000929
Paul Jakmaab005292010-11-27 22:48:34 +0000930/* Parse AS4 path information. This function is another wrapper of
931 aspath_parse. */
932static int
Paul Jakmab881c702010-11-23 16:35:42 +0000933bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
934 struct attr *attr, u_char flag, u_char *startp,
935 struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +0000936{
Paul Jakmab881c702010-11-23 16:35:42 +0000937 bgp_size_t total;
938
939 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
940
941 /* Flag check. */
942 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
943 || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
944 {
945 zlog (peer->log, LOG_ERR,
946 "As4-Path attribute flag isn't optional/transitive %d", flag);
947 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
948 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
949 startp, total);
950 }
951
Paul Jakmaab005292010-11-27 22:48:34 +0000952 *as4_path = aspath_parse (peer->ibuf, length, 1);
953
Paul Jakmab881c702010-11-23 16:35:42 +0000954 /* In case of IBGP, length will be zero. */
955 if (!*as4_path)
956 {
957 zlog (peer->log, LOG_ERR,
958 "Malformed AS4 path from %s, length is %d",
959 peer->host, length);
960 return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
961 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
962 NULL, 0);
963 }
964
Paul Jakmaab005292010-11-27 22:48:34 +0000965 /* Set aspath attribute flag. */
966 if (as4_path)
967 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
968
Paul Jakmab881c702010-11-23 16:35:42 +0000969 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000970}
971
paul718e3742002-12-13 20:15:29 +0000972/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +0000973static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000974bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
975 struct attr *attr, u_char flag, u_char *startp)
976{
977 bgp_size_t total;
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400978 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +0000979
980 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
981
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400982 /* Flags check. */
Denis Ovsienkob84b62d2011-09-27 15:47:25 +0400983 if (flag != BGP_ATTR_FLAG_TRANS)
984 {
985 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
986 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag);
987 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
988 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag);
989 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
990 zlog (peer->log, LOG_ERR, "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag);
991 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
992 }
paul718e3742002-12-13 20:15:29 +0000993
994 /* Check nexthop attribute length. */
995 if (length != 4)
996 {
997 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
998 length);
999
Paul Jakmab881c702010-11-23 16:35:42 +00001000 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1001 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1002 startp, total);
paul718e3742002-12-13 20:15:29 +00001003 }
1004
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001005 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1006 attribute must result in a NOTIFICATION message (this is implemented below).
1007 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1008 logged locally (this is implemented somewhere else). The UPDATE message
1009 gets ignored in any of these cases. */
1010 nexthop_n = stream_get_ipv4 (peer->ibuf);
1011 nexthop_h = ntohl (nexthop_n);
1012 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1013 {
1014 char buf[INET_ADDRSTRLEN];
1015 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1016 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
1017 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1018 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
1019 startp, total);
1020 }
1021
1022 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001023 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1024
Paul Jakmab881c702010-11-23 16:35:42 +00001025 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001026}
1027
1028/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001029static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001030bgp_attr_med (struct peer *peer, bgp_size_t length,
1031 struct attr *attr, u_char flag, u_char *startp)
1032{
1033 bgp_size_t total;
1034
1035 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1036
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001037 /* Flag checks. */
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001038 if (flag != BGP_ATTR_FLAG_OPTIONAL)
1039 {
1040 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1041 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
1042 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1043 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
1044 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1045 zlog (peer->log, LOG_ERR, "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
1046 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1047 return -1;
1048 }
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001049
paul718e3742002-12-13 20:15:29 +00001050 /* Length check. */
1051 if (length != 4)
1052 {
1053 zlog (peer->log, LOG_ERR,
1054 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001055
1056 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1057 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1058 startp, total);
paul718e3742002-12-13 20:15:29 +00001059 }
1060
1061 attr->med = stream_getl (peer->ibuf);
1062
1063 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1064
Paul Jakmab881c702010-11-23 16:35:42 +00001065 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001066}
1067
1068/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001069static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001070bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001071 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001072{
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001073 bgp_size_t total;
1074
1075 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1076 /* Flag checks. */
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001077 if (flag != BGP_ATTR_FLAG_TRANS)
1078 {
1079 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1080 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"optional\" (%u)", flag);
1081 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1082 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1083 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1084 zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute must not be flagged as \"partial\" (%u)", flag);
1085 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1086 return -1;
1087 }
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001088
paul718e3742002-12-13 20:15:29 +00001089 /* If it is contained in an UPDATE message that is received from an
1090 external peer, then this attribute MUST be ignored by the
1091 receiving speaker. */
1092 if (peer_sort (peer) == BGP_PEER_EBGP)
1093 {
paul9985f832005-02-09 15:51:56 +00001094 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001095 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001096 }
1097
1098 if (length == 4)
1099 attr->local_pref = stream_getl (peer->ibuf);
1100 else
1101 attr->local_pref = 0;
1102
1103 /* Set atomic aggregate flag. */
1104 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1105
Paul Jakmab881c702010-11-23 16:35:42 +00001106 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001107}
1108
1109/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001110static int
paul718e3742002-12-13 20:15:29 +00001111bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001112 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001113{
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001114 bgp_size_t total;
1115
1116 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1117 /* Flag checks. */
Denis Ovsienkob84b62d2011-09-27 15:47:25 +04001118 if (flag != BGP_ATTR_FLAG_TRANS)
1119 {
1120 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1121 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
1122 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1123 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
1124 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1125 zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
1126 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
1127 return -1;
1128 }
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001129
1130 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001131 if (length != 0)
1132 {
1133 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1134
Paul Jakmab881c702010-11-23 16:35:42 +00001135 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1136 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1137 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001138 }
1139
1140 /* Set atomic aggregate flag. */
1141 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1142
Paul Jakmab881c702010-11-23 16:35:42 +00001143 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001144}
1145
1146/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001147static int
paul718e3742002-12-13 20:15:29 +00001148bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1149 struct attr *attr, u_char flag)
1150{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001151 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001152 struct attr_extra *attre = bgp_attr_extra_get (attr);
1153
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001154 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001155 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001156 wantedlen = 8;
1157
1158 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001159 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001160 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001161
Paul Jakmab881c702010-11-23 16:35:42 +00001162 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1163 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1164 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001165 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001166
1167 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1168 attre->aggregator_as = stream_getl (peer->ibuf);
1169 else
1170 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001171 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001172
1173 /* Set atomic aggregate flag. */
1174 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1175
Paul Jakmab881c702010-11-23 16:35:42 +00001176 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001177}
1178
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001179/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001180static bgp_attr_parse_ret_t
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001181bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001182 struct attr *attr, u_char flag,
1183 as_t *as4_aggregator_as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001184 struct in_addr *as4_aggregator_addr)
1185{
1186 if (length != 8)
1187 {
1188 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001189 return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
1190 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1191 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001192 }
1193 *as4_aggregator_as = stream_getl (peer->ibuf);
1194 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1195
1196 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1197
Paul Jakmab881c702010-11-23 16:35:42 +00001198 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001199}
1200
1201/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1202 */
Paul Jakmab881c702010-11-23 16:35:42 +00001203static bgp_attr_parse_ret_t
1204bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001205 struct aspath *as4_path, as_t as4_aggregator,
1206 struct in_addr *as4_aggregator_addr)
1207{
1208 int ignore_as4_path = 0;
1209 struct aspath *newpath;
1210 struct attr_extra *attre = attr->extra;
1211
Paul Jakmab881c702010-11-23 16:35:42 +00001212 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001213 {
1214 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1215 * if given.
1216 * It is worth a warning though, because the peer really
1217 * should not send them
1218 */
1219 if (BGP_DEBUG(as4, AS4))
1220 {
1221 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1222 zlog_debug ("[AS4] %s %s AS4_PATH",
1223 peer->host, "AS4 capable peer, yet it sent");
1224
1225 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1226 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1227 peer->host, "AS4 capable peer, yet it sent");
1228 }
1229
Paul Jakmab881c702010-11-23 16:35:42 +00001230 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001231 }
1232
Paul Jakmab881c702010-11-23 16:35:42 +00001233 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
1234 && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001235 {
1236 /* Hu? This is not supposed to happen at all!
1237 * got as4_path and no aspath,
1238 * This should already
1239 * have been handled by 'well known attributes missing'
1240 * But... yeah, paranoia
1241 * Take this as a "malformed attribute"
1242 */
1243 zlog (peer->log, LOG_ERR,
1244 "%s BGP not AS4 capable peer sent AS4_PATH but"
1245 " no AS_PATH, cant do anything here", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001246 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1247 BGP_NOTIFY_UPDATE_MAL_ATTR,
1248 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001249 }
1250
1251 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1252 * because that may override AS4_PATH
1253 */
1254 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1255 {
Paul Jakmab881c702010-11-23 16:35:42 +00001256 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001257 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001258 assert (attre);
1259
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001260 /* received both.
1261 * if the as_number in aggregator is not AS_TRANS,
1262 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1263 * and the Aggregator shall be taken as
1264 * info on the aggregating node, and the AS_PATH
1265 * shall be taken as the AS_PATH
1266 * otherwise
1267 * the Aggregator shall be ignored and the
1268 * AS4_AGGREGATOR shall be taken as the
1269 * Aggregating node and the AS_PATH is to be
1270 * constructed "as in all other cases"
1271 */
Paul Jakmab881c702010-11-23 16:35:42 +00001272 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001273 {
1274 /* ignore */
1275 if ( BGP_DEBUG(as4, AS4))
1276 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1277 " send AGGREGATOR != AS_TRANS and"
1278 " AS4_AGGREGATOR, so ignore"
1279 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1280 ignore_as4_path = 1;
1281 }
1282 else
1283 {
1284 /* "New_aggregator shall be taken as aggregator" */
1285 attre->aggregator_as = as4_aggregator;
1286 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1287 }
1288 }
1289 else
1290 {
1291 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1292 * That is bogus - but reading the conditions
1293 * we have to handle AS4_AGGREGATOR as if it were
1294 * AGGREGATOR in that case
1295 */
1296 if ( BGP_DEBUG(as4, AS4))
1297 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1298 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1299 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001300 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001301 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1302 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1303 }
1304 }
1305
1306 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001307 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001308 {
1309 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001310 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001311 attr->aspath = aspath_intern (newpath);
1312 }
Paul Jakmab881c702010-11-23 16:35:42 +00001313 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001314}
1315
paul718e3742002-12-13 20:15:29 +00001316/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001317static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001318bgp_attr_community (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001319 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001320{
Paul Jakmab881c702010-11-23 16:35:42 +00001321 bgp_size_t total
1322 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1323
paul718e3742002-12-13 20:15:29 +00001324 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001325 {
1326 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001327 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001328 }
Paul Jakma0c466382010-12-05 17:17:26 +00001329
1330 attr->community =
1331 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1332
1333 /* XXX: fix community_parse to use stream API and remove this */
1334 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001335
Paul Jakma0c466382010-12-05 17:17:26 +00001336 if (!attr->community)
Paul Jakmab881c702010-11-23 16:35:42 +00001337 return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
1338 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1339 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001340
paul718e3742002-12-13 20:15:29 +00001341 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1342
Paul Jakmab881c702010-11-23 16:35:42 +00001343 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001344}
1345
1346/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001347static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001348bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1349 struct attr *attr, u_char flag)
1350{
1351 if (length != 4)
1352 {
1353 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1354
Paul Jakmab881c702010-11-23 16:35:42 +00001355 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1356 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1357 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001358 }
1359
Paul Jakmafb982c22007-05-04 20:15:47 +00001360 (bgp_attr_extra_get (attr))->originator_id.s_addr
1361 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001362
1363 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1364
Paul Jakmab881c702010-11-23 16:35:42 +00001365 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001366}
1367
1368/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001369static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001370bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1371 struct attr *attr, u_char flag)
1372{
1373 /* Check length. */
1374 if (length % 4)
1375 {
1376 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1377
Paul Jakmab881c702010-11-23 16:35:42 +00001378 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1379 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1380 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001381 }
1382
Paul Jakmafb982c22007-05-04 20:15:47 +00001383 (bgp_attr_extra_get (attr))->cluster
1384 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001385
1386 /* XXX: Fix cluster_parse to use stream API and then remove this */
1387 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001388
1389 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1390
Paul Jakmab881c702010-11-23 16:35:42 +00001391 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001392}
1393
1394/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001395int
paul718e3742002-12-13 20:15:29 +00001396bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1397 struct bgp_nlri *mp_update)
1398{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001399 afi_t afi;
1400 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001401 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001402 size_t start;
paul718e3742002-12-13 20:15:29 +00001403 int ret;
1404 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001405 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001406
1407 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001408 s = BGP_INPUT(peer);
1409 start = stream_get_getp(s);
1410
1411 /* safe to read statically sized header? */
1412#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001413#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001414 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001415 {
1416 zlog_info ("%s: %s sent invalid length, %lu",
1417 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001418 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001419 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001420
paul718e3742002-12-13 20:15:29 +00001421 /* Load AFI, SAFI. */
1422 afi = stream_getw (s);
1423 safi = stream_getc (s);
1424
1425 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001426 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001427
Paul Jakma03292802008-06-07 20:37:10 +00001428 if (LEN_LEFT < attre->mp_nexthop_len)
1429 {
1430 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1431 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001432 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001433 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001434
paul718e3742002-12-13 20:15:29 +00001435 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001436 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001437 {
1438 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001439 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001440 /* Probably needed for RFC 2283 */
1441 if (attr->nexthop.s_addr == 0)
1442 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001443 break;
1444 case 12:
1445 {
1446 u_int32_t rd_high;
1447 u_int32_t rd_low;
1448
1449 rd_high = stream_getl (s);
1450 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001451 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001452 }
1453 break;
1454#ifdef HAVE_IPV6
1455 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001456 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001457 break;
1458 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001459 stream_get (&attre->mp_nexthop_global, s, 16);
1460 stream_get (&attre->mp_nexthop_local, s, 16);
1461 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001462 {
1463 char buf1[INET6_ADDRSTRLEN];
1464 char buf2[INET6_ADDRSTRLEN];
1465
1466 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001467 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 +00001468 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001469 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001470 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001471 buf2, INET6_ADDRSTRLEN));
1472
Paul Jakmafb982c22007-05-04 20:15:47 +00001473 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001474 }
1475 break;
1476#endif /* HAVE_IPV6 */
1477 default:
Paul Jakma03292802008-06-07 20:37:10 +00001478 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1479 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001480 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001481 }
1482
Paul Jakma03292802008-06-07 20:37:10 +00001483 if (!LEN_LEFT)
1484 {
1485 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1486 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001487 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001488 }
paul718e3742002-12-13 20:15:29 +00001489
Paul Jakma6e4ab122007-04-10 19:36:48 +00001490 {
1491 u_char val;
1492 if ((val = stream_getc (s)))
1493 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1494 peer->host, val);
1495 }
1496
1497 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001498 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001499 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001500 {
1501 zlog_info ("%s: (%s) Failed to read NLRI",
1502 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001503 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001504 }
paul718e3742002-12-13 20:15:29 +00001505
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001506 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001507 {
1508 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001509 if (ret < 0)
1510 {
1511 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1512 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001513 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001514 }
paul718e3742002-12-13 20:15:29 +00001515 }
1516
1517 mp_update->afi = afi;
1518 mp_update->safi = safi;
1519 mp_update->nlri = stream_pnt (s);
1520 mp_update->length = nlri_len;
1521
paul9985f832005-02-09 15:51:56 +00001522 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001523
Paul Jakmab881c702010-11-23 16:35:42 +00001524 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001525#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001526}
1527
1528/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001529int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001530bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001531 struct bgp_nlri *mp_withdraw)
1532{
1533 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001534 afi_t afi;
1535 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001536 u_int16_t withdraw_len;
1537 int ret;
1538
1539 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001540
1541#define BGP_MP_UNREACH_MIN_SIZE 3
1542 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001543 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001544
paul718e3742002-12-13 20:15:29 +00001545 afi = stream_getw (s);
1546 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001547
1548 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001549
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001550 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001551 {
1552 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1553 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001554 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001555 }
1556
1557 mp_withdraw->afi = afi;
1558 mp_withdraw->safi = safi;
1559 mp_withdraw->nlri = stream_pnt (s);
1560 mp_withdraw->length = withdraw_len;
1561
paul9985f832005-02-09 15:51:56 +00001562 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001563
Paul Jakmab881c702010-11-23 16:35:42 +00001564 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001565}
1566
1567/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001568static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001569bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001570 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001571{
Paul Jakmab881c702010-11-23 16:35:42 +00001572 bgp_size_t total
1573 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1574
paul718e3742002-12-13 20:15:29 +00001575 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001576 {
1577 if (attr->extra)
1578 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001579 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001580 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001581 }
Paul Jakma0c466382010-12-05 17:17:26 +00001582
1583 (bgp_attr_extra_get (attr))->ecommunity =
1584 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1585 /* XXX: fix ecommunity_parse to use stream API */
1586 stream_forward_getp (peer->ibuf, length);
1587
1588 if (!attr->extra->ecommunity)
Paul Jakmab881c702010-11-23 16:35:42 +00001589 return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
1590 flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1591 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001592
paul718e3742002-12-13 20:15:29 +00001593 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1594
Paul Jakmab881c702010-11-23 16:35:42 +00001595 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001596}
1597
1598/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001599static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001600bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1601 u_char type, bgp_size_t length, u_char *startp)
1602{
1603 bgp_size_t total;
1604 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001605 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001606
hassof4184462005-02-01 20:13:16 +00001607 if (BGP_DEBUG (normal, NORMAL))
1608 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1609 peer->host, type, length);
1610
paul718e3742002-12-13 20:15:29 +00001611 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001612 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001613 "Unknown attribute type %d length %d is received", type, length);
1614
1615 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001616 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001617
1618 /* Adjest total length to include type and length. */
1619 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1620
1621 /* If any of the mandatory well-known attributes are not recognized,
1622 then the Error Subcode is set to Unrecognized Well-known
1623 Attribute. The Data field contains the unrecognized attribute
1624 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001625 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001626 {
Paul Jakmab881c702010-11-23 16:35:42 +00001627 return bgp_attr_malformed (peer, type, flag,
1628 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1629 startp, total);
paul718e3742002-12-13 20:15:29 +00001630 }
1631
1632 /* Unrecognized non-transitive optional attributes must be quietly
1633 ignored and not passed along to other BGP peers. */
1634 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001635 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001636
1637 /* If a path with recognized transitive optional attribute is
1638 accepted and passed along to other BGP peers and the Partial bit
1639 in the Attribute Flags octet is set to 1 by some previous AS, it
1640 is not set back to 0 by the current AS. */
1641 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1642
1643 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001644 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001645 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001646
Paul Jakmafb982c22007-05-04 20:15:47 +00001647 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001648
1649 if (transit->val)
1650 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1651 transit->length + total);
1652 else
1653 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1654
1655 memcpy (transit->val + transit->length, startp, total);
1656 transit->length += total;
1657
Paul Jakmab881c702010-11-23 16:35:42 +00001658 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001659}
1660
1661/* Read attribute of update packet. This function is called from
1662 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001663bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001664bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1665 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1666{
1667 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001668 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001669 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001670 bgp_size_t length;
1671 u_char *startp, *endp;
1672 u_char *attr_endp;
1673 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001674 /* we need the as4_path only until we have synthesized the as_path with it */
1675 /* same goes for as4_aggregator */
1676 struct aspath *as4_path = NULL;
1677 as_t as4_aggregator = 0;
1678 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001679
1680 /* Initialize bitmap. */
1681 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1682
1683 /* End pointer of BGP attribute. */
1684 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001685
paul718e3742002-12-13 20:15:29 +00001686 /* Get attributes to the end of attribute length. */
1687 while (BGP_INPUT_PNT (peer) < endp)
1688 {
1689 /* Check remaining length check.*/
1690 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1691 {
gdtc29fdba2004-12-09 14:46:46 +00001692 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001693 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001694 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001695 peer->host,
1696 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001697
1698 bgp_notify_send (peer,
1699 BGP_NOTIFY_UPDATE_ERR,
1700 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001701 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001702 }
1703
1704 /* Fetch attribute flag and type. */
1705 startp = BGP_INPUT_PNT (peer);
Denis Ovsienko2d42e682011-09-27 15:35:39 +04001706 /* "The lower-order four bits of the Attribute Flags octet are
1707 unused. They MUST be zero when sent and MUST be ignored when
1708 received." */
1709 flag = 0xF0 & stream_getc (BGP_INPUT (peer));
paul718e3742002-12-13 20:15:29 +00001710 type = stream_getc (BGP_INPUT (peer));
1711
Paul Jakma370b64a2007-12-22 16:49:52 +00001712 /* Check whether Extended-Length applies and is in bounds */
1713 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1714 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1715 {
1716 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001717 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001718 peer->host,
1719 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1720
1721 bgp_notify_send (peer,
1722 BGP_NOTIFY_UPDATE_ERR,
1723 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001724 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001725 }
1726
paul718e3742002-12-13 20:15:29 +00001727 /* Check extended attribue length bit. */
1728 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1729 length = stream_getw (BGP_INPUT (peer));
1730 else
1731 length = stream_getc (BGP_INPUT (peer));
1732
1733 /* If any attribute appears more than once in the UPDATE
1734 message, then the Error Subcode is set to Malformed Attribute
1735 List. */
1736
1737 if (CHECK_BITMAP (seen, type))
1738 {
1739 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001740 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001741 peer->host, type);
1742
1743 bgp_notify_send (peer,
1744 BGP_NOTIFY_UPDATE_ERR,
1745 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001746 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001747 }
1748
1749 /* Set type to bitmap to check duplicate attribute. `type' is
1750 unsigned char so it never overflow bitmap range. */
1751
1752 SET_BITMAP (seen, type);
1753
1754 /* Overflow check. */
1755 attr_endp = BGP_INPUT_PNT (peer) + length;
1756
1757 if (attr_endp > endp)
1758 {
1759 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001760 "%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 +00001761 bgp_notify_send (peer,
1762 BGP_NOTIFY_UPDATE_ERR,
1763 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001764 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001765 }
1766
1767 /* OK check attribute and store it's value. */
1768 switch (type)
1769 {
1770 case BGP_ATTR_ORIGIN:
1771 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1772 break;
1773 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001774 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001775 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001776 case BGP_ATTR_AS4_PATH:
Paul Jakmab881c702010-11-23 16:35:42 +00001777 ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001778 break;
paul718e3742002-12-13 20:15:29 +00001779 case BGP_ATTR_NEXT_HOP:
1780 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1781 break;
1782 case BGP_ATTR_MULTI_EXIT_DISC:
1783 ret = bgp_attr_med (peer, length, attr, flag, startp);
1784 break;
1785 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001786 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001787 break;
1788 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001789 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001790 break;
1791 case BGP_ATTR_AGGREGATOR:
1792 ret = bgp_attr_aggregator (peer, length, attr, flag);
1793 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001794 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakmab881c702010-11-23 16:35:42 +00001795 ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
1796 &as4_aggregator,
1797 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001798 break;
paul718e3742002-12-13 20:15:29 +00001799 case BGP_ATTR_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001800 ret = bgp_attr_community (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001801 break;
1802 case BGP_ATTR_ORIGINATOR_ID:
1803 ret = bgp_attr_originator_id (peer, length, attr, flag);
1804 break;
1805 case BGP_ATTR_CLUSTER_LIST:
1806 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1807 break;
1808 case BGP_ATTR_MP_REACH_NLRI:
1809 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1810 break;
1811 case BGP_ATTR_MP_UNREACH_NLRI:
1812 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1813 break;
1814 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001815 ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001816 break;
1817 default:
1818 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1819 break;
1820 }
Paul Jakmab881c702010-11-23 16:35:42 +00001821
1822 /* If hard error occured immediately return to the caller. */
1823 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001824 {
1825 zlog (peer->log, LOG_WARNING,
1826 "%s: Attribute %s, parse error",
1827 peer->host,
1828 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001829 bgp_notify_send (peer,
1830 BGP_NOTIFY_UPDATE_ERR,
1831 BGP_NOTIFY_UPDATE_MAL_ATTR);
1832 if (as4_path)
1833 aspath_unintern (&as4_path);
1834 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001835 }
Paul Jakmab881c702010-11-23 16:35:42 +00001836 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1837 {
1838
1839 zlog (peer->log, LOG_WARNING,
1840 "%s: Attribute %s, parse error - treating as withdrawal",
1841 peer->host,
1842 LOOKUP (attr_str, type));
1843 if (as4_path)
1844 aspath_unintern (&as4_path);
1845 return ret;
1846 }
1847
paul718e3742002-12-13 20:15:29 +00001848 /* Check the fetched length. */
1849 if (BGP_INPUT_PNT (peer) != attr_endp)
1850 {
1851 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001852 "%s: BGP attribute %s, fetch error",
1853 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001854 bgp_notify_send (peer,
1855 BGP_NOTIFY_UPDATE_ERR,
1856 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001857 if (as4_path)
1858 aspath_unintern (&as4_path);
1859 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001860 }
1861 }
1862
1863 /* Check final read pointer is same as end pointer. */
1864 if (BGP_INPUT_PNT (peer) != endp)
1865 {
1866 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001867 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001868 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001869 bgp_notify_send (peer,
1870 BGP_NOTIFY_UPDATE_ERR,
1871 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001872 if (as4_path)
1873 aspath_unintern (&as4_path);
1874 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001875 }
1876
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001877 /*
1878 * At this place we can see whether we got AS4_PATH and/or
1879 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1880 * We can not do this before we've read all attributes because
1881 * the as4 handling does not say whether AS4_PATH has to be sent
1882 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1883 * in relationship to AGGREGATOR.
1884 * So, to be defensive, we are not relying on any order and read
1885 * all attributes first, including these 32bit ones, and now,
1886 * afterwards, we look what and if something is to be done for as4.
1887 */
Paul Jakmab881c702010-11-23 16:35:42 +00001888 if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001889 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001890 {
1891 if (as4_path)
1892 aspath_unintern (&as4_path);
1893 return BGP_ATTR_PARSE_ERROR;
1894 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001895
1896 /* At this stage, we have done all fiddling with as4, and the
1897 * resulting info is in attr->aggregator resp. attr->aspath
1898 * so we can chuck as4_aggregator and as4_path alltogether in
1899 * order to save memory
1900 */
Paul Jakmab881c702010-11-23 16:35:42 +00001901 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001902 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001903 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001904 /* The flag that we got this is still there, but that does not
1905 * do any trouble
1906 */
1907 }
1908 /*
1909 * The "rest" of the code does nothing with as4_aggregator.
1910 * there is no memory attached specifically which is not part
1911 * of the attr.
1912 * so ignoring just means do nothing.
1913 */
1914 /*
1915 * Finally do the checks on the aspath we did not do yet
1916 * because we waited for a potentially synthesized aspath.
1917 */
Paul Jakmab881c702010-11-23 16:35:42 +00001918 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001919 {
Paul Jakmab881c702010-11-23 16:35:42 +00001920 ret = bgp_attr_aspath_check (peer, attr, flag);
1921 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001922 return ret;
1923 }
1924
paul718e3742002-12-13 20:15:29 +00001925 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001926 if (attr->extra && attr->extra->transit)
1927 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001928
Paul Jakmab881c702010-11-23 16:35:42 +00001929 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001930}
1931
1932/* Well-known attribute check. */
1933int
1934bgp_attr_check (struct peer *peer, struct attr *attr)
1935{
1936 u_char type = 0;
1937
1938 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1939 type = BGP_ATTR_ORIGIN;
1940
1941 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1942 type = BGP_ATTR_AS_PATH;
1943
1944 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1945 type = BGP_ATTR_NEXT_HOP;
1946
1947 if (peer_sort (peer) == BGP_PEER_IBGP
1948 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1949 type = BGP_ATTR_LOCAL_PREF;
1950
1951 if (type)
1952 {
1953 zlog (peer->log, LOG_WARNING,
1954 "%s Missing well-known attribute %d.",
1955 peer->host, type);
1956 bgp_notify_send_with_data (peer,
1957 BGP_NOTIFY_UPDATE_ERR,
1958 BGP_NOTIFY_UPDATE_MISS_ATTR,
1959 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00001960 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001961 }
Paul Jakmab881c702010-11-23 16:35:42 +00001962 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001963}
1964
1965int stream_put_prefix (struct stream *, struct prefix *);
1966
1967/* Make attribute packet. */
1968bgp_size_t
1969bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1970 struct stream *s, struct attr *attr, struct prefix *p,
1971 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001972 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001973{
paulfe69a502005-09-10 16:55:02 +00001974 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001975 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001976 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001977 int send_as4_path = 0;
1978 int send_as4_aggregator = 0;
1979 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001980
1981 if (! bgp)
1982 bgp = bgp_get_default ();
1983
1984 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001985 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001986
1987 /* Origin attribute. */
1988 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1989 stream_putc (s, BGP_ATTR_ORIGIN);
1990 stream_putc (s, 1);
1991 stream_putc (s, attr->origin);
1992
1993 /* AS path attribute. */
1994
1995 /* If remote-peer is EBGP */
1996 if (peer_sort (peer) == BGP_PEER_EBGP
1997 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001998 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001999 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002000 {
2001 aspath = aspath_dup (attr->aspath);
2002
2003 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2004 {
2005 /* Strip the confed info, and then stuff our path CONFED_ID
2006 on the front */
2007 aspath = aspath_delete_confed_seq (aspath);
2008 aspath = aspath_add_seq (aspath, bgp->confed_id);
2009 }
2010 else
2011 {
2012 aspath = aspath_add_seq (aspath, peer->local_as);
2013 if (peer->change_local_as)
2014 aspath = aspath_add_seq (aspath, peer->change_local_as);
2015 }
2016 }
2017 else if (peer_sort (peer) == BGP_PEER_CONFED)
2018 {
2019 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2020 aspath = aspath_dup (attr->aspath);
2021 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2022 }
2023 else
2024 aspath = attr->aspath;
2025
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002026 /* If peer is not AS4 capable, then:
2027 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2028 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2029 * types are in it (i.e. exclude them if they are there)
2030 * AND do this only if there is at least one asnum > 65535 in the path!
2031 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2032 * all ASnums > 65535 to BGP_AS_TRANS
2033 */
paul718e3742002-12-13 20:15:29 +00002034
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002035 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2036 stream_putc (s, BGP_ATTR_AS_PATH);
2037 aspath_sizep = stream_get_endp (s);
2038 stream_putw (s, 0);
2039 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2040
2041 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2042 * in the path
2043 */
2044 if (!use32bit && aspath_has_as4 (aspath))
2045 send_as4_path = 1; /* we'll do this later, at the correct place */
2046
paul718e3742002-12-13 20:15:29 +00002047 /* Nexthop attribute. */
2048 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2049 {
2050 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2051 stream_putc (s, BGP_ATTR_NEXT_HOP);
2052 stream_putc (s, 4);
2053 if (safi == SAFI_MPLS_VPN)
2054 {
2055 if (attr->nexthop.s_addr == 0)
2056 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2057 else
2058 stream_put_ipv4 (s, attr->nexthop.s_addr);
2059 }
2060 else
2061 stream_put_ipv4 (s, attr->nexthop.s_addr);
2062 }
2063
2064 /* MED attribute. */
2065 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2066 {
2067 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2068 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2069 stream_putc (s, 4);
2070 stream_putl (s, attr->med);
2071 }
2072
2073 /* Local preference. */
2074 if (peer_sort (peer) == BGP_PEER_IBGP ||
2075 peer_sort (peer) == BGP_PEER_CONFED)
2076 {
2077 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2078 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2079 stream_putc (s, 4);
2080 stream_putl (s, attr->local_pref);
2081 }
2082
2083 /* Atomic aggregate. */
2084 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2085 {
2086 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2087 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2088 stream_putc (s, 0);
2089 }
2090
2091 /* Aggregator. */
2092 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2093 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002094 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002095
2096 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002097 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2098 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002099
2100 if (use32bit)
2101 {
2102 /* AS4 capable peer */
2103 stream_putc (s, 8);
2104 stream_putl (s, attr->extra->aggregator_as);
2105 }
2106 else
2107 {
2108 /* 2-byte AS peer */
2109 stream_putc (s, 6);
2110
2111 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2112 if ( attr->extra->aggregator_as > 65535 )
2113 {
2114 stream_putw (s, BGP_AS_TRANS);
2115
2116 /* we have to send AS4_AGGREGATOR, too.
2117 * we'll do that later in order to send attributes in ascending
2118 * order.
2119 */
2120 send_as4_aggregator = 1;
2121 }
2122 else
2123 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2124 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002125 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002126 }
2127
2128 /* Community attribute. */
2129 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2130 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2131 {
2132 if (attr->community->size * 4 > 255)
2133 {
2134 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2135 stream_putc (s, BGP_ATTR_COMMUNITIES);
2136 stream_putw (s, attr->community->size * 4);
2137 }
2138 else
2139 {
2140 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2141 stream_putc (s, BGP_ATTR_COMMUNITIES);
2142 stream_putc (s, attr->community->size * 4);
2143 }
2144 stream_put (s, attr->community->val, attr->community->size * 4);
2145 }
2146
2147 /* Route Reflector. */
2148 if (peer_sort (peer) == BGP_PEER_IBGP
2149 && from
2150 && peer_sort (from) == BGP_PEER_IBGP)
2151 {
2152 /* Originator ID. */
2153 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2154 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2155 stream_putc (s, 4);
2156
2157 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002158 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002159 else
2160 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002161
2162 /* Cluster list. */
2163 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2164 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2165
Paul Jakma9eda90c2007-08-30 13:36:17 +00002166 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002167 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002168 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002169 /* If this peer configuration's parent BGP has cluster_id. */
2170 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2171 stream_put_in_addr (s, &bgp->cluster_id);
2172 else
2173 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002174 stream_put (s, attr->extra->cluster->list,
2175 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002176 }
2177 else
2178 {
2179 stream_putc (s, 4);
2180 /* If this peer configuration's parent BGP has cluster_id. */
2181 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2182 stream_put_in_addr (s, &bgp->cluster_id);
2183 else
2184 stream_put_in_addr (s, &bgp->router_id);
2185 }
2186 }
2187
2188#ifdef HAVE_IPV6
2189 /* If p is IPv6 address put it into attribute. */
2190 if (p->family == AF_INET6)
2191 {
2192 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002193 struct attr_extra *attre = attr->extra;
2194
2195 assert (attr->extra);
2196
paul718e3742002-12-13 20:15:29 +00002197 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2198 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002199 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002200 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002201 stream_putw (s, AFI_IP6); /* AFI */
2202 stream_putc (s, safi); /* SAFI */
2203
Paul Jakmafb982c22007-05-04 20:15:47 +00002204 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002205
Paul Jakmafb982c22007-05-04 20:15:47 +00002206 if (attre->mp_nexthop_len == 16)
2207 stream_put (s, &attre->mp_nexthop_global, 16);
2208 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002209 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002210 stream_put (s, &attre->mp_nexthop_global, 16);
2211 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002212 }
2213
2214 /* SNPA */
2215 stream_putc (s, 0);
2216
paul718e3742002-12-13 20:15:29 +00002217 /* Prefix write. */
2218 stream_put_prefix (s, p);
2219
2220 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002221 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002222 }
2223#endif /* HAVE_IPV6 */
2224
2225 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2226 {
2227 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002228
2229 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2230 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002231 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002232 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002233 stream_putw (s, AFI_IP); /* AFI */
2234 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2235
2236 stream_putc (s, 4);
2237 stream_put_ipv4 (s, attr->nexthop.s_addr);
2238
2239 /* SNPA */
2240 stream_putc (s, 0);
2241
paul718e3742002-12-13 20:15:29 +00002242 /* Prefix write. */
2243 stream_put_prefix (s, p);
2244
2245 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002246 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002247 }
2248
2249 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2250 {
2251 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002252
2253 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2254 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002255 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002256 stream_putc (s, 0); /* Length of this attribute. */
2257 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002258 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002259
2260 stream_putc (s, 12);
2261 stream_putl (s, 0);
2262 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002263 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002264
2265 /* SNPA */
2266 stream_putc (s, 0);
2267
paul718e3742002-12-13 20:15:29 +00002268 /* Tag, RD, Prefix write. */
2269 stream_putc (s, p->prefixlen + 88);
2270 stream_put (s, tag, 3);
2271 stream_put (s, prd->val, 8);
2272 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2273
2274 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002275 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002276 }
2277
2278 /* Extended Communities attribute. */
2279 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2280 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2281 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002282 struct attr_extra *attre = attr->extra;
2283
2284 assert (attre);
2285
2286 if (peer_sort (peer) == BGP_PEER_IBGP
2287 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002288 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002289 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002290 {
2291 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2292 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002293 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002294 }
2295 else
2296 {
2297 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2298 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002299 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002300 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002301 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002302 }
2303 else
2304 {
paul5228ad22004-06-04 17:58:18 +00002305 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002306 int tbit;
2307 int ecom_tr_size = 0;
2308 int i;
2309
Paul Jakmafb982c22007-05-04 20:15:47 +00002310 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002311 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002312 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002313 tbit = *pnt;
2314
2315 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2316 continue;
2317
2318 ecom_tr_size++;
2319 }
2320
2321 if (ecom_tr_size)
2322 {
2323 if (ecom_tr_size * 8 > 255)
2324 {
2325 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2326 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2327 stream_putw (s, ecom_tr_size * 8);
2328 }
2329 else
2330 {
2331 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2332 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2333 stream_putc (s, ecom_tr_size * 8);
2334 }
2335
Paul Jakmafb982c22007-05-04 20:15:47 +00002336 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002337 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002338 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002339 tbit = *pnt;
2340
2341 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2342 continue;
2343
2344 stream_put (s, pnt, 8);
2345 }
2346 }
paul718e3742002-12-13 20:15:29 +00002347 }
paul718e3742002-12-13 20:15:29 +00002348 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002349
2350 if ( send_as4_path )
2351 {
2352 /* If the peer is NOT As4 capable, AND */
2353 /* there are ASnums > 65535 in path THEN
2354 * give out AS4_PATH */
2355
2356 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2357 * path segments!
2358 * Hm, I wonder... confederation things *should* only be at
2359 * the beginning of an aspath, right? Then we should use
2360 * aspath_delete_confed_seq for this, because it is already
2361 * there! (JK)
2362 * Folks, talk to me: what is reasonable here!?
2363 */
2364 aspath = aspath_delete_confed_seq (aspath);
2365
2366 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2367 stream_putc (s, BGP_ATTR_AS4_PATH);
2368 aspath_sizep = stream_get_endp (s);
2369 stream_putw (s, 0);
2370 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2371 }
2372
2373 if (aspath != attr->aspath)
2374 aspath_free (aspath);
2375
2376 if ( send_as4_aggregator )
2377 {
2378 assert (attr->extra);
2379
2380 /* send AS4_AGGREGATOR, at this place */
2381 /* this section of code moved here in order to ensure the correct
2382 * *ascending* order of attributes
2383 */
2384 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2385 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2386 stream_putc (s, 8);
2387 stream_putl (s, attr->extra->aggregator_as);
2388 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2389 }
Paul Jakma41367172007-08-06 15:24:51 +00002390
paul718e3742002-12-13 20:15:29 +00002391 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002392 if (attr->extra && attr->extra->transit)
2393 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002394
2395 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002396 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002397}
2398
2399bgp_size_t
2400bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2401 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002402 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002403{
2404 unsigned long cp;
2405 unsigned long attrlen_pnt;
2406 bgp_size_t size;
2407
paul9985f832005-02-09 15:51:56 +00002408 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002409
2410 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2411 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2412
paul9985f832005-02-09 15:51:56 +00002413 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002414 stream_putc (s, 0); /* Length of this attribute. */
2415
2416 stream_putw (s, family2afi (p->family));
2417
2418 if (safi == SAFI_MPLS_VPN)
2419 {
2420 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002421 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002422
2423 /* prefix. */
2424 stream_putc (s, p->prefixlen + 88);
2425 stream_put (s, tag, 3);
2426 stream_put (s, prd->val, 8);
2427 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2428 }
2429 else
2430 {
2431 /* SAFI */
2432 stream_putc (s, safi);
2433
2434 /* prefix */
2435 stream_put_prefix (s, p);
2436 }
2437
2438 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002439 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002440 stream_putc_at (s, attrlen_pnt, size);
2441
paul9985f832005-02-09 15:51:56 +00002442 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002443}
2444
2445/* Initialization of attribute. */
2446void
paulfe69a502005-09-10 16:55:02 +00002447bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002448{
paul718e3742002-12-13 20:15:29 +00002449 aspath_init ();
2450 attrhash_init ();
2451 community_init ();
2452 ecommunity_init ();
2453 cluster_init ();
2454 transit_init ();
2455}
2456
Chris Caputo228da422009-07-18 05:44:03 +00002457void
2458bgp_attr_finish (void)
2459{
2460 aspath_finish ();
2461 attrhash_finish ();
2462 community_finish ();
2463 ecommunity_finish ();
2464 cluster_finish ();
2465 transit_finish ();
2466}
2467
paul718e3742002-12-13 20:15:29 +00002468/* Make attribute packet. */
2469void
paula3845922003-10-18 01:30:50 +00002470bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2471 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002472{
2473 unsigned long cp;
2474 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002475 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002476 struct aspath *aspath;
2477
2478 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002479 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002480
2481 /* Place holder of length. */
2482 stream_putw (s, 0);
2483
2484 /* Origin attribute. */
2485 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2486 stream_putc (s, BGP_ATTR_ORIGIN);
2487 stream_putc (s, 1);
2488 stream_putc (s, attr->origin);
2489
2490 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002491
2492 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2493 stream_putc (s, BGP_ATTR_AS_PATH);
2494 aspath_lenp = stream_get_endp (s);
2495 stream_putw (s, 0);
2496
2497 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002498
2499 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002500 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2501 if(prefix != NULL
2502#ifdef HAVE_IPV6
2503 && prefix->family != AF_INET6
2504#endif /* HAVE_IPV6 */
2505 )
2506 {
2507 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2508 stream_putc (s, BGP_ATTR_NEXT_HOP);
2509 stream_putc (s, 4);
2510 stream_put_ipv4 (s, attr->nexthop.s_addr);
2511 }
paul718e3742002-12-13 20:15:29 +00002512
2513 /* MED attribute. */
2514 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2515 {
2516 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2517 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2518 stream_putc (s, 4);
2519 stream_putl (s, attr->med);
2520 }
2521
2522 /* Local preference. */
2523 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2524 {
2525 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2526 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2527 stream_putc (s, 4);
2528 stream_putl (s, attr->local_pref);
2529 }
2530
2531 /* Atomic aggregate. */
2532 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2533 {
2534 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2535 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2536 stream_putc (s, 0);
2537 }
2538
2539 /* Aggregator. */
2540 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2541 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002542 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002543 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2544 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002545 stream_putc (s, 8);
2546 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002547 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002548 }
2549
2550 /* Community attribute. */
2551 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2552 {
2553 if (attr->community->size * 4 > 255)
2554 {
2555 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2556 stream_putc (s, BGP_ATTR_COMMUNITIES);
2557 stream_putw (s, attr->community->size * 4);
2558 }
2559 else
2560 {
2561 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2562 stream_putc (s, BGP_ATTR_COMMUNITIES);
2563 stream_putc (s, attr->community->size * 4);
2564 }
2565 stream_put (s, attr->community->val, attr->community->size * 4);
2566 }
2567
paula3845922003-10-18 01:30:50 +00002568#ifdef HAVE_IPV6
2569 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002570 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2571 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002572 {
2573 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002574 struct attr_extra *attre = attr->extra;
2575
paula3845922003-10-18 01:30:50 +00002576 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2577 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002578 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002579
2580 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002581 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002582 stream_putw(s, AFI_IP6); /* AFI */
2583 stream_putc(s, SAFI_UNICAST); /* SAFI */
2584
2585 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002586 stream_putc(s, attre->mp_nexthop_len);
2587 stream_put(s, &attre->mp_nexthop_global, 16);
2588 if (attre->mp_nexthop_len == 32)
2589 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002590
2591 /* SNPA */
2592 stream_putc(s, 0);
2593
2594 /* Prefix */
2595 stream_put_prefix(s, prefix);
2596
2597 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002598 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002599 }
2600#endif /* HAVE_IPV6 */
2601
paul718e3742002-12-13 20:15:29 +00002602 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002603 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002604 stream_putw_at (s, cp, len);
2605}