blob: 26f62f5af52d8fc5134d3efa780f7d1f14cf2842 [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. */
Paul Jakma6e4ab122007-04-10 19:36:48 +000042static 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};
Paul Jakma6e4ab122007-04-10 19:36:48 +000064int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000065
66struct hash *cluster_hash;
67
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
Paul Jakma923de652007-04-29 18:25:17 +0000134cluster_hash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000135{
Paul Jakma923de652007-04-29 18:25:17 +0000136 struct cluster_list * cluster1 = (struct cluster_list *) p1;
137 struct cluster_list * cluster2 = (struct cluster_list *) p2;
138
paul718e3742002-12-13 20:15:29 +0000139 if (cluster1->length == cluster2->length &&
140 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0)
141 return 1;
142 return 0;
143}
144
paul94f2b392005-06-28 12:44:16 +0000145static void
paul718e3742002-12-13 20:15:29 +0000146cluster_free (struct cluster_list *cluster)
147{
148 if (cluster->list)
149 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
150 XFREE (MTYPE_CLUSTER, cluster);
151}
152
paul94f2b392005-06-28 12:44:16 +0000153static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000154cluster_dup (struct cluster_list *cluster)
155{
156 struct cluster_list *new;
157
158 new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
159 memset (new, 0, sizeof (struct cluster_list));
160 new->length = cluster->length;
161
162 if (cluster->length)
163 {
164 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
165 memcpy (new->list, cluster->list, cluster->length);
166 }
167 else
168 new->list = NULL;
169
170 return new;
171}
172
paul94f2b392005-06-28 12:44:16 +0000173static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000174cluster_intern (struct cluster_list *cluster)
175{
176 struct cluster_list *find;
177
178 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
179 find->refcnt++;
180
181 return find;
182}
183
184void
185cluster_unintern (struct cluster_list *cluster)
186{
187 struct cluster_list *ret;
188
189 if (cluster->refcnt)
190 cluster->refcnt--;
191
192 if (cluster->refcnt == 0)
193 {
194 ret = hash_release (cluster_hash, cluster);
195 cluster_free (cluster);
196 }
197}
198
paul94f2b392005-06-28 12:44:16 +0000199static void
200cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000201{
202 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
203}
204
205/* Unknown transit attribute. */
206struct hash *transit_hash;
207
paul94f2b392005-06-28 12:44:16 +0000208static void
paul718e3742002-12-13 20:15:29 +0000209transit_free (struct transit *transit)
210{
211 if (transit->val)
212 XFREE (MTYPE_TRANSIT_VAL, transit->val);
213 XFREE (MTYPE_TRANSIT, transit);
214}
215
Paul Jakma923de652007-04-29 18:25:17 +0000216
paul94f2b392005-06-28 12:44:16 +0000217static void *
Paul Jakma923de652007-04-29 18:25:17 +0000218transit_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000219{
220 /* Transit structure is already allocated. */
Paul Jakma923de652007-04-29 18:25:17 +0000221 return p;
paul718e3742002-12-13 20:15:29 +0000222}
223
paul94f2b392005-06-28 12:44:16 +0000224static struct transit *
paul718e3742002-12-13 20:15:29 +0000225transit_intern (struct transit *transit)
226{
227 struct transit *find;
228
229 find = hash_get (transit_hash, transit, transit_hash_alloc);
230 if (find != transit)
231 transit_free (transit);
232 find->refcnt++;
233
234 return find;
235}
236
237void
238transit_unintern (struct transit *transit)
239{
240 struct transit *ret;
241
242 if (transit->refcnt)
243 transit->refcnt--;
244
245 if (transit->refcnt == 0)
246 {
247 ret = hash_release (transit_hash, transit);
248 transit_free (transit);
249 }
250}
251
paul94f2b392005-06-28 12:44:16 +0000252static unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000253transit_hash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000254{
Paul Jakma923de652007-04-29 18:25:17 +0000255 struct transit * transit = (struct transit *) p;
paul718e3742002-12-13 20:15:29 +0000256 unsigned int key = 0;
257 int length;
258 caddr_t pnt;
259
260 length = transit->length;
261 pnt = (caddr_t) transit->val;
262
263 while (length)
264 key += pnt[--length];
265
266 return key;
267}
268
paul94f2b392005-06-28 12:44:16 +0000269static int
Paul Jakma923de652007-04-29 18:25:17 +0000270transit_hash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000271{
Paul Jakma923de652007-04-29 18:25:17 +0000272 struct transit * transit1 = (struct transit *) p1;
273 struct transit * transit2 = (struct transit *) p2;
274
paul718e3742002-12-13 20:15:29 +0000275 if (transit1->length == transit2->length &&
276 memcmp (transit1->val, transit2->val, transit1->length) == 0)
277 return 1;
278 return 0;
279}
280
paul94f2b392005-06-28 12:44:16 +0000281static void
paul718e3742002-12-13 20:15:29 +0000282transit_init ()
283{
284 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
285}
286
287/* Attribute hash routines. */
paul718e3742002-12-13 20:15:29 +0000288struct hash *attrhash;
289
Paul Jakmafb982c22007-05-04 20:15:47 +0000290static struct attr_extra *
291bgp_attr_extra_new (void)
292{
293 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
294}
295
296void
297bgp_attr_extra_free (struct attr *attr)
298{
299 if (attr->extra)
300 {
301 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
302 attr->extra = NULL;
303 }
304}
305
306struct attr_extra *
307bgp_attr_extra_get (struct attr *attr)
308{
309 if (!attr->extra)
310 attr->extra = bgp_attr_extra_new();
311 return attr->extra;
312}
313
314/* Shallow copy of an attribute
315 * Though, not so shallow that it doesn't copy the contents
316 * of the attr_extra pointed to by 'extra'
317 */
318void
319bgp_attr_dup (struct attr *new, struct attr *orig)
320{
321 *new = *orig;
322 if (orig->extra)
323 {
324 new->extra = bgp_attr_extra_new();
325 *new->extra = *orig->extra;
326 }
327}
328
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000329unsigned long int
330attr_count (void)
331{
332 return attrhash->count;
333}
334
335unsigned long int
336attr_unknown_count (void)
337{
338 return transit_hash->count;
339}
340
paul718e3742002-12-13 20:15:29 +0000341unsigned int
Paul Jakma923de652007-04-29 18:25:17 +0000342attrhash_key_make (void *p)
paul718e3742002-12-13 20:15:29 +0000343{
Paul Jakma923de652007-04-29 18:25:17 +0000344 struct attr * attr = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000345 unsigned int key = 0;
346
347 key += attr->origin;
348 key += attr->nexthop.s_addr;
349 key += attr->med;
350 key += attr->local_pref;
Paul Jakma41367172007-08-06 15:24:51 +0000351 if (attr->pathlimit.as)
352 {
353 key += attr->pathlimit.ttl;
354 key += attr->pathlimit.as;
355 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000356
357 if (attr->extra)
358 {
359 key += attr->extra->aggregator_as;
360 key += attr->extra->aggregator_addr.s_addr;
361 key += attr->extra->weight;
362 key += attr->extra->mp_nexthop_global_in.s_addr;
363 }
364
paul718e3742002-12-13 20:15:29 +0000365 if (attr->aspath)
366 key += aspath_key_make (attr->aspath);
367 if (attr->community)
368 key += community_hash_make (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000369
370 if (attr->extra)
371 {
372 if (attr->extra->ecommunity)
373 key += ecommunity_hash_make (attr->extra->ecommunity);
374 if (attr->extra->cluster)
375 key += cluster_hash_key_make (attr->extra->cluster);
376 if (attr->extra->transit)
377 key += transit_hash_key_make (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +0000378
379#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000380 {
381 int i;
382
383 key += attr->extra->mp_nexthop_len;
384 for (i = 0; i < 16; i++)
385 key += attr->extra->mp_nexthop_global.s6_addr[i];
386 for (i = 0; i < 16; i++)
387 key += attr->extra->mp_nexthop_local.s6_addr[i];
388 }
paul718e3742002-12-13 20:15:29 +0000389#endif /* HAVE_IPV6 */
Paul Jakmafb982c22007-05-04 20:15:47 +0000390 }
paul718e3742002-12-13 20:15:29 +0000391
392 return key;
393}
394
395int
Paul Jakma923de652007-04-29 18:25:17 +0000396attrhash_cmp (void *p1, void *p2)
paul718e3742002-12-13 20:15:29 +0000397{
Paul Jakma923de652007-04-29 18:25:17 +0000398 struct attr * attr1 = (struct attr *) p1;
399 struct attr * attr2 = (struct attr *) p2;
400
paul718e3742002-12-13 20:15:29 +0000401 if (attr1->flag == attr2->flag
402 && attr1->origin == attr2->origin
403 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
paul718e3742002-12-13 20:15:29 +0000404 && attr1->aspath == attr2->aspath
405 && attr1->community == attr2->community
Paul Jakmafb982c22007-05-04 20:15:47 +0000406 && attr1->med == attr2->med
Paul Jakma41367172007-08-06 15:24:51 +0000407 && attr1->local_pref == attr2->local_pref
408 && attr1->pathlimit.ttl == attr2->pathlimit.ttl
409 && attr1->pathlimit.as == attr2->pathlimit.as)
Paul Jakmafb982c22007-05-04 20:15:47 +0000410 {
411 struct attr_extra *ae1 = attr1->extra;
412 struct attr_extra *ae2 = attr2->extra;
413
414 if (ae1 && ae2
415 && ae1->aggregator_as == ae2->aggregator_as
416 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
417 && ae1->weight == ae2->weight
418#ifdef HAVE_IPV6
419 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
420 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
421 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
422#endif /* HAVE_IPV6 */
423 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
424 && ae1->ecommunity == ae2->ecommunity
425 && ae1->cluster == ae2->cluster
426 && ae1->transit == ae2->transit)
427 return 1;
428 else if (ae1 || ae2)
429 return 0;
430 /* neither attribute has extra attributes, so they're same */
431 return 1;
432 }
paul718e3742002-12-13 20:15:29 +0000433 else
434 return 0;
435}
436
paul94f2b392005-06-28 12:44:16 +0000437static void
paul718e3742002-12-13 20:15:29 +0000438attrhash_init ()
439{
440 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
441}
442
paul94f2b392005-06-28 12:44:16 +0000443static void
paul718e3742002-12-13 20:15:29 +0000444attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
445{
446 struct attr *attr = backet->data;
447
448 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
449 inet_ntoa (attr->nexthop), VTY_NEWLINE);
450}
451
452void
453attr_show_all (struct vty *vty)
454{
455 hash_iterate (attrhash,
456 (void (*)(struct hash_backet *, void *))
457 attr_show_all_iterator,
458 vty);
459}
460
paul94f2b392005-06-28 12:44:16 +0000461static void *
Paul Jakma923de652007-04-29 18:25:17 +0000462bgp_attr_hash_alloc (void *p)
paul718e3742002-12-13 20:15:29 +0000463{
Paul Jakma923de652007-04-29 18:25:17 +0000464 struct attr * val = (struct attr *) p;
paul718e3742002-12-13 20:15:29 +0000465 struct attr *attr;
466
467 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
468 *attr = *val;
Paul Jakmafb982c22007-05-04 20:15:47 +0000469 if (val->extra)
470 {
471 attr->extra = bgp_attr_extra_new ();
472 *attr->extra = *val->extra;
473 }
paul718e3742002-12-13 20:15:29 +0000474 attr->refcnt = 0;
475 return attr;
476}
477
478/* Internet argument attribute. */
479struct attr *
480bgp_attr_intern (struct attr *attr)
481{
482 struct attr *find;
483
484 /* Intern referenced strucutre. */
485 if (attr->aspath)
486 {
487 if (! attr->aspath->refcnt)
488 attr->aspath = aspath_intern (attr->aspath);
489 else
490 attr->aspath->refcnt++;
491 }
492 if (attr->community)
493 {
494 if (! attr->community->refcnt)
495 attr->community = community_intern (attr->community);
496 else
497 attr->community->refcnt++;
498 }
Paul Jakmafb982c22007-05-04 20:15:47 +0000499 if (attr->extra)
paul718e3742002-12-13 20:15:29 +0000500 {
Paul Jakmafb982c22007-05-04 20:15:47 +0000501 struct attr_extra *attre = attr->extra;
502
503 if (attre->ecommunity)
504 {
505 if (! attre->ecommunity->refcnt)
506 attre->ecommunity = ecommunity_intern (attre->ecommunity);
507 else
508 attre->ecommunity->refcnt++;
509 }
510 if (attre->cluster)
511 {
512 if (! attre->cluster->refcnt)
513 attre->cluster = cluster_intern (attre->cluster);
514 else
515 attre->cluster->refcnt++;
516 }
517 if (attre->transit)
518 {
519 if (! attre->transit->refcnt)
520 attre->transit = transit_intern (attre->transit);
521 else
522 attre->transit->refcnt++;
523 }
paul718e3742002-12-13 20:15:29 +0000524 }
525
526 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
527 find->refcnt++;
528
529 return find;
530}
531
Paul Jakma03e214c2007-04-29 18:31:07 +0000532
paul718e3742002-12-13 20:15:29 +0000533/* Make network statement's attribute. */
534struct attr *
535bgp_attr_default_set (struct attr *attr, u_char origin)
536{
537 memset (attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000538 bgp_attr_extra_get (attr);
539
paul718e3742002-12-13 20:15:29 +0000540 attr->origin = origin;
541 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
542 attr->aspath = aspath_empty ();
543 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
Paul Jakmafb982c22007-05-04 20:15:47 +0000544 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000545 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
546#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000547 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000548#endif
Paul Jakma03e214c2007-04-29 18:31:07 +0000549
paul718e3742002-12-13 20:15:29 +0000550 return attr;
551}
552
Paul Jakma03e214c2007-04-29 18:31:07 +0000553
paul718e3742002-12-13 20:15:29 +0000554/* Make network statement's attribute. */
555struct attr *
556bgp_attr_default_intern (u_char origin)
557{
558 struct attr attr;
559 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000560 struct attr_extra *attre;
561
562 memset (&attr, 0, sizeof (struct attr));
563 attre = bgp_attr_extra_get (&attr);
564
Paul Jakma03e214c2007-04-29 18:31:07 +0000565 bgp_attr_default_set(&attr, origin);
paul718e3742002-12-13 20:15:29 +0000566
567 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000568 bgp_attr_extra_free (&attr);
569
paul718e3742002-12-13 20:15:29 +0000570 aspath_unintern (new->aspath);
571 return new;
572}
573
574struct attr *
575bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
576 struct aspath *aspath,
577 struct community *community, int as_set)
578{
579 struct attr attr;
580 struct attr *new;
Paul Jakmafb982c22007-05-04 20:15:47 +0000581 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +0000582
583 memset (&attr, 0, sizeof (struct attr));
Paul Jakmafb982c22007-05-04 20:15:47 +0000584 attre = bgp_attr_extra_get (&attr);
585
paul718e3742002-12-13 20:15:29 +0000586 /* Origin attribute. */
587 attr.origin = origin;
588 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
589
590 /* AS path attribute. */
591 if (aspath)
592 attr.aspath = aspath_intern (aspath);
593 else
594 attr.aspath = aspath_empty ();
595 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
596
597 /* Next hop attribute. */
598 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
599
600 if (community)
601 {
602 attr.community = community;
603 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
604 }
605
Paul Jakmafb982c22007-05-04 20:15:47 +0000606 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
paul718e3742002-12-13 20:15:29 +0000607#ifdef HAVE_IPV6
Paul Jakmafb982c22007-05-04 20:15:47 +0000608 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
paul718e3742002-12-13 20:15:29 +0000609#endif
610 if (! as_set)
611 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
612 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
613 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
Paul Jakmafb982c22007-05-04 20:15:47 +0000614 attre->aggregator_as = bgp->confed_id;
paul718e3742002-12-13 20:15:29 +0000615 else
Paul Jakmafb982c22007-05-04 20:15:47 +0000616 attre->aggregator_as = bgp->as;
617 attre->aggregator_addr = bgp->router_id;
paul718e3742002-12-13 20:15:29 +0000618
619 new = bgp_attr_intern (&attr);
Paul Jakmafb982c22007-05-04 20:15:47 +0000620 bgp_attr_extra_free (&attr);
621
paul718e3742002-12-13 20:15:29 +0000622 aspath_unintern (new->aspath);
623 return new;
624}
625
626/* Free bgp attribute and aspath. */
627void
628bgp_attr_unintern (struct attr *attr)
629{
630 struct attr *ret;
631 struct aspath *aspath;
632 struct community *community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000633 struct ecommunity *ecommunity = NULL;
634 struct cluster_list *cluster = NULL;
635 struct transit *transit = NULL;
paul718e3742002-12-13 20:15:29 +0000636
637 /* Decrement attribute reference. */
638 attr->refcnt--;
639 aspath = attr->aspath;
640 community = attr->community;
Paul Jakmafb982c22007-05-04 20:15:47 +0000641 if (attr->extra)
642 {
643 ecommunity = attr->extra->ecommunity;
644 cluster = attr->extra->cluster;
645 transit = attr->extra->transit;
646 }
paul718e3742002-12-13 20:15:29 +0000647
648 /* If reference becomes zero then free attribute object. */
649 if (attr->refcnt == 0)
650 {
651 ret = hash_release (attrhash, attr);
652 assert (ret != NULL);
Paul Jakmafb982c22007-05-04 20:15:47 +0000653 bgp_attr_extra_free (attr);
paul718e3742002-12-13 20:15:29 +0000654 XFREE (MTYPE_ATTR, attr);
655 }
656
657 /* aspath refcount shoud be decrement. */
658 if (aspath)
659 aspath_unintern (aspath);
660 if (community)
661 community_unintern (community);
662 if (ecommunity)
663 ecommunity_unintern (ecommunity);
664 if (cluster)
665 cluster_unintern (cluster);
666 if (transit)
667 transit_unintern (transit);
668}
669
670void
671bgp_attr_flush (struct attr *attr)
672{
673 if (attr->aspath && ! attr->aspath->refcnt)
674 aspath_free (attr->aspath);
675 if (attr->community && ! attr->community->refcnt)
676 community_free (attr->community);
Paul Jakmafb982c22007-05-04 20:15:47 +0000677 if (attr->extra)
678 {
679 struct attr_extra *attre = attr->extra;
680 if (attre->ecommunity && ! attre->ecommunity->refcnt)
681 ecommunity_free (attre->ecommunity);
682 if (attre->cluster && ! attre->cluster->refcnt)
683 cluster_free (attre->cluster);
684 if (attre->transit && ! attre->transit->refcnt)
685 transit_free (attre->transit);
686 }
paul718e3742002-12-13 20:15:29 +0000687}
688
Paul Jakma41367172007-08-06 15:24:51 +0000689/* Parse AS_PATHLIMIT attribute in an UPDATE */
690static int
691bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
692 struct attr *attr, u_char flag, u_char *startp)
693{
694 bgp_size_t total;
695
696 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
697
698 if (flag != (BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL))
699 {
700 zlog (peer->log, LOG_ERR,
701 "AS-Pathlimit attribute flag isn't transitive %d", flag);
702 bgp_notify_send_with_data (peer,
703 BGP_NOTIFY_UPDATE_ERR,
704 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
705 startp, total);
706 return -1;
707 }
708
709 if (length != 5)
710 {
711 zlog (peer->log, LOG_ERR,
712 "AS-Pathlimit length, %u, is not 5", length);
713 bgp_notify_send_with_data (peer,
714 BGP_NOTIFY_UPDATE_ERR,
715 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
716 startp, total);
717 return -1;
718 }
719
720 attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer));
721 attr->pathlimit.as = stream_getl (BGP_INPUT(peer));
722 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
723 return 0;
724}
paul718e3742002-12-13 20:15:29 +0000725/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000726static int
paul718e3742002-12-13 20:15:29 +0000727bgp_attr_origin (struct peer *peer, bgp_size_t length,
728 struct attr *attr, u_char flag, u_char *startp)
729{
730 bgp_size_t total;
731
732 /* total is entire attribute length include Attribute Flags (1),
733 Attribute Type code (1) and Attribute length (1 or 2). */
734 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
735
736 /* If any recognized attribute has Attribute Flags that conflict
737 with the Attribute Type Code, then the Error Subcode is set to
738 Attribute Flags Error. The Data field contains the erroneous
739 attribute (type, length and value). */
740 if (flag != BGP_ATTR_FLAG_TRANS)
741 {
742 zlog (peer->log, LOG_ERR,
743 "Origin attribute flag isn't transitive %d", flag);
744 bgp_notify_send_with_data (peer,
745 BGP_NOTIFY_UPDATE_ERR,
746 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
747 startp, total);
748 return -1;
749 }
750
751 /* If any recognized attribute has Attribute Length that conflicts
752 with the expected length (based on the attribute type code), then
753 the Error Subcode is set to Attribute Length Error. The Data
754 field contains the erroneous attribute (type, length and
755 value). */
756 if (length != 1)
757 {
758 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
759 length);
760 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
761 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
762 startp, total);
763 return -1;
764 }
765
766 /* Fetch origin attribute. */
767 attr->origin = stream_getc (BGP_INPUT (peer));
768
769 /* If the ORIGIN attribute has an undefined value, then the Error
770 Subcode is set to Invalid Origin Attribute. The Data field
771 contains the unrecognized attribute (type, length and value). */
772 if ((attr->origin != BGP_ORIGIN_IGP)
773 && (attr->origin != BGP_ORIGIN_EGP)
774 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
775 {
776 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
777 attr->origin);
778
779 bgp_notify_send_with_data (peer,
780 BGP_NOTIFY_UPDATE_ERR,
781 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
782 startp, total);
783 return -1;
784 }
785
786 /* Set oring attribute flag. */
787 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
788
789 return 0;
790}
791
792/* Parse AS path information. This function is wrapper of
793 aspath_parse. */
paul94f2b392005-06-28 12:44:16 +0000794static int
paul718e3742002-12-13 20:15:29 +0000795bgp_attr_aspath (struct peer *peer, bgp_size_t length,
796 struct attr *attr, u_char flag, u_char *startp)
797{
paul718e3742002-12-13 20:15:29 +0000798 bgp_size_t total;
799
800 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
801
802 /* Flag check. */
803 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
804 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
805 {
806 zlog (peer->log, LOG_ERR,
807 "Origin attribute flag isn't transitive %d", flag);
808 bgp_notify_send_with_data (peer,
809 BGP_NOTIFY_UPDATE_ERR,
810 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
811 startp, total);
812 return -1;
813 }
814
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000815 /*
816 * peer with AS4 => will get 4Byte ASnums
817 * otherwise, will get 16 Bit
818 */
819 attr->aspath = aspath_parse (peer->ibuf, length,
820 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
821
paul718e3742002-12-13 20:15:29 +0000822 /* In case of IBGP, length will be zero. */
paul718e3742002-12-13 20:15:29 +0000823 if (! attr->aspath)
824 {
825 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
826 bgp_notify_send (peer,
827 BGP_NOTIFY_UPDATE_ERR,
828 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
829 return -1;
830 }
831
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000832 /* Forward pointer. */
833/* stream_forward_getp (peer->ibuf, length);*/
834
835 /* Set aspath attribute flag. */
836 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
837
838 return 0;
839}
840
841static int bgp_attr_aspath_check( struct peer *peer,
842 struct attr *attr)
843{
844 /* These checks were part of bgp_attr_aspath, but with
845 * as4 we should to check aspath things when
846 * aspath synthesizing with as4_path has already taken place.
847 * Otherwise we check ASPATH and use the synthesized thing, and that is
848 * not right.
849 * So do the checks later, i.e. here
850 */
851 struct bgp *bgp = peer->bgp;
852 struct aspath *aspath;
853
paul718e3742002-12-13 20:15:29 +0000854 bgp = peer->bgp;
855
856 /* First AS check for EBGP. */
857 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
858 {
859 if (peer_sort (peer) == BGP_PEER_EBGP
860 && ! aspath_firstas_check (attr->aspath, peer->as))
861 {
862 zlog (peer->log, LOG_ERR,
863 "%s incorrect first AS (must be %d)", peer->host, peer->as);
864 bgp_notify_send (peer,
865 BGP_NOTIFY_UPDATE_ERR,
866 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
867 return -1;
868 }
869 }
870
871 /* local-as prepend */
872 if (peer->change_local_as &&
873 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
874 {
875 aspath = aspath_dup (attr->aspath);
876 aspath = aspath_add_seq (aspath, peer->change_local_as);
877 aspath_unintern (attr->aspath);
878 attr->aspath = aspath_intern (aspath);
879 }
880
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000881 return 0;
882
883}
884
885/* Parse AS4 path information. This function is another wrapper of
886 aspath_parse. */
887static int
888bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
889 struct attr *attr, struct aspath **as4_path)
890{
891 *as4_path = aspath_parse (peer->ibuf, length, 1);
paul718e3742002-12-13 20:15:29 +0000892
893 /* Set aspath attribute flag. */
Paul Jakma370b64a2007-12-22 16:49:52 +0000894 if (as4_path)
895 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
paul718e3742002-12-13 20:15:29 +0000896
897 return 0;
898}
899
900/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000901static int
paul718e3742002-12-13 20:15:29 +0000902bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
903 struct attr *attr, u_char flag, u_char *startp)
904{
905 bgp_size_t total;
906
907 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
908
909 /* Flag check. */
910 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
911 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
912 {
913 zlog (peer->log, LOG_ERR,
914 "Origin attribute flag isn't transitive %d", flag);
915 bgp_notify_send_with_data (peer,
916 BGP_NOTIFY_UPDATE_ERR,
917 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
918 startp, total);
919 return -1;
920 }
921
922 /* Check nexthop attribute length. */
923 if (length != 4)
924 {
925 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
926 length);
927
928 bgp_notify_send_with_data (peer,
929 BGP_NOTIFY_UPDATE_ERR,
930 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
931 startp, total);
932 return -1;
933 }
934
935 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
936 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
937
938 return 0;
939}
940
941/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000942static int
paul718e3742002-12-13 20:15:29 +0000943bgp_attr_med (struct peer *peer, bgp_size_t length,
944 struct attr *attr, u_char flag, u_char *startp)
945{
946 bgp_size_t total;
947
948 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
949
950 /* Length check. */
951 if (length != 4)
952 {
953 zlog (peer->log, LOG_ERR,
954 "MED attribute length isn't four [%d]", length);
955
956 bgp_notify_send_with_data (peer,
957 BGP_NOTIFY_UPDATE_ERR,
958 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
959 startp, total);
960 return -1;
961 }
962
963 attr->med = stream_getl (peer->ibuf);
964
965 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
966
967 return 0;
968}
969
970/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000971static int
paul718e3742002-12-13 20:15:29 +0000972bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
973 struct attr *attr, u_char flag)
974{
975 /* If it is contained in an UPDATE message that is received from an
976 external peer, then this attribute MUST be ignored by the
977 receiving speaker. */
978 if (peer_sort (peer) == BGP_PEER_EBGP)
979 {
paul9985f832005-02-09 15:51:56 +0000980 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000981 return 0;
982 }
983
984 if (length == 4)
985 attr->local_pref = stream_getl (peer->ibuf);
986 else
987 attr->local_pref = 0;
988
989 /* Set atomic aggregate flag. */
990 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
991
992 return 0;
993}
994
995/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000996static int
paul718e3742002-12-13 20:15:29 +0000997bgp_attr_atomic (struct peer *peer, bgp_size_t length,
998 struct attr *attr, u_char flag)
999{
1000 if (length != 0)
1001 {
1002 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1003
1004 bgp_notify_send (peer,
1005 BGP_NOTIFY_UPDATE_ERR,
1006 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1007 return -1;
1008 }
1009
1010 /* Set atomic aggregate flag. */
1011 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1012
1013 return 0;
1014}
1015
1016/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001017static int
paul718e3742002-12-13 20:15:29 +00001018bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1019 struct attr *attr, u_char flag)
1020{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001021 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001022 struct attr_extra *attre = bgp_attr_extra_get (attr);
1023
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001024 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1025 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1026 wantedlen = 8;
1027
1028 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001029 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001030 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001031
1032 bgp_notify_send (peer,
1033 BGP_NOTIFY_UPDATE_ERR,
1034 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1035 return -1;
1036 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001037
1038 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1039 attre->aggregator_as = stream_getl (peer->ibuf);
1040 else
1041 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001042 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001043
1044 /* Set atomic aggregate flag. */
1045 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1046
1047 return 0;
1048}
1049
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001050/* New Aggregator attribute */
1051static int
1052bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1053 struct attr *attr, as_t *as4_aggregator_as,
1054 struct in_addr *as4_aggregator_addr)
1055{
1056 if (length != 8)
1057 {
1058 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1059
1060 bgp_notify_send (peer,
1061 BGP_NOTIFY_UPDATE_ERR,
1062 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1063 return -1;
1064 }
1065 *as4_aggregator_as = stream_getl (peer->ibuf);
1066 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1067
1068 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1069
1070 return 0;
1071}
1072
1073/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1074 */
1075static int
1076bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1077 struct aspath *as4_path, as_t as4_aggregator,
1078 struct in_addr *as4_aggregator_addr)
1079{
1080 int ignore_as4_path = 0;
1081 struct aspath *newpath;
1082 struct attr_extra *attre = attr->extra;
1083
1084 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1085 {
1086 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1087 * if given.
1088 * It is worth a warning though, because the peer really
1089 * should not send them
1090 */
1091 if (BGP_DEBUG(as4, AS4))
1092 {
1093 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1094 zlog_debug ("[AS4] %s %s AS4_PATH",
1095 peer->host, "AS4 capable peer, yet it sent");
1096
1097 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1098 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1099 peer->host, "AS4 capable peer, yet it sent");
1100 }
1101
1102 return 0;
1103 }
1104
1105 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1106 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1107 {
1108 /* Hu? This is not supposed to happen at all!
1109 * got as4_path and no aspath,
1110 * This should already
1111 * have been handled by 'well known attributes missing'
1112 * But... yeah, paranoia
1113 * Take this as a "malformed attribute"
1114 */
1115 zlog (peer->log, LOG_ERR,
1116 "%s BGP not AS4 capable peer sent AS4_PATH but"
1117 " no AS_PATH, cant do anything here", peer->host);
1118 bgp_notify_send (peer,
1119 BGP_NOTIFY_UPDATE_ERR,
1120 BGP_NOTIFY_UPDATE_MAL_ATTR);
1121 return -1;
1122 }
1123
1124 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1125 * because that may override AS4_PATH
1126 */
1127 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1128 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001129 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1130 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001131 assert (attre);
1132
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001133 /* received both.
1134 * if the as_number in aggregator is not AS_TRANS,
1135 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1136 * and the Aggregator shall be taken as
1137 * info on the aggregating node, and the AS_PATH
1138 * shall be taken as the AS_PATH
1139 * otherwise
1140 * the Aggregator shall be ignored and the
1141 * AS4_AGGREGATOR shall be taken as the
1142 * Aggregating node and the AS_PATH is to be
1143 * constructed "as in all other cases"
1144 */
1145 if ( attre->aggregator_as != BGP_AS_TRANS )
1146 {
1147 /* ignore */
1148 if ( BGP_DEBUG(as4, AS4))
1149 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1150 " send AGGREGATOR != AS_TRANS and"
1151 " AS4_AGGREGATOR, so ignore"
1152 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1153 ignore_as4_path = 1;
1154 }
1155 else
1156 {
1157 /* "New_aggregator shall be taken as aggregator" */
1158 attre->aggregator_as = as4_aggregator;
1159 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1160 }
1161 }
1162 else
1163 {
1164 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1165 * That is bogus - but reading the conditions
1166 * we have to handle AS4_AGGREGATOR as if it were
1167 * AGGREGATOR in that case
1168 */
1169 if ( BGP_DEBUG(as4, AS4))
1170 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1171 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1172 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001173 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001174 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1175 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1176 }
1177 }
1178
1179 /* need to reconcile NEW_AS_PATH and AS_PATH */
1180 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1181 {
1182 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1183 aspath_unintern (attr->aspath);
1184 attr->aspath = aspath_intern (newpath);
1185 }
1186 return 0;
1187}
1188
paul718e3742002-12-13 20:15:29 +00001189/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001190static int
paul718e3742002-12-13 20:15:29 +00001191bgp_attr_community (struct peer *peer, bgp_size_t length,
1192 struct attr *attr, u_char flag)
1193{
1194 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001195 {
1196 attr->community = NULL;
1197 return 0;
1198 }
paul718e3742002-12-13 20:15:29 +00001199 else
1200 {
paul5228ad22004-06-04 17:58:18 +00001201 attr->community =
1202 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001203 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001204 }
1205
1206 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1207
1208 return 0;
1209}
1210
1211/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001212static int
paul718e3742002-12-13 20:15:29 +00001213bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1214 struct attr *attr, u_char flag)
1215{
1216 if (length != 4)
1217 {
1218 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1219
1220 bgp_notify_send (peer,
1221 BGP_NOTIFY_UPDATE_ERR,
1222 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1223 return -1;
1224 }
1225
Paul Jakmafb982c22007-05-04 20:15:47 +00001226 (bgp_attr_extra_get (attr))->originator_id.s_addr
1227 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001228
1229 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1230
1231 return 0;
1232}
1233
1234/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001235static int
paul718e3742002-12-13 20:15:29 +00001236bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1237 struct attr *attr, u_char flag)
1238{
1239 /* Check length. */
1240 if (length % 4)
1241 {
1242 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1243
1244 bgp_notify_send (peer,
1245 BGP_NOTIFY_UPDATE_ERR,
1246 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1247 return -1;
1248 }
1249
Paul Jakmafb982c22007-05-04 20:15:47 +00001250 (bgp_attr_extra_get (attr))->cluster
1251 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001252
paul9985f832005-02-09 15:51:56 +00001253 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001254
1255 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1256
1257 return 0;
1258}
1259
1260/* Multiprotocol reachability information parse. */
paul94f2b392005-06-28 12:44:16 +00001261static int
paul718e3742002-12-13 20:15:29 +00001262bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1263 struct bgp_nlri *mp_update)
1264{
1265 u_int16_t afi;
1266 u_char safi;
paul718e3742002-12-13 20:15:29 +00001267 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001268 size_t start;
paul718e3742002-12-13 20:15:29 +00001269 int ret;
1270 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001271 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001272
1273 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001274 s = BGP_INPUT(peer);
1275 start = stream_get_getp(s);
1276
1277 /* safe to read statically sized header? */
1278#define BGP_MP_REACH_MIN_SIZE 5
1279 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
1280 return -1;
1281
paul718e3742002-12-13 20:15:29 +00001282 /* Load AFI, SAFI. */
1283 afi = stream_getw (s);
1284 safi = stream_getc (s);
1285
1286 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001287 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001288
Paul Jakmafb982c22007-05-04 20:15:47 +00001289 if (STREAM_READABLE(s) < attre->mp_nexthop_len)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001290 return -1;
1291
paul718e3742002-12-13 20:15:29 +00001292 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001293 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001294 {
1295 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001296 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001297 break;
1298 case 12:
1299 {
1300 u_int32_t rd_high;
1301 u_int32_t rd_low;
1302
1303 rd_high = stream_getl (s);
1304 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001305 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001306 }
1307 break;
1308#ifdef HAVE_IPV6
1309 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001310 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001311 break;
1312 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001313 stream_get (&attre->mp_nexthop_global, s, 16);
1314 stream_get (&attre->mp_nexthop_local, s, 16);
1315 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001316 {
1317 char buf1[INET6_ADDRSTRLEN];
1318 char buf2[INET6_ADDRSTRLEN];
1319
1320 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001321 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 +00001322 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001323 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001324 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001325 buf2, INET6_ADDRSTRLEN));
1326
Paul Jakmafb982c22007-05-04 20:15:47 +00001327 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001328 }
1329 break;
1330#endif /* HAVE_IPV6 */
1331 default:
1332 zlog_info ("Wrong multiprotocol next hop length: %d",
Paul Jakmafb982c22007-05-04 20:15:47 +00001333 attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001334 return -1;
paul718e3742002-12-13 20:15:29 +00001335 }
1336
Paul Jakma6e4ab122007-04-10 19:36:48 +00001337 if (!STREAM_READABLE(s))
1338 return -1;
paul718e3742002-12-13 20:15:29 +00001339
Paul Jakma6e4ab122007-04-10 19:36:48 +00001340 {
1341 u_char val;
1342 if ((val = stream_getc (s)))
1343 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1344 peer->host, val);
1345 }
1346
1347 /* must have nrli_len, what is left of the attribute */
1348 nlri_len = length - (stream_get_getp(s) - start);
1349 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
1350 return -1;
paul718e3742002-12-13 20:15:29 +00001351
1352 if (safi != BGP_SAFI_VPNV4)
1353 {
1354 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1355 if (ret < 0)
1356 return -1;
1357 }
1358
1359 mp_update->afi = afi;
1360 mp_update->safi = safi;
1361 mp_update->nlri = stream_pnt (s);
1362 mp_update->length = nlri_len;
1363
paul9985f832005-02-09 15:51:56 +00001364 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001365
1366 return 0;
1367}
1368
1369/* Multiprotocol unreachable parse */
paul94f2b392005-06-28 12:44:16 +00001370static int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001371bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001372 struct bgp_nlri *mp_withdraw)
1373{
1374 struct stream *s;
1375 u_int16_t afi;
1376 u_char safi;
paul718e3742002-12-13 20:15:29 +00001377 u_int16_t withdraw_len;
1378 int ret;
1379
1380 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001381
1382#define BGP_MP_UNREACH_MIN_SIZE 3
1383 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1384 return -1;
1385
paul718e3742002-12-13 20:15:29 +00001386 afi = stream_getw (s);
1387 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001388
1389 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001390
1391 if (safi != BGP_SAFI_VPNV4)
1392 {
1393 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1394 if (ret < 0)
1395 return -1;
1396 }
1397
1398 mp_withdraw->afi = afi;
1399 mp_withdraw->safi = safi;
1400 mp_withdraw->nlri = stream_pnt (s);
1401 mp_withdraw->length = withdraw_len;
1402
paul9985f832005-02-09 15:51:56 +00001403 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001404
1405 return 0;
1406}
1407
1408/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001409static int
paul718e3742002-12-13 20:15:29 +00001410bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1411 struct attr *attr, u_char flag)
1412{
1413 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001414 {
1415 if (attr->extra)
1416 attr->extra->ecommunity = NULL;
1417 }
paul718e3742002-12-13 20:15:29 +00001418 else
1419 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001420 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001421 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001422 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001423 }
1424 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1425
1426 return 0;
1427}
1428
1429/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001430static int
paul718e3742002-12-13 20:15:29 +00001431bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1432 u_char type, bgp_size_t length, u_char *startp)
1433{
1434 bgp_size_t total;
1435 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001436 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001437
hassof4184462005-02-01 20:13:16 +00001438 if (BGP_DEBUG (normal, NORMAL))
1439 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1440 peer->host, type, length);
1441
paul718e3742002-12-13 20:15:29 +00001442 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001443 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001444 "Unknown attribute type %d length %d is received", type, length);
1445
1446 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001447 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001448
1449 /* Adjest total length to include type and length. */
1450 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1451
1452 /* If any of the mandatory well-known attributes are not recognized,
1453 then the Error Subcode is set to Unrecognized Well-known
1454 Attribute. The Data field contains the unrecognized attribute
1455 (type, length and value). */
1456 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1457 {
1458 /* Adjust startp to do not include flag value. */
1459 bgp_notify_send_with_data (peer,
1460 BGP_NOTIFY_UPDATE_ERR,
1461 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1462 startp, total);
1463 return -1;
1464 }
1465
1466 /* Unrecognized non-transitive optional attributes must be quietly
1467 ignored and not passed along to other BGP peers. */
1468 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1469 return 0;
1470
1471 /* If a path with recognized transitive optional attribute is
1472 accepted and passed along to other BGP peers and the Partial bit
1473 in the Attribute Flags octet is set to 1 by some previous AS, it
1474 is not set back to 0 by the current AS. */
1475 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1476
1477 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001478 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
paul718e3742002-12-13 20:15:29 +00001479 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001480 attre->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1481 memset (attre->transit, 0, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001482 }
1483
Paul Jakmafb982c22007-05-04 20:15:47 +00001484 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001485
1486 if (transit->val)
1487 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1488 transit->length + total);
1489 else
1490 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1491
1492 memcpy (transit->val + transit->length, startp, total);
1493 transit->length += total;
1494
1495 return 0;
1496}
1497
1498/* Read attribute of update packet. This function is called from
1499 bgp_update() in bgpd.c. */
1500int
1501bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1502 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1503{
1504 int ret;
1505 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001506 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001507 bgp_size_t length;
1508 u_char *startp, *endp;
1509 u_char *attr_endp;
1510 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001511 /* we need the as4_path only until we have synthesized the as_path with it */
1512 /* same goes for as4_aggregator */
1513 struct aspath *as4_path = NULL;
1514 as_t as4_aggregator = 0;
1515 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001516
1517 /* Initialize bitmap. */
1518 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1519
1520 /* End pointer of BGP attribute. */
1521 endp = BGP_INPUT_PNT (peer) + size;
1522
1523 /* Get attributes to the end of attribute length. */
1524 while (BGP_INPUT_PNT (peer) < endp)
1525 {
1526 /* Check remaining length check.*/
1527 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1528 {
gdtc29fdba2004-12-09 14:46:46 +00001529 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001530 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001531 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001532 peer->host,
1533 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001534
1535 bgp_notify_send (peer,
1536 BGP_NOTIFY_UPDATE_ERR,
1537 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1538 return -1;
1539 }
1540
1541 /* Fetch attribute flag and type. */
1542 startp = BGP_INPUT_PNT (peer);
1543 flag = stream_getc (BGP_INPUT (peer));
1544 type = stream_getc (BGP_INPUT (peer));
1545
Paul Jakma370b64a2007-12-22 16:49:52 +00001546 /* Check whether Extended-Length applies and is in bounds */
1547 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1548 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1549 {
1550 zlog (peer->log, LOG_WARNING,
1551 "%s Extended length set, but just %u bytes of attr header",
1552 peer->host,
1553 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1554
1555 bgp_notify_send (peer,
1556 BGP_NOTIFY_UPDATE_ERR,
1557 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1558 return -1;
1559 }
1560
paul718e3742002-12-13 20:15:29 +00001561 /* Check extended attribue length bit. */
1562 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1563 length = stream_getw (BGP_INPUT (peer));
1564 else
1565 length = stream_getc (BGP_INPUT (peer));
1566
1567 /* If any attribute appears more than once in the UPDATE
1568 message, then the Error Subcode is set to Malformed Attribute
1569 List. */
1570
1571 if (CHECK_BITMAP (seen, type))
1572 {
1573 zlog (peer->log, LOG_WARNING,
1574 "%s error BGP attribute type %d appears twice in a message",
1575 peer->host, type);
1576
1577 bgp_notify_send (peer,
1578 BGP_NOTIFY_UPDATE_ERR,
1579 BGP_NOTIFY_UPDATE_MAL_ATTR);
1580 return -1;
1581 }
1582
1583 /* Set type to bitmap to check duplicate attribute. `type' is
1584 unsigned char so it never overflow bitmap range. */
1585
1586 SET_BITMAP (seen, type);
1587
1588 /* Overflow check. */
1589 attr_endp = BGP_INPUT_PNT (peer) + length;
1590
1591 if (attr_endp > endp)
1592 {
1593 zlog (peer->log, LOG_WARNING,
1594 "%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);
1595 bgp_notify_send (peer,
1596 BGP_NOTIFY_UPDATE_ERR,
1597 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1598 return -1;
1599 }
1600
1601 /* OK check attribute and store it's value. */
1602 switch (type)
1603 {
1604 case BGP_ATTR_ORIGIN:
1605 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1606 break;
1607 case BGP_ATTR_AS_PATH:
1608 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1609 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001610 case BGP_ATTR_AS4_PATH:
1611 ret = bgp_attr_as4_path (peer, length, attr, &as4_path );
1612 break;
paul718e3742002-12-13 20:15:29 +00001613 case BGP_ATTR_NEXT_HOP:
1614 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1615 break;
1616 case BGP_ATTR_MULTI_EXIT_DISC:
1617 ret = bgp_attr_med (peer, length, attr, flag, startp);
1618 break;
1619 case BGP_ATTR_LOCAL_PREF:
1620 ret = bgp_attr_local_pref (peer, length, attr, flag);
1621 break;
1622 case BGP_ATTR_ATOMIC_AGGREGATE:
1623 ret = bgp_attr_atomic (peer, length, attr, flag);
1624 break;
1625 case BGP_ATTR_AGGREGATOR:
1626 ret = bgp_attr_aggregator (peer, length, attr, flag);
1627 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001628 case BGP_ATTR_AS4_AGGREGATOR:
1629 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1630 break;
paul718e3742002-12-13 20:15:29 +00001631 case BGP_ATTR_COMMUNITIES:
1632 ret = bgp_attr_community (peer, length, attr, flag);
1633 break;
1634 case BGP_ATTR_ORIGINATOR_ID:
1635 ret = bgp_attr_originator_id (peer, length, attr, flag);
1636 break;
1637 case BGP_ATTR_CLUSTER_LIST:
1638 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1639 break;
1640 case BGP_ATTR_MP_REACH_NLRI:
1641 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1642 break;
1643 case BGP_ATTR_MP_UNREACH_NLRI:
1644 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1645 break;
1646 case BGP_ATTR_EXT_COMMUNITIES:
1647 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1648 break;
Paul Jakma41367172007-08-06 15:24:51 +00001649 case BGP_ATTR_AS_PATHLIMIT:
1650 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1651 break;
paul718e3742002-12-13 20:15:29 +00001652 default:
1653 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1654 break;
1655 }
1656
1657 /* If error occured immediately return to the caller. */
1658 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001659 {
1660 zlog (peer->log, LOG_WARNING,
1661 "%s: Attribute %s, parse error",
1662 peer->host,
1663 LOOKUP (attr_str, type));
1664 bgp_notify_send (peer,
1665 BGP_NOTIFY_UPDATE_ERR,
1666 BGP_NOTIFY_UPDATE_MAL_ATTR);
1667 return ret;
1668 }
paul718e3742002-12-13 20:15:29 +00001669
1670 /* Check the fetched length. */
1671 if (BGP_INPUT_PNT (peer) != attr_endp)
1672 {
1673 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001674 "%s: BGP attribute %s, fetch error",
1675 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001676 bgp_notify_send (peer,
1677 BGP_NOTIFY_UPDATE_ERR,
1678 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1679 return -1;
1680 }
1681 }
1682
1683 /* Check final read pointer is same as end pointer. */
1684 if (BGP_INPUT_PNT (peer) != endp)
1685 {
1686 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001687 "%s BGP attribute %s, length mismatch",
1688 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001689 bgp_notify_send (peer,
1690 BGP_NOTIFY_UPDATE_ERR,
1691 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1692 return -1;
1693 }
1694
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001695 /*
1696 * At this place we can see whether we got AS4_PATH and/or
1697 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1698 * We can not do this before we've read all attributes because
1699 * the as4 handling does not say whether AS4_PATH has to be sent
1700 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1701 * in relationship to AGGREGATOR.
1702 * So, to be defensive, we are not relying on any order and read
1703 * all attributes first, including these 32bit ones, and now,
1704 * afterwards, we look what and if something is to be done for as4.
1705 */
1706 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1707 as4_aggregator, &as4_aggregator_addr))
1708 return -1;
1709
1710 /* At this stage, we have done all fiddling with as4, and the
1711 * resulting info is in attr->aggregator resp. attr->aspath
1712 * so we can chuck as4_aggregator and as4_path alltogether in
1713 * order to save memory
1714 */
1715 if ( as4_path )
1716 {
1717 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1718 as4_path = NULL;
1719 /* The flag that we got this is still there, but that does not
1720 * do any trouble
1721 */
1722 }
1723 /*
1724 * The "rest" of the code does nothing with as4_aggregator.
1725 * there is no memory attached specifically which is not part
1726 * of the attr.
1727 * so ignoring just means do nothing.
1728 */
1729 /*
1730 * Finally do the checks on the aspath we did not do yet
1731 * because we waited for a potentially synthesized aspath.
1732 */
1733 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1734 {
1735 ret = bgp_attr_aspath_check( peer, attr );
1736 if ( ret < 0 )
1737 return ret;
1738 }
1739
paul718e3742002-12-13 20:15:29 +00001740 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001741 if (attr->extra && attr->extra->transit)
1742 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001743
1744 return 0;
1745}
1746
1747/* Well-known attribute check. */
1748int
1749bgp_attr_check (struct peer *peer, struct attr *attr)
1750{
1751 u_char type = 0;
1752
1753 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1754 type = BGP_ATTR_ORIGIN;
1755
1756 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1757 type = BGP_ATTR_AS_PATH;
1758
1759 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1760 type = BGP_ATTR_NEXT_HOP;
1761
1762 if (peer_sort (peer) == BGP_PEER_IBGP
1763 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1764 type = BGP_ATTR_LOCAL_PREF;
1765
1766 if (type)
1767 {
1768 zlog (peer->log, LOG_WARNING,
1769 "%s Missing well-known attribute %d.",
1770 peer->host, type);
1771 bgp_notify_send_with_data (peer,
1772 BGP_NOTIFY_UPDATE_ERR,
1773 BGP_NOTIFY_UPDATE_MISS_ATTR,
1774 &type, 1);
1775 return -1;
1776 }
1777 return 0;
1778}
1779
1780int stream_put_prefix (struct stream *, struct prefix *);
1781
1782/* Make attribute packet. */
1783bgp_size_t
1784bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1785 struct stream *s, struct attr *attr, struct prefix *p,
1786 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001787 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001788{
paulfe69a502005-09-10 16:55:02 +00001789 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001790 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001791 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001792 int send_as4_path = 0;
1793 int send_as4_aggregator = 0;
1794 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001795
1796 if (! bgp)
1797 bgp = bgp_get_default ();
1798
1799 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001800 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001801
1802 /* Origin attribute. */
1803 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1804 stream_putc (s, BGP_ATTR_ORIGIN);
1805 stream_putc (s, 1);
1806 stream_putc (s, attr->origin);
1807
1808 /* AS path attribute. */
1809
1810 /* If remote-peer is EBGP */
1811 if (peer_sort (peer) == BGP_PEER_EBGP
1812 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001813 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001814 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001815 {
1816 aspath = aspath_dup (attr->aspath);
1817
1818 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1819 {
1820 /* Strip the confed info, and then stuff our path CONFED_ID
1821 on the front */
1822 aspath = aspath_delete_confed_seq (aspath);
1823 aspath = aspath_add_seq (aspath, bgp->confed_id);
1824 }
1825 else
1826 {
1827 aspath = aspath_add_seq (aspath, peer->local_as);
1828 if (peer->change_local_as)
1829 aspath = aspath_add_seq (aspath, peer->change_local_as);
1830 }
1831 }
1832 else if (peer_sort (peer) == BGP_PEER_CONFED)
1833 {
1834 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1835 aspath = aspath_dup (attr->aspath);
1836 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1837 }
1838 else
1839 aspath = attr->aspath;
1840
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001841 /* If peer is not AS4 capable, then:
1842 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1843 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1844 * types are in it (i.e. exclude them if they are there)
1845 * AND do this only if there is at least one asnum > 65535 in the path!
1846 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1847 * all ASnums > 65535 to BGP_AS_TRANS
1848 */
paul718e3742002-12-13 20:15:29 +00001849
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001850 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1851 stream_putc (s, BGP_ATTR_AS_PATH);
1852 aspath_sizep = stream_get_endp (s);
1853 stream_putw (s, 0);
1854 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1855
1856 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1857 * in the path
1858 */
1859 if (!use32bit && aspath_has_as4 (aspath))
1860 send_as4_path = 1; /* we'll do this later, at the correct place */
1861
paul718e3742002-12-13 20:15:29 +00001862 /* Nexthop attribute. */
1863 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1864 {
1865 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1866 stream_putc (s, BGP_ATTR_NEXT_HOP);
1867 stream_putc (s, 4);
1868 if (safi == SAFI_MPLS_VPN)
1869 {
1870 if (attr->nexthop.s_addr == 0)
1871 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1872 else
1873 stream_put_ipv4 (s, attr->nexthop.s_addr);
1874 }
1875 else
1876 stream_put_ipv4 (s, attr->nexthop.s_addr);
1877 }
1878
1879 /* MED attribute. */
1880 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1881 {
1882 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1883 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1884 stream_putc (s, 4);
1885 stream_putl (s, attr->med);
1886 }
1887
1888 /* Local preference. */
1889 if (peer_sort (peer) == BGP_PEER_IBGP ||
1890 peer_sort (peer) == BGP_PEER_CONFED)
1891 {
1892 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1893 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1894 stream_putc (s, 4);
1895 stream_putl (s, attr->local_pref);
1896 }
1897
1898 /* Atomic aggregate. */
1899 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1900 {
1901 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1902 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1903 stream_putc (s, 0);
1904 }
1905
1906 /* Aggregator. */
1907 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1908 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001909 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001910
1911 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001912 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1913 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001914
1915 if (use32bit)
1916 {
1917 /* AS4 capable peer */
1918 stream_putc (s, 8);
1919 stream_putl (s, attr->extra->aggregator_as);
1920 }
1921 else
1922 {
1923 /* 2-byte AS peer */
1924 stream_putc (s, 6);
1925
1926 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1927 if ( attr->extra->aggregator_as > 65535 )
1928 {
1929 stream_putw (s, BGP_AS_TRANS);
1930
1931 /* we have to send AS4_AGGREGATOR, too.
1932 * we'll do that later in order to send attributes in ascending
1933 * order.
1934 */
1935 send_as4_aggregator = 1;
1936 }
1937 else
1938 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1939 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001940 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001941 }
1942
1943 /* Community attribute. */
1944 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1945 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1946 {
1947 if (attr->community->size * 4 > 255)
1948 {
1949 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1950 stream_putc (s, BGP_ATTR_COMMUNITIES);
1951 stream_putw (s, attr->community->size * 4);
1952 }
1953 else
1954 {
1955 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1956 stream_putc (s, BGP_ATTR_COMMUNITIES);
1957 stream_putc (s, attr->community->size * 4);
1958 }
1959 stream_put (s, attr->community->val, attr->community->size * 4);
1960 }
1961
1962 /* Route Reflector. */
1963 if (peer_sort (peer) == BGP_PEER_IBGP
1964 && from
1965 && peer_sort (from) == BGP_PEER_IBGP)
1966 {
1967 /* Originator ID. */
1968 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1969 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1970 stream_putc (s, 4);
1971
1972 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00001973 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001974 else
1975 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001976
1977 /* Cluster list. */
1978 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1979 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1980
Paul Jakma9eda90c2007-08-30 13:36:17 +00001981 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00001982 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001983 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00001984 /* If this peer configuration's parent BGP has cluster_id. */
1985 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1986 stream_put_in_addr (s, &bgp->cluster_id);
1987 else
1988 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00001989 stream_put (s, attr->extra->cluster->list,
1990 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00001991 }
1992 else
1993 {
1994 stream_putc (s, 4);
1995 /* If this peer configuration's parent BGP has cluster_id. */
1996 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1997 stream_put_in_addr (s, &bgp->cluster_id);
1998 else
1999 stream_put_in_addr (s, &bgp->router_id);
2000 }
2001 }
2002
2003#ifdef HAVE_IPV6
2004 /* If p is IPv6 address put it into attribute. */
2005 if (p->family == AF_INET6)
2006 {
2007 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002008 struct attr_extra *attre = attr->extra;
2009
2010 assert (attr->extra);
2011
paul718e3742002-12-13 20:15:29 +00002012 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2013 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002014 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002015 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002016 stream_putw (s, AFI_IP6); /* AFI */
2017 stream_putc (s, safi); /* SAFI */
2018
Paul Jakmafb982c22007-05-04 20:15:47 +00002019 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002020
Paul Jakmafb982c22007-05-04 20:15:47 +00002021 if (attre->mp_nexthop_len == 16)
2022 stream_put (s, &attre->mp_nexthop_global, 16);
2023 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002024 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002025 stream_put (s, &attre->mp_nexthop_global, 16);
2026 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002027 }
2028
2029 /* SNPA */
2030 stream_putc (s, 0);
2031
paul718e3742002-12-13 20:15:29 +00002032 /* Prefix write. */
2033 stream_put_prefix (s, p);
2034
2035 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002036 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002037 }
2038#endif /* HAVE_IPV6 */
2039
2040 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2041 {
2042 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002043
2044 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2045 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002046 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002047 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002048 stream_putw (s, AFI_IP); /* AFI */
2049 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2050
2051 stream_putc (s, 4);
2052 stream_put_ipv4 (s, attr->nexthop.s_addr);
2053
2054 /* SNPA */
2055 stream_putc (s, 0);
2056
paul718e3742002-12-13 20:15:29 +00002057 /* Prefix write. */
2058 stream_put_prefix (s, p);
2059
2060 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002061 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002062 }
2063
2064 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2065 {
2066 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002067
2068 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2069 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002070 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002071 stream_putc (s, 0); /* Length of this attribute. */
2072 stream_putw (s, AFI_IP); /* AFI */
2073 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2074
2075 stream_putc (s, 12);
2076 stream_putl (s, 0);
2077 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002078 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002079
2080 /* SNPA */
2081 stream_putc (s, 0);
2082
paul718e3742002-12-13 20:15:29 +00002083 /* Tag, RD, Prefix write. */
2084 stream_putc (s, p->prefixlen + 88);
2085 stream_put (s, tag, 3);
2086 stream_put (s, prd->val, 8);
2087 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2088
2089 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002090 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002091 }
2092
2093 /* Extended Communities attribute. */
2094 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2095 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2096 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002097 struct attr_extra *attre = attr->extra;
2098
2099 assert (attre);
2100
2101 if (peer_sort (peer) == BGP_PEER_IBGP
2102 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002103 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002104 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002105 {
2106 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2107 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002108 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002109 }
2110 else
2111 {
2112 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2113 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002114 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002115 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002116 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002117 }
2118 else
2119 {
paul5228ad22004-06-04 17:58:18 +00002120 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002121 int tbit;
2122 int ecom_tr_size = 0;
2123 int i;
2124
Paul Jakmafb982c22007-05-04 20:15:47 +00002125 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002126 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002127 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002128 tbit = *pnt;
2129
2130 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2131 continue;
2132
2133 ecom_tr_size++;
2134 }
2135
2136 if (ecom_tr_size)
2137 {
2138 if (ecom_tr_size * 8 > 255)
2139 {
2140 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2141 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2142 stream_putw (s, ecom_tr_size * 8);
2143 }
2144 else
2145 {
2146 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2147 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2148 stream_putc (s, ecom_tr_size * 8);
2149 }
2150
Paul Jakmafb982c22007-05-04 20:15:47 +00002151 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002152 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002153 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002154 tbit = *pnt;
2155
2156 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2157 continue;
2158
2159 stream_put (s, pnt, 8);
2160 }
2161 }
paul718e3742002-12-13 20:15:29 +00002162 }
paul718e3742002-12-13 20:15:29 +00002163 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002164
2165 if ( send_as4_path )
2166 {
2167 /* If the peer is NOT As4 capable, AND */
2168 /* there are ASnums > 65535 in path THEN
2169 * give out AS4_PATH */
2170
2171 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2172 * path segments!
2173 * Hm, I wonder... confederation things *should* only be at
2174 * the beginning of an aspath, right? Then we should use
2175 * aspath_delete_confed_seq for this, because it is already
2176 * there! (JK)
2177 * Folks, talk to me: what is reasonable here!?
2178 */
2179 aspath = aspath_delete_confed_seq (aspath);
2180
2181 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2182 stream_putc (s, BGP_ATTR_AS4_PATH);
2183 aspath_sizep = stream_get_endp (s);
2184 stream_putw (s, 0);
2185 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2186 }
2187
2188 if (aspath != attr->aspath)
2189 aspath_free (aspath);
2190
2191 if ( send_as4_aggregator )
2192 {
2193 assert (attr->extra);
2194
2195 /* send AS4_AGGREGATOR, at this place */
2196 /* this section of code moved here in order to ensure the correct
2197 * *ascending* order of attributes
2198 */
2199 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2200 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2201 stream_putc (s, 8);
2202 stream_putl (s, attr->extra->aggregator_as);
2203 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2204 }
Paul Jakma41367172007-08-06 15:24:51 +00002205
2206 /* AS-Pathlimit */
2207 if (attr->pathlimit.ttl)
2208 {
2209 u_int32_t as = attr->pathlimit.as;
2210
2211 /* should already have been done in announce_check(),
2212 * but just in case..
2213 */
2214 if (!as)
2215 as = peer->local_as;
2216
2217 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2218 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2219 stream_putc (s, 5);
2220 stream_putc (s, attr->pathlimit.ttl);
2221 stream_putl (s, as);
2222 }
2223
paul718e3742002-12-13 20:15:29 +00002224 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002225 if (attr->extra && attr->extra->transit)
2226 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002227
2228 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002229 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002230}
2231
2232bgp_size_t
2233bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2234 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002235 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002236{
2237 unsigned long cp;
2238 unsigned long attrlen_pnt;
2239 bgp_size_t size;
2240
paul9985f832005-02-09 15:51:56 +00002241 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002242
2243 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2244 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2245
paul9985f832005-02-09 15:51:56 +00002246 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002247 stream_putc (s, 0); /* Length of this attribute. */
2248
2249 stream_putw (s, family2afi (p->family));
2250
2251 if (safi == SAFI_MPLS_VPN)
2252 {
2253 /* SAFI */
2254 stream_putc (s, BGP_SAFI_VPNV4);
2255
2256 /* prefix. */
2257 stream_putc (s, p->prefixlen + 88);
2258 stream_put (s, tag, 3);
2259 stream_put (s, prd->val, 8);
2260 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2261 }
2262 else
2263 {
2264 /* SAFI */
2265 stream_putc (s, safi);
2266
2267 /* prefix */
2268 stream_put_prefix (s, p);
2269 }
2270
2271 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002272 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002273 stream_putc_at (s, attrlen_pnt, size);
2274
paul9985f832005-02-09 15:51:56 +00002275 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002276}
2277
2278/* Initialization of attribute. */
2279void
paulfe69a502005-09-10 16:55:02 +00002280bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002281{
2282 void attrhash_init ();
2283
2284 aspath_init ();
2285 attrhash_init ();
2286 community_init ();
2287 ecommunity_init ();
2288 cluster_init ();
2289 transit_init ();
2290}
2291
2292/* Make attribute packet. */
2293void
paula3845922003-10-18 01:30:50 +00002294bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2295 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002296{
2297 unsigned long cp;
2298 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002299 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002300 struct aspath *aspath;
2301
2302 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002303 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002304
2305 /* Place holder of length. */
2306 stream_putw (s, 0);
2307
2308 /* Origin attribute. */
2309 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2310 stream_putc (s, BGP_ATTR_ORIGIN);
2311 stream_putc (s, 1);
2312 stream_putc (s, attr->origin);
2313
2314 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002315
2316 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2317 stream_putc (s, BGP_ATTR_AS_PATH);
2318 aspath_lenp = stream_get_endp (s);
2319 stream_putw (s, 0);
2320
2321 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002322
2323 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002324 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2325 if(prefix != NULL
2326#ifdef HAVE_IPV6
2327 && prefix->family != AF_INET6
2328#endif /* HAVE_IPV6 */
2329 )
2330 {
2331 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2332 stream_putc (s, BGP_ATTR_NEXT_HOP);
2333 stream_putc (s, 4);
2334 stream_put_ipv4 (s, attr->nexthop.s_addr);
2335 }
paul718e3742002-12-13 20:15:29 +00002336
2337 /* MED attribute. */
2338 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2339 {
2340 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2341 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2342 stream_putc (s, 4);
2343 stream_putl (s, attr->med);
2344 }
2345
2346 /* Local preference. */
2347 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2348 {
2349 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2350 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2351 stream_putc (s, 4);
2352 stream_putl (s, attr->local_pref);
2353 }
2354
2355 /* Atomic aggregate. */
2356 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2357 {
2358 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2359 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2360 stream_putc (s, 0);
2361 }
2362
2363 /* Aggregator. */
2364 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2365 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002366 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002367 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2368 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002369 stream_putc (s, 8);
2370 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002371 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002372 }
2373
2374 /* Community attribute. */
2375 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2376 {
2377 if (attr->community->size * 4 > 255)
2378 {
2379 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2380 stream_putc (s, BGP_ATTR_COMMUNITIES);
2381 stream_putw (s, attr->community->size * 4);
2382 }
2383 else
2384 {
2385 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2386 stream_putc (s, BGP_ATTR_COMMUNITIES);
2387 stream_putc (s, attr->community->size * 4);
2388 }
2389 stream_put (s, attr->community->val, attr->community->size * 4);
2390 }
2391
paula3845922003-10-18 01:30:50 +00002392#ifdef HAVE_IPV6
2393 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002394 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2395 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002396 {
2397 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002398 struct attr_extra *attre = attr->extra;
2399
paula3845922003-10-18 01:30:50 +00002400 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2401 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002402 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002403
2404 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002405 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002406 stream_putw(s, AFI_IP6); /* AFI */
2407 stream_putc(s, SAFI_UNICAST); /* SAFI */
2408
2409 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002410 stream_putc(s, attre->mp_nexthop_len);
2411 stream_put(s, &attre->mp_nexthop_global, 16);
2412 if (attre->mp_nexthop_len == 32)
2413 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002414
2415 /* SNPA */
2416 stream_putc(s, 0);
2417
2418 /* Prefix */
2419 stream_put_prefix(s, prefix);
2420
2421 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002422 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002423 }
2424#endif /* HAVE_IPV6 */
2425
Paul Jakma41367172007-08-06 15:24:51 +00002426 /* AS-Pathlimit */
2427 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2428 {
2429 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2430 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2431 stream_putc (s, 5);
2432 stream_putc (s, attr->pathlimit.ttl);
2433 stream_putl (s, attr->pathlimit.as);
2434 }
2435
paul718e3742002-12-13 20:15:29 +00002436 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002437 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002438 stream_putw_at (s, cp, len);
2439}