blob: c6fd3a573667621fb8aaa399b92b8f504f7569a6 [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 Jakma41367172007-08-06 15:24:51 +0000362 if (attr->pathlimit.as)
363 {
364 key += attr->pathlimit.ttl;
365 key += attr->pathlimit.as;
366 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000367
368 if (attr->extra)
369 {
370 key += attr->extra->aggregator_as;
371 key += attr->extra->aggregator_addr.s_addr;
372 key += attr->extra->weight;
373 key += attr->extra->mp_nexthop_global_in.s_addr;
374 }
375
paul718e3742002-12-13 20:15:29 +0000376 if (attr->aspath)
377 key += aspath_key_make (attr->aspath);
378 if (attr->community)
379 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000380
381 if (attr->extra)
382 {
383 if (attr->extra->ecommunity)
384 key += ecommunity_hash_make (attr->extra->ecommunity);
385 if (attr->extra->cluster)
386 key += cluster_hash_key_make (attr->extra->cluster);
387 if (attr->extra->transit)
388 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000389
390#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000391 {
392 int i;
393
394 key += attr->extra->mp_nexthop_len;
395 for (i = 0; i < 16; i++)
396 key += attr->extra->mp_nexthop_global.s6_addr[i];
397 for (i = 0; i < 16; i++)
398 key += attr->extra->mp_nexthop_local.s6_addr[i];
399 }
paul718e3742002-12-13 20:15:29 +0000400#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000401 }
paul718e3742002-12-13 20:15:29 +0000402
403 return key;
404}
405
406int
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100407attrhash_cmp (const void *p1, const void *p2)
paul718e3742002-12-13 20:15:29 +0000408{
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100409 const struct attr * attr1 = p1;
410 const struct attr * attr2 = p2;
Paul Jakma923de652007-04-29 18:25:17 +0000411
paul718e3742002-12-13 20:15:29 +0000412 if (attr1->flag == attr2->flag
413 && attr1->origin == attr2->origin
414 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000415 && attr1->aspath == attr2->aspath
416 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000417 && attr1->med == attr2->med
Paul Jakma41367172007-08-06 15:24:51 +0000418 && attr1->local_pref == attr2->local_pref
419 && attr1->pathlimit.ttl == attr2->pathlimit.ttl
420 && attr1->pathlimit.as == attr2->pathlimit.as)
Paul Jakmafb982c22007-05-04 20:15:47 +0000421 {
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100422 const struct attr_extra *ae1 = attr1->extra;
423 const struct attr_extra *ae2 = attr2->extra;
Paul Jakmafb982c22007-05-04 20:15:47 +0000424
425 if (ae1 && ae2
426 && ae1->aggregator_as == ae2->aggregator_as
427 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
428 && ae1->weight == ae2->weight
429#ifdef HAVE_IPV6
430 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
431 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
432 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
433#endif /* HAVE_IPV6 */
434 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
435 && ae1->ecommunity == ae2->ecommunity
436 && ae1->cluster == ae2->cluster
437 && ae1->transit == ae2->transit)
438 return 1;
439 else if (ae1 || ae2)
440 return 0;
441 /* neither attribute has extra attributes, so they're same */
442 return 1;
443 }
paul718e3742002-12-13 20:15:29 +0000444 else
445 return 0;
446}
447
paul94f2b392005-06-28 12:44:16 +0000448static void
Stephen Hemmingerffe11cf2008-08-14 16:25:25 +0100449attrhash_init (void)
paul718e3742002-12-13 20:15:29 +0000450{
451 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
452}
453
paul94f2b392005-06-28 12:44:16 +0000454static void
Chris Caputo228da422009-07-18 05:44:03 +0000455attrhash_finish (void)
456{
457 hash_free (attrhash);
458 attrhash = NULL;
459}
460
461static void
paul718e3742002-12-13 20:15:29 +0000462attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
463{
464 struct attr *attr = backet->data;
465
466 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
467 inet_ntoa (attr->nexthop), VTY_NEWLINE);
468}
469
470void
471attr_show_all (struct vty *vty)
472{
473 hash_iterate (attrhash,
474 (void (*)(struct hash_backet *, void *))
475 attr_show_all_iterator,
476 vty);
477}
478
paul94f2b392005-06-28 12:44:16 +0000479static void *
Paul Jakma923de652007-04-29 18:25:17 +0000480bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000481{
Paul Jakma923de652007-04-29 18:25:17 +0000482 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000483 struct attr *attr;
484
485 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
486 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000487 if (val->extra)
488 {
489 attr->extra = bgp_attr_extra_new ();
490 *attr->extra = *val->extra;
491 }
paul718e3742002-12-13 20:15:29 +0000492 attr->refcnt = 0;
493 return attr;
494}
495
496/* Internet argument attribute. */
497struct attr *
498bgp_attr_intern (struct attr *attr)
499{
500 struct attr *find;
501
502 /* Intern referenced strucutre. */
503 if (attr->aspath)
504 {
505 if (! attr->aspath->refcnt)
506 attr->aspath = aspath_intern (attr->aspath);
507 else
508 attr->aspath->refcnt++;
509 }
510 if (attr->community)
511 {
512 if (! attr->community->refcnt)
513 attr->community = community_intern (attr->community);
514 else
515 attr->community->refcnt++;
516 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000517 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000518 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000519 struct attr_extra *attre = attr->extra;
520
521 if (attre->ecommunity)
522 {
523 if (! attre->ecommunity->refcnt)
524 attre->ecommunity = ecommunity_intern (attre->ecommunity);
525 else
526 attre->ecommunity->refcnt++;
527 }
528 if (attre->cluster)
529 {
530 if (! attre->cluster->refcnt)
531 attre->cluster = cluster_intern (attre->cluster);
532 else
533 attre->cluster->refcnt++;
534 }
535 if (attre->transit)
536 {
537 if (! attre->transit->refcnt)
538 attre->transit = transit_intern (attre->transit);
539 else
540 attre->transit->refcnt++;
541 }
paul718e3742002-12-13 20:15:29 +0000542 }
543
544 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
545 find->refcnt++;
546
547 return find;
548}
549
Paul Jakma03e214c2007-04-29 18:31:07 +0000550
paul718e3742002-12-13 20:15:29 +0000551/* Make network statement's attribute. */
552struct attr *
553bgp_attr_default_set (struct attr *attr, u_char origin)
554{
555 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000556 bgp_attr_extra_get (attr);
557
paul718e3742002-12-13 20:15:29 +0000558 attr->origin = origin;
559 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
560 attr->aspath = aspath_empty ();
561 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000562 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000563 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
564#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000565 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000566#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000567
paul718e3742002-12-13 20:15:29 +0000568 return attr;
569}
570
Paul Jakma03e214c2007-04-29 18:31:07 +0000571
paul718e3742002-12-13 20:15:29 +0000572/* Make network statement's attribute. */
573struct attr *
574bgp_attr_default_intern (u_char origin)
575{
576 struct attr attr;
577 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000578 struct attr_extra *attre;
579
580 memset (&attr, 0, sizeof (struct attr));
581 attre = bgp_attr_extra_get (&attr);
582
Paul Jakma03e214c2007-04-29 18:31:07 +0000583 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000584
585 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000586 bgp_attr_extra_free (&attr);
587
paul718e3742002-12-13 20:15:29 +0000588 aspath_unintern (new->aspath);
589 return new;
590}
591
592struct attr *
593bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
594 struct aspath *aspath,
595 struct community *community, int as_set)
596{
597 struct attr attr;
598 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000599 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000600
601 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000602 attre = bgp_attr_extra_get (&attr);
603
paul718e3742002-12-13 20:15:29 +0000604 /* Origin attribute. */
605 attr.origin = origin;
606 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
607
608 /* AS path attribute. */
609 if (aspath)
610 attr.aspath = aspath_intern (aspath);
611 else
612 attr.aspath = aspath_empty ();
613 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
614
615 /* Next hop attribute. */
616 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
617
618 if (community)
619 {
620 attr.community = community;
621 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
622 }
623
Paul Jakmafb982c22007-05-04 20:15:47 +0000624 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000625#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000626 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000627#endif
628 if (! as_set)
629 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
630 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
631 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000632 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000633 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000634 attre->aggregator_as = bgp->as;
635 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000636
637 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000638 bgp_attr_extra_free (&attr);
639
paul718e3742002-12-13 20:15:29 +0000640 aspath_unintern (new->aspath);
641 return new;
642}
643
644/* Free bgp attribute and aspath. */
645void
646bgp_attr_unintern (struct attr *attr)
647{
648 struct attr *ret;
649 struct aspath *aspath;
650 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000651 struct ecommunity *ecommunity = NULL;
652 struct cluster_list *cluster = NULL;
653 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000654
655 /* Decrement attribute reference. */
656 attr->refcnt--;
657 aspath = attr->aspath;
658 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000659 if (attr->extra)
660 {
661 ecommunity = attr->extra->ecommunity;
662 cluster = attr->extra->cluster;
663 transit = attr->extra->transit;
664 }
paul718e3742002-12-13 20:15:29 +0000665
666 /* If reference becomes zero then free attribute object. */
667 if (attr->refcnt == 0)
668 {
669 ret = hash_release (attrhash, attr);
670 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000671 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000672 XFREE (MTYPE_ATTR, attr);
673 }
674
675 /* aspath refcount shoud be decrement. */
676 if (aspath)
677 aspath_unintern (aspath);
678 if (community)
679 community_unintern (community);
680 if (ecommunity)
681 ecommunity_unintern (ecommunity);
682 if (cluster)
683 cluster_unintern (cluster);
684 if (transit)
685 transit_unintern (transit);
686}
687
688void
689bgp_attr_flush (struct attr *attr)
690{
691 if (attr->aspath && ! attr->aspath->refcnt)
692 aspath_free (attr->aspath);
693 if (attr->community && ! attr->community->refcnt)
694 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000695 if (attr->extra)
696 {
697 struct attr_extra *attre = attr->extra;
698 if (attre->ecommunity && ! attre->ecommunity->refcnt)
699 ecommunity_free (attre->ecommunity);
700 if (attre->cluster && ! attre->cluster->refcnt)
701 cluster_free (attre->cluster);
702 if (attre->transit && ! attre->transit->refcnt)
703 transit_free (attre->transit);
704 }
paul718e3742002-12-13 20:15:29 +0000705}
706
Paul Jakma41367172007-08-06 15:24:51 +0000707/* Parse AS_PATHLIMIT attribute in an UPDATE */
708static int
709bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
710 struct attr *attr, u_char flag, u_char *startp)
711{
712 bgp_size_t total;
713
714 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
715
Paul Jakmaa15cfd12008-06-01 14:29:03 +0000716 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
717 || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
Paul Jakma41367172007-08-06 15:24:51 +0000718 {
719 zlog (peer->log, LOG_ERR,
720 "AS-Pathlimit attribute flag isn't transitive %d", flag);
721 bgp_notify_send_with_data (peer,
722 BGP_NOTIFY_UPDATE_ERR,
723 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
724 startp, total);
725 return -1;
726 }
727
728 if (length != 5)
729 {
730 zlog (peer->log, LOG_ERR,
731 "AS-Pathlimit length, %u, is not 5", length);
732 bgp_notify_send_with_data (peer,
733 BGP_NOTIFY_UPDATE_ERR,
734 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
735 startp, total);
736 return -1;
737 }
738
739 attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer));
740 attr->pathlimit.as = stream_getl (BGP_INPUT(peer));
741 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
742 return 0;
743}
paul718e3742002-12-13 20:15:29 +0000744/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000745static int
paul718e3742002-12-13 20:15:29 +0000746bgp_attr_origin (struct peer *peer, bgp_size_t length,
747 struct attr *attr, u_char flag, u_char *startp)
748{
749 bgp_size_t total;
750
751 /* total is entire attribute length include Attribute Flags (1),
752 Attribute Type code (1) and Attribute length (1 or 2). */
753 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
754
755 /* If any recognized attribute has Attribute Flags that conflict
756 with the Attribute Type Code, then the Error Subcode is set to
757 Attribute Flags Error. The Data field contains the erroneous
758 attribute (type, length and value). */
759 if (flag != BGP_ATTR_FLAG_TRANS)
760 {
761 zlog (peer->log, LOG_ERR,
762 "Origin attribute flag isn't transitive %d", flag);
763 bgp_notify_send_with_data (peer,
764 BGP_NOTIFY_UPDATE_ERR,
765 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
766 startp, total);
767 return -1;
768 }
769
770 /* If any recognized attribute has Attribute Length that conflicts
771 with the expected length (based on the attribute type code), then
772 the Error Subcode is set to Attribute Length Error. The Data
773 field contains the erroneous attribute (type, length and
774 value). */
775 if (length != 1)
776 {
777 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
778 length);
779 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
780 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
781 startp, total);
782 return -1;
783 }
784
785 /* Fetch origin attribute. */
786 attr->origin = stream_getc (BGP_INPUT (peer));
787
788 /* If the ORIGIN attribute has an undefined value, then the Error
789 Subcode is set to Invalid Origin Attribute. The Data field
790 contains the unrecognized attribute (type, length and value). */
791 if ((attr->origin != BGP_ORIGIN_IGP)
792 && (attr->origin != BGP_ORIGIN_EGP)
793 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
794 {
795 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
796 attr->origin);
797
798 bgp_notify_send_with_data (peer,
799 BGP_NOTIFY_UPDATE_ERR,
800 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
801 startp, total);
802 return -1;
803 }
804
805 /* Set oring attribute flag. */
806 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
807
808 return 0;
809}
Chris Hallcddb8112010-08-09 22:31:37 +0400810/* Parse AS path information. This function is wrapper of aspath_parse.
811 *
812 * Parses AS_PATH or AS4_PATH.
813 *
814 * Returns: if valid: address of struct aspath in the hash of known aspaths,
815 * with reference count incremented.
816 * else: NULL
817 *
818 * NB: empty AS path (length == 0) is valid. The returned struct aspath will
819 * have segments == NULL and str == zero length string (unique).
820 */
821static struct aspath *
paul718e3742002-12-13 20:15:29 +0000822bgp_attr_aspath (struct peer *peer, bgp_size_t length,
Chris Hallcddb8112010-08-09 22:31:37 +0400823 struct attr *attr, u_char flag, u_char *startp, int as4_path)
paul718e3742002-12-13 20:15:29 +0000824{
Chris Hallcddb8112010-08-09 22:31:37 +0400825 u_char require ;
826 struct aspath *asp ;
paul718e3742002-12-13 20:15:29 +0000827
Chris Hallcddb8112010-08-09 22:31:37 +0400828 /* Check the attribute flags */
829 require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS
830 : BGP_ATTR_FLAG_TRANS ;
paul718e3742002-12-13 20:15:29 +0000831
Chris Hallcddb8112010-08-09 22:31:37 +0400832 if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require)
paul718e3742002-12-13 20:15:29 +0000833 {
Chris Hallcddb8112010-08-09 22:31:37 +0400834 const char* path_type ;
835 bgp_size_t total;
836
837 path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
838
839 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
paul718e3742002-12-13 20:15:29 +0000840 zlog (peer->log, LOG_ERR,
Chris Hallcddb8112010-08-09 22:31:37 +0400841 "%s attribute flag isn't transitive %d", path_type, flag) ;
842
843 if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL))
844 zlog (peer->log, LOG_ERR,
845 "%s attribute flag must %sbe optional %d", path_type,
846 (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ;
847
848 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
849
paul718e3742002-12-13 20:15:29 +0000850 bgp_notify_send_with_data (peer,
851 BGP_NOTIFY_UPDATE_ERR,
852 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
853 startp, total);
paul718e3742002-12-13 20:15:29 +0000854
Chris Hallcddb8112010-08-09 22:31:37 +0400855 return NULL ;
856 } ;
857
858 /* Parse the AS_PATH/AS4_PATH body.
859 *
860 * For AS_PATH peer with AS4 => 4Byte ASN otherwise 2Byte ASN
861 * AS4_PATH 4Byte ASN
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000862 */
Chris Hallcddb8112010-08-09 22:31:37 +0400863 asp = aspath_parse (peer->ibuf, length,
864 as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000865
Chris Hallcddb8112010-08-09 22:31:37 +0400866 if (asp != NULL)
867 {
868 attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
869 : BGP_ATTR_AS_PATH) ;
870 }
871 else
paul718e3742002-12-13 20:15:29 +0000872 {
873 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
Chris Hallcddb8112010-08-09 22:31:37 +0400874
875 /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ?? */
paul718e3742002-12-13 20:15:29 +0000876 bgp_notify_send (peer,
877 BGP_NOTIFY_UPDATE_ERR,
878 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
Chris Hallcddb8112010-08-09 22:31:37 +0400879 } ;
paul718e3742002-12-13 20:15:29 +0000880
Chris Hallcddb8112010-08-09 22:31:37 +0400881 return asp ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000882}
883
884static int bgp_attr_aspath_check( struct peer *peer,
885 struct attr *attr)
886{
887 /* These checks were part of bgp_attr_aspath, but with
888 * as4 we should to check aspath things when
889 * aspath synthesizing with as4_path has already taken place.
890 * Otherwise we check ASPATH and use the synthesized thing, and that is
891 * not right.
892 * So do the checks later, i.e. here
893 */
894 struct bgp *bgp = peer->bgp;
895 struct aspath *aspath;
896
paul718e3742002-12-13 20:15:29 +0000897 bgp = peer->bgp;
898
Vasilis Tsiligiannisca87e1d2009-07-20 01:28:35 +0300899 /* Confederation sanity check. */
900 if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
901 (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
902 {
903 zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
904 bgp_notify_send (peer,
905 BGP_NOTIFY_UPDATE_ERR,
906 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
907 return -1;
908 }
909
paul718e3742002-12-13 20:15:29 +0000910 /* First AS check for EBGP. */
911 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
912 {
913 if (peer_sort (peer) == BGP_PEER_EBGP
914 && ! aspath_firstas_check (attr->aspath, peer->as))
915 {
916 zlog (peer->log, LOG_ERR,
Denis Ovsienkoaea339f2009-04-30 17:16:22 +0400917 "%s incorrect first AS (must be %u)", peer->host, peer->as);
paul718e3742002-12-13 20:15:29 +0000918 bgp_notify_send (peer,
919 BGP_NOTIFY_UPDATE_ERR,
920 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
921 return -1;
922 }
923 }
924
925 /* local-as prepend */
926 if (peer->change_local_as &&
927 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
928 {
929 aspath = aspath_dup (attr->aspath);
930 aspath = aspath_add_seq (aspath, peer->change_local_as);
931 aspath_unintern (attr->aspath);
932 attr->aspath = aspath_intern (aspath);
933 }
934
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000935 return 0;
936
937}
938
paul718e3742002-12-13 20:15:29 +0000939/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000940static int
paul718e3742002-12-13 20:15:29 +0000941bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
942 struct attr *attr, u_char flag, u_char *startp)
943{
944 bgp_size_t total;
945
946 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
947
948 /* Flag check. */
949 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
950 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
951 {
952 zlog (peer->log, LOG_ERR,
953 "Origin attribute flag isn't transitive %d", flag);
954 bgp_notify_send_with_data (peer,
955 BGP_NOTIFY_UPDATE_ERR,
956 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
957 startp, total);
958 return -1;
959 }
960
961 /* Check nexthop attribute length. */
962 if (length != 4)
963 {
964 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
965 length);
966
967 bgp_notify_send_with_data (peer,
968 BGP_NOTIFY_UPDATE_ERR,
969 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
970 startp, total);
971 return -1;
972 }
973
974 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
975 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
976
977 return 0;
978}
979
980/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000981static int
paul718e3742002-12-13 20:15:29 +0000982bgp_attr_med (struct peer *peer, bgp_size_t length,
983 struct attr *attr, u_char flag, u_char *startp)
984{
985 bgp_size_t total;
986
987 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
988
989 /* Length check. */
990 if (length != 4)
991 {
992 zlog (peer->log, LOG_ERR,
993 "MED attribute length isn't four [%d]", length);
994
995 bgp_notify_send_with_data (peer,
996 BGP_NOTIFY_UPDATE_ERR,
997 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
998 startp, total);
999 return -1;
1000 }
1001
1002 attr->med = stream_getl (peer->ibuf);
1003
1004 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
1005
1006 return 0;
1007}
1008
1009/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +00001010static int
paul718e3742002-12-13 20:15:29 +00001011bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
1012 struct attr *attr, u_char flag)
1013{
1014 /* If it is contained in an UPDATE message that is received from an
1015 external peer, then this attribute MUST be ignored by the
1016 receiving speaker. */
1017 if (peer_sort (peer) == BGP_PEER_EBGP)
1018 {
paul9985f832005-02-09 15:51:56 +00001019 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001020 return 0;
1021 }
1022
1023 if (length == 4)
1024 attr->local_pref = stream_getl (peer->ibuf);
1025 else
1026 attr->local_pref = 0;
1027
1028 /* Set atomic aggregate flag. */
1029 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
1030
1031 return 0;
1032}
1033
1034/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +00001035static int
paul718e3742002-12-13 20:15:29 +00001036bgp_attr_atomic (struct peer *peer, bgp_size_t length,
1037 struct attr *attr, u_char flag)
1038{
1039 if (length != 0)
1040 {
1041 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1042
1043 bgp_notify_send (peer,
1044 BGP_NOTIFY_UPDATE_ERR,
1045 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1046 return -1;
1047 }
1048
1049 /* Set atomic aggregate flag. */
1050 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1051
1052 return 0;
1053}
1054
1055/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001056static int
paul718e3742002-12-13 20:15:29 +00001057bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1058 struct attr *attr, u_char flag)
1059{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001060 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001061 struct attr_extra *attre = bgp_attr_extra_get (attr);
1062
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001063 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1064 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1065 wantedlen = 8;
1066
1067 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001068 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001069 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001070
1071 bgp_notify_send (peer,
1072 BGP_NOTIFY_UPDATE_ERR,
1073 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1074 return -1;
1075 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001076
1077 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1078 attre->aggregator_as = stream_getl (peer->ibuf);
1079 else
1080 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001081 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001082
1083 /* Set atomic aggregate flag. */
1084 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1085
1086 return 0;
1087}
1088
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001089/* New Aggregator attribute */
1090static int
1091bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1092 struct attr *attr, as_t *as4_aggregator_as,
1093 struct in_addr *as4_aggregator_addr)
1094{
1095 if (length != 8)
1096 {
1097 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1098
1099 bgp_notify_send (peer,
1100 BGP_NOTIFY_UPDATE_ERR,
1101 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1102 return -1;
1103 }
1104 *as4_aggregator_as = stream_getl (peer->ibuf);
1105 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1106
1107 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1108
1109 return 0;
1110}
1111
1112/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1113 */
1114static int
1115bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1116 struct aspath *as4_path, as_t as4_aggregator,
1117 struct in_addr *as4_aggregator_addr)
1118{
1119 int ignore_as4_path = 0;
1120 struct aspath *newpath;
1121 struct attr_extra *attre = attr->extra;
1122
1123 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1124 {
1125 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1126 * if given.
1127 * It is worth a warning though, because the peer really
1128 * should not send them
1129 */
1130 if (BGP_DEBUG(as4, AS4))
1131 {
1132 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1133 zlog_debug ("[AS4] %s %s AS4_PATH",
1134 peer->host, "AS4 capable peer, yet it sent");
1135
1136 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1137 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1138 peer->host, "AS4 capable peer, yet it sent");
1139 }
1140
1141 return 0;
1142 }
1143
1144 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1145 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1146 {
1147 /* Hu? This is not supposed to happen at all!
1148 * got as4_path and no aspath,
1149 * This should already
1150 * have been handled by 'well known attributes missing'
1151 * But... yeah, paranoia
1152 * Take this as a "malformed attribute"
1153 */
1154 zlog (peer->log, LOG_ERR,
1155 "%s BGP not AS4 capable peer sent AS4_PATH but"
1156 " no AS_PATH, cant do anything here", peer->host);
1157 bgp_notify_send (peer,
1158 BGP_NOTIFY_UPDATE_ERR,
1159 BGP_NOTIFY_UPDATE_MAL_ATTR);
1160 return -1;
1161 }
1162
1163 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1164 * because that may override AS4_PATH
1165 */
1166 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1167 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001168 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1169 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001170 assert (attre);
1171
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001172 /* received both.
1173 * if the as_number in aggregator is not AS_TRANS,
1174 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1175 * and the Aggregator shall be taken as
1176 * info on the aggregating node, and the AS_PATH
1177 * shall be taken as the AS_PATH
1178 * otherwise
1179 * the Aggregator shall be ignored and the
1180 * AS4_AGGREGATOR shall be taken as the
1181 * Aggregating node and the AS_PATH is to be
1182 * constructed "as in all other cases"
1183 */
1184 if ( attre->aggregator_as != BGP_AS_TRANS )
1185 {
1186 /* ignore */
1187 if ( BGP_DEBUG(as4, AS4))
1188 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1189 " send AGGREGATOR != AS_TRANS and"
1190 " AS4_AGGREGATOR, so ignore"
1191 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1192 ignore_as4_path = 1;
1193 }
1194 else
1195 {
1196 /* "New_aggregator shall be taken as aggregator" */
1197 attre->aggregator_as = as4_aggregator;
1198 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1199 }
1200 }
1201 else
1202 {
1203 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1204 * That is bogus - but reading the conditions
1205 * we have to handle AS4_AGGREGATOR as if it were
1206 * AGGREGATOR in that case
1207 */
1208 if ( BGP_DEBUG(as4, AS4))
1209 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1210 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1211 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001212 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001213 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1214 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1215 }
1216 }
1217
1218 /* need to reconcile NEW_AS_PATH and AS_PATH */
1219 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1220 {
1221 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1222 aspath_unintern (attr->aspath);
1223 attr->aspath = aspath_intern (newpath);
1224 }
1225 return 0;
1226}
1227
paul718e3742002-12-13 20:15:29 +00001228/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001229static int
paul718e3742002-12-13 20:15:29 +00001230bgp_attr_community (struct peer *peer, bgp_size_t length,
1231 struct attr *attr, u_char flag)
1232{
1233 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001234 {
1235 attr->community = NULL;
1236 return 0;
1237 }
Paul Jakmafc097162010-12-05 17:17:26 +00001238
1239 attr->community =
1240 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1241
1242 /* XXX: fix community_parse to use stream API and remove this */
1243 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001244
Paul Jakmafc097162010-12-05 17:17:26 +00001245 if (!attr->community)
1246 return -1;
1247
paul718e3742002-12-13 20:15:29 +00001248 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1249
1250 return 0;
1251}
1252
1253/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001254static int
paul718e3742002-12-13 20:15:29 +00001255bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1256 struct attr *attr, u_char flag)
1257{
1258 if (length != 4)
1259 {
1260 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1261
1262 bgp_notify_send (peer,
1263 BGP_NOTIFY_UPDATE_ERR,
1264 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1265 return -1;
1266 }
1267
Paul Jakmafb982c22007-05-04 20:15:47 +00001268 (bgp_attr_extra_get (attr))->originator_id.s_addr
1269 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001270
1271 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1272
1273 return 0;
1274}
1275
1276/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001277static int
paul718e3742002-12-13 20:15:29 +00001278bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1279 struct attr *attr, u_char flag)
1280{
1281 /* Check length. */
1282 if (length % 4)
1283 {
1284 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1285
1286 bgp_notify_send (peer,
1287 BGP_NOTIFY_UPDATE_ERR,
1288 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1289 return -1;
1290 }
1291
Paul Jakmafb982c22007-05-04 20:15:47 +00001292 (bgp_attr_extra_get (attr))->cluster
1293 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001294
paul9985f832005-02-09 15:51:56 +00001295 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001296
1297 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1298
1299 return 0;
1300}
1301
1302/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001303int
paul718e3742002-12-13 20:15:29 +00001304bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1305 struct bgp_nlri *mp_update)
1306{
Michael Lambert4c9641b2010-07-22 13:20:55 -04001307 afi_t afi;
1308 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001309 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001310 size_t start;
paul718e3742002-12-13 20:15:29 +00001311 int ret;
1312 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001313 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001314
1315 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001316 s = BGP_INPUT(peer);
1317 start = stream_get_getp(s);
1318
1319 /* safe to read statically sized header? */
1320#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001321#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001322 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001323 {
1324 zlog_info ("%s: %s sent invalid length, %lu",
1325 __func__, peer->host, (unsigned long)length);
1326 return -1;
1327 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001328
paul718e3742002-12-13 20:15:29 +00001329 /* Load AFI, SAFI. */
1330 afi = stream_getw (s);
1331 safi = stream_getc (s);
1332
1333 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001334 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001335
Paul Jakma03292802008-06-07 20:37:10 +00001336 if (LEN_LEFT < attre->mp_nexthop_len)
1337 {
1338 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1339 __func__, peer->host, attre->mp_nexthop_len);
1340 return -1;
1341 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001342
paul718e3742002-12-13 20:15:29 +00001343 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001344 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001345 {
1346 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001347 stream_get (&attre->mp_nexthop_global_in, s, 4);
Michael Lambert66bed4f2009-07-28 11:26:14 -04001348 /* Probably needed for RFC 2283 */
1349 if (attr->nexthop.s_addr == 0)
1350 memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00001351 break;
1352 case 12:
1353 {
1354 u_int32_t rd_high;
1355 u_int32_t rd_low;
1356
1357 rd_high = stream_getl (s);
1358 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001359 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001360 }
1361 break;
1362#ifdef HAVE_IPV6
1363 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001364 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001365 break;
1366 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001367 stream_get (&attre->mp_nexthop_global, s, 16);
1368 stream_get (&attre->mp_nexthop_local, s, 16);
1369 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001370 {
1371 char buf1[INET6_ADDRSTRLEN];
1372 char buf2[INET6_ADDRSTRLEN];
1373
1374 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001375 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 +00001376 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001377 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001378 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001379 buf2, INET6_ADDRSTRLEN));
1380
Paul Jakmafb982c22007-05-04 20:15:47 +00001381 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001382 }
1383 break;
1384#endif /* HAVE_IPV6 */
1385 default:
Paul Jakma03292802008-06-07 20:37:10 +00001386 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1387 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001388 return -1;
paul718e3742002-12-13 20:15:29 +00001389 }
1390
Paul Jakma03292802008-06-07 20:37:10 +00001391 if (!LEN_LEFT)
1392 {
1393 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1394 __func__, peer->host);
1395 return -1;
1396 }
paul718e3742002-12-13 20:15:29 +00001397
Paul Jakma6e4ab122007-04-10 19:36:48 +00001398 {
1399 u_char val;
1400 if ((val = stream_getc (s)))
1401 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1402 peer->host, val);
1403 }
1404
1405 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001406 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001407 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001408 {
1409 zlog_info ("%s: (%s) Failed to read NLRI",
1410 __func__, peer->host);
1411 return -1;
1412 }
paul718e3742002-12-13 20:15:29 +00001413
1414 if (safi != BGP_SAFI_VPNV4)
1415 {
1416 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001417 if (ret < 0)
1418 {
1419 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1420 __func__, peer->host);
1421 return -1;
1422 }
paul718e3742002-12-13 20:15:29 +00001423 }
1424
1425 mp_update->afi = afi;
1426 mp_update->safi = safi;
1427 mp_update->nlri = stream_pnt (s);
1428 mp_update->length = nlri_len;
1429
paul9985f832005-02-09 15:51:56 +00001430 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001431
1432 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001433#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001434}
1435
1436/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001437int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001438bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001439 struct bgp_nlri *mp_withdraw)
1440{
1441 struct stream *s;
Michael Lambert4c9641b2010-07-22 13:20:55 -04001442 afi_t afi;
1443 safi_t safi;
paul718e3742002-12-13 20:15:29 +00001444 u_int16_t withdraw_len;
1445 int ret;
1446
1447 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001448
1449#define BGP_MP_UNREACH_MIN_SIZE 3
1450 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1451 return -1;
1452
paul718e3742002-12-13 20:15:29 +00001453 afi = stream_getw (s);
1454 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001455
1456 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001457
1458 if (safi != BGP_SAFI_VPNV4)
1459 {
1460 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1461 if (ret < 0)
1462 return -1;
1463 }
1464
1465 mp_withdraw->afi = afi;
1466 mp_withdraw->safi = safi;
1467 mp_withdraw->nlri = stream_pnt (s);
1468 mp_withdraw->length = withdraw_len;
1469
paul9985f832005-02-09 15:51:56 +00001470 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001471
1472 return 0;
1473}
1474
1475/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001476static int
paul718e3742002-12-13 20:15:29 +00001477bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1478 struct attr *attr, u_char flag)
1479{
1480 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001481 {
1482 if (attr->extra)
1483 attr->extra->ecommunity = NULL;
Paul Jakmafc097162010-12-05 17:17:26 +00001484 /* Empty extcomm doesn't seem to be invalid per se */
1485 return 0;
Paul Jakmafb982c22007-05-04 20:15:47 +00001486 }
Paul Jakmafc097162010-12-05 17:17:26 +00001487
1488 (bgp_attr_extra_get (attr))->ecommunity =
1489 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1490 /* XXX: fix ecommunity_parse to use stream API */
1491 stream_forward_getp (peer->ibuf, length);
1492
1493 if (!attr->extra->ecommunity)
1494 return -1;
1495
paul718e3742002-12-13 20:15:29 +00001496 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1497
1498 return 0;
1499}
1500
1501/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001502static int
paul718e3742002-12-13 20:15:29 +00001503bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1504 u_char type, bgp_size_t length, u_char *startp)
1505{
1506 bgp_size_t total;
1507 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001508 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001509
hassof4184462005-02-01 20:13:16 +00001510 if (BGP_DEBUG (normal, NORMAL))
1511 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1512 peer->host, type, length);
1513
paul718e3742002-12-13 20:15:29 +00001514 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001515 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001516 "Unknown attribute type %d length %d is received", type, length);
1517
1518 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001519 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001520
1521 /* Adjest total length to include type and length. */
1522 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1523
1524 /* If any of the mandatory well-known attributes are not recognized,
1525 then the Error Subcode is set to Unrecognized Well-known
1526 Attribute. The Data field contains the unrecognized attribute
1527 (type, length and value). */
1528 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1529 {
1530 /* Adjust startp to do not include flag value. */
1531 bgp_notify_send_with_data (peer,
1532 BGP_NOTIFY_UPDATE_ERR,
1533 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1534 startp, total);
1535 return -1;
1536 }
1537
1538 /* Unrecognized non-transitive optional attributes must be quietly
1539 ignored and not passed along to other BGP peers. */
1540 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1541 return 0;
1542
1543 /* If a path with recognized transitive optional attribute is
1544 accepted and passed along to other BGP peers and the Partial bit
1545 in the Attribute Flags octet is set to 1 by some previous AS, it
1546 is not set back to 0 by the current AS. */
1547 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1548
1549 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001550 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
Stephen Hemminger393deb92008-08-18 14:13:29 -07001551 attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001552
Paul Jakmafb982c22007-05-04 20:15:47 +00001553 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001554
1555 if (transit->val)
1556 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1557 transit->length + total);
1558 else
1559 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1560
1561 memcpy (transit->val + transit->length, startp, total);
1562 transit->length += total;
1563
1564 return 0;
1565}
1566
1567/* Read attribute of update packet. This function is called from
1568 bgp_update() in bgpd.c. */
1569int
1570bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1571 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1572{
1573 int ret;
1574 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001575 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001576 bgp_size_t length;
1577 u_char *startp, *endp;
1578 u_char *attr_endp;
1579 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001580 /* we need the as4_path only until we have synthesized the as_path with it */
1581 /* same goes for as4_aggregator */
1582 struct aspath *as4_path = NULL;
1583 as_t as4_aggregator = 0;
1584 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001585
1586 /* Initialize bitmap. */
1587 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1588
1589 /* End pointer of BGP attribute. */
1590 endp = BGP_INPUT_PNT (peer) + size;
1591
1592 /* Get attributes to the end of attribute length. */
1593 while (BGP_INPUT_PNT (peer) < endp)
1594 {
1595 /* Check remaining length check.*/
1596 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1597 {
gdtc29fdba2004-12-09 14:46:46 +00001598 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001599 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001600 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001601 peer->host,
1602 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001603
1604 bgp_notify_send (peer,
1605 BGP_NOTIFY_UPDATE_ERR,
1606 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1607 return -1;
1608 }
1609
1610 /* Fetch attribute flag and type. */
1611 startp = BGP_INPUT_PNT (peer);
1612 flag = stream_getc (BGP_INPUT (peer));
1613 type = stream_getc (BGP_INPUT (peer));
1614
Paul Jakma370b64a2007-12-22 16:49:52 +00001615 /* Check whether Extended-Length applies and is in bounds */
1616 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1617 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1618 {
1619 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001620 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001621 peer->host,
1622 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1623
1624 bgp_notify_send (peer,
1625 BGP_NOTIFY_UPDATE_ERR,
1626 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1627 return -1;
1628 }
1629
paul718e3742002-12-13 20:15:29 +00001630 /* Check extended attribue length bit. */
1631 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1632 length = stream_getw (BGP_INPUT (peer));
1633 else
1634 length = stream_getc (BGP_INPUT (peer));
1635
1636 /* If any attribute appears more than once in the UPDATE
1637 message, then the Error Subcode is set to Malformed Attribute
1638 List. */
1639
1640 if (CHECK_BITMAP (seen, type))
1641 {
1642 zlog (peer->log, LOG_WARNING,
1643 "%s error BGP attribute type %d appears twice in a message",
1644 peer->host, type);
1645
1646 bgp_notify_send (peer,
1647 BGP_NOTIFY_UPDATE_ERR,
1648 BGP_NOTIFY_UPDATE_MAL_ATTR);
1649 return -1;
1650 }
1651
1652 /* Set type to bitmap to check duplicate attribute. `type' is
1653 unsigned char so it never overflow bitmap range. */
1654
1655 SET_BITMAP (seen, type);
1656
1657 /* Overflow check. */
1658 attr_endp = BGP_INPUT_PNT (peer) + length;
1659
1660 if (attr_endp > endp)
1661 {
1662 zlog (peer->log, LOG_WARNING,
1663 "%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);
1664 bgp_notify_send (peer,
1665 BGP_NOTIFY_UPDATE_ERR,
1666 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1667 return -1;
1668 }
1669
1670 /* OK check attribute and store it's value. */
1671 switch (type)
1672 {
1673 case BGP_ATTR_ORIGIN:
1674 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1675 break;
1676 case BGP_ATTR_AS_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001677 attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0);
1678 ret = attr->aspath ? 0 : -1 ;
paul718e3742002-12-13 20:15:29 +00001679 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001680 case BGP_ATTR_AS4_PATH:
Chris Hallcddb8112010-08-09 22:31:37 +04001681 as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1);
1682 ret = as4_path ? 0 : -1 ;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001683 break;
paul718e3742002-12-13 20:15:29 +00001684 case BGP_ATTR_NEXT_HOP:
1685 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1686 break;
1687 case BGP_ATTR_MULTI_EXIT_DISC:
1688 ret = bgp_attr_med (peer, length, attr, flag, startp);
1689 break;
1690 case BGP_ATTR_LOCAL_PREF:
1691 ret = bgp_attr_local_pref (peer, length, attr, flag);
1692 break;
1693 case BGP_ATTR_ATOMIC_AGGREGATE:
1694 ret = bgp_attr_atomic (peer, length, attr, flag);
1695 break;
1696 case BGP_ATTR_AGGREGATOR:
1697 ret = bgp_attr_aggregator (peer, length, attr, flag);
1698 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001699 case BGP_ATTR_AS4_AGGREGATOR:
1700 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1701 break;
paul718e3742002-12-13 20:15:29 +00001702 case BGP_ATTR_COMMUNITIES:
1703 ret = bgp_attr_community (peer, length, attr, flag);
1704 break;
1705 case BGP_ATTR_ORIGINATOR_ID:
1706 ret = bgp_attr_originator_id (peer, length, attr, flag);
1707 break;
1708 case BGP_ATTR_CLUSTER_LIST:
1709 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1710 break;
1711 case BGP_ATTR_MP_REACH_NLRI:
1712 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1713 break;
1714 case BGP_ATTR_MP_UNREACH_NLRI:
1715 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1716 break;
1717 case BGP_ATTR_EXT_COMMUNITIES:
1718 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1719 break;
Paul Jakma41367172007-08-06 15:24:51 +00001720 case BGP_ATTR_AS_PATHLIMIT:
1721 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1722 break;
paul718e3742002-12-13 20:15:29 +00001723 default:
1724 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1725 break;
1726 }
1727
1728 /* If error occured immediately return to the caller. */
1729 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001730 {
1731 zlog (peer->log, LOG_WARNING,
1732 "%s: Attribute %s, parse error",
1733 peer->host,
1734 LOOKUP (attr_str, type));
1735 bgp_notify_send (peer,
1736 BGP_NOTIFY_UPDATE_ERR,
1737 BGP_NOTIFY_UPDATE_MAL_ATTR);
1738 return ret;
1739 }
paul718e3742002-12-13 20:15:29 +00001740
1741 /* Check the fetched length. */
1742 if (BGP_INPUT_PNT (peer) != attr_endp)
1743 {
1744 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001745 "%s: BGP attribute %s, fetch error",
1746 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001747 bgp_notify_send (peer,
1748 BGP_NOTIFY_UPDATE_ERR,
1749 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1750 return -1;
1751 }
1752 }
1753
1754 /* Check final read pointer is same as end pointer. */
1755 if (BGP_INPUT_PNT (peer) != endp)
1756 {
1757 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001758 "%s BGP attribute %s, length mismatch",
1759 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001760 bgp_notify_send (peer,
1761 BGP_NOTIFY_UPDATE_ERR,
1762 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1763 return -1;
1764 }
1765
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001766 /*
1767 * At this place we can see whether we got AS4_PATH and/or
1768 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1769 * We can not do this before we've read all attributes because
1770 * the as4 handling does not say whether AS4_PATH has to be sent
1771 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1772 * in relationship to AGGREGATOR.
1773 * So, to be defensive, we are not relying on any order and read
1774 * all attributes first, including these 32bit ones, and now,
1775 * afterwards, we look what and if something is to be done for as4.
1776 */
1777 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1778 as4_aggregator, &as4_aggregator_addr))
1779 return -1;
1780
1781 /* At this stage, we have done all fiddling with as4, and the
1782 * resulting info is in attr->aggregator resp. attr->aspath
1783 * so we can chuck as4_aggregator and as4_path alltogether in
1784 * order to save memory
1785 */
1786 if ( as4_path )
1787 {
1788 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1789 as4_path = NULL;
1790 /* The flag that we got this is still there, but that does not
1791 * do any trouble
1792 */
1793 }
1794 /*
1795 * The "rest" of the code does nothing with as4_aggregator.
1796 * there is no memory attached specifically which is not part
1797 * of the attr.
1798 * so ignoring just means do nothing.
1799 */
1800 /*
1801 * Finally do the checks on the aspath we did not do yet
1802 * because we waited for a potentially synthesized aspath.
1803 */
1804 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1805 {
1806 ret = bgp_attr_aspath_check( peer, attr );
1807 if ( ret < 0 )
1808 return ret;
1809 }
1810
paul718e3742002-12-13 20:15:29 +00001811 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001812 if (attr->extra && attr->extra->transit)
1813 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001814
1815 return 0;
1816}
1817
1818/* Well-known attribute check. */
1819int
1820bgp_attr_check (struct peer *peer, struct attr *attr)
1821{
1822 u_char type = 0;
1823
1824 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1825 type = BGP_ATTR_ORIGIN;
1826
1827 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1828 type = BGP_ATTR_AS_PATH;
1829
1830 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1831 type = BGP_ATTR_NEXT_HOP;
1832
1833 if (peer_sort (peer) == BGP_PEER_IBGP
1834 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1835 type = BGP_ATTR_LOCAL_PREF;
1836
1837 if (type)
1838 {
1839 zlog (peer->log, LOG_WARNING,
1840 "%s Missing well-known attribute %d.",
1841 peer->host, type);
1842 bgp_notify_send_with_data (peer,
1843 BGP_NOTIFY_UPDATE_ERR,
1844 BGP_NOTIFY_UPDATE_MISS_ATTR,
1845 &type, 1);
1846 return -1;
1847 }
1848 return 0;
1849}
1850
1851int stream_put_prefix (struct stream *, struct prefix *);
1852
1853/* Make attribute packet. */
1854bgp_size_t
1855bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1856 struct stream *s, struct attr *attr, struct prefix *p,
1857 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001858 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001859{
paulfe69a502005-09-10 16:55:02 +00001860 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001861 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001862 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001863 int send_as4_path = 0;
1864 int send_as4_aggregator = 0;
1865 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001866
1867 if (! bgp)
1868 bgp = bgp_get_default ();
1869
1870 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001871 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001872
1873 /* Origin attribute. */
1874 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1875 stream_putc (s, BGP_ATTR_ORIGIN);
1876 stream_putc (s, 1);
1877 stream_putc (s, attr->origin);
1878
1879 /* AS path attribute. */
1880
1881 /* If remote-peer is EBGP */
1882 if (peer_sort (peer) == BGP_PEER_EBGP
1883 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001884 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001885 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001886 {
1887 aspath = aspath_dup (attr->aspath);
1888
1889 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1890 {
1891 /* Strip the confed info, and then stuff our path CONFED_ID
1892 on the front */
1893 aspath = aspath_delete_confed_seq (aspath);
1894 aspath = aspath_add_seq (aspath, bgp->confed_id);
1895 }
1896 else
1897 {
1898 aspath = aspath_add_seq (aspath, peer->local_as);
1899 if (peer->change_local_as)
1900 aspath = aspath_add_seq (aspath, peer->change_local_as);
1901 }
1902 }
1903 else if (peer_sort (peer) == BGP_PEER_CONFED)
1904 {
1905 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1906 aspath = aspath_dup (attr->aspath);
1907 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1908 }
1909 else
1910 aspath = attr->aspath;
1911
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001912 /* If peer is not AS4 capable, then:
1913 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1914 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1915 * types are in it (i.e. exclude them if they are there)
1916 * AND do this only if there is at least one asnum > 65535 in the path!
1917 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1918 * all ASnums > 65535 to BGP_AS_TRANS
1919 */
paul718e3742002-12-13 20:15:29 +00001920
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001921 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1922 stream_putc (s, BGP_ATTR_AS_PATH);
1923 aspath_sizep = stream_get_endp (s);
1924 stream_putw (s, 0);
1925 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1926
1927 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1928 * in the path
1929 */
1930 if (!use32bit && aspath_has_as4 (aspath))
1931 send_as4_path = 1; /* we'll do this later, at the correct place */
1932
paul718e3742002-12-13 20:15:29 +00001933 /* Nexthop attribute. */
1934 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1935 {
1936 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1937 stream_putc (s, BGP_ATTR_NEXT_HOP);
1938 stream_putc (s, 4);
1939 if (safi == SAFI_MPLS_VPN)
1940 {
1941 if (attr->nexthop.s_addr == 0)
1942 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1943 else
1944 stream_put_ipv4 (s, attr->nexthop.s_addr);
1945 }
1946 else
1947 stream_put_ipv4 (s, attr->nexthop.s_addr);
1948 }
1949
1950 /* MED attribute. */
1951 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1952 {
1953 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1954 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1955 stream_putc (s, 4);
1956 stream_putl (s, attr->med);
1957 }
1958
1959 /* Local preference. */
1960 if (peer_sort (peer) == BGP_PEER_IBGP ||
1961 peer_sort (peer) == BGP_PEER_CONFED)
1962 {
1963 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1964 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1965 stream_putc (s, 4);
1966 stream_putl (s, attr->local_pref);
1967 }
1968
1969 /* Atomic aggregate. */
1970 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1971 {
1972 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1973 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1974 stream_putc (s, 0);
1975 }
1976
1977 /* Aggregator. */
1978 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1979 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001980 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001981
1982 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001983 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1984 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001985
1986 if (use32bit)
1987 {
1988 /* AS4 capable peer */
1989 stream_putc (s, 8);
1990 stream_putl (s, attr->extra->aggregator_as);
1991 }
1992 else
1993 {
1994 /* 2-byte AS peer */
1995 stream_putc (s, 6);
1996
1997 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1998 if ( attr->extra->aggregator_as > 65535 )
1999 {
2000 stream_putw (s, BGP_AS_TRANS);
2001
2002 /* we have to send AS4_AGGREGATOR, too.
2003 * we'll do that later in order to send attributes in ascending
2004 * order.
2005 */
2006 send_as4_aggregator = 1;
2007 }
2008 else
2009 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
2010 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002011 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002012 }
2013
2014 /* Community attribute. */
2015 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
2016 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
2017 {
2018 if (attr->community->size * 4 > 255)
2019 {
2020 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2021 stream_putc (s, BGP_ATTR_COMMUNITIES);
2022 stream_putw (s, attr->community->size * 4);
2023 }
2024 else
2025 {
2026 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2027 stream_putc (s, BGP_ATTR_COMMUNITIES);
2028 stream_putc (s, attr->community->size * 4);
2029 }
2030 stream_put (s, attr->community->val, attr->community->size * 4);
2031 }
2032
2033 /* Route Reflector. */
2034 if (peer_sort (peer) == BGP_PEER_IBGP
2035 && from
2036 && peer_sort (from) == BGP_PEER_IBGP)
2037 {
2038 /* Originator ID. */
2039 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2040 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
2041 stream_putc (s, 4);
2042
2043 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00002044 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00002045 else
2046 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00002047
2048 /* Cluster list. */
2049 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2050 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2051
Paul Jakma9eda90c2007-08-30 13:36:17 +00002052 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002053 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002054 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002055 /* If this peer configuration's parent BGP has cluster_id. */
2056 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2057 stream_put_in_addr (s, &bgp->cluster_id);
2058 else
2059 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002060 stream_put (s, attr->extra->cluster->list,
2061 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002062 }
2063 else
2064 {
2065 stream_putc (s, 4);
2066 /* If this peer configuration's parent BGP has cluster_id. */
2067 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2068 stream_put_in_addr (s, &bgp->cluster_id);
2069 else
2070 stream_put_in_addr (s, &bgp->router_id);
2071 }
2072 }
2073
2074#ifdef HAVE_IPV6
2075 /* If p is IPv6 address put it into attribute. */
2076 if (p->family == AF_INET6)
2077 {
2078 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002079 struct attr_extra *attre = attr->extra;
2080
2081 assert (attr->extra);
2082
paul718e3742002-12-13 20:15:29 +00002083 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2084 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002085 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002086 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002087 stream_putw (s, AFI_IP6); /* AFI */
2088 stream_putc (s, safi); /* SAFI */
2089
Paul Jakmafb982c22007-05-04 20:15:47 +00002090 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002091
Paul Jakmafb982c22007-05-04 20:15:47 +00002092 if (attre->mp_nexthop_len == 16)
2093 stream_put (s, &attre->mp_nexthop_global, 16);
2094 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002095 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002096 stream_put (s, &attre->mp_nexthop_global, 16);
2097 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002098 }
2099
2100 /* SNPA */
2101 stream_putc (s, 0);
2102
paul718e3742002-12-13 20:15:29 +00002103 /* Prefix write. */
2104 stream_put_prefix (s, p);
2105
2106 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002107 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002108 }
2109#endif /* HAVE_IPV6 */
2110
2111 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2112 {
2113 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002114
2115 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2116 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002117 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002118 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002119 stream_putw (s, AFI_IP); /* AFI */
2120 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2121
2122 stream_putc (s, 4);
2123 stream_put_ipv4 (s, attr->nexthop.s_addr);
2124
2125 /* SNPA */
2126 stream_putc (s, 0);
2127
paul718e3742002-12-13 20:15:29 +00002128 /* Prefix write. */
2129 stream_put_prefix (s, p);
2130
2131 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002132 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002133 }
2134
2135 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2136 {
2137 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002138
2139 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2140 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002141 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002142 stream_putc (s, 0); /* Length of this attribute. */
2143 stream_putw (s, AFI_IP); /* AFI */
2144 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2145
2146 stream_putc (s, 12);
2147 stream_putl (s, 0);
2148 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002149 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002150
2151 /* SNPA */
2152 stream_putc (s, 0);
2153
paul718e3742002-12-13 20:15:29 +00002154 /* Tag, RD, Prefix write. */
2155 stream_putc (s, p->prefixlen + 88);
2156 stream_put (s, tag, 3);
2157 stream_put (s, prd->val, 8);
2158 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2159
2160 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002161 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002162 }
2163
2164 /* Extended Communities attribute. */
2165 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2166 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2167 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002168 struct attr_extra *attre = attr->extra;
2169
2170 assert (attre);
2171
2172 if (peer_sort (peer) == BGP_PEER_IBGP
2173 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002174 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002175 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002176 {
2177 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2178 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002179 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002180 }
2181 else
2182 {
2183 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2184 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002185 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002186 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002187 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002188 }
2189 else
2190 {
paul5228ad22004-06-04 17:58:18 +00002191 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002192 int tbit;
2193 int ecom_tr_size = 0;
2194 int i;
2195
Paul Jakmafb982c22007-05-04 20:15:47 +00002196 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002197 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002198 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002199 tbit = *pnt;
2200
2201 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2202 continue;
2203
2204 ecom_tr_size++;
2205 }
2206
2207 if (ecom_tr_size)
2208 {
2209 if (ecom_tr_size * 8 > 255)
2210 {
2211 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2212 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2213 stream_putw (s, ecom_tr_size * 8);
2214 }
2215 else
2216 {
2217 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2218 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2219 stream_putc (s, ecom_tr_size * 8);
2220 }
2221
Paul Jakmafb982c22007-05-04 20:15:47 +00002222 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002223 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002224 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002225 tbit = *pnt;
2226
2227 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2228 continue;
2229
2230 stream_put (s, pnt, 8);
2231 }
2232 }
paul718e3742002-12-13 20:15:29 +00002233 }
paul718e3742002-12-13 20:15:29 +00002234 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002235
2236 if ( send_as4_path )
2237 {
2238 /* If the peer is NOT As4 capable, AND */
2239 /* there are ASnums > 65535 in path THEN
2240 * give out AS4_PATH */
2241
2242 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2243 * path segments!
2244 * Hm, I wonder... confederation things *should* only be at
2245 * the beginning of an aspath, right? Then we should use
2246 * aspath_delete_confed_seq for this, because it is already
2247 * there! (JK)
2248 * Folks, talk to me: what is reasonable here!?
2249 */
2250 aspath = aspath_delete_confed_seq (aspath);
2251
2252 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2253 stream_putc (s, BGP_ATTR_AS4_PATH);
2254 aspath_sizep = stream_get_endp (s);
2255 stream_putw (s, 0);
2256 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2257 }
2258
2259 if (aspath != attr->aspath)
2260 aspath_free (aspath);
2261
2262 if ( send_as4_aggregator )
2263 {
2264 assert (attr->extra);
2265
2266 /* send AS4_AGGREGATOR, at this place */
2267 /* this section of code moved here in order to ensure the correct
2268 * *ascending* order of attributes
2269 */
2270 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2271 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2272 stream_putc (s, 8);
2273 stream_putl (s, attr->extra->aggregator_as);
2274 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2275 }
Paul Jakma41367172007-08-06 15:24:51 +00002276
2277 /* AS-Pathlimit */
2278 if (attr->pathlimit.ttl)
2279 {
2280 u_int32_t as = attr->pathlimit.as;
2281
2282 /* should already have been done in announce_check(),
2283 * but just in case..
2284 */
2285 if (!as)
2286 as = peer->local_as;
2287
2288 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2289 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2290 stream_putc (s, 5);
2291 stream_putc (s, attr->pathlimit.ttl);
2292 stream_putl (s, as);
2293 }
2294
paul718e3742002-12-13 20:15:29 +00002295 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002296 if (attr->extra && attr->extra->transit)
2297 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002298
2299 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002300 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002301}
2302
2303bgp_size_t
2304bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2305 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002306 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002307{
2308 unsigned long cp;
2309 unsigned long attrlen_pnt;
2310 bgp_size_t size;
2311
paul9985f832005-02-09 15:51:56 +00002312 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002313
2314 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2315 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2316
paul9985f832005-02-09 15:51:56 +00002317 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002318 stream_putc (s, 0); /* Length of this attribute. */
2319
2320 stream_putw (s, family2afi (p->family));
2321
2322 if (safi == SAFI_MPLS_VPN)
2323 {
2324 /* SAFI */
2325 stream_putc (s, BGP_SAFI_VPNV4);
2326
2327 /* prefix. */
2328 stream_putc (s, p->prefixlen + 88);
2329 stream_put (s, tag, 3);
2330 stream_put (s, prd->val, 8);
2331 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2332 }
2333 else
2334 {
2335 /* SAFI */
2336 stream_putc (s, safi);
2337
2338 /* prefix */
2339 stream_put_prefix (s, p);
2340 }
2341
2342 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002343 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002344 stream_putc_at (s, attrlen_pnt, size);
2345
paul9985f832005-02-09 15:51:56 +00002346 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002347}
2348
2349/* Initialization of attribute. */
2350void
paulfe69a502005-09-10 16:55:02 +00002351bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002352{
paul718e3742002-12-13 20:15:29 +00002353 aspath_init ();
2354 attrhash_init ();
2355 community_init ();
2356 ecommunity_init ();
2357 cluster_init ();
2358 transit_init ();
2359}
2360
Chris Caputo228da422009-07-18 05:44:03 +00002361void
2362bgp_attr_finish (void)
2363{
2364 aspath_finish ();
2365 attrhash_finish ();
2366 community_finish ();
2367 ecommunity_finish ();
2368 cluster_finish ();
2369 transit_finish ();
2370}
2371
paul718e3742002-12-13 20:15:29 +00002372/* Make attribute packet. */
2373void
paula3845922003-10-18 01:30:50 +00002374bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2375 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002376{
2377 unsigned long cp;
2378 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002379 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002380 struct aspath *aspath;
2381
2382 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002383 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002384
2385 /* Place holder of length. */
2386 stream_putw (s, 0);
2387
2388 /* Origin attribute. */
2389 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2390 stream_putc (s, BGP_ATTR_ORIGIN);
2391 stream_putc (s, 1);
2392 stream_putc (s, attr->origin);
2393
2394 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002395
2396 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2397 stream_putc (s, BGP_ATTR_AS_PATH);
2398 aspath_lenp = stream_get_endp (s);
2399 stream_putw (s, 0);
2400
2401 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002402
2403 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002404 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2405 if(prefix != NULL
2406#ifdef HAVE_IPV6
2407 && prefix->family != AF_INET6
2408#endif /* HAVE_IPV6 */
2409 )
2410 {
2411 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2412 stream_putc (s, BGP_ATTR_NEXT_HOP);
2413 stream_putc (s, 4);
2414 stream_put_ipv4 (s, attr->nexthop.s_addr);
2415 }
paul718e3742002-12-13 20:15:29 +00002416
2417 /* MED attribute. */
2418 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2419 {
2420 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2421 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2422 stream_putc (s, 4);
2423 stream_putl (s, attr->med);
2424 }
2425
2426 /* Local preference. */
2427 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2428 {
2429 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2430 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2431 stream_putc (s, 4);
2432 stream_putl (s, attr->local_pref);
2433 }
2434
2435 /* Atomic aggregate. */
2436 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2437 {
2438 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2439 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2440 stream_putc (s, 0);
2441 }
2442
2443 /* Aggregator. */
2444 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2445 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002446 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002447 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2448 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002449 stream_putc (s, 8);
2450 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002451 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002452 }
2453
2454 /* Community attribute. */
2455 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2456 {
2457 if (attr->community->size * 4 > 255)
2458 {
2459 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2460 stream_putc (s, BGP_ATTR_COMMUNITIES);
2461 stream_putw (s, attr->community->size * 4);
2462 }
2463 else
2464 {
2465 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2466 stream_putc (s, BGP_ATTR_COMMUNITIES);
2467 stream_putc (s, attr->community->size * 4);
2468 }
2469 stream_put (s, attr->community->val, attr->community->size * 4);
2470 }
2471
paula3845922003-10-18 01:30:50 +00002472#ifdef HAVE_IPV6
2473 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002474 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2475 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002476 {
2477 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002478 struct attr_extra *attre = attr->extra;
2479
paula3845922003-10-18 01:30:50 +00002480 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2481 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002482 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002483
2484 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002485 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002486 stream_putw(s, AFI_IP6); /* AFI */
2487 stream_putc(s, SAFI_UNICAST); /* SAFI */
2488
2489 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002490 stream_putc(s, attre->mp_nexthop_len);
2491 stream_put(s, &attre->mp_nexthop_global, 16);
2492 if (attre->mp_nexthop_len == 32)
2493 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002494
2495 /* SNPA */
2496 stream_putc(s, 0);
2497
2498 /* Prefix */
2499 stream_put_prefix(s, prefix);
2500
2501 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002502 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002503 }
2504#endif /* HAVE_IPV6 */
2505
Paul Jakma41367172007-08-06 15:24:51 +00002506 /* AS-Pathlimit */
2507 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2508 {
2509 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2510 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2511 stream_putc (s, 5);
2512 stream_putc (s, attr->pathlimit.ttl);
2513 stream_putl (s, attr->pathlimit.as);
2514 }
2515
paul718e3742002-12-13 20:15:29 +00002516 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002517 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002518 stream_putw_at (s, cp, len);
2519}