blob: 9b2c0162d10d99fc63ff87ecb4b239c9a7304958 [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"
31
32#include "bgpd/bgpd.h"
33#include "bgpd/bgp_attr.h"
34#include "bgpd/bgp_route.h"
35#include "bgpd/bgp_aspath.h"
36#include "bgpd/bgp_community.h"
37#include "bgpd/bgp_debug.h"
38#include "bgpd/bgp_packet.h"
39#include "bgpd/bgp_ecommunity.h"
40
41/* Attribute strings for logging. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -070042static const struct message attr_str [] =
paul718e3742002-12-13 20:15:29 +000043{
44 { BGP_ATTR_ORIGIN, "ORIGIN" },
45 { BGP_ATTR_AS_PATH, "AS_PATH" },
46 { BGP_ATTR_NEXT_HOP, "NEXT_HOP" },
47 { BGP_ATTR_MULTI_EXIT_DISC, "MULTI_EXIT_DISC" },
48 { BGP_ATTR_LOCAL_PREF, "LOCAL_PREF" },
49 { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" },
50 { BGP_ATTR_AGGREGATOR, "AGGREGATOR" },
51 { BGP_ATTR_COMMUNITIES, "COMMUNITY" },
52 { BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID" },
53 { BGP_ATTR_CLUSTER_LIST, "CLUSTERLIST" },
54 { BGP_ATTR_DPA, "DPA" },
55 { BGP_ATTR_ADVERTISER, "ADVERTISER"} ,
56 { BGP_ATTR_RCID_PATH, "RCID_PATH" },
57 { BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI" },
58 { BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI" },
Paul Jakma0b2aa3a2007-10-14 22:32:21 +000059 { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
60 { BGP_ATTR_AS4_PATH, "AS4_PATH" },
61 { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
62 { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
paul718e3742002-12-13 20:15:29 +000063};
Stephen Hemminger9bddac42009-05-15 09:59:51 -070064static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000065
Stephen Hemminger9bddac42009-05-15 09:59:51 -070066static struct hash *cluster_hash;
paul718e3742002-12-13 20:15:29 +000067
paul94f2b392005-06-28 12:44:16 +000068static void *
Paul Jakma923de652007-04-29 18:25:17 +000069cluster_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +000070{
Paul Jakma923de652007-04-29 18:25:17 +000071 struct cluster_list * val = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +000072 struct cluster_list *cluster;
73
74 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
75 cluster->length = val->length;
76
77 if (cluster->length)
78 {
79 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
80 memcpy (cluster->list, val->list, val->length);
81 }
82 else
83 cluster->list = NULL;
84
85 cluster->refcnt = 0;
86
87 return cluster;
88}
89
90/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000091static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000092cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000093{
94 struct cluster_list tmp;
95 struct cluster_list *cluster;
96
97 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000098 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +000099
100 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
101 cluster->refcnt++;
102 return cluster;
103}
104
105int
106cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
107{
108 int i;
109
110 for (i = 0; i < cluster->length / 4; i++)
111 if (cluster->list[i].s_addr == originator.s_addr)
112 return 1;
113 return 0;
114}
115
paul94f2b392005-06-28 12:44:16 +0000116static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000117cluster_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000118{
Paul Jakma923de652007-04-29 18:25:17 +0000119 struct cluster_list * cluster = (struct cluster_list *) p;
paul718e3742002-12-13 20:15:29 +0000120 unsigned int key = 0;
121 int length;
122 caddr_t pnt;
123
124 length = cluster->length;
125 pnt = (caddr_t) cluster->list;
126
127 while (length)
128 key += pnt[--length];
129
130 return key;
131}
132
paul94f2b392005-06-28 12:44:16 +0000133static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100134cluster_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000135{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100136 const struct cluster_list * cluster1 = p1;
137 const struct cluster_list * cluster2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000138
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100139 return (cluster1->length == cluster2->length &&
140 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000141}
142
paul94f2b392005-06-28 12:44:16 +0000143static void
paul718e3742002-12-13 20:15:29 +0000144cluster_free (struct cluster_list *cluster)
145{
146 if (cluster->list)
147 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
148 XFREE (MTYPE_CLUSTER, cluster);
149}
150
Chris Caputo228da422009-07-18 05:44:03 +0000151#if 0
paul94f2b392005-06-28 12:44:16 +0000152static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000153cluster_dup (struct cluster_list *cluster)
154{
155 struct cluster_list *new;
156
Stephen Hemminger393deb92008-08-18 14:13:29 -0700157 new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
paul718e3742002-12-13 20:15:29 +0000158 new->length = cluster->length;
159
160 if (cluster->length)
161 {
162 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
163 memcpy (new->list, cluster->list, cluster->length);
164 }
165 else
166 new->list = NULL;
167
168 return new;
169}
Chris Caputo228da422009-07-18 05:44:03 +0000170#endif
paul718e3742002-12-13 20:15:29 +0000171
paul94f2b392005-06-28 12:44:16 +0000172static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000173cluster_intern (struct cluster_list *cluster)
174{
175 struct cluster_list *find;
176
177 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
178 find->refcnt++;
179
180 return find;
181}
182
183void
184cluster_unintern (struct cluster_list *cluster)
185{
186 struct cluster_list *ret;
187
188 if (cluster->refcnt)
189 cluster->refcnt--;
190
191 if (cluster->refcnt == 0)
192 {
193 ret = hash_release (cluster_hash, cluster);
194 cluster_free (cluster);
195 }
196}
197
paul94f2b392005-06-28 12:44:16 +0000198static void
199cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000200{
201 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
202}
Chris Caputo228da422009-07-18 05:44:03 +0000203
204static void
205cluster_finish (void)
206{
207 hash_free (cluster_hash);
208 cluster_hash = NULL;
209}
paul718e3742002-12-13 20:15:29 +0000210
211/* Unknown transit attribute. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700212static struct hash *transit_hash;
paul718e3742002-12-13 20:15:29 +0000213
paul94f2b392005-06-28 12:44:16 +0000214static void
paul718e3742002-12-13 20:15:29 +0000215transit_free (struct transit *transit)
216{
217 if (transit->val)
218 XFREE (MTYPE_TRANSIT_VAL, transit->val);
219 XFREE (MTYPE_TRANSIT, transit);
220}
221
Paul Jakma923de652007-04-29 18:25:17 +0000222
paul94f2b392005-06-28 12:44:16 +0000223static void *
Paul Jakma923de652007-04-29 18:25:17 +0000224transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000225{
226 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000227 return p;
paul718e3742002-12-13 20:15:29 +0000228}
229
paul94f2b392005-06-28 12:44:16 +0000230static struct transit *
paul718e3742002-12-13 20:15:29 +0000231transit_intern (struct transit *transit)
232{
233 struct transit *find;
234
235 find = hash_get (transit_hash, transit, transit_hash_alloc);
236 if (find != transit)
237 transit_free (transit);
238 find->refcnt++;
239
240 return find;
241}
242
243void
244transit_unintern (struct transit *transit)
245{
246 struct transit *ret;
247
248 if (transit->refcnt)
249 transit->refcnt--;
250
251 if (transit->refcnt == 0)
252 {
253 ret = hash_release (transit_hash, transit);
254 transit_free (transit);
255 }
256}
257
paul94f2b392005-06-28 12:44:16 +0000258static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000259transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000260{
Paul Jakma923de652007-04-29 18:25:17 +0000261 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000262 unsigned int key = 0;
263 int length;
264 caddr_t pnt;
265
266 length = transit->length;
267 pnt = (caddr_t) transit->val;
268
269 while (length)
270 key += pnt[--length];
271
272 return key;
273}
274
paul94f2b392005-06-28 12:44:16 +0000275static int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100276transit_hash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000277{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100278 const struct transit * transit1 = p1;
279 const struct transit * transit2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000280
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100281 return (transit1->length == transit2->length &&
282 memcmp (transit1->val, transit2->val, transit1->length) == 0);
paul718e3742002-12-13 20:15:29 +0000283}
284
paul94f2b392005-06-28 12:44:16 +0000285static void
Stephen Hemminger66e5cd82009-02-09 10:14:16 -0800286transit_init (void)
paul718e3742002-12-13 20:15:29 +0000287{
288 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
289}
Chris Caputo228da422009-07-18 05:44:03 +0000290
291static void
292transit_finish (void)
293{
294 hash_free (transit_hash);
295 transit_hash = NULL;
296}
paul718e3742002-12-13 20:15:29 +0000297
298/* Attribute hash routines. */
Stephen Hemminger9bddac42009-05-15 09:59:51 -0700299static struct hash *attrhash;
paul718e3742002-12-13 20:15:29 +0000300
Paul Jakmafb982c22007-05-04 20:15:47 +0000301static struct attr_extra *
302bgp_attr_extra_new (void)
303{
304 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
305}
306
307void
308bgp_attr_extra_free (struct attr *attr)
309{
310 if (attr->extra)
311 {
312 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
313 attr->extra = NULL;
314 }
315}
316
317struct attr_extra *
318bgp_attr_extra_get (struct attr *attr)
319{
320 if (!attr->extra)
321 attr->extra = bgp_attr_extra_new();
322 return attr->extra;
323}
324
325/* Shallow copy of an attribute
326 * Though, not so shallow that it doesn't copy the contents
327 * of the attr_extra pointed to by 'extra'
328 */
329void
330bgp_attr_dup (struct attr *new, struct attr *orig)
331{
332 *new = *orig;
333 if (orig->extra)
334 {
335 new->extra = bgp_attr_extra_new();
336 *new->extra = *orig->extra;
337 }
338}
339
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000340unsigned long int
341attr_count (void)
342{
343 return attrhash->count;
344}
345
346unsigned long int
347attr_unknown_count (void)
348{
349 return transit_hash->count;
350}
351
paul718e3742002-12-13 20:15:29 +0000352unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000353attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000354{
Paul Jakma923de652007-04-29 18:25:17 +0000355 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000356 unsigned int key = 0;
357
358 key += attr->origin;
359 key += attr->nexthop.s_addr;
360 key += attr->med;
361 key += attr->local_pref;
Paul Jakmafb982c22007-05-04 20:15:47 +0000362
363 if (attr->extra)
364 {
365 key += attr->extra->aggregator_as;
366 key += attr->extra->aggregator_addr.s_addr;
367 key += attr->extra->weight;
368 key += attr->extra->mp_nexthop_global_in.s_addr;
369 }
370
paul718e3742002-12-13 20:15:29 +0000371 if (attr->aspath)
372 key += aspath_key_make (attr->aspath);
373 if (attr->community)
374 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000375
376 if (attr->extra)
377 {
378 if (attr->extra->ecommunity)
379 key += ecommunity_hash_make (attr->extra->ecommunity);
380 if (attr->extra->cluster)
381 key += cluster_hash_key_make (attr->extra->cluster);
382 if (attr->extra->transit)
383 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000384
385#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000386 {
387 int i;
388
389 key += attr->extra->mp_nexthop_len;
390 for (i = 0; i < 16; i++)
391 key += attr->extra->mp_nexthop_global.s6_addr[i];
392 for (i = 0; i < 16; i++)
393 key += attr->extra->mp_nexthop_local.s6_addr[i];
394 }
paul718e3742002-12-13 20:15:29 +0000395#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000396 }
paul718e3742002-12-13 20:15:29 +0000397
398 return key;
399}
400
401int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100402attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000403{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100404 const struct attr * attr1 = p1;
405 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000406
paul718e3742002-12-13 20:15:29 +0000407 if (attr1->flag == attr2->flag
408 && attr1->origin == attr2->origin
409 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000410 && attr1->aspath == attr2->aspath
411 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000412 && attr1->med == attr2->med
Paul Jakmae70e5752011-07-05 00:41:59 +0400413 && attr1->local_pref == attr2->local_pref)
Paul Jakmafb982c22007-05-04 20:15:47 +0000414 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100415 const struct attr_extra *ae1 = attr1->extra;
416 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000417
418 if (ae1 && ae2
419 && ae1->aggregator_as == ae2->aggregator_as
420 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
421 && ae1->weight == ae2->weight
422#ifdef HAVE_IPV6
423 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
424 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
425 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
426#endif /* HAVE_IPV6 */
427 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
428 && ae1->ecommunity == ae2->ecommunity
429 && ae1->cluster == ae2->cluster
430 && ae1->transit == ae2->transit)
431 return 1;
432 else if (ae1 || ae2)
433 return 0;
434 /* neither attribute has extra attributes, so they're same */
435 return 1;
436 }
paul718e3742002-12-13 20:15:29 +0000437 else
438 return 0;
439}
440
paul94f2b392005-06-28 12:44:16 +0000441static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100442attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000443{
444 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
445}
446
paul94f2b392005-06-28 12:44:16 +0000447static void
Chris Caputo228da422009-07-18 05:44:03 +0000448attrhash_finish (void)
449{
450 hash_free (attrhash);
451 attrhash = NULL;
452}
453
454static void
paul718e3742002-12-13 20:15:29 +0000455attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
456{
457 struct attr *attr = backet->data;
458
459 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
460 inet_ntoa (attr->nexthop), VTY_NEWLINE);
461}
462
463void
464attr_show_all (struct vty *vty)
465{
466 hash_iterate (attrhash,
467 (void (*)(struct hash_backet *, void *))
468 attr_show_all_iterator,
469 vty);
470}
471
paul94f2b392005-06-28 12:44:16 +0000472static void *
Paul Jakma923de652007-04-29 18:25:17 +0000473bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000474{
Paul Jakma923de652007-04-29 18:25:17 +0000475 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000476 struct attr *attr;
477
478 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
479 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000480 if (val->extra)
481 {
482 attr->extra = bgp_attr_extra_new ();
483 *attr->extra = *val->extra;
484 }
paul718e3742002-12-13 20:15:29 +0000485 attr->refcnt = 0;
486 return attr;
487}
488
489/* Internet argument attribute. */
490struct attr *
491bgp_attr_intern (struct attr *attr)
492{
493 struct attr *find;
494
495 /* Intern referenced strucutre. */
496 if (attr->aspath)
497 {
498 if (! attr->aspath->refcnt)
499 attr->aspath = aspath_intern (attr->aspath);
500 else
501 attr->aspath->refcnt++;
502 }
503 if (attr->community)
504 {
505 if (! attr->community->refcnt)
506 attr->community = community_intern (attr->community);
507 else
508 attr->community->refcnt++;
509 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000510 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000511 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000512 struct attr_extra *attre = attr->extra;
513
514 if (attre->ecommunity)
515 {
516 if (! attre->ecommunity->refcnt)
517 attre->ecommunity = ecommunity_intern (attre->ecommunity);
518 else
519 attre->ecommunity->refcnt++;
520 }
521 if (attre->cluster)
522 {
523 if (! attre->cluster->refcnt)
524 attre->cluster = cluster_intern (attre->cluster);
525 else
526 attre->cluster->refcnt++;
527 }
528 if (attre->transit)
529 {
530 if (! attre->transit->refcnt)
531 attre->transit = transit_intern (attre->transit);
532 else
533 attre->transit->refcnt++;
534 }
paul718e3742002-12-13 20:15:29 +0000535 }
536
537 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
538 find->refcnt++;
539
540 return find;
541}
542
Paul Jakma03e214c2007-04-29 18:31:07 +0000543
paul718e3742002-12-13 20:15:29 +0000544/* Make network statement's attribute. */
545struct attr *
546bgp_attr_default_set (struct attr *attr, u_char origin)
547{
548 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000549 bgp_attr_extra_get (attr);
550
paul718e3742002-12-13 20:15:29 +0000551 attr->origin = origin;
552 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
553 attr->aspath = aspath_empty ();
554 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000555 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000556 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
557#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000558 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000559#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000560
paul718e3742002-12-13 20:15:29 +0000561 return attr;
562}
563
Paul Jakma03e214c2007-04-29 18:31:07 +0000564
paul718e3742002-12-13 20:15:29 +0000565/* Make network statement's attribute. */
566struct attr *
567bgp_attr_default_intern (u_char origin)
568{
569 struct attr attr;
570 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000571 struct attr_extra *attre;
572
573 memset (&attr, 0, sizeof (struct attr));
574 attre = bgp_attr_extra_get (&attr);
575
Paul Jakma03e214c2007-04-29 18:31:07 +0000576 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000577
578 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000579 bgp_attr_extra_free (&attr);
580
paul718e3742002-12-13 20:15:29 +0000581 aspath_unintern (new->aspath);
582 return new;
583}
584
585struct attr *
586bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
587 struct aspath *aspath,
588 struct community *community, int as_set)
589{
590 struct attr attr;
591 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000592 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000593
594 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000595 attre = bgp_attr_extra_get (&attr);
596
paul718e3742002-12-13 20:15:29 +0000597 /* Origin attribute. */
598 attr.origin = origin;
599 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
600
601 /* AS path attribute. */
602 if (aspath)
603 attr.aspath = aspath_intern (aspath);
604 else
605 attr.aspath = aspath_empty ();
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
607
608 /* Next hop attribute. */
609 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
610
611 if (community)
612 {
613 attr.community = community;
614 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
615 }
616
Paul Jakmafb982c22007-05-04 20:15:47 +0000617 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000618#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000619 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000620#endif
621 if (! as_set)
622 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
623 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
624 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000625 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000626 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000627 attre->aggregator_as = bgp->as;
628 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000629
630 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000631 bgp_attr_extra_free (&attr);
632
paul718e3742002-12-13 20:15:29 +0000633 aspath_unintern (new->aspath);
634 return new;
635}
636
637/* Free bgp attribute and aspath. */
638void
639bgp_attr_unintern (struct attr *attr)
640{
641 struct attr *ret;
642 struct aspath *aspath;
643 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000644 struct ecommunity *ecommunity = NULL;
645 struct cluster_list *cluster = NULL;
646 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000647
648 /* Decrement attribute reference. */
649 attr->refcnt--;
650 aspath = attr->aspath;
651 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000652 if (attr->extra)
653 {
654 ecommunity = attr->extra->ecommunity;
655 cluster = attr->extra->cluster;
656 transit = attr->extra->transit;
657 }
paul718e3742002-12-13 20:15:29 +0000658
659 /* If reference becomes zero then free attribute object. */
660 if (attr->refcnt == 0)
661 {
662 ret = hash_release (attrhash, attr);
663 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000664 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000665 XFREE (MTYPE_ATTR, attr);
666 }
667
668 /* aspath refcount shoud be decrement. */
669 if (aspath)
670 aspath_unintern (aspath);
671 if (community)
672 community_unintern (community);
673 if (ecommunity)
674 ecommunity_unintern (ecommunity);
675 if (cluster)
676 cluster_unintern (cluster);
677 if (transit)
678 transit_unintern (transit);
679}
680
681void
682bgp_attr_flush (struct attr *attr)
683{
684 if (attr->aspath && ! attr->aspath->refcnt)
685 aspath_free (attr->aspath);
686 if (attr->community && ! attr->community->refcnt)
687 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000688 if (attr->extra)
689 {
690 struct attr_extra *attre = attr->extra;
691 if (attre->ecommunity && ! attre->ecommunity->refcnt)
692 ecommunity_free (attre->ecommunity);
693 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
700/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000701static int
paul718e3742002-12-13 20:15:29 +0000702bgp_attr_origin (struct peer *peer, bgp_size_t length,
703 struct attr *attr, u_char flag, u_char *startp)
704{
705 bgp_size_t total;
706
707 /* total is entire attribute length include Attribute Flags (1),
708 Attribute Type code (1) and Attribute length (1 or 2). */
709 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
710
711 /* If any recognized attribute has Attribute Flags that conflict
712 with the Attribute Type Code, then the Error Subcode is set to
713 Attribute Flags Error. The Data field contains the erroneous
714 attribute (type, length and value). */
715 if (flag != BGP_ATTR_FLAG_TRANS)
716 {
717 zlog (peer->log, LOG_ERR,
718 "Origin attribute flag isn't transitive %d", flag);
719 bgp_notify_send_with_data (peer,
720 BGP_NOTIFY_UPDATE_ERR,
721 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
722 startp, total);
723 return -1;
724 }
725
726 /* If any recognized attribute has Attribute Length that conflicts
727 with the expected length (based on the attribute type code), then
728 the Error Subcode is set to Attribute Length Error. The Data
729 field contains the erroneous attribute (type, length and
730 value). */
731 if (length != 1)
732 {
733 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
734 length);
735 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
736 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
737 startp, total);
738 return -1;
739 }
740
741 /* Fetch origin attribute. */
742 attr->origin = stream_getc (BGP_INPUT (peer));
743
744 /* If the ORIGIN attribute has an undefined value, then the Error
745 Subcode is set to Invalid Origin Attribute. The Data field
746 contains the unrecognized attribute (type, length and value). */
747 if ((attr->origin != BGP_ORIGIN_IGP)
748 && (attr->origin != BGP_ORIGIN_EGP)
749 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
750 {
751 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
752 attr->origin);
753
754 bgp_notify_send_with_data (peer,
755 BGP_NOTIFY_UPDATE_ERR,
756 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
757 startp, total);
758 return -1;
759 }
760
761 /* Set oring attribute flag. */
762 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
763
764 return 0;
765}
Chris Hallcddb8112010-08-09 22:31:37 +0400766/* Parse AS path information. This function is wrapper of aspath_parse.
767 *
768 * Parses AS_PATH or AS4_PATH.
769 *
770 * Returns: if valid: address of struct aspath in the hash of known aspaths,
771 * with reference count incremented.
772 * else: NULL
773 *
774 * NB: empty AS path (length == 0) is valid. The returned struct aspath will
775 * have segments == NULL and str == zero length string (unique).
776 */
777static struct aspath *
paul718e3742002-12-13 20:15:29 +0000778bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Chris Hallcddb8112010-08-09 22:31:37 +0400779 struct attr *attr, u_char flag, u_char *startp, int as4_path)
paul718e3742002-12-13 20:15:29 +0000780{
Chris Hallcddb8112010-08-09 22:31:37 +0400781 u_char require ;
782 struct aspath *asp ;
paul718e3742002-12-13 20:15:29 +0000783
Chris Hallcddb8112010-08-09 22:31:37 +0400784 /* Check the attribute flags */
785 require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
786 : BGP_ATTR_FLAG_TRANS ;
paul718e3742002-12-13 20:15:29 +0000787
Chris Hallcddb8112010-08-09 22:31:37 +0400788 if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require)
paul718e3742002-12-13 20:15:29 +0000789 {
Chris Hallcddb8112010-08-09 22:31:37 +0400790 const char* path_type ;
791 bgp_size_t total;
792
793 path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
794
795 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000796 zlog (peer->log, LOG_ERR,
Chris Hallcddb8112010-08-09 22:31:37 +0400797 "%s attribute flag isn't transitive %d", path_type, flag) ;
798
799 if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL))
800 zlog (peer->log, LOG_ERR,
801 "%s attribute flag must %sbe optional %d", path_type,
802 (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ;
803
804 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
805
paul718e3742002-12-13 20:15:29 +0000806 bgp_notify_send_with_data (peer,
807 BGP_NOTIFY_UPDATE_ERR,
808 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
809 startp, total);
paul718e3742002-12-13 20:15:29 +0000810
Chris Hallcddb8112010-08-09 22:31:37 +0400811 return NULL ;
812 } ;
813
814 /* Parse the AS_PATH/AS4_PATH body.
815 *
816 * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN
817 * AS4_PATH 4Byte ASN
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000818 */
Chris Hallcddb8112010-08-09 22:31:37 +0400819 asp = aspath_parse (peer->ibuf, length,
820 as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000821
Chris Hallcddb8112010-08-09 22:31:37 +0400822 if (asp != NULL)
823 {
824 attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
825 : BGP_ATTR_AS_PATH) ;
826 }
827 else
paul718e3742002-12-13 20:15:29 +0000828 {
829 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
Chris Hallcddb8112010-08-09 22:31:37 +0400830
831 /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */
paul718e3742002-12-13 20:15:29 +0000832 bgp_notify_send (peer,
833 BGP_NOTIFY_UPDATE_ERR,
834 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Chris Hallcddb8112010-08-09 22:31:37 +0400835 } ;
paul718e3742002-12-13 20:15:29 +0000836
Chris Hallcddb8112010-08-09 22:31:37 +0400837 return asp ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000838}
839
840static int bgp_attr_aspath_check( struct peer *peer,
841 struct attr *attr)
842{
843 /* These checks were part of bgp_attr_aspath, but with
844 * as4 we should to check aspath things when
845 * aspath synthesizing with as4_path has already taken place.
846 * Otherwise we check ASPATH and use the synthesized thing, and that is
847 * not right.
848 * So do the checks later, i.e. here
849 */
850 struct bgp *bgp = peer->bgp;
851 struct aspath *aspath;
852
paul718e3742002-12-13 20:15:29 +0000853 bgp = peer->bgp;
854
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300855 /* Confederation sanity check. */
856 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
857 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
858 {
859 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
860 bgp_notify_send (peer,
861 BGP_NOTIFY_UPDATE_ERR,
862 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
863 return -1;
864 }
865
paul718e3742002-12-13 20:15:29 +0000866 /* First AS check for EBGP. */
867 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
868 {
869 if (peer_sort (peer) == BGP_PEER_EBGP
870 && ! aspath_firstas_check (attr->aspath, peer->as))
871 {
872 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400873 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000874 bgp_notify_send (peer,
875 BGP_NOTIFY_UPDATE_ERR,
876 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
877 return -1;
878 }
879 }
880
881 /* local-as prepend */
882 if (peer->change_local_as &&
883 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
884 {
885 aspath = aspath_dup (attr->aspath);
886 aspath = aspath_add_seq (aspath, peer->change_local_as);
887 aspath_unintern (attr->aspath);
888 attr->aspath = aspath_intern (aspath);
889 }
890
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000891 return 0;
892
893}
894
paul718e3742002-12-13 20:15:29 +0000895/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000896static int
paul718e3742002-12-13 20:15:29 +0000897bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
898 struct attr *attr, u_char flag, u_char *startp)
899{
900 bgp_size_t total;
901
902 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
903
904 /* Flag check. */
905 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
906 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
907 {
908 zlog (peer->log, LOG_ERR,
909 "Origin attribute flag isn't transitive %d", flag);
910 bgp_notify_send_with_data (peer,
911 BGP_NOTIFY_UPDATE_ERR,
912 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
913 startp, total);
914 return -1;
915 }
916
917 /* Check nexthop attribute length. */
918 if (length != 4)
919 {
920 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
921 length);
922
923 bgp_notify_send_with_data (peer,
924 BGP_NOTIFY_UPDATE_ERR,
925 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
926 startp, total);
927 return -1;
928 }
929
930 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
931 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
932
933 return 0;
934}
935
936/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000937static int
paul718e3742002-12-13 20:15:29 +0000938bgp_attr_med (struct peer *peer, bgp_size_t length,
939 struct attr *attr, u_char flag, u_char *startp)
940{
941 bgp_size_t total;
942
943 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
944
Denis Ovsienko7d25f182011-09-20 10:54:25 +0400945 /* Flag checks. */
946 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
947 {
948 zlog (peer->log, LOG_ERR,
949 "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
950 bgp_notify_send_with_data (peer,
951 BGP_NOTIFY_UPDATE_ERR,
952 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
953 startp, total);
954 return -1;
955 }
956 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
957 {
958 zlog (peer->log, LOG_ERR,
959 "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
960 bgp_notify_send_with_data (peer,
961 BGP_NOTIFY_UPDATE_ERR,
962 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
963 startp, total);
964 return -1;
965 }
966 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
967 {
968 zlog (peer->log, LOG_ERR,
969 "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
970 bgp_notify_send_with_data (peer,
971 BGP_NOTIFY_UPDATE_ERR,
972 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
973 startp, total);
974 return -1;
975 }
976
paul718e3742002-12-13 20:15:29 +0000977 /* Length check. */
978 if (length != 4)
979 {
980 zlog (peer->log, LOG_ERR,
981 "MED attribute length isn't four [%d]", length);
982
983 bgp_notify_send_with_data (peer,
984 BGP_NOTIFY_UPDATE_ERR,
985 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
986 startp, total);
987 return -1;
988 }
989
990 attr->med = stream_getl (peer->ibuf);
991
992 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
993
994 return 0;
995}
996
997/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000998static int
paul718e3742002-12-13 20:15:29 +0000999bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001000 struct attr *attr, u_char flag, u_char *startp)
paul718e3742002-12-13 20:15:29 +00001001{
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001002 bgp_size_t total;
1003
1004 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1005 /* Flag checks. */
1006 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1007 {
1008 zlog (peer->log, LOG_ERR,
1009 "LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag);
1010 bgp_notify_send_with_data (peer,
1011 BGP_NOTIFY_UPDATE_ERR,
1012 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1013 startp, total);
1014 return -1;
1015 }
1016 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1017 {
1018 zlog (peer->log, LOG_ERR,
1019 "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
1020 bgp_notify_send_with_data (peer,
1021 BGP_NOTIFY_UPDATE_ERR,
1022 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
1023 startp, total);
1024 return -1;
1025 }
1026
paul718e3742002-12-13 20:15:29 +00001027 /* If it is contained in an UPDATE message that is received from an
1028 external peer, then this attribute MUST be ignored by the
1029 receiving speaker. */
1030 if (peer_sort (peer) == BGP_PEER_EBGP)
1031 {
paul9985f832005-02-09 15:51:56 +00001032 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001033 return 0;
1034 }
1035
1036 if (length == 4)
1037 attr->local_pref = stream_getl (peer->ibuf);
1038 else
1039 attr->local_pref = 0;
1040
1041 /* Set atomic aggregate flag. */
1042 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1043
1044 return 0;
1045}
1046
1047/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001048static int
paul718e3742002-12-13 20:15:29 +00001049bgp_attr_atomic (struct peer *peer, bgp_size_t length,
1050 struct attr *attr, u_char flag)
1051{
1052 if (length != 0)
1053 {
1054 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1055
1056 bgp_notify_send (peer,
1057 BGP_NOTIFY_UPDATE_ERR,
1058 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1059 return -1;
1060 }
1061
1062 /* Set atomic aggregate flag. */
1063 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1064
1065 return 0;
1066}
1067
1068/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001069static int
paul718e3742002-12-13 20:15:29 +00001070bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1071 struct attr *attr, u_char flag)
1072{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001073 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001074 struct attr_extra *attre = bgp_attr_extra_get (attr);
1075
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001076 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1077 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1078 wantedlen = 8;
1079
1080 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001081 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001082 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001083
1084 bgp_notify_send (peer,
1085 BGP_NOTIFY_UPDATE_ERR,
1086 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1087 return -1;
1088 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001089
1090 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1091 attre->aggregator_as = stream_getl (peer->ibuf);
1092 else
1093 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001094 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001095
1096 /* Set atomic aggregate flag. */
1097 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1098
1099 return 0;
1100}
1101
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001102/* New Aggregator attribute */
1103static int
1104bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1105 struct attr *attr, as_t *as4_aggregator_as,
1106 struct in_addr *as4_aggregator_addr)
1107{
1108 if (length != 8)
1109 {
1110 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1111
1112 bgp_notify_send (peer,
1113 BGP_NOTIFY_UPDATE_ERR,
1114 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1115 return -1;
1116 }
1117 *as4_aggregator_as = stream_getl (peer->ibuf);
1118 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1119
1120 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1121
1122 return 0;
1123}
1124
1125/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1126 */
1127static int
1128bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1129 struct aspath *as4_path, as_t as4_aggregator,
1130 struct in_addr *as4_aggregator_addr)
1131{
1132 int ignore_as4_path = 0;
1133 struct aspath *newpath;
1134 struct attr_extra *attre = attr->extra;
1135
1136 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1137 {
1138 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1139 * if given.
1140 * It is worth a warning though, because the peer really
1141 * should not send them
1142 */
1143 if (BGP_DEBUG(as4, AS4))
1144 {
1145 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1146 zlog_debug ("[AS4] %s %s AS4_PATH",
1147 peer->host, "AS4 capable peer, yet it sent");
1148
1149 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1150 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1151 peer->host, "AS4 capable peer, yet it sent");
1152 }
1153
1154 return 0;
1155 }
1156
1157 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1158 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1159 {
1160 /* Hu? This is not supposed to happen at all!
1161 * got as4_path and no aspath,
1162 * This should already
1163 * have been handled by 'well known attributes missing'
1164 * But... yeah, paranoia
1165 * Take this as a "malformed attribute"
1166 */
1167 zlog (peer->log, LOG_ERR,
1168 "%s BGP not AS4 capable peer sent AS4_PATH but"
1169 " no AS_PATH, cant do anything here", peer->host);
1170 bgp_notify_send (peer,
1171 BGP_NOTIFY_UPDATE_ERR,
1172 BGP_NOTIFY_UPDATE_MAL_ATTR);
1173 return -1;
1174 }
1175
1176 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1177 * because that may override AS4_PATH
1178 */
1179 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1180 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001181 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1182 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001183 assert (attre);
1184
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001185 /* received both.
1186 * if the as_number in aggregator is not AS_TRANS,
1187 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1188 * and the Aggregator shall be taken as
1189 * info on the aggregating node, and the AS_PATH
1190 * shall be taken as the AS_PATH
1191 * otherwise
1192 * the Aggregator shall be ignored and the
1193 * AS4_AGGREGATOR shall be taken as the
1194 * Aggregating node and the AS_PATH is to be
1195 * constructed "as in all other cases"
1196 */
1197 if ( attre->aggregator_as != BGP_AS_TRANS )
1198 {
1199 /* ignore */
1200 if ( BGP_DEBUG(as4, AS4))
1201 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1202 " send AGGREGATOR != AS_TRANS and"
1203 " AS4_AGGREGATOR, so ignore"
1204 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1205 ignore_as4_path = 1;
1206 }
1207 else
1208 {
1209 /* "New_aggregator shall be taken as aggregator" */
1210 attre->aggregator_as = as4_aggregator;
1211 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1212 }
1213 }
1214 else
1215 {
1216 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1217 * That is bogus - but reading the conditions
1218 * we have to handle AS4_AGGREGATOR as if it were
1219 * AGGREGATOR in that case
1220 */
1221 if ( BGP_DEBUG(as4, AS4))
1222 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1223 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1224 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001225 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001226 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1227 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1228 }
1229 }
1230
1231 /* need to reconcile NEW_AS_PATH and AS_PATH */
1232 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1233 {
1234 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1235 aspath_unintern (attr->aspath);
1236 attr->aspath = aspath_intern (newpath);
1237 }
1238 return 0;
1239}
1240
paul718e3742002-12-13 20:15:29 +00001241/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001242static int
paul718e3742002-12-13 20:15:29 +00001243bgp_attr_community (struct peer *peer, bgp_size_t length,
1244 struct attr *attr, u_char flag)
1245{
1246 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001247 {
1248 attr->community = NULL;
1249 return 0;
1250 }
Paul Jakmafc097162010-12-05 17:17:26 +00001251
1252 attr->community =
1253 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1254
1255 /* XXX: fix community_parse to use stream API and remove this */
1256 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001257
Paul Jakmafc097162010-12-05 17:17:26 +00001258 if (!attr->community)
1259 return -1;
1260
paul718e3742002-12-13 20:15:29 +00001261 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1262
1263 return 0;
1264}
1265
1266/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001267static int
paul718e3742002-12-13 20:15:29 +00001268bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1269 struct attr *attr, u_char flag)
1270{
1271 if (length != 4)
1272 {
1273 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1274
1275 bgp_notify_send (peer,
1276 BGP_NOTIFY_UPDATE_ERR,
1277 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1278 return -1;
1279 }
1280
Paul Jakmafb982c22007-05-04 20:15:47 +00001281 (bgp_attr_extra_get (attr))->originator_id.s_addr
1282 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001283
1284 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1285
1286 return 0;
1287}
1288
1289/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001290static int
paul718e3742002-12-13 20:15:29 +00001291bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1292 struct attr *attr, u_char flag)
1293{
1294 /* Check length. */
1295 if (length % 4)
1296 {
1297 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1298
1299 bgp_notify_send (peer,
1300 BGP_NOTIFY_UPDATE_ERR,
1301 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1302 return -1;
1303 }
1304
Paul Jakmafb982c22007-05-04 20:15:47 +00001305 (bgp_attr_extra_get (attr))->cluster
1306 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001307
paul9985f832005-02-09 15:51:56 +00001308 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001309
1310 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1311
1312 return 0;
1313}
1314
1315/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001316int
paul718e3742002-12-13 20:15:29 +00001317bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1318 struct bgp_nlri *mp_update)
1319{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001320 afi_t afi;
1321 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001322 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001323 size_t start;
paul718e3742002-12-13 20:15:29 +00001324 int ret;
1325 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001326 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001327
1328 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001329 s = BGP_INPUT(peer);
1330 start = stream_get_getp(s);
1331
1332 /* safe to read statically sized header? */
1333#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001334#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001335 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001336 {
1337 zlog_info ("%s: %s sent invalid length, %lu",
1338 __func__, peer->host, (unsigned long)length);
1339 return -1;
1340 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001341
paul718e3742002-12-13 20:15:29 +00001342 /* Load AFI, SAFI. */
1343 afi = stream_getw (s);
1344 safi = stream_getc (s);
1345
1346 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001347 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001348
Paul Jakma03292802008-06-07 20:37:10 +00001349 if (LEN_LEFT < attre->mp_nexthop_len)
1350 {
1351 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1352 __func__, peer->host, attre->mp_nexthop_len);
1353 return -1;
1354 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001355
paul718e3742002-12-13 20:15:29 +00001356 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001357 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001358 {
1359 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001360 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001361 /* Probably needed for RFC 2283 */
1362 if (attr->nexthop.s_addr == 0)
1363 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001364 break;
1365 case 12:
1366 {
1367 u_int32_t rd_high;
1368 u_int32_t rd_low;
1369
1370 rd_high = stream_getl (s);
1371 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001372 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001373 }
1374 break;
1375#ifdef HAVE_IPV6
1376 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001377 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001378 break;
1379 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001380 stream_get (&attre->mp_nexthop_global, s, 16);
1381 stream_get (&attre->mp_nexthop_local, s, 16);
1382 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001383 {
1384 char buf1[INET6_ADDRSTRLEN];
1385 char buf2[INET6_ADDRSTRLEN];
1386
1387 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001388 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 +00001389 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001390 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001391 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001392 buf2, INET6_ADDRSTRLEN));
1393
Paul Jakmafb982c22007-05-04 20:15:47 +00001394 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001395 }
1396 break;
1397#endif /* HAVE_IPV6 */
1398 default:
Paul Jakma03292802008-06-07 20:37:10 +00001399 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1400 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001401 return -1;
paul718e3742002-12-13 20:15:29 +00001402 }
1403
Paul Jakma03292802008-06-07 20:37:10 +00001404 if (!LEN_LEFT)
1405 {
1406 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1407 __func__, peer->host);
1408 return -1;
1409 }
paul718e3742002-12-13 20:15:29 +00001410
Paul Jakma6e4ab122007-04-10 19:36:48 +00001411 {
1412 u_char val;
1413 if ((val = stream_getc (s)))
1414 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1415 peer->host, val);
1416 }
1417
1418 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001419 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001420 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001421 {
1422 zlog_info ("%s: (%s) Failed to read NLRI",
1423 __func__, peer->host);
1424 return -1;
1425 }
paul718e3742002-12-13 20:15:29 +00001426
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001427 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001428 {
1429 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001430 if (ret < 0)
1431 {
1432 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1433 __func__, peer->host);
1434 return -1;
1435 }
paul718e3742002-12-13 20:15:29 +00001436 }
1437
1438 mp_update->afi = afi;
1439 mp_update->safi = safi;
1440 mp_update->nlri = stream_pnt (s);
1441 mp_update->length = nlri_len;
1442
paul9985f832005-02-09 15:51:56 +00001443 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001444
1445 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001446#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001447}
1448
1449/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001450int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001451bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001452 struct bgp_nlri *mp_withdraw)
1453{
1454 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001455 afi_t afi;
1456 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001457 u_int16_t withdraw_len;
1458 int ret;
1459
1460 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001461
1462#define BGP_MP_UNREACH_MIN_SIZE 3
1463 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1464 return -1;
1465
paul718e3742002-12-13 20:15:29 +00001466 afi = stream_getw (s);
1467 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001468
1469 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001470
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04001471 if (safi != SAFI_MPLS_LABELED_VPN)
paul718e3742002-12-13 20:15:29 +00001472 {
1473 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1474 if (ret < 0)
1475 return -1;
1476 }
1477
1478 mp_withdraw->afi = afi;
1479 mp_withdraw->safi = safi;
1480 mp_withdraw->nlri = stream_pnt (s);
1481 mp_withdraw->length = withdraw_len;
1482
paul9985f832005-02-09 15:51:56 +00001483 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001484
1485 return 0;
1486}
1487
1488/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001489static int
paul718e3742002-12-13 20:15:29 +00001490bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1491 struct attr *attr, u_char flag)
1492{
1493 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001494 {
1495 if (attr->extra)
1496 attr->extra->ecommunity = NULL;
Paul Jakmafc097162010-12-05 17:17:26 +00001497 /* Empty extcomm doesn't seem to be invalid per se */
1498 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001499 }
Paul Jakmafc097162010-12-05 17:17:26 +00001500
1501 (bgp_attr_extra_get (attr))->ecommunity =
1502 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1503 /* XXX: fix ecommunity_parse to use stream API */
1504 stream_forward_getp (peer->ibuf, length);
1505
1506 if (!attr->extra->ecommunity)
1507 return -1;
1508
paul718e3742002-12-13 20:15:29 +00001509 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1510
1511 return 0;
1512}
1513
1514/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001515static int
paul718e3742002-12-13 20:15:29 +00001516bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1517 u_char type, bgp_size_t length, u_char *startp)
1518{
1519 bgp_size_t total;
1520 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001521 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001522
hassof4184462005-02-01 20:13:16 +00001523 if (BGP_DEBUG (normal, NORMAL))
1524 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1525 peer->host, type, length);
1526
paul718e3742002-12-13 20:15:29 +00001527 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001528 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001529 "Unknown attribute type %d length %d is received", type, length);
1530
1531 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001532 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001533
1534 /* Adjest total length to include type and length. */
1535 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1536
1537 /* If any of the mandatory well-known attributes are not recognized,
1538 then the Error Subcode is set to Unrecognized Well-known
1539 Attribute. The Data field contains the unrecognized attribute
1540 (type, length and value). */
1541 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1542 {
1543 /* Adjust startp to do not include flag value. */
1544 bgp_notify_send_with_data (peer,
1545 BGP_NOTIFY_UPDATE_ERR,
1546 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1547 startp, total);
1548 return -1;
1549 }
1550
1551 /* Unrecognized non-transitive optional attributes must be quietly
1552 ignored and not passed along to other BGP peers. */
1553 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1554 return 0;
1555
1556 /* If a path with recognized transitive optional attribute is
1557 accepted and passed along to other BGP peers and the Partial bit
1558 in the Attribute Flags octet is set to 1 by some previous AS, it
1559 is not set back to 0 by the current AS. */
1560 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1561
1562 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001563 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001564 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001565
Paul Jakmafb982c22007-05-04 20:15:47 +00001566 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001567
1568 if (transit->val)
1569 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1570 transit->length + total);
1571 else
1572 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1573
1574 memcpy (transit->val + transit->length, startp, total);
1575 transit->length += total;
1576
1577 return 0;
1578}
1579
1580/* Read attribute of update packet. This function is called from
1581 bgp_update() in bgpd.c. */
1582int
1583bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1584 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1585{
1586 int ret;
1587 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001588 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001589 bgp_size_t length;
1590 u_char *startp, *endp;
1591 u_char *attr_endp;
1592 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001593 /* we need the as4_path only until we have synthesized the as_path with it */
1594 /* same goes for as4_aggregator */
1595 struct aspath *as4_path = NULL;
1596 as_t as4_aggregator = 0;
1597 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001598
1599 /* Initialize bitmap. */
1600 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1601
1602 /* End pointer of BGP attribute. */
1603 endp = BGP_INPUT_PNT (peer) + size;
1604
1605 /* Get attributes to the end of attribute length. */
1606 while (BGP_INPUT_PNT (peer) < endp)
1607 {
1608 /* Check remaining length check.*/
1609 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1610 {
gdtc29fdba2004-12-09 14:46:46 +00001611 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001612 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001613 "%s: error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001614 peer->host,
1615 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001616
1617 bgp_notify_send (peer,
1618 BGP_NOTIFY_UPDATE_ERR,
1619 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1620 return -1;
1621 }
1622
1623 /* Fetch attribute flag and type. */
1624 startp = BGP_INPUT_PNT (peer);
1625 flag = stream_getc (BGP_INPUT (peer));
1626 type = stream_getc (BGP_INPUT (peer));
1627
Paul Jakma370b64a2007-12-22 16:49:52 +00001628 /* Check whether Extended-Length applies and is in bounds */
1629 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1630 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1631 {
1632 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001633 "%s: Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001634 peer->host,
1635 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1636
1637 bgp_notify_send (peer,
1638 BGP_NOTIFY_UPDATE_ERR,
1639 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1640 return -1;
1641 }
1642
paul718e3742002-12-13 20:15:29 +00001643 /* Check extended attribue length bit. */
1644 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1645 length = stream_getw (BGP_INPUT (peer));
1646 else
1647 length = stream_getc (BGP_INPUT (peer));
1648
1649 /* If any attribute appears more than once in the UPDATE
1650 message, then the Error Subcode is set to Malformed Attribute
1651 List. */
1652
1653 if (CHECK_BITMAP (seen, type))
1654 {
1655 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001656 "%s: error BGP attribute type %d appears twice in a message",
paul718e3742002-12-13 20:15:29 +00001657 peer->host, type);
1658
1659 bgp_notify_send (peer,
1660 BGP_NOTIFY_UPDATE_ERR,
1661 BGP_NOTIFY_UPDATE_MAL_ATTR);
1662 return -1;
1663 }
1664
1665 /* Set type to bitmap to check duplicate attribute. `type' is
1666 unsigned char so it never overflow bitmap range. */
1667
1668 SET_BITMAP (seen, type);
1669
1670 /* Overflow check. */
1671 attr_endp = BGP_INPUT_PNT (peer) + length;
1672
1673 if (attr_endp > endp)
1674 {
1675 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001676 "%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 +00001677 bgp_notify_send (peer,
1678 BGP_NOTIFY_UPDATE_ERR,
1679 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1680 return -1;
1681 }
1682
1683 /* OK check attribute and store it's value. */
1684 switch (type)
1685 {
1686 case BGP_ATTR_ORIGIN:
1687 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1688 break;
1689 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001690 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1691 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001692 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001693 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001694 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1695 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001696 break;
paul718e3742002-12-13 20:15:29 +00001697 case BGP_ATTR_NEXT_HOP:
1698 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1699 break;
1700 case BGP_ATTR_MULTI_EXIT_DISC:
1701 ret = bgp_attr_med (peer, length, attr, flag, startp);
1702 break;
1703 case BGP_ATTR_LOCAL_PREF:
Denis Ovsienkod0511bd2011-09-19 16:30:47 +04001704 ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
paul718e3742002-12-13 20:15:29 +00001705 break;
1706 case BGP_ATTR_ATOMIC_AGGREGATE:
1707 ret = bgp_attr_atomic (peer, length, attr, flag);
1708 break;
1709 case BGP_ATTR_AGGREGATOR:
1710 ret = bgp_attr_aggregator (peer, length, attr, flag);
1711 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001712 case BGP_ATTR_AS4_AGGREGATOR:
1713 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1714 break;
paul718e3742002-12-13 20:15:29 +00001715 case BGP_ATTR_COMMUNITIES:
1716 ret = bgp_attr_community (peer, length, attr, flag);
1717 break;
1718 case BGP_ATTR_ORIGINATOR_ID:
1719 ret = bgp_attr_originator_id (peer, length, attr, flag);
1720 break;
1721 case BGP_ATTR_CLUSTER_LIST:
1722 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1723 break;
1724 case BGP_ATTR_MP_REACH_NLRI:
1725 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1726 break;
1727 case BGP_ATTR_MP_UNREACH_NLRI:
1728 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1729 break;
1730 case BGP_ATTR_EXT_COMMUNITIES:
1731 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1732 break;
1733 default:
1734 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1735 break;
1736 }
1737
1738 /* If error occured immediately return to the caller. */
1739 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001740 {
1741 zlog (peer->log, LOG_WARNING,
1742 "%s: Attribute %s, parse error",
1743 peer->host,
1744 LOOKUP (attr_str, type));
1745 bgp_notify_send (peer,
1746 BGP_NOTIFY_UPDATE_ERR,
1747 BGP_NOTIFY_UPDATE_MAL_ATTR);
1748 return ret;
1749 }
paul718e3742002-12-13 20:15:29 +00001750
1751 /* Check the fetched length. */
1752 if (BGP_INPUT_PNT (peer) != attr_endp)
1753 {
1754 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001755 "%s: BGP attribute %s, fetch error",
1756 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001757 bgp_notify_send (peer,
1758 BGP_NOTIFY_UPDATE_ERR,
1759 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1760 return -1;
1761 }
1762 }
1763
1764 /* Check final read pointer is same as end pointer. */
1765 if (BGP_INPUT_PNT (peer) != endp)
1766 {
1767 zlog (peer->log, LOG_WARNING,
heasleyea15b202011-07-12 20:09:18 +04001768 "%s: BGP attribute %s, length mismatch",
Paul Jakma6e4ab122007-04-10 19:36:48 +00001769 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001770 bgp_notify_send (peer,
1771 BGP_NOTIFY_UPDATE_ERR,
1772 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1773 return -1;
1774 }
1775
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001776 /*
1777 * At this place we can see whether we got AS4_PATH and/or
1778 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1779 * We can not do this before we've read all attributes because
1780 * the as4 handling does not say whether AS4_PATH has to be sent
1781 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1782 * in relationship to AGGREGATOR.
1783 * So, to be defensive, we are not relying on any order and read
1784 * all attributes first, including these 32bit ones, and now,
1785 * afterwards, we look what and if something is to be done for as4.
1786 */
1787 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1788 as4_aggregator, &as4_aggregator_addr))
1789 return -1;
1790
1791 /* At this stage, we have done all fiddling with as4, and the
1792 * resulting info is in attr->aggregator resp. attr->aspath
1793 * so we can chuck as4_aggregator and as4_path alltogether in
1794 * order to save memory
1795 */
1796 if ( as4_path )
1797 {
1798 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1799 as4_path = NULL;
1800 /* The flag that we got this is still there, but that does not
1801 * do any trouble
1802 */
1803 }
1804 /*
1805 * The "rest" of the code does nothing with as4_aggregator.
1806 * there is no memory attached specifically which is not part
1807 * of the attr.
1808 * so ignoring just means do nothing.
1809 */
1810 /*
1811 * Finally do the checks on the aspath we did not do yet
1812 * because we waited for a potentially synthesized aspath.
1813 */
1814 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1815 {
1816 ret = bgp_attr_aspath_check( peer, attr );
1817 if ( ret < 0 )
1818 return ret;
1819 }
1820
paul718e3742002-12-13 20:15:29 +00001821 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001822 if (attr->extra && attr->extra->transit)
1823 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001824
1825 return 0;
1826}
1827
1828/* Well-known attribute check. */
1829int
1830bgp_attr_check (struct peer *peer, struct attr *attr)
1831{
1832 u_char type = 0;
1833
1834 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1835 type = BGP_ATTR_ORIGIN;
1836
1837 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1838 type = BGP_ATTR_AS_PATH;
1839
1840 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1841 type = BGP_ATTR_NEXT_HOP;
1842
1843 if (peer_sort (peer) == BGP_PEER_IBGP
1844 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1845 type = BGP_ATTR_LOCAL_PREF;
1846
1847 if (type)
1848 {
1849 zlog (peer->log, LOG_WARNING,
1850 "%s Missing well-known attribute %d.",
1851 peer->host, type);
1852 bgp_notify_send_with_data (peer,
1853 BGP_NOTIFY_UPDATE_ERR,
1854 BGP_NOTIFY_UPDATE_MISS_ATTR,
1855 &type, 1);
1856 return -1;
1857 }
1858 return 0;
1859}
1860
1861int stream_put_prefix (struct stream *, struct prefix *);
1862
1863/* Make attribute packet. */
1864bgp_size_t
1865bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1866 struct stream *s, struct attr *attr, struct prefix *p,
1867 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001868 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001869{
paulfe69a502005-09-10 16:55:02 +00001870 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001871 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001872 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001873 int send_as4_path = 0;
1874 int send_as4_aggregator = 0;
1875 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001876
1877 if (! bgp)
1878 bgp = bgp_get_default ();
1879
1880 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001881 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001882
1883 /* Origin attribute. */
1884 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1885 stream_putc (s, BGP_ATTR_ORIGIN);
1886 stream_putc (s, 1);
1887 stream_putc (s, attr->origin);
1888
1889 /* AS path attribute. */
1890
1891 /* If remote-peer is EBGP */
1892 if (peer_sort (peer) == BGP_PEER_EBGP
1893 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001894 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001895 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001896 {
1897 aspath = aspath_dup (attr->aspath);
1898
1899 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1900 {
1901 /* Strip the confed info, and then stuff our path CONFED_ID
1902 on the front */
1903 aspath = aspath_delete_confed_seq (aspath);
1904 aspath = aspath_add_seq (aspath, bgp->confed_id);
1905 }
1906 else
1907 {
1908 aspath = aspath_add_seq (aspath, peer->local_as);
1909 if (peer->change_local_as)
1910 aspath = aspath_add_seq (aspath, peer->change_local_as);
1911 }
1912 }
1913 else if (peer_sort (peer) == BGP_PEER_CONFED)
1914 {
1915 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1916 aspath = aspath_dup (attr->aspath);
1917 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1918 }
1919 else
1920 aspath = attr->aspath;
1921
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001922 /* If peer is not AS4 capable, then:
1923 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1924 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1925 * types are in it (i.e. exclude them if they are there)
1926 * AND do this only if there is at least one asnum > 65535 in the path!
1927 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1928 * all ASnums > 65535 to BGP_AS_TRANS
1929 */
paul718e3742002-12-13 20:15:29 +00001930
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001931 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1932 stream_putc (s, BGP_ATTR_AS_PATH);
1933 aspath_sizep = stream_get_endp (s);
1934 stream_putw (s, 0);
1935 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1936
1937 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1938 * in the path
1939 */
1940 if (!use32bit && aspath_has_as4 (aspath))
1941 send_as4_path = 1; /* we'll do this later, at the correct place */
1942
paul718e3742002-12-13 20:15:29 +00001943 /* Nexthop attribute. */
1944 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1945 {
1946 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1947 stream_putc (s, BGP_ATTR_NEXT_HOP);
1948 stream_putc (s, 4);
1949 if (safi == SAFI_MPLS_VPN)
1950 {
1951 if (attr->nexthop.s_addr == 0)
1952 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1953 else
1954 stream_put_ipv4 (s, attr->nexthop.s_addr);
1955 }
1956 else
1957 stream_put_ipv4 (s, attr->nexthop.s_addr);
1958 }
1959
1960 /* MED attribute. */
1961 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1962 {
1963 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1964 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1965 stream_putc (s, 4);
1966 stream_putl (s, attr->med);
1967 }
1968
1969 /* Local preference. */
1970 if (peer_sort (peer) == BGP_PEER_IBGP ||
1971 peer_sort (peer) == BGP_PEER_CONFED)
1972 {
1973 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1974 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1975 stream_putc (s, 4);
1976 stream_putl (s, attr->local_pref);
1977 }
1978
1979 /* Atomic aggregate. */
1980 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1981 {
1982 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1983 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1984 stream_putc (s, 0);
1985 }
1986
1987 /* Aggregator. */
1988 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1989 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001990 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001991
1992 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001993 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1994 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001995
1996 if (use32bit)
1997 {
1998 /* AS4 capable peer */
1999 stream_putc (s, 8);
2000 stream_putl (s, attr->extra->aggregator_as);
2001 }
2002 else
2003 {
2004 /* 2-byte AS peer */
2005 stream_putc (s, 6);
2006
2007 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
2008 if ( attr->extra->aggregator_as > 65535 )
2009 {
2010 stream_putw (s, BGP_AS_TRANS);
2011
2012 /* we have to send AS4_AGGREGATOR, too.
2013 * we'll do that later in order to send attributes in ascending
2014 * order.
2015 */
2016 send_as4_aggregator = 1;
2017 }
2018 else
2019 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2020 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002021 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002022 }
2023
2024 /* Community attribute. */
2025 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2026 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2027 {
2028 if (attr->community->size * 4 > 255)
2029 {
2030 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2031 stream_putc (s, BGP_ATTR_COMMUNITIES);
2032 stream_putw (s, attr->community->size * 4);
2033 }
2034 else
2035 {
2036 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2037 stream_putc (s, BGP_ATTR_COMMUNITIES);
2038 stream_putc (s, attr->community->size * 4);
2039 }
2040 stream_put (s, attr->community->val, attr->community->size * 4);
2041 }
2042
2043 /* Route Reflector. */
2044 if (peer_sort (peer) == BGP_PEER_IBGP
2045 && from
2046 && peer_sort (from) == BGP_PEER_IBGP)
2047 {
2048 /* Originator ID. */
2049 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2050 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2051 stream_putc (s, 4);
2052
2053 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002054 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002055 else
2056 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002057
2058 /* Cluster list. */
2059 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2060 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2061
Paul Jakma9eda90c2007-08-30 13:36:17 +00002062 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002063 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002064 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002065 /* If this peer configuration's parent BGP has cluster_id. */
2066 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2067 stream_put_in_addr (s, &bgp->cluster_id);
2068 else
2069 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002070 stream_put (s, attr->extra->cluster->list,
2071 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002072 }
2073 else
2074 {
2075 stream_putc (s, 4);
2076 /* If this peer configuration's parent BGP has cluster_id. */
2077 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2078 stream_put_in_addr (s, &bgp->cluster_id);
2079 else
2080 stream_put_in_addr (s, &bgp->router_id);
2081 }
2082 }
2083
2084#ifdef HAVE_IPV6
2085 /* If p is IPv6 address put it into attribute. */
2086 if (p->family == AF_INET6)
2087 {
2088 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002089 struct attr_extra *attre = attr->extra;
2090
2091 assert (attr->extra);
2092
paul718e3742002-12-13 20:15:29 +00002093 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2094 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002095 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002096 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002097 stream_putw (s, AFI_IP6); /* AFI */
2098 stream_putc (s, safi); /* SAFI */
2099
Paul Jakmafb982c22007-05-04 20:15:47 +00002100 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002101
Paul Jakmafb982c22007-05-04 20:15:47 +00002102 if (attre->mp_nexthop_len == 16)
2103 stream_put (s, &attre->mp_nexthop_global, 16);
2104 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002105 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002106 stream_put (s, &attre->mp_nexthop_global, 16);
2107 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002108 }
2109
2110 /* SNPA */
2111 stream_putc (s, 0);
2112
paul718e3742002-12-13 20:15:29 +00002113 /* Prefix write. */
2114 stream_put_prefix (s, p);
2115
2116 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002117 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002118 }
2119#endif /* HAVE_IPV6 */
2120
2121 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2122 {
2123 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002124
2125 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2126 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002127 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002128 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002129 stream_putw (s, AFI_IP); /* AFI */
2130 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2131
2132 stream_putc (s, 4);
2133 stream_put_ipv4 (s, attr->nexthop.s_addr);
2134
2135 /* SNPA */
2136 stream_putc (s, 0);
2137
paul718e3742002-12-13 20:15:29 +00002138 /* Prefix write. */
2139 stream_put_prefix (s, p);
2140
2141 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002142 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002143 }
2144
2145 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2146 {
2147 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002148
2149 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2150 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002151 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002152 stream_putc (s, 0); /* Length of this attribute. */
2153 stream_putw (s, AFI_IP); /* AFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002154 stream_putc (s, SAFI_MPLS_LABELED_VPN); /* SAFI */
paul718e3742002-12-13 20:15:29 +00002155
2156 stream_putc (s, 12);
2157 stream_putl (s, 0);
2158 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002159 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002160
2161 /* SNPA */
2162 stream_putc (s, 0);
2163
paul718e3742002-12-13 20:15:29 +00002164 /* Tag, RD, Prefix write. */
2165 stream_putc (s, p->prefixlen + 88);
2166 stream_put (s, tag, 3);
2167 stream_put (s, prd->val, 8);
2168 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2169
2170 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002171 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002172 }
2173
2174 /* Extended Communities attribute. */
2175 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2176 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2177 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002178 struct attr_extra *attre = attr->extra;
2179
2180 assert (attre);
2181
2182 if (peer_sort (peer) == BGP_PEER_IBGP
2183 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002184 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002185 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002186 {
2187 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2188 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002189 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002190 }
2191 else
2192 {
2193 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2194 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002195 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002196 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002197 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002198 }
2199 else
2200 {
paul5228ad22004-06-04 17:58:18 +00002201 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002202 int tbit;
2203 int ecom_tr_size = 0;
2204 int i;
2205
Paul Jakmafb982c22007-05-04 20:15:47 +00002206 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002207 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002208 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002209 tbit = *pnt;
2210
2211 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2212 continue;
2213
2214 ecom_tr_size++;
2215 }
2216
2217 if (ecom_tr_size)
2218 {
2219 if (ecom_tr_size * 8 > 255)
2220 {
2221 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2222 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2223 stream_putw (s, ecom_tr_size * 8);
2224 }
2225 else
2226 {
2227 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2228 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2229 stream_putc (s, ecom_tr_size * 8);
2230 }
2231
Paul Jakmafb982c22007-05-04 20:15:47 +00002232 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002233 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002234 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002235 tbit = *pnt;
2236
2237 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2238 continue;
2239
2240 stream_put (s, pnt, 8);
2241 }
2242 }
paul718e3742002-12-13 20:15:29 +00002243 }
paul718e3742002-12-13 20:15:29 +00002244 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002245
2246 if ( send_as4_path )
2247 {
2248 /* If the peer is NOT As4 capable, AND */
2249 /* there are ASnums > 65535 in path THEN
2250 * give out AS4_PATH */
2251
2252 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2253 * path segments!
2254 * Hm, I wonder... confederation things *should* only be at
2255 * the beginning of an aspath, right? Then we should use
2256 * aspath_delete_confed_seq for this, because it is already
2257 * there! (JK)
2258 * Folks, talk to me: what is reasonable here!?
2259 */
2260 aspath = aspath_delete_confed_seq (aspath);
2261
2262 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2263 stream_putc (s, BGP_ATTR_AS4_PATH);
2264 aspath_sizep = stream_get_endp (s);
2265 stream_putw (s, 0);
2266 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2267 }
2268
2269 if (aspath != attr->aspath)
2270 aspath_free (aspath);
2271
2272 if ( send_as4_aggregator )
2273 {
2274 assert (attr->extra);
2275
2276 /* send AS4_AGGREGATOR, at this place */
2277 /* this section of code moved here in order to ensure the correct
2278 * *ascending* order of attributes
2279 */
2280 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2281 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2282 stream_putc (s, 8);
2283 stream_putl (s, attr->extra->aggregator_as);
2284 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2285 }
Paul Jakma41367172007-08-06 15:24:51 +00002286
paul718e3742002-12-13 20:15:29 +00002287 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002288 if (attr->extra && attr->extra->transit)
2289 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002290
2291 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002292 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002293}
2294
2295bgp_size_t
2296bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2297 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002298 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002299{
2300 unsigned long cp;
2301 unsigned long attrlen_pnt;
2302 bgp_size_t size;
2303
paul9985f832005-02-09 15:51:56 +00002304 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002305
2306 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2307 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2308
paul9985f832005-02-09 15:51:56 +00002309 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002310 stream_putc (s, 0); /* Length of this attribute. */
2311
2312 stream_putw (s, family2afi (p->family));
2313
2314 if (safi == SAFI_MPLS_VPN)
2315 {
2316 /* SAFI */
Denis Ovsienkoe81537d2011-07-14 12:36:19 +04002317 stream_putc (s, SAFI_MPLS_LABELED_VPN);
paul718e3742002-12-13 20:15:29 +00002318
2319 /* prefix. */
2320 stream_putc (s, p->prefixlen + 88);
2321 stream_put (s, tag, 3);
2322 stream_put (s, prd->val, 8);
2323 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2324 }
2325 else
2326 {
2327 /* SAFI */
2328 stream_putc (s, safi);
2329
2330 /* prefix */
2331 stream_put_prefix (s, p);
2332 }
2333
2334 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002335 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002336 stream_putc_at (s, attrlen_pnt, size);
2337
paul9985f832005-02-09 15:51:56 +00002338 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002339}
2340
2341/* Initialization of attribute. */
2342void
paulfe69a502005-09-10 16:55:02 +00002343bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002344{
paul718e3742002-12-13 20:15:29 +00002345 aspath_init ();
2346 attrhash_init ();
2347 community_init ();
2348 ecommunity_init ();
2349 cluster_init ();
2350 transit_init ();
2351}
2352
Chris Caputo228da422009-07-18 05:44:03 +00002353void
2354bgp_attr_finish (void)
2355{
2356 aspath_finish ();
2357 attrhash_finish ();
2358 community_finish ();
2359 ecommunity_finish ();
2360 cluster_finish ();
2361 transit_finish ();
2362}
2363
paul718e3742002-12-13 20:15:29 +00002364/* Make attribute packet. */
2365void
paula3845922003-10-18 01:30:50 +00002366bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2367 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002368{
2369 unsigned long cp;
2370 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002371 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002372 struct aspath *aspath;
2373
2374 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002375 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002376
2377 /* Place holder of length. */
2378 stream_putw (s, 0);
2379
2380 /* Origin attribute. */
2381 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2382 stream_putc (s, BGP_ATTR_ORIGIN);
2383 stream_putc (s, 1);
2384 stream_putc (s, attr->origin);
2385
2386 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002387
2388 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2389 stream_putc (s, BGP_ATTR_AS_PATH);
2390 aspath_lenp = stream_get_endp (s);
2391 stream_putw (s, 0);
2392
2393 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002394
2395 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002396 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2397 if(prefix != NULL
2398#ifdef HAVE_IPV6
2399 && prefix->family != AF_INET6
2400#endif /* HAVE_IPV6 */
2401 )
2402 {
2403 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2404 stream_putc (s, BGP_ATTR_NEXT_HOP);
2405 stream_putc (s, 4);
2406 stream_put_ipv4 (s, attr->nexthop.s_addr);
2407 }
paul718e3742002-12-13 20:15:29 +00002408
2409 /* MED attribute. */
2410 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2411 {
2412 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2413 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2414 stream_putc (s, 4);
2415 stream_putl (s, attr->med);
2416 }
2417
2418 /* Local preference. */
2419 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2420 {
2421 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2422 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2423 stream_putc (s, 4);
2424 stream_putl (s, attr->local_pref);
2425 }
2426
2427 /* Atomic aggregate. */
2428 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2429 {
2430 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2431 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2432 stream_putc (s, 0);
2433 }
2434
2435 /* Aggregator. */
2436 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2437 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002438 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002439 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2440 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002441 stream_putc (s, 8);
2442 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002443 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002444 }
2445
2446 /* Community attribute. */
2447 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2448 {
2449 if (attr->community->size * 4 > 255)
2450 {
2451 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2452 stream_putc (s, BGP_ATTR_COMMUNITIES);
2453 stream_putw (s, attr->community->size * 4);
2454 }
2455 else
2456 {
2457 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2458 stream_putc (s, BGP_ATTR_COMMUNITIES);
2459 stream_putc (s, attr->community->size * 4);
2460 }
2461 stream_put (s, attr->community->val, attr->community->size * 4);
2462 }
2463
paula3845922003-10-18 01:30:50 +00002464#ifdef HAVE_IPV6
2465 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002466 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2467 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002468 {
2469 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002470 struct attr_extra *attre = attr->extra;
2471
paula3845922003-10-18 01:30:50 +00002472 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2473 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002474 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002475
2476 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002477 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002478 stream_putw(s, AFI_IP6); /* AFI */
2479 stream_putc(s, SAFI_UNICAST); /* SAFI */
2480
2481 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002482 stream_putc(s, attre->mp_nexthop_len);
2483 stream_put(s, &attre->mp_nexthop_global, 16);
2484 if (attre->mp_nexthop_len == 32)
2485 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002486
2487 /* SNPA */
2488 stream_putc(s, 0);
2489
2490 /* Prefix */
2491 stream_put_prefix(s, prefix);
2492
2493 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002494 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002495 }
2496#endif /* HAVE_IPV6 */
2497
paul718e3742002-12-13 20:15:29 +00002498 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002499 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002500 stream_putw_at (s, cp, len);
2501}