blob: 6905ab522f6c40437a0618d2b1cb40c879e3d269 [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). */
776 if (flag != BGP_ATTR_FLAG_TRANS)
777 {
778 zlog (peer->log, LOG_ERR,
779 "Origin attribute flag isn't transitive %d", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000780 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
781 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
782 startp, total);
paul718e3742002-12-13 20:15:29 +0000783 }
784
785 /* If any recognized attribute has Attribute Length that conflicts
786 with the expected length (based on the attribute type code), then
787 the Error Subcode is set to Attribute Length Error. The Data
788 field contains the erroneous attribute (type, length and
789 value). */
790 if (length != 1)
791 {
792 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
793 length);
Paul Jakmab881c702010-11-23 16:35:42 +0000794 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
795 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
796 startp, total);
paul718e3742002-12-13 20:15:29 +0000797 }
798
799 /* Fetch origin attribute. */
800 attr->origin = stream_getc (BGP_INPUT (peer));
801
802 /* If the ORIGIN attribute has an undefined value, then the Error
803 Subcode is set to Invalid Origin Attribute. The Data field
804 contains the unrecognized attribute (type, length and value). */
805 if ((attr->origin != BGP_ORIGIN_IGP)
806 && (attr->origin != BGP_ORIGIN_EGP)
807 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
808 {
809 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
810 attr->origin);
Paul Jakmab881c702010-11-23 16:35:42 +0000811 return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
812 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
813 startp, total);
paul718e3742002-12-13 20:15:29 +0000814 }
815
816 /* Set oring attribute flag. */
817 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
818
819 return 0;
820}
Paul Jakmaab005292010-11-27 22:48:34 +0000821
822/* Parse AS path information. This function is wrapper of
823 aspath_parse. */
824static int
paul718e3742002-12-13 20:15:29 +0000825bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Paul Jakmaab005292010-11-27 22:48:34 +0000826 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +0000827{
Paul Jakmaab005292010-11-27 22:48:34 +0000828 bgp_size_t total;
paul718e3742002-12-13 20:15:29 +0000829
Paul Jakmaab005292010-11-27 22:48:34 +0000830 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
paul718e3742002-12-13 20:15:29 +0000831
Paul Jakmaab005292010-11-27 22:48:34 +0000832 /* Flag check. */
833 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
834 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000835 {
836 zlog (peer->log, LOG_ERR,
Paul Jakmaab005292010-11-27 22:48:34 +0000837 "As-Path attribute flag isn't transitive %d", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000838 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
839 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
840 startp, total);
Chris Hallcddb8112010-08-09 22:31:37 +0400841 }
Paul Jakmaab005292010-11-27 22:48:34 +0000842
843 /*
844 * peer with AS4 => will get 4Byte ASnums
845 * otherwise, will get 16 Bit
846 */
847 attr->aspath = aspath_parse (peer->ibuf, length,
848 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
849
850 /* In case of IBGP, length will be zero. */
851 if (! attr->aspath)
paul718e3742002-12-13 20:15:29 +0000852 {
Paul Jakmab881c702010-11-23 16:35:42 +0000853 zlog (peer->log, LOG_ERR,
854 "Malformed AS path from %s, length is %d",
855 peer->host, length);
856 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
857 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
858 NULL, 0);
Paul Jakmaab005292010-11-27 22:48:34 +0000859 }
Chris Hallcddb8112010-08-09 22:31:37 +0400860
Paul Jakmaab005292010-11-27 22:48:34 +0000861 /* Set aspath attribute flag. */
862 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
paul718e3742002-12-13 20:15:29 +0000863
Paul Jakmab881c702010-11-23 16:35:42 +0000864 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000865}
866
Paul Jakmab881c702010-11-23 16:35:42 +0000867static bgp_attr_parse_ret_t
868bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000869{
870 /* These checks were part of bgp_attr_aspath, but with
871 * as4 we should to check aspath things when
872 * aspath synthesizing with as4_path has already taken place.
873 * Otherwise we check ASPATH and use the synthesized thing, and that is
874 * not right.
875 * So do the checks later, i.e. here
876 */
877 struct bgp *bgp = peer->bgp;
878 struct aspath *aspath;
879
paul718e3742002-12-13 20:15:29 +0000880 bgp = peer->bgp;
881
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300882 /* Confederation sanity check. */
883 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
884 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
885 {
886 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +0000887 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
888 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
889 NULL, 0);
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300890 }
891
paul718e3742002-12-13 20:15:29 +0000892 /* First AS check for EBGP. */
893 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
894 {
895 if (peer_sort (peer) == BGP_PEER_EBGP
896 && ! aspath_firstas_check (attr->aspath, peer->as))
897 {
898 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400899 "%s incorrect first AS (must be %u)", peer->host, peer->as);
Paul Jakmab881c702010-11-23 16:35:42 +0000900 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
901 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
902 NULL, 0);
paul718e3742002-12-13 20:15:29 +0000903 }
904 }
905
906 /* local-as prepend */
907 if (peer->change_local_as &&
908 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
909 {
910 aspath = aspath_dup (attr->aspath);
911 aspath = aspath_add_seq (aspath, peer->change_local_as);
Paul Jakmaf6f434b2010-11-23 21:28:03 +0000912 aspath_unintern (&attr->aspath);
paul718e3742002-12-13 20:15:29 +0000913 attr->aspath = aspath_intern (aspath);
914 }
915
Paul Jakmab881c702010-11-23 16:35:42 +0000916 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000917}
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000918
Paul Jakmaab005292010-11-27 22:48:34 +0000919/* Parse AS4 path information. This function is another wrapper of
920 aspath_parse. */
921static int
Paul Jakmab881c702010-11-23 16:35:42 +0000922bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
923 struct attr *attr, u_char flag, u_char *startp,
924 struct aspath **as4_path)
Paul Jakmaab005292010-11-27 22:48:34 +0000925{
Paul Jakmab881c702010-11-23 16:35:42 +0000926 bgp_size_t total;
927
928 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
929
930 /* Flag check. */
931 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
932 || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
933 {
934 zlog (peer->log, LOG_ERR,
935 "As4-Path attribute flag isn't optional/transitive %d", flag);
936 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
937 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
938 startp, total);
939 }
940
Paul Jakmaab005292010-11-27 22:48:34 +0000941 *as4_path = aspath_parse (peer->ibuf, length, 1);
942
Paul Jakmab881c702010-11-23 16:35:42 +0000943 /* In case of IBGP, length will be zero. */
944 if (!*as4_path)
945 {
946 zlog (peer->log, LOG_ERR,
947 "Malformed AS4 path from %s, length is %d",
948 peer->host, length);
949 return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
950 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
951 NULL, 0);
952 }
953
Paul Jakmaab005292010-11-27 22:48:34 +0000954 /* Set aspath attribute flag. */
955 if (as4_path)
956 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
957
Paul Jakmab881c702010-11-23 16:35:42 +0000958 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000959}
960
paul718e3742002-12-13 20:15:29 +0000961/* Nexthop attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +0000962static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +0000963bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
964 struct attr *attr, u_char flag, u_char *startp)
965{
966 bgp_size_t total;
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400967 in_addr_t nexthop_h, nexthop_n;
paul718e3742002-12-13 20:15:29 +0000968
969 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
970
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400971 /* Flags check. */
972 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +0000973 {
Denis Ovsienkobc3443e2011-09-22 12:48:14 +0400974 zlog (peer->log, LOG_ERR,
975 "NEXT_HOP attribute must not be flagged as \"optional\" (%u)", flag);
976 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
977 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
978 startp, total);
979 }
980 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
981 {
982 zlog (peer->log, LOG_ERR,
983 "NEXT_HOP attribute must be flagged as \"transitive\" (%u)", flag);
984 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
985 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
986 startp, total);
987 }
988 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
989 {
990 zlog (peer->log, LOG_ERR,
991 "NEXT_HOP attribute must not be flagged as \"partial\" (%u)", flag);
Paul Jakmab881c702010-11-23 16:35:42 +0000992 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
993 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
994 startp, total);
paul718e3742002-12-13 20:15:29 +0000995 }
996
997 /* Check nexthop attribute length. */
998 if (length != 4)
999 {
1000 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
1001 length);
1002
Paul Jakmab881c702010-11-23 16:35:42 +00001003 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1004 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1005 startp, total);
paul718e3742002-12-13 20:15:29 +00001006 }
1007
Denis Ovsienkobc3443e2011-09-22 12:48:14 +04001008 /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
1009 attribute must result in a NOTIFICATION message (this is implemented below).
1010 At the same time, semantically incorrect NEXT_HOP is more likely to be just
1011 logged locally (this is implemented somewhere else). The UPDATE message
1012 gets ignored in any of these cases. */
1013 nexthop_n = stream_get_ipv4 (peer->ibuf);
1014 nexthop_h = ntohl (nexthop_n);
1015 if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
1016 {
1017 char buf[INET_ADDRSTRLEN];
1018 inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
1019 zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
1020 return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
1021 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
1022 startp, total);
1023 }
1024
1025 attr->nexthop.s_addr = nexthop_n;
paul718e3742002-12-13 20:15:29 +00001026 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
1027
Paul Jakmab881c702010-11-23 16:35:42 +00001028 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001029}
1030
1031/* MED atrribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001032static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001033bgp_attr_med (struct peer *peer, bgp_size_t length,
1034 struct attr *attr, u_char flag, u_char *startp)
1035{
1036 bgp_size_t total;
1037
1038 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1039
Denis Ovsienko2cfadf02011-09-20 10:54:25 +04001040 /* Flag checks. */
1041 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1042 {
1043 zlog (peer->log, LOG_ERR,
1044 "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
1045 bgp_notify_send_with_data (peer,
1046 BGP_NOTIFY_UPDATE_ERR,
1047 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1048 startp, total);
1049 return -1;
1050 }
1051 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1052 {
1053 zlog (peer->log, LOG_ERR,
1054 "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
1055 bgp_notify_send_with_data (peer,
1056 BGP_NOTIFY_UPDATE_ERR,
1057 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1058 startp, total);
1059 return -1;
1060 }
1061 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1062 {
1063 zlog (peer->log, LOG_ERR,
1064 "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
1065 bgp_notify_send_with_data (peer,
1066 BGP_NOTIFY_UPDATE_ERR,
1067 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1068 startp, total);
1069 return -1;
1070 }
1071
paul718e3742002-12-13 20:15:29 +00001072 /* Length check. */
1073 if (length != 4)
1074 {
1075 zlog (peer->log, LOG_ERR,
1076 "MED attribute length isn't four [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001077
1078 return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
1079 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1080 startp, total);
paul718e3742002-12-13 20:15:29 +00001081 }
1082
1083 attr->med = stream_getl (peer->ibuf);
1084
1085 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1086
Paul Jakmab881c702010-11-23 16:35:42 +00001087 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001088}
1089
1090/* Local preference attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001091static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001092bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001093 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001094{
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001095 bgp_size_t total;
1096
1097 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1098 /* Flag checks. */
1099 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1100 {
1101 zlog (peer->log, LOG_ERR,
1102 "LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag);
1103 bgp_notify_send_with_data (peer,
1104 BGP_NOTIFY_UPDATE_ERR,
1105 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1106 startp, total);
1107 return -1;
1108 }
1109 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1110 {
1111 zlog (peer->log, LOG_ERR,
1112 "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1113 bgp_notify_send_with_data (peer,
1114 BGP_NOTIFY_UPDATE_ERR,
1115 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1116 startp, total);
1117 return -1;
1118 }
1119
paul718e3742002-12-13 20:15:29 +00001120 /* If it is contained in an UPDATE message that is received from an
1121 external peer, then this attribute MUST be ignored by the
1122 receiving speaker. */
1123 if (peer_sort (peer) == BGP_PEER_EBGP)
1124 {
paul9985f832005-02-09 15:51:56 +00001125 stream_forward_getp (peer->ibuf, length);
Paul Jakmab881c702010-11-23 16:35:42 +00001126 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001127 }
1128
1129 if (length == 4)
1130 attr->local_pref = stream_getl (peer->ibuf);
1131 else
1132 attr->local_pref = 0;
1133
1134 /* Set atomic aggregate flag. */
1135 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1136
Paul Jakmab881c702010-11-23 16:35:42 +00001137 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001138}
1139
1140/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001141static int
paul718e3742002-12-13 20:15:29 +00001142bgp_attr_atomic (struct peer *peer, bgp_size_t length,
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001143 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001144{
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001145 bgp_size_t total;
1146
1147 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1148 /* Flag checks. */
1149 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1150 {
1151 zlog (peer->log, LOG_ERR,
1152 "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
1153 bgp_notify_send_with_data (peer,
1154 BGP_NOTIFY_UPDATE_ERR,
1155 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1156 startp, total);
1157 return -1;
1158 }
1159 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1160 {
1161 zlog (peer->log, LOG_ERR,
1162 "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
1163 bgp_notify_send_with_data (peer,
1164 BGP_NOTIFY_UPDATE_ERR,
1165 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1166 startp, total);
1167 return -1;
1168 }
1169 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
1170 {
1171 zlog (peer->log, LOG_ERR,
1172 "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
1173 bgp_notify_send_with_data (peer,
1174 BGP_NOTIFY_UPDATE_ERR,
1175 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1176 startp, total);
1177 return -1;
1178 }
1179
1180 /* Length check. */
paul718e3742002-12-13 20:15:29 +00001181 if (length != 0)
1182 {
1183 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1184
Paul Jakmab881c702010-11-23 16:35:42 +00001185 return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
1186 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1187 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001188 }
1189
1190 /* Set atomic aggregate flag. */
1191 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1192
Paul Jakmab881c702010-11-23 16:35:42 +00001193 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001194}
1195
1196/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001197static int
paul718e3742002-12-13 20:15:29 +00001198bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1199 struct attr *attr, u_char flag)
1200{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001201 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001202 struct attr_extra *attre = bgp_attr_extra_get (attr);
1203
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001204 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
Paul Jakmab881c702010-11-23 16:35:42 +00001205 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001206 wantedlen = 8;
1207
1208 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001209 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001210 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001211
Paul Jakmab881c702010-11-23 16:35:42 +00001212 return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
1213 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1214 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001215 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001216
1217 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1218 attre->aggregator_as = stream_getl (peer->ibuf);
1219 else
1220 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001221 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001222
1223 /* Set atomic aggregate flag. */
1224 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1225
Paul Jakmab881c702010-11-23 16:35:42 +00001226 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001227}
1228
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001229/* New Aggregator attribute */
Paul Jakmab881c702010-11-23 16:35:42 +00001230static bgp_attr_parse_ret_t
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001231bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001232 struct attr *attr, u_char flag,
1233 as_t *as4_aggregator_as,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001234 struct in_addr *as4_aggregator_addr)
1235{
1236 if (length != 8)
1237 {
1238 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
Paul Jakmab881c702010-11-23 16:35:42 +00001239 return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
1240 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1241 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001242 }
1243 *as4_aggregator_as = stream_getl (peer->ibuf);
1244 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1245
1246 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1247
Paul Jakmab881c702010-11-23 16:35:42 +00001248 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001249}
1250
1251/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1252 */
Paul Jakmab881c702010-11-23 16:35:42 +00001253static bgp_attr_parse_ret_t
1254bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001255 struct aspath *as4_path, as_t as4_aggregator,
1256 struct in_addr *as4_aggregator_addr)
1257{
1258 int ignore_as4_path = 0;
1259 struct aspath *newpath;
1260 struct attr_extra *attre = attr->extra;
1261
Paul Jakmab881c702010-11-23 16:35:42 +00001262 if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001263 {
1264 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1265 * if given.
1266 * It is worth a warning though, because the peer really
1267 * should not send them
1268 */
1269 if (BGP_DEBUG(as4, AS4))
1270 {
1271 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1272 zlog_debug ("[AS4] %s %s AS4_PATH",
1273 peer->host, "AS4 capable peer, yet it sent");
1274
1275 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1276 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1277 peer->host, "AS4 capable peer, yet it sent");
1278 }
1279
Paul Jakmab881c702010-11-23 16:35:42 +00001280 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001281 }
1282
Paul Jakmab881c702010-11-23 16:35:42 +00001283 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
1284 && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001285 {
1286 /* Hu? This is not supposed to happen at all!
1287 * got as4_path and no aspath,
1288 * This should already
1289 * have been handled by 'well known attributes missing'
1290 * But... yeah, paranoia
1291 * Take this as a "malformed attribute"
1292 */
1293 zlog (peer->log, LOG_ERR,
1294 "%s BGP not AS4 capable peer sent AS4_PATH but"
1295 " no AS_PATH, cant do anything here", peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001296 return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
1297 BGP_NOTIFY_UPDATE_MAL_ATTR,
1298 NULL, 0);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001299 }
1300
1301 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1302 * because that may override AS4_PATH
1303 */
1304 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1305 {
Paul Jakmab881c702010-11-23 16:35:42 +00001306 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001307 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001308 assert (attre);
1309
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001310 /* received both.
1311 * if the as_number in aggregator is not AS_TRANS,
1312 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1313 * and the Aggregator shall be taken as
1314 * info on the aggregating node, and the AS_PATH
1315 * shall be taken as the AS_PATH
1316 * otherwise
1317 * the Aggregator shall be ignored and the
1318 * AS4_AGGREGATOR shall be taken as the
1319 * Aggregating node and the AS_PATH is to be
1320 * constructed "as in all other cases"
1321 */
Paul Jakmab881c702010-11-23 16:35:42 +00001322 if (attre->aggregator_as != BGP_AS_TRANS)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001323 {
1324 /* ignore */
1325 if ( BGP_DEBUG(as4, AS4))
1326 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1327 " send AGGREGATOR != AS_TRANS and"
1328 " AS4_AGGREGATOR, so ignore"
1329 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1330 ignore_as4_path = 1;
1331 }
1332 else
1333 {
1334 /* "New_aggregator shall be taken as aggregator" */
1335 attre->aggregator_as = as4_aggregator;
1336 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1337 }
1338 }
1339 else
1340 {
1341 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1342 * That is bogus - but reading the conditions
1343 * we have to handle AS4_AGGREGATOR as if it were
1344 * AGGREGATOR in that case
1345 */
1346 if ( BGP_DEBUG(as4, AS4))
1347 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1348 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1349 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001350 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001351 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1352 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1353 }
1354 }
1355
1356 /* need to reconcile NEW_AS_PATH and AS_PATH */
Paul Jakmab881c702010-11-23 16:35:42 +00001357 if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001358 {
1359 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001360 aspath_unintern (&attr->aspath);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001361 attr->aspath = aspath_intern (newpath);
1362 }
Paul Jakmab881c702010-11-23 16:35:42 +00001363 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001364}
1365
paul718e3742002-12-13 20:15:29 +00001366/* Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001367static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001368bgp_attr_community (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001369 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001370{
Paul Jakmab881c702010-11-23 16:35:42 +00001371 bgp_size_t total
1372 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1373
paul718e3742002-12-13 20:15:29 +00001374 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001375 {
1376 attr->community = NULL;
Paul Jakmab881c702010-11-23 16:35:42 +00001377 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmab2ceea12007-09-07 14:24:55 +00001378 }
Paul Jakma0c466382010-12-05 17:17:26 +00001379
1380 attr->community =
1381 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1382
1383 /* XXX: fix community_parse to use stream API and remove this */
1384 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001385
Paul Jakma0c466382010-12-05 17:17:26 +00001386 if (!attr->community)
Paul Jakmab881c702010-11-23 16:35:42 +00001387 return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
1388 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1389 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001390
paul718e3742002-12-13 20:15:29 +00001391 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1392
Paul Jakmab881c702010-11-23 16:35:42 +00001393 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001394}
1395
1396/* Originator ID attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001397static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001398bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1399 struct attr *attr, u_char flag)
1400{
1401 if (length != 4)
1402 {
1403 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1404
Paul Jakmab881c702010-11-23 16:35:42 +00001405 return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
1406 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1407 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001408 }
1409
Paul Jakmafb982c22007-05-04 20:15:47 +00001410 (bgp_attr_extra_get (attr))->originator_id.s_addr
1411 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001412
1413 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1414
Paul Jakmab881c702010-11-23 16:35:42 +00001415 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001416}
1417
1418/* Cluster list attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001419static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001420bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1421 struct attr *attr, u_char flag)
1422{
1423 /* Check length. */
1424 if (length % 4)
1425 {
1426 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1427
Paul Jakmab881c702010-11-23 16:35:42 +00001428 return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
1429 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
1430 NULL, 0);
paul718e3742002-12-13 20:15:29 +00001431 }
1432
Paul Jakmafb982c22007-05-04 20:15:47 +00001433 (bgp_attr_extra_get (attr))->cluster
1434 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
Paul Jakmab881c702010-11-23 16:35:42 +00001435
1436 /* XXX: Fix cluster_parse to use stream API and then remove this */
1437 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001438
1439 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1440
Paul Jakmab881c702010-11-23 16:35:42 +00001441 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001442}
1443
1444/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001445int
paul718e3742002-12-13 20:15:29 +00001446bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1447 struct bgp_nlri *mp_update)
1448{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001449 afi_t afi;
1450 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001451 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001452 size_t start;
paul718e3742002-12-13 20:15:29 +00001453 int ret;
1454 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001455 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001456
1457 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001458 s = BGP_INPUT(peer);
1459 start = stream_get_getp(s);
1460
1461 /* safe to read statically sized header? */
1462#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001463#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001464 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001465 {
1466 zlog_info ("%s: %s sent invalid length, %lu",
1467 __func__, peer->host, (unsigned long)length);
Paul Jakmab881c702010-11-23 16:35:42 +00001468 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001469 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001470
paul718e3742002-12-13 20:15:29 +00001471 /* Load AFI, SAFI. */
1472 afi = stream_getw (s);
1473 safi = stream_getc (s);
1474
1475 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001476 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001477
Paul Jakma03292802008-06-07 20:37:10 +00001478 if (LEN_LEFT < attre->mp_nexthop_len)
1479 {
1480 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1481 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001482 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001483 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001484
paul718e3742002-12-13 20:15:29 +00001485 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001486 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001487 {
1488 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001489 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001490 /* Probably needed for RFC 2283 */
1491 if (attr->nexthop.s_addr == 0)
1492 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001493 break;
1494 case 12:
1495 {
1496 u_int32_t rd_high;
1497 u_int32_t rd_low;
1498
1499 rd_high = stream_getl (s);
1500 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001501 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001502 }
1503 break;
1504#ifdef HAVE_IPV6
1505 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001506 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001507 break;
1508 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001509 stream_get (&attre->mp_nexthop_global, s, 16);
1510 stream_get (&attre->mp_nexthop_local, s, 16);
1511 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001512 {
1513 char buf1[INET6_ADDRSTRLEN];
1514 char buf2[INET6_ADDRSTRLEN];
1515
1516 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001517 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 +00001518 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001519 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001520 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001521 buf2, INET6_ADDRSTRLEN));
1522
Paul Jakmafb982c22007-05-04 20:15:47 +00001523 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001524 }
1525 break;
1526#endif /* HAVE_IPV6 */
1527 default:
Paul Jakma03292802008-06-07 20:37:10 +00001528 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1529 __func__, peer->host, attre->mp_nexthop_len);
Paul Jakmab881c702010-11-23 16:35:42 +00001530 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001531 }
1532
Paul Jakma03292802008-06-07 20:37:10 +00001533 if (!LEN_LEFT)
1534 {
1535 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1536 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001537 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001538 }
paul718e3742002-12-13 20:15:29 +00001539
Paul Jakma6e4ab122007-04-10 19:36:48 +00001540 {
1541 u_char val;
1542 if ((val = stream_getc (s)))
1543 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1544 peer->host, val);
1545 }
1546
1547 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001548 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001549 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001550 {
1551 zlog_info ("%s: (%s) Failed to read NLRI",
1552 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001553 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001554 }
paul718e3742002-12-13 20:15:29 +00001555
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001556 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001557 {
1558 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001559 if (ret < 0)
1560 {
1561 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1562 __func__, peer->host);
Paul Jakmab881c702010-11-23 16:35:42 +00001563 return BGP_ATTR_PARSE_ERROR;
Paul Jakma03292802008-06-07 20:37:10 +00001564 }
paul718e3742002-12-13 20:15:29 +00001565 }
1566
1567 mp_update->afi = afi;
1568 mp_update->safi = safi;
1569 mp_update->nlri = stream_pnt (s);
1570 mp_update->length = nlri_len;
1571
paul9985f832005-02-09 15:51:56 +00001572 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001573
Paul Jakmab881c702010-11-23 16:35:42 +00001574 return BGP_ATTR_PARSE_PROCEED;
Paul Jakma03292802008-06-07 20:37:10 +00001575#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001576}
1577
1578/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001579int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001580bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001581 struct bgp_nlri *mp_withdraw)
1582{
1583 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001584 afi_t afi;
1585 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001586 u_int16_t withdraw_len;
1587 int ret;
1588
1589 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001590
1591#define BGP_MP_UNREACH_MIN_SIZE 3
1592 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
Paul Jakmab881c702010-11-23 16:35:42 +00001593 return BGP_ATTR_PARSE_ERROR;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001594
paul718e3742002-12-13 20:15:29 +00001595 afi = stream_getw (s);
1596 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001597
1598 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001599
Denis Ovsienko42e6d742011-07-14 12:36:19 +04001600 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001601 {
1602 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1603 if (ret < 0)
Paul Jakmab881c702010-11-23 16:35:42 +00001604 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001605 }
1606
1607 mp_withdraw->afi = afi;
1608 mp_withdraw->safi = safi;
1609 mp_withdraw->nlri = stream_pnt (s);
1610 mp_withdraw->length = withdraw_len;
1611
paul9985f832005-02-09 15:51:56 +00001612 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001613
Paul Jakmab881c702010-11-23 16:35:42 +00001614 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001615}
1616
1617/* Extended Community attribute. */
Paul Jakmab881c702010-11-23 16:35:42 +00001618static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001619bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
Paul Jakmab881c702010-11-23 16:35:42 +00001620 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001621{
Paul Jakmab881c702010-11-23 16:35:42 +00001622 bgp_size_t total
1623 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1624
paul718e3742002-12-13 20:15:29 +00001625 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001626 {
1627 if (attr->extra)
1628 attr->extra->ecommunity = NULL;
Paul Jakma0c466382010-12-05 17:17:26 +00001629 /* Empty extcomm doesn't seem to be invalid per se */
Paul Jakmab881c702010-11-23 16:35:42 +00001630 return BGP_ATTR_PARSE_PROCEED;
Paul Jakmafb982c22007-05-04 20:15:47 +00001631 }
Paul Jakma0c466382010-12-05 17:17:26 +00001632
1633 (bgp_attr_extra_get (attr))->ecommunity =
1634 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1635 /* XXX: fix ecommunity_parse to use stream API */
1636 stream_forward_getp (peer->ibuf, length);
1637
1638 if (!attr->extra->ecommunity)
Paul Jakmab881c702010-11-23 16:35:42 +00001639 return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
1640 flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
1641 startp, total);
Paul Jakma0c466382010-12-05 17:17:26 +00001642
paul718e3742002-12-13 20:15:29 +00001643 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1644
Paul Jakmab881c702010-11-23 16:35:42 +00001645 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001646}
1647
1648/* BGP unknown attribute treatment. */
Paul Jakmab881c702010-11-23 16:35:42 +00001649static bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001650bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1651 u_char type, bgp_size_t length, u_char *startp)
1652{
1653 bgp_size_t total;
1654 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001655 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001656
hassof4184462005-02-01 20:13:16 +00001657 if (BGP_DEBUG (normal, NORMAL))
1658 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1659 peer->host, type, length);
1660
paul718e3742002-12-13 20:15:29 +00001661 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001662 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001663 "Unknown attribute type %d length %d is received", type, length);
1664
1665 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001666 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001667
1668 /* Adjest total length to include type and length. */
1669 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1670
1671 /* If any of the mandatory well-known attributes are not recognized,
1672 then the Error Subcode is set to Unrecognized Well-known
1673 Attribute. The Data field contains the unrecognized attribute
1674 (type, length and value). */
Paul Jakmab881c702010-11-23 16:35:42 +00001675 if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
paul718e3742002-12-13 20:15:29 +00001676 {
Paul Jakmab881c702010-11-23 16:35:42 +00001677 return bgp_attr_malformed (peer, type, flag,
1678 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1679 startp, total);
paul718e3742002-12-13 20:15:29 +00001680 }
1681
1682 /* Unrecognized non-transitive optional attributes must be quietly
1683 ignored and not passed along to other BGP peers. */
1684 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
Paul Jakmab881c702010-11-23 16:35:42 +00001685 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001686
1687 /* If a path with recognized transitive optional attribute is
1688 accepted and passed along to other BGP peers and the Partial bit
1689 in the Attribute Flags octet is set to 1 by some previous AS, it
1690 is not set back to 0 by the current AS. */
1691 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1692
1693 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001694 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001695 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001696
Paul Jakmafb982c22007-05-04 20:15:47 +00001697 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001698
1699 if (transit->val)
1700 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1701 transit->length + total);
1702 else
1703 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1704
1705 memcpy (transit->val + transit->length, startp, total);
1706 transit->length += total;
1707
Paul Jakmab881c702010-11-23 16:35:42 +00001708 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001709}
1710
1711/* Read attribute of update packet. This function is called from
1712 bgp_update() in bgpd.c. */
Paul Jakmab881c702010-11-23 16:35:42 +00001713bgp_attr_parse_ret_t
paul718e3742002-12-13 20:15:29 +00001714bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1715 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1716{
1717 int ret;
Paul Jakmab881c702010-11-23 16:35:42 +00001718 u_char flag = 0;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001719 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001720 bgp_size_t length;
1721 u_char *startp, *endp;
1722 u_char *attr_endp;
1723 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001724 /* we need the as4_path only until we have synthesized the as_path with it */
1725 /* same goes for as4_aggregator */
1726 struct aspath *as4_path = NULL;
1727 as_t as4_aggregator = 0;
1728 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001729
1730 /* Initialize bitmap. */
1731 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1732
1733 /* End pointer of BGP attribute. */
1734 endp = BGP_INPUT_PNT (peer) + size;
Paul Jakmab881c702010-11-23 16:35:42 +00001735
paul718e3742002-12-13 20:15:29 +00001736 /* Get attributes to the end of attribute length. */
1737 while (BGP_INPUT_PNT (peer) < endp)
1738 {
1739 /* Check remaining length check.*/
1740 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1741 {
gdtc29fdba2004-12-09 14:46:46 +00001742 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001743 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001744 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001745 peer->host,
1746 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001747
1748 bgp_notify_send (peer,
1749 BGP_NOTIFY_UPDATE_ERR,
1750 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001751 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001752 }
1753
1754 /* Fetch attribute flag and type. */
1755 startp = BGP_INPUT_PNT (peer);
1756 flag = stream_getc (BGP_INPUT (peer));
1757 type = stream_getc (BGP_INPUT (peer));
1758
Paul Jakma370b64a2007-12-22 16:49:52 +00001759 /* Check whether Extended-Length applies and is in bounds */
1760 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1761 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1762 {
1763 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001764 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001765 peer->host,
1766 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1767
1768 bgp_notify_send (peer,
1769 BGP_NOTIFY_UPDATE_ERR,
1770 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001771 return BGP_ATTR_PARSE_ERROR;
Paul Jakma370b64a2007-12-22 16:49:52 +00001772 }
1773
paul718e3742002-12-13 20:15:29 +00001774 /* Check extended attribue length bit. */
1775 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1776 length = stream_getw (BGP_INPUT (peer));
1777 else
1778 length = stream_getc (BGP_INPUT (peer));
1779
1780 /* If any attribute appears more than once in the UPDATE
1781 message, then the Error Subcode is set to Malformed Attribute
1782 List. */
1783
1784 if (CHECK_BITMAP (seen, type))
1785 {
1786 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001787 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001788 peer->host, type);
1789
1790 bgp_notify_send (peer,
1791 BGP_NOTIFY_UPDATE_ERR,
1792 BGP_NOTIFY_UPDATE_MAL_ATTR);
Paul Jakmab881c702010-11-23 16:35:42 +00001793 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001794 }
1795
1796 /* Set type to bitmap to check duplicate attribute. `type' is
1797 unsigned char so it never overflow bitmap range. */
1798
1799 SET_BITMAP (seen, type);
1800
1801 /* Overflow check. */
1802 attr_endp = BGP_INPUT_PNT (peer) + length;
1803
1804 if (attr_endp > endp)
1805 {
1806 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001807 "%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 +00001808 bgp_notify_send (peer,
1809 BGP_NOTIFY_UPDATE_ERR,
1810 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001811 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001812 }
1813
1814 /* OK check attribute and store it's value. */
1815 switch (type)
1816 {
1817 case BGP_ATTR_ORIGIN:
1818 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1819 break;
1820 case BGP_ATTR_AS_PATH:
Paul Jakmaab005292010-11-27 22:48:34 +00001821 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001822 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001823 case BGP_ATTR_AS4_PATH:
Paul Jakmab881c702010-11-23 16:35:42 +00001824 ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001825 break;
paul718e3742002-12-13 20:15:29 +00001826 case BGP_ATTR_NEXT_HOP:
1827 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1828 break;
1829 case BGP_ATTR_MULTI_EXIT_DISC:
1830 ret = bgp_attr_med (peer, length, attr, flag, startp);
1831 break;
1832 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienko0ea968d2011-09-19 16:30:47 +04001833 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001834 break;
1835 case BGP_ATTR_ATOMIC_AGGREGATE:
Denis Ovsienko9eba2ad2011-09-20 14:43:50 +04001836 ret = bgp_attr_atomic (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001837 break;
1838 case BGP_ATTR_AGGREGATOR:
1839 ret = bgp_attr_aggregator (peer, length, attr, flag);
1840 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001841 case BGP_ATTR_AS4_AGGREGATOR:
Paul Jakmab881c702010-11-23 16:35:42 +00001842 ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
1843 &as4_aggregator,
1844 &as4_aggregator_addr);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001845 break;
paul718e3742002-12-13 20:15:29 +00001846 case BGP_ATTR_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001847 ret = bgp_attr_community (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001848 break;
1849 case BGP_ATTR_ORIGINATOR_ID:
1850 ret = bgp_attr_originator_id (peer, length, attr, flag);
1851 break;
1852 case BGP_ATTR_CLUSTER_LIST:
1853 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1854 break;
1855 case BGP_ATTR_MP_REACH_NLRI:
1856 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1857 break;
1858 case BGP_ATTR_MP_UNREACH_NLRI:
1859 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1860 break;
1861 case BGP_ATTR_EXT_COMMUNITIES:
Paul Jakmab881c702010-11-23 16:35:42 +00001862 ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001863 break;
1864 default:
1865 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1866 break;
1867 }
Paul Jakmab881c702010-11-23 16:35:42 +00001868
1869 /* If hard error occured immediately return to the caller. */
1870 if (ret == BGP_ATTR_PARSE_ERROR)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001871 {
1872 zlog (peer->log, LOG_WARNING,
1873 "%s: Attribute %s, parse error",
1874 peer->host,
1875 LOOKUP (attr_str, type));
Paul Jakmab881c702010-11-23 16:35:42 +00001876 bgp_notify_send (peer,
1877 BGP_NOTIFY_UPDATE_ERR,
1878 BGP_NOTIFY_UPDATE_MAL_ATTR);
1879 if (as4_path)
1880 aspath_unintern (&as4_path);
1881 return ret;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001882 }
Paul Jakmab881c702010-11-23 16:35:42 +00001883 if (ret == BGP_ATTR_PARSE_WITHDRAW)
1884 {
1885
1886 zlog (peer->log, LOG_WARNING,
1887 "%s: Attribute %s, parse error - treating as withdrawal",
1888 peer->host,
1889 LOOKUP (attr_str, type));
1890 if (as4_path)
1891 aspath_unintern (&as4_path);
1892 return ret;
1893 }
1894
paul718e3742002-12-13 20:15:29 +00001895 /* Check the fetched length. */
1896 if (BGP_INPUT_PNT (peer) != attr_endp)
1897 {
1898 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001899 "%s: BGP attribute %s, fetch error",
1900 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001901 bgp_notify_send (peer,
1902 BGP_NOTIFY_UPDATE_ERR,
1903 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001904 if (as4_path)
1905 aspath_unintern (&as4_path);
1906 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001907 }
1908 }
1909
1910 /* Check final read pointer is same as end pointer. */
1911 if (BGP_INPUT_PNT (peer) != endp)
1912 {
1913 zlog (peer->log, LOG_WARNING,
heasleyd68ab102011-07-12 20:09:18 +04001914 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001915 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001916 bgp_notify_send (peer,
1917 BGP_NOTIFY_UPDATE_ERR,
1918 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
Paul Jakmab881c702010-11-23 16:35:42 +00001919 if (as4_path)
1920 aspath_unintern (&as4_path);
1921 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00001922 }
1923
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001924 /*
1925 * At this place we can see whether we got AS4_PATH and/or
1926 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1927 * We can not do this before we've read all attributes because
1928 * the as4 handling does not say whether AS4_PATH has to be sent
1929 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1930 * in relationship to AGGREGATOR.
1931 * So, to be defensive, we are not relying on any order and read
1932 * all attributes first, including these 32bit ones, and now,
1933 * afterwards, we look what and if something is to be done for as4.
1934 */
Paul Jakmab881c702010-11-23 16:35:42 +00001935 if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001936 as4_aggregator, &as4_aggregator_addr))
Paul Jakmab881c702010-11-23 16:35:42 +00001937 {
1938 if (as4_path)
1939 aspath_unintern (&as4_path);
1940 return BGP_ATTR_PARSE_ERROR;
1941 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001942
1943 /* At this stage, we have done all fiddling with as4, and the
1944 * resulting info is in attr->aggregator resp. attr->aspath
1945 * so we can chuck as4_aggregator and as4_path alltogether in
1946 * order to save memory
1947 */
Paul Jakmab881c702010-11-23 16:35:42 +00001948 if (as4_path)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001949 {
Paul Jakmaf6f434b2010-11-23 21:28:03 +00001950 aspath_unintern (&as4_path); /* unintern - it is in the hash */
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001951 /* The flag that we got this is still there, but that does not
1952 * do any trouble
1953 */
1954 }
1955 /*
1956 * The "rest" of the code does nothing with as4_aggregator.
1957 * there is no memory attached specifically which is not part
1958 * of the attr.
1959 * so ignoring just means do nothing.
1960 */
1961 /*
1962 * Finally do the checks on the aspath we did not do yet
1963 * because we waited for a potentially synthesized aspath.
1964 */
Paul Jakmab881c702010-11-23 16:35:42 +00001965 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001966 {
Paul Jakmab881c702010-11-23 16:35:42 +00001967 ret = bgp_attr_aspath_check (peer, attr, flag);
1968 if (ret != BGP_ATTR_PARSE_PROCEED)
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001969 return ret;
1970 }
1971
paul718e3742002-12-13 20:15:29 +00001972 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001973 if (attr->extra && attr->extra->transit)
1974 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001975
Paul Jakmab881c702010-11-23 16:35:42 +00001976 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00001977}
1978
1979/* Well-known attribute check. */
1980int
1981bgp_attr_check (struct peer *peer, struct attr *attr)
1982{
1983 u_char type = 0;
1984
1985 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1986 type = BGP_ATTR_ORIGIN;
1987
1988 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1989 type = BGP_ATTR_AS_PATH;
1990
1991 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1992 type = BGP_ATTR_NEXT_HOP;
1993
1994 if (peer_sort (peer) == BGP_PEER_IBGP
1995 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1996 type = BGP_ATTR_LOCAL_PREF;
1997
1998 if (type)
1999 {
2000 zlog (peer->log, LOG_WARNING,
2001 "%s Missing well-known attribute %d.",
2002 peer->host, type);
2003 bgp_notify_send_with_data (peer,
2004 BGP_NOTIFY_UPDATE_ERR,
2005 BGP_NOTIFY_UPDATE_MISS_ATTR,
2006 &type, 1);
Paul Jakmab881c702010-11-23 16:35:42 +00002007 return BGP_ATTR_PARSE_ERROR;
paul718e3742002-12-13 20:15:29 +00002008 }
Paul Jakmab881c702010-11-23 16:35:42 +00002009 return BGP_ATTR_PARSE_PROCEED;
paul718e3742002-12-13 20:15:29 +00002010}
2011
2012int stream_put_prefix (struct stream *, struct prefix *);
2013
2014/* Make attribute packet. */
2015bgp_size_t
2016bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
2017 struct stream *s, struct attr *attr, struct prefix *p,
2018 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002019 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00002020{
paulfe69a502005-09-10 16:55:02 +00002021 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002022 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00002023 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002024 int send_as4_path = 0;
2025 int send_as4_aggregator = 0;
2026 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00002027
2028 if (! bgp)
2029 bgp = bgp_get_default ();
2030
2031 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002032 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002033
2034 /* Origin attribute. */
2035 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2036 stream_putc (s, BGP_ATTR_ORIGIN);
2037 stream_putc (s, 1);
2038 stream_putc (s, attr->origin);
2039
2040 /* AS path attribute. */
2041
2042 /* If remote-peer is EBGP */
2043 if (peer_sort (peer) == BGP_PEER_EBGP
2044 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00002045 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00002046 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00002047 {
2048 aspath = aspath_dup (attr->aspath);
2049
2050 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
2051 {
2052 /* Strip the confed info, and then stuff our path CONFED_ID
2053 on the front */
2054 aspath = aspath_delete_confed_seq (aspath);
2055 aspath = aspath_add_seq (aspath, bgp->confed_id);
2056 }
2057 else
2058 {
2059 aspath = aspath_add_seq (aspath, peer->local_as);
2060 if (peer->change_local_as)
2061 aspath = aspath_add_seq (aspath, peer->change_local_as);
2062 }
2063 }
2064 else if (peer_sort (peer) == BGP_PEER_CONFED)
2065 {
2066 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
2067 aspath = aspath_dup (attr->aspath);
2068 aspath = aspath_add_confed_seq (aspath, peer->local_as);
2069 }
2070 else
2071 aspath = attr->aspath;
2072
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002073 /* If peer is not AS4 capable, then:
2074 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
2075 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
2076 * types are in it (i.e. exclude them if they are there)
2077 * AND do this only if there is at least one asnum > 65535 in the path!
2078 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
2079 * all ASnums > 65535 to BGP_AS_TRANS
2080 */
paul718e3742002-12-13 20:15:29 +00002081
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002082 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2083 stream_putc (s, BGP_ATTR_AS_PATH);
2084 aspath_sizep = stream_get_endp (s);
2085 stream_putw (s, 0);
2086 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
2087
2088 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
2089 * in the path
2090 */
2091 if (!use32bit && aspath_has_as4 (aspath))
2092 send_as4_path = 1; /* we'll do this later, at the correct place */
2093
paul718e3742002-12-13 20:15:29 +00002094 /* Nexthop attribute. */
2095 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
2096 {
2097 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2098 stream_putc (s, BGP_ATTR_NEXT_HOP);
2099 stream_putc (s, 4);
2100 if (safi == SAFI_MPLS_VPN)
2101 {
2102 if (attr->nexthop.s_addr == 0)
2103 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
2104 else
2105 stream_put_ipv4 (s, attr->nexthop.s_addr);
2106 }
2107 else
2108 stream_put_ipv4 (s, attr->nexthop.s_addr);
2109 }
2110
2111 /* MED attribute. */
2112 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2113 {
2114 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2115 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2116 stream_putc (s, 4);
2117 stream_putl (s, attr->med);
2118 }
2119
2120 /* Local preference. */
2121 if (peer_sort (peer) == BGP_PEER_IBGP ||
2122 peer_sort (peer) == BGP_PEER_CONFED)
2123 {
2124 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2125 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2126 stream_putc (s, 4);
2127 stream_putl (s, attr->local_pref);
2128 }
2129
2130 /* Atomic aggregate. */
2131 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2132 {
2133 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2134 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2135 stream_putc (s, 0);
2136 }
2137
2138 /* Aggregator. */
2139 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2140 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002141 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002142
2143 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00002144 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2145 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002146
2147 if (use32bit)
2148 {
2149 /* AS4 capable peer */
2150 stream_putc (s, 8);
2151 stream_putl (s, attr->extra->aggregator_as);
2152 }
2153 else
2154 {
2155 /* 2-byte AS peer */
2156 stream_putc (s, 6);
2157
2158 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2159 if ( attr->extra->aggregator_as > 65535 )
2160 {
2161 stream_putw (s, BGP_AS_TRANS);
2162
2163 /* we have to send AS4_AGGREGATOR, too.
2164 * we'll do that later in order to send attributes in ascending
2165 * order.
2166 */
2167 send_as4_aggregator = 1;
2168 }
2169 else
2170 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2171 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002172 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002173 }
2174
2175 /* Community attribute. */
2176 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2177 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2178 {
2179 if (attr->community->size * 4 > 255)
2180 {
2181 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2182 stream_putc (s, BGP_ATTR_COMMUNITIES);
2183 stream_putw (s, attr->community->size * 4);
2184 }
2185 else
2186 {
2187 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2188 stream_putc (s, BGP_ATTR_COMMUNITIES);
2189 stream_putc (s, attr->community->size * 4);
2190 }
2191 stream_put (s, attr->community->val, attr->community->size * 4);
2192 }
2193
2194 /* Route Reflector. */
2195 if (peer_sort (peer) == BGP_PEER_IBGP
2196 && from
2197 && peer_sort (from) == BGP_PEER_IBGP)
2198 {
2199 /* Originator ID. */
2200 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2201 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2202 stream_putc (s, 4);
2203
2204 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002205 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002206 else
2207 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002208
2209 /* Cluster list. */
2210 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2211 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2212
Paul Jakma9eda90c2007-08-30 13:36:17 +00002213 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002214 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002215 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002216 /* If this peer configuration's parent BGP has cluster_id. */
2217 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2218 stream_put_in_addr (s, &bgp->cluster_id);
2219 else
2220 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002221 stream_put (s, attr->extra->cluster->list,
2222 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002223 }
2224 else
2225 {
2226 stream_putc (s, 4);
2227 /* If this peer configuration's parent BGP has cluster_id. */
2228 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2229 stream_put_in_addr (s, &bgp->cluster_id);
2230 else
2231 stream_put_in_addr (s, &bgp->router_id);
2232 }
2233 }
2234
2235#ifdef HAVE_IPV6
2236 /* If p is IPv6 address put it into attribute. */
2237 if (p->family == AF_INET6)
2238 {
2239 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002240 struct attr_extra *attre = attr->extra;
2241
2242 assert (attr->extra);
2243
paul718e3742002-12-13 20:15:29 +00002244 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2245 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002246 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002247 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002248 stream_putw (s, AFI_IP6); /* AFI */
2249 stream_putc (s, safi); /* SAFI */
2250
Paul Jakmafb982c22007-05-04 20:15:47 +00002251 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002252
Paul Jakmafb982c22007-05-04 20:15:47 +00002253 if (attre->mp_nexthop_len == 16)
2254 stream_put (s, &attre->mp_nexthop_global, 16);
2255 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002256 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002257 stream_put (s, &attre->mp_nexthop_global, 16);
2258 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002259 }
2260
2261 /* SNPA */
2262 stream_putc (s, 0);
2263
paul718e3742002-12-13 20:15:29 +00002264 /* Prefix write. */
2265 stream_put_prefix (s, p);
2266
2267 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002268 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002269 }
2270#endif /* HAVE_IPV6 */
2271
2272 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2273 {
2274 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002275
2276 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2277 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002278 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002279 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002280 stream_putw (s, AFI_IP); /* AFI */
2281 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2282
2283 stream_putc (s, 4);
2284 stream_put_ipv4 (s, attr->nexthop.s_addr);
2285
2286 /* SNPA */
2287 stream_putc (s, 0);
2288
paul718e3742002-12-13 20:15:29 +00002289 /* Prefix write. */
2290 stream_put_prefix (s, p);
2291
2292 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002293 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002294 }
2295
2296 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2297 {
2298 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002299
2300 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2301 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002302 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002303 stream_putc (s, 0); /* Length of this attribute. */
2304 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002305 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002306
2307 stream_putc (s, 12);
2308 stream_putl (s, 0);
2309 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002310 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002311
2312 /* SNPA */
2313 stream_putc (s, 0);
2314
paul718e3742002-12-13 20:15:29 +00002315 /* Tag, RD, Prefix write. */
2316 stream_putc (s, p->prefixlen + 88);
2317 stream_put (s, tag, 3);
2318 stream_put (s, prd->val, 8);
2319 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2320
2321 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002322 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002323 }
2324
2325 /* Extended Communities attribute. */
2326 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2327 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2328 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002329 struct attr_extra *attre = attr->extra;
2330
2331 assert (attre);
2332
2333 if (peer_sort (peer) == BGP_PEER_IBGP
2334 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002335 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002336 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002337 {
2338 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2339 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002340 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002341 }
2342 else
2343 {
2344 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2345 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002346 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002347 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002348 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002349 }
2350 else
2351 {
paul5228ad22004-06-04 17:58:18 +00002352 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002353 int tbit;
2354 int ecom_tr_size = 0;
2355 int i;
2356
Paul Jakmafb982c22007-05-04 20:15:47 +00002357 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002358 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002359 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002360 tbit = *pnt;
2361
2362 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2363 continue;
2364
2365 ecom_tr_size++;
2366 }
2367
2368 if (ecom_tr_size)
2369 {
2370 if (ecom_tr_size * 8 > 255)
2371 {
2372 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2373 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2374 stream_putw (s, ecom_tr_size * 8);
2375 }
2376 else
2377 {
2378 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2379 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2380 stream_putc (s, ecom_tr_size * 8);
2381 }
2382
Paul Jakmafb982c22007-05-04 20:15:47 +00002383 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002384 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002385 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002386 tbit = *pnt;
2387
2388 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2389 continue;
2390
2391 stream_put (s, pnt, 8);
2392 }
2393 }
paul718e3742002-12-13 20:15:29 +00002394 }
paul718e3742002-12-13 20:15:29 +00002395 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002396
2397 if ( send_as4_path )
2398 {
2399 /* If the peer is NOT As4 capable, AND */
2400 /* there are ASnums > 65535 in path THEN
2401 * give out AS4_PATH */
2402
2403 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2404 * path segments!
2405 * Hm, I wonder... confederation things *should* only be at
2406 * the beginning of an aspath, right? Then we should use
2407 * aspath_delete_confed_seq for this, because it is already
2408 * there! (JK)
2409 * Folks, talk to me: what is reasonable here!?
2410 */
2411 aspath = aspath_delete_confed_seq (aspath);
2412
2413 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2414 stream_putc (s, BGP_ATTR_AS4_PATH);
2415 aspath_sizep = stream_get_endp (s);
2416 stream_putw (s, 0);
2417 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2418 }
2419
2420 if (aspath != attr->aspath)
2421 aspath_free (aspath);
2422
2423 if ( send_as4_aggregator )
2424 {
2425 assert (attr->extra);
2426
2427 /* send AS4_AGGREGATOR, at this place */
2428 /* this section of code moved here in order to ensure the correct
2429 * *ascending* order of attributes
2430 */
2431 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2432 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2433 stream_putc (s, 8);
2434 stream_putl (s, attr->extra->aggregator_as);
2435 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2436 }
Paul Jakma41367172007-08-06 15:24:51 +00002437
paul718e3742002-12-13 20:15:29 +00002438 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002439 if (attr->extra && attr->extra->transit)
2440 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002441
2442 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002443 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002444}
2445
2446bgp_size_t
2447bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2448 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002449 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002450{
2451 unsigned long cp;
2452 unsigned long attrlen_pnt;
2453 bgp_size_t size;
2454
paul9985f832005-02-09 15:51:56 +00002455 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002456
2457 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2458 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2459
paul9985f832005-02-09 15:51:56 +00002460 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002461 stream_putc (s, 0); /* Length of this attribute. */
2462
2463 stream_putw (s, family2afi (p->family));
2464
2465 if (safi == SAFI_MPLS_VPN)
2466 {
2467 /* SAFI */
Denis Ovsienko42e6d742011-07-14 12:36:19 +04002468 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002469
2470 /* prefix. */
2471 stream_putc (s, p->prefixlen + 88);
2472 stream_put (s, tag, 3);
2473 stream_put (s, prd->val, 8);
2474 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2475 }
2476 else
2477 {
2478 /* SAFI */
2479 stream_putc (s, safi);
2480
2481 /* prefix */
2482 stream_put_prefix (s, p);
2483 }
2484
2485 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002486 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002487 stream_putc_at (s, attrlen_pnt, size);
2488
paul9985f832005-02-09 15:51:56 +00002489 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002490}
2491
2492/* Initialization of attribute. */
2493void
paulfe69a502005-09-10 16:55:02 +00002494bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002495{
paul718e3742002-12-13 20:15:29 +00002496 aspath_init ();
2497 attrhash_init ();
2498 community_init ();
2499 ecommunity_init ();
2500 cluster_init ();
2501 transit_init ();
2502}
2503
Chris Caputo228da422009-07-18 05:44:03 +00002504void
2505bgp_attr_finish (void)
2506{
2507 aspath_finish ();
2508 attrhash_finish ();
2509 community_finish ();
2510 ecommunity_finish ();
2511 cluster_finish ();
2512 transit_finish ();
2513}
2514
paul718e3742002-12-13 20:15:29 +00002515/* Make attribute packet. */
2516void
paula3845922003-10-18 01:30:50 +00002517bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2518 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002519{
2520 unsigned long cp;
2521 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002522 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002523 struct aspath *aspath;
2524
2525 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002526 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002527
2528 /* Place holder of length. */
2529 stream_putw (s, 0);
2530
2531 /* Origin attribute. */
2532 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2533 stream_putc (s, BGP_ATTR_ORIGIN);
2534 stream_putc (s, 1);
2535 stream_putc (s, attr->origin);
2536
2537 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002538
2539 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2540 stream_putc (s, BGP_ATTR_AS_PATH);
2541 aspath_lenp = stream_get_endp (s);
2542 stream_putw (s, 0);
2543
2544 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002545
2546 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002547 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2548 if(prefix != NULL
2549#ifdef HAVE_IPV6
2550 && prefix->family != AF_INET6
2551#endif /* HAVE_IPV6 */
2552 )
2553 {
2554 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2555 stream_putc (s, BGP_ATTR_NEXT_HOP);
2556 stream_putc (s, 4);
2557 stream_put_ipv4 (s, attr->nexthop.s_addr);
2558 }
paul718e3742002-12-13 20:15:29 +00002559
2560 /* MED attribute. */
2561 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2562 {
2563 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2564 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2565 stream_putc (s, 4);
2566 stream_putl (s, attr->med);
2567 }
2568
2569 /* Local preference. */
2570 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2571 {
2572 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2573 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2574 stream_putc (s, 4);
2575 stream_putl (s, attr->local_pref);
2576 }
2577
2578 /* Atomic aggregate. */
2579 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2580 {
2581 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2582 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2583 stream_putc (s, 0);
2584 }
2585
2586 /* Aggregator. */
2587 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2588 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002589 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002590 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2591 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002592 stream_putc (s, 8);
2593 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002594 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002595 }
2596
2597 /* Community attribute. */
2598 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2599 {
2600 if (attr->community->size * 4 > 255)
2601 {
2602 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2603 stream_putc (s, BGP_ATTR_COMMUNITIES);
2604 stream_putw (s, attr->community->size * 4);
2605 }
2606 else
2607 {
2608 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2609 stream_putc (s, BGP_ATTR_COMMUNITIES);
2610 stream_putc (s, attr->community->size * 4);
2611 }
2612 stream_put (s, attr->community->val, attr->community->size * 4);
2613 }
2614
paula3845922003-10-18 01:30:50 +00002615#ifdef HAVE_IPV6
2616 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002617 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2618 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002619 {
2620 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002621 struct attr_extra *attre = attr->extra;
2622
paula3845922003-10-18 01:30:50 +00002623 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2624 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002625 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002626
2627 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002628 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002629 stream_putw(s, AFI_IP6); /* AFI */
2630 stream_putc(s, SAFI_UNICAST); /* SAFI */
2631
2632 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002633 stream_putc(s, attre->mp_nexthop_len);
2634 stream_put(s, &attre->mp_nexthop_global, 16);
2635 if (attre->mp_nexthop_len == 32)
2636 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002637
2638 /* SNPA */
2639 stream_putc(s, 0);
2640
2641 /* Prefix */
2642 stream_put_prefix(s, prefix);
2643
2644 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002645 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002646 }
2647#endif /* HAVE_IPV6 */
2648
paul718e3742002-12-13 20:15:29 +00002649 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002650 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002651 stream_putw_at (s, cp, len);
2652}