blob: 752099d1fc0df34807e740833e958bece5ebc669 [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
Paul Jakmaa15cfd12008-06-01 14:29:03 +0000698 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
699 || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
Paul Jakma41367172007-08-06 15:24:51 +0000700 {
701 zlog (peer->log, LOG_ERR,
702 "AS-Pathlimit attribute flag isn't transitive %d", flag);
703 bgp_notify_send_with_data (peer,
704 BGP_NOTIFY_UPDATE_ERR,
705 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
706 startp, total);
707 return -1;
708 }
709
710 if (length != 5)
711 {
712 zlog (peer->log, LOG_ERR,
713 "AS-Pathlimit length, %u, is not 5", length);
714 bgp_notify_send_with_data (peer,
715 BGP_NOTIFY_UPDATE_ERR,
716 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
717 startp, total);
718 return -1;
719 }
720
721 attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer));
722 attr->pathlimit.as = stream_getl (BGP_INPUT(peer));
723 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
724 return 0;
725}
paul718e3742002-12-13 20:15:29 +0000726/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000727static int
paul718e3742002-12-13 20:15:29 +0000728bgp_attr_origin (struct peer *peer, bgp_size_t length,
729 struct attr *attr, u_char flag, u_char *startp)
730{
731 bgp_size_t total;
732
733 /* total is entire attribute length include Attribute Flags (1),
734 Attribute Type code (1) and Attribute length (1 or 2). */
735 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
736
737 /* If any recognized attribute has Attribute Flags that conflict
738 with the Attribute Type Code, then the Error Subcode is set to
739 Attribute Flags Error. The Data field contains the erroneous
740 attribute (type, length and value). */
741 if (flag != BGP_ATTR_FLAG_TRANS)
742 {
743 zlog (peer->log, LOG_ERR,
744 "Origin attribute flag isn't transitive %d", flag);
745 bgp_notify_send_with_data (peer,
746 BGP_NOTIFY_UPDATE_ERR,
747 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
748 startp, total);
749 return -1;
750 }
751
752 /* If any recognized attribute has Attribute Length that conflicts
753 with the expected length (based on the attribute type code), then
754 the Error Subcode is set to Attribute Length Error. The Data
755 field contains the erroneous attribute (type, length and
756 value). */
757 if (length != 1)
758 {
759 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
760 length);
761 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
762 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
763 startp, total);
764 return -1;
765 }
766
767 /* Fetch origin attribute. */
768 attr->origin = stream_getc (BGP_INPUT (peer));
769
770 /* If the ORIGIN attribute has an undefined value, then the Error
771 Subcode is set to Invalid Origin Attribute. The Data field
772 contains the unrecognized attribute (type, length and value). */
773 if ((attr->origin != BGP_ORIGIN_IGP)
774 && (attr->origin != BGP_ORIGIN_EGP)
775 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
776 {
777 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
778 attr->origin);
779
780 bgp_notify_send_with_data (peer,
781 BGP_NOTIFY_UPDATE_ERR,
782 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
783 startp, total);
784 return -1;
785 }
786
787 /* Set oring attribute flag. */
788 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
789
790 return 0;
791}
792
793/* Parse AS path information. This function is wrapper of
794 aspath_parse. */
paul94f2b392005-06-28 12:44:16 +0000795static int
paul718e3742002-12-13 20:15:29 +0000796bgp_attr_aspath (struct peer *peer, bgp_size_t length,
797 struct attr *attr, u_char flag, u_char *startp)
798{
paul718e3742002-12-13 20:15:29 +0000799 bgp_size_t total;
800
801 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
802
803 /* Flag check. */
804 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
805 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
806 {
807 zlog (peer->log, LOG_ERR,
Paul Jakmaa15cfd12008-06-01 14:29:03 +0000808 "As-Path attribute flag isn't transitive %d", flag);
paul718e3742002-12-13 20:15:29 +0000809 bgp_notify_send_with_data (peer,
810 BGP_NOTIFY_UPDATE_ERR,
811 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
812 startp, total);
813 return -1;
814 }
815
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000816 /*
817 * peer with AS4 => will get 4Byte ASnums
818 * otherwise, will get 16 Bit
819 */
820 attr->aspath = aspath_parse (peer->ibuf, length,
821 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
822
paul718e3742002-12-13 20:15:29 +0000823 /* In case of IBGP, length will be zero. */
paul718e3742002-12-13 20:15:29 +0000824 if (! attr->aspath)
825 {
826 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
827 bgp_notify_send (peer,
828 BGP_NOTIFY_UPDATE_ERR,
829 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
830 return -1;
831 }
832
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000833 /* Forward pointer. */
834/* stream_forward_getp (peer->ibuf, length);*/
835
836 /* Set aspath attribute flag. */
837 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
838
839 return 0;
840}
841
842static int bgp_attr_aspath_check( struct peer *peer,
843 struct attr *attr)
844{
845 /* These checks were part of bgp_attr_aspath, but with
846 * as4 we should to check aspath things when
847 * aspath synthesizing with as4_path has already taken place.
848 * Otherwise we check ASPATH and use the synthesized thing, and that is
849 * not right.
850 * So do the checks later, i.e. here
851 */
852 struct bgp *bgp = peer->bgp;
853 struct aspath *aspath;
854
paul718e3742002-12-13 20:15:29 +0000855 bgp = peer->bgp;
856
857 /* First AS check for EBGP. */
858 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
859 {
860 if (peer_sort (peer) == BGP_PEER_EBGP
861 && ! aspath_firstas_check (attr->aspath, peer->as))
862 {
863 zlog (peer->log, LOG_ERR,
864 "%s incorrect first AS (must be %d)", peer->host, peer->as);
865 bgp_notify_send (peer,
866 BGP_NOTIFY_UPDATE_ERR,
867 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
868 return -1;
869 }
870 }
871
872 /* local-as prepend */
873 if (peer->change_local_as &&
874 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
875 {
876 aspath = aspath_dup (attr->aspath);
877 aspath = aspath_add_seq (aspath, peer->change_local_as);
878 aspath_unintern (attr->aspath);
879 attr->aspath = aspath_intern (aspath);
880 }
881
Paul Jakma0b2aa3a2007-10-14 22:32:21 +0000882 return 0;
883
884}
885
886/* Parse AS4 path information. This function is another wrapper of
887 aspath_parse. */
888static int
889bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
890 struct attr *attr, struct aspath **as4_path)
891{
892 *as4_path = aspath_parse (peer->ibuf, length, 1);
paul718e3742002-12-13 20:15:29 +0000893
894 /* Set aspath attribute flag. */
Paul Jakma370b64a2007-12-22 16:49:52 +0000895 if (as4_path)
896 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
paul718e3742002-12-13 20:15:29 +0000897
898 return 0;
899}
900
901/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000902static int
paul718e3742002-12-13 20:15:29 +0000903bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
904 struct attr *attr, u_char flag, u_char *startp)
905{
906 bgp_size_t total;
907
908 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
909
910 /* Flag check. */
911 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
912 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
913 {
914 zlog (peer->log, LOG_ERR,
915 "Origin attribute flag isn't transitive %d", flag);
916 bgp_notify_send_with_data (peer,
917 BGP_NOTIFY_UPDATE_ERR,
918 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
919 startp, total);
920 return -1;
921 }
922
923 /* Check nexthop attribute length. */
924 if (length != 4)
925 {
926 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
927 length);
928
929 bgp_notify_send_with_data (peer,
930 BGP_NOTIFY_UPDATE_ERR,
931 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
932 startp, total);
933 return -1;
934 }
935
936 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
937 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
938
939 return 0;
940}
941
942/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000943static int
paul718e3742002-12-13 20:15:29 +0000944bgp_attr_med (struct peer *peer, bgp_size_t length,
945 struct attr *attr, u_char flag, u_char *startp)
946{
947 bgp_size_t total;
948
949 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
950
951 /* Length check. */
952 if (length != 4)
953 {
954 zlog (peer->log, LOG_ERR,
955 "MED attribute length isn't four [%d]", length);
956
957 bgp_notify_send_with_data (peer,
958 BGP_NOTIFY_UPDATE_ERR,
959 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
960 startp, total);
961 return -1;
962 }
963
964 attr->med = stream_getl (peer->ibuf);
965
966 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
967
968 return 0;
969}
970
971/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000972static int
paul718e3742002-12-13 20:15:29 +0000973bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
974 struct attr *attr, u_char flag)
975{
976 /* If it is contained in an UPDATE message that is received from an
977 external peer, then this attribute MUST be ignored by the
978 receiving speaker. */
979 if (peer_sort (peer) == BGP_PEER_EBGP)
980 {
paul9985f832005-02-09 15:51:56 +0000981 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000982 return 0;
983 }
984
985 if (length == 4)
986 attr->local_pref = stream_getl (peer->ibuf);
987 else
988 attr->local_pref = 0;
989
990 /* Set atomic aggregate flag. */
991 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
992
993 return 0;
994}
995
996/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000997static int
paul718e3742002-12-13 20:15:29 +0000998bgp_attr_atomic (struct peer *peer, bgp_size_t length,
999 struct attr *attr, u_char flag)
1000{
1001 if (length != 0)
1002 {
1003 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1004
1005 bgp_notify_send (peer,
1006 BGP_NOTIFY_UPDATE_ERR,
1007 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1008 return -1;
1009 }
1010
1011 /* Set atomic aggregate flag. */
1012 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1013
1014 return 0;
1015}
1016
1017/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +00001018static int
paul718e3742002-12-13 20:15:29 +00001019bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1020 struct attr *attr, u_char flag)
1021{
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001022 int wantedlen = 6;
Paul Jakmafb982c22007-05-04 20:15:47 +00001023 struct attr_extra *attre = bgp_attr_extra_get (attr);
1024
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001025 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1026 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1027 wantedlen = 8;
1028
1029 if (length != wantedlen)
paul718e3742002-12-13 20:15:29 +00001030 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001031 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
paul718e3742002-12-13 20:15:29 +00001032
1033 bgp_notify_send (peer,
1034 BGP_NOTIFY_UPDATE_ERR,
1035 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1036 return -1;
1037 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001038
1039 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1040 attre->aggregator_as = stream_getl (peer->ibuf);
1041 else
1042 attre->aggregator_as = stream_getw (peer->ibuf);
Paul Jakmafb982c22007-05-04 20:15:47 +00001043 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001044
1045 /* Set atomic aggregate flag. */
1046 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1047
1048 return 0;
1049}
1050
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001051/* New Aggregator attribute */
1052static int
1053bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1054 struct attr *attr, as_t *as4_aggregator_as,
1055 struct in_addr *as4_aggregator_addr)
1056{
1057 if (length != 8)
1058 {
1059 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1060
1061 bgp_notify_send (peer,
1062 BGP_NOTIFY_UPDATE_ERR,
1063 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1064 return -1;
1065 }
1066 *as4_aggregator_as = stream_getl (peer->ibuf);
1067 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1068
1069 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1070
1071 return 0;
1072}
1073
1074/* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1075 */
1076static int
1077bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1078 struct aspath *as4_path, as_t as4_aggregator,
1079 struct in_addr *as4_aggregator_addr)
1080{
1081 int ignore_as4_path = 0;
1082 struct aspath *newpath;
1083 struct attr_extra *attre = attr->extra;
1084
1085 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1086 {
1087 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1088 * if given.
1089 * It is worth a warning though, because the peer really
1090 * should not send them
1091 */
1092 if (BGP_DEBUG(as4, AS4))
1093 {
1094 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1095 zlog_debug ("[AS4] %s %s AS4_PATH",
1096 peer->host, "AS4 capable peer, yet it sent");
1097
1098 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1099 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1100 peer->host, "AS4 capable peer, yet it sent");
1101 }
1102
1103 return 0;
1104 }
1105
1106 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1107 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1108 {
1109 /* Hu? This is not supposed to happen at all!
1110 * got as4_path and no aspath,
1111 * This should already
1112 * have been handled by 'well known attributes missing'
1113 * But... yeah, paranoia
1114 * Take this as a "malformed attribute"
1115 */
1116 zlog (peer->log, LOG_ERR,
1117 "%s BGP not AS4 capable peer sent AS4_PATH but"
1118 " no AS_PATH, cant do anything here", peer->host);
1119 bgp_notify_send (peer,
1120 BGP_NOTIFY_UPDATE_ERR,
1121 BGP_NOTIFY_UPDATE_MAL_ATTR);
1122 return -1;
1123 }
1124
1125 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1126 * because that may override AS4_PATH
1127 */
1128 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1129 {
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001130 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1131 {
Paul Jakma370b64a2007-12-22 16:49:52 +00001132 assert (attre);
1133
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001134 /* received both.
1135 * if the as_number in aggregator is not AS_TRANS,
1136 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1137 * and the Aggregator shall be taken as
1138 * info on the aggregating node, and the AS_PATH
1139 * shall be taken as the AS_PATH
1140 * otherwise
1141 * the Aggregator shall be ignored and the
1142 * AS4_AGGREGATOR shall be taken as the
1143 * Aggregating node and the AS_PATH is to be
1144 * constructed "as in all other cases"
1145 */
1146 if ( attre->aggregator_as != BGP_AS_TRANS )
1147 {
1148 /* ignore */
1149 if ( BGP_DEBUG(as4, AS4))
1150 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1151 " send AGGREGATOR != AS_TRANS and"
1152 " AS4_AGGREGATOR, so ignore"
1153 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1154 ignore_as4_path = 1;
1155 }
1156 else
1157 {
1158 /* "New_aggregator shall be taken as aggregator" */
1159 attre->aggregator_as = as4_aggregator;
1160 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1161 }
1162 }
1163 else
1164 {
1165 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1166 * That is bogus - but reading the conditions
1167 * we have to handle AS4_AGGREGATOR as if it were
1168 * AGGREGATOR in that case
1169 */
1170 if ( BGP_DEBUG(as4, AS4))
1171 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1172 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1173 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
Paul Jakma370b64a2007-12-22 16:49:52 +00001174 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001175 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1176 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1177 }
1178 }
1179
1180 /* need to reconcile NEW_AS_PATH and AS_PATH */
1181 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1182 {
1183 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1184 aspath_unintern (attr->aspath);
1185 attr->aspath = aspath_intern (newpath);
1186 }
1187 return 0;
1188}
1189
paul718e3742002-12-13 20:15:29 +00001190/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001191static int
paul718e3742002-12-13 20:15:29 +00001192bgp_attr_community (struct peer *peer, bgp_size_t length,
1193 struct attr *attr, u_char flag)
1194{
1195 if (length == 0)
Paul Jakmab2ceea12007-09-07 14:24:55 +00001196 {
1197 attr->community = NULL;
1198 return 0;
1199 }
paul718e3742002-12-13 20:15:29 +00001200 else
1201 {
paul5228ad22004-06-04 17:58:18 +00001202 attr->community =
1203 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001204 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001205 }
1206
1207 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1208
1209 return 0;
1210}
1211
1212/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +00001213static int
paul718e3742002-12-13 20:15:29 +00001214bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1215 struct attr *attr, u_char flag)
1216{
1217 if (length != 4)
1218 {
1219 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1220
1221 bgp_notify_send (peer,
1222 BGP_NOTIFY_UPDATE_ERR,
1223 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1224 return -1;
1225 }
1226
Paul Jakmafb982c22007-05-04 20:15:47 +00001227 (bgp_attr_extra_get (attr))->originator_id.s_addr
1228 = stream_get_ipv4 (peer->ibuf);
paul718e3742002-12-13 20:15:29 +00001229
1230 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1231
1232 return 0;
1233}
1234
1235/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +00001236static int
paul718e3742002-12-13 20:15:29 +00001237bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1238 struct attr *attr, u_char flag)
1239{
1240 /* Check length. */
1241 if (length % 4)
1242 {
1243 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1244
1245 bgp_notify_send (peer,
1246 BGP_NOTIFY_UPDATE_ERR,
1247 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1248 return -1;
1249 }
1250
Paul Jakmafb982c22007-05-04 20:15:47 +00001251 (bgp_attr_extra_get (attr))->cluster
1252 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
paul718e3742002-12-13 20:15:29 +00001253
paul9985f832005-02-09 15:51:56 +00001254 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +00001255
1256 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1257
1258 return 0;
1259}
1260
1261/* Multiprotocol reachability information parse. */
Paul Jakma03292802008-06-07 20:37:10 +00001262int
paul718e3742002-12-13 20:15:29 +00001263bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1264 struct bgp_nlri *mp_update)
1265{
1266 u_int16_t afi;
1267 u_char safi;
paul718e3742002-12-13 20:15:29 +00001268 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001269 size_t start;
paul718e3742002-12-13 20:15:29 +00001270 int ret;
1271 struct stream *s;
Paul Jakmafb982c22007-05-04 20:15:47 +00001272 struct attr_extra *attre = bgp_attr_extra_get(attr);
paul718e3742002-12-13 20:15:29 +00001273
1274 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +00001275 s = BGP_INPUT(peer);
1276 start = stream_get_getp(s);
1277
1278 /* safe to read statically sized header? */
1279#define BGP_MP_REACH_MIN_SIZE 5
Paul Jakma03292802008-06-07 20:37:10 +00001280#define LEN_LEFT (length - (stream_get_getp(s) - start))
Paul Jakma6e4ab122007-04-10 19:36:48 +00001281 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
Paul Jakma03292802008-06-07 20:37:10 +00001282 {
1283 zlog_info ("%s: %s sent invalid length, %lu",
1284 __func__, peer->host, (unsigned long)length);
1285 return -1;
1286 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001287
paul718e3742002-12-13 20:15:29 +00001288 /* Load AFI, SAFI. */
1289 afi = stream_getw (s);
1290 safi = stream_getc (s);
1291
1292 /* Get nexthop length. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001293 attre->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001294
Paul Jakma03292802008-06-07 20:37:10 +00001295 if (LEN_LEFT < attre->mp_nexthop_len)
1296 {
1297 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1298 __func__, peer->host, attre->mp_nexthop_len);
1299 return -1;
1300 }
Paul Jakma6e4ab122007-04-10 19:36:48 +00001301
paul718e3742002-12-13 20:15:29 +00001302 /* Nexthop length check. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001303 switch (attre->mp_nexthop_len)
paul718e3742002-12-13 20:15:29 +00001304 {
1305 case 4:
Paul Jakmafb982c22007-05-04 20:15:47 +00001306 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001307 break;
1308 case 12:
1309 {
1310 u_int32_t rd_high;
1311 u_int32_t rd_low;
1312
1313 rd_high = stream_getl (s);
1314 rd_low = stream_getl (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00001315 stream_get (&attre->mp_nexthop_global_in, s, 4);
paul718e3742002-12-13 20:15:29 +00001316 }
1317 break;
1318#ifdef HAVE_IPV6
1319 case 16:
Paul Jakmafb982c22007-05-04 20:15:47 +00001320 stream_get (&attre->mp_nexthop_global, s, 16);
paul718e3742002-12-13 20:15:29 +00001321 break;
1322 case 32:
Paul Jakmafb982c22007-05-04 20:15:47 +00001323 stream_get (&attre->mp_nexthop_global, s, 16);
1324 stream_get (&attre->mp_nexthop_local, s, 16);
1325 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
paul718e3742002-12-13 20:15:29 +00001326 {
1327 char buf1[INET6_ADDRSTRLEN];
1328 char buf2[INET6_ADDRSTRLEN];
1329
1330 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +00001331 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 +00001332 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
paul718e3742002-12-13 20:15:29 +00001333 buf1, INET6_ADDRSTRLEN),
Paul Jakmafb982c22007-05-04 20:15:47 +00001334 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
paul718e3742002-12-13 20:15:29 +00001335 buf2, INET6_ADDRSTRLEN));
1336
Paul Jakmafb982c22007-05-04 20:15:47 +00001337 attre->mp_nexthop_len = 16;
paul718e3742002-12-13 20:15:29 +00001338 }
1339 break;
1340#endif /* HAVE_IPV6 */
1341 default:
Paul Jakma03292802008-06-07 20:37:10 +00001342 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1343 __func__, peer->host, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00001344 return -1;
paul718e3742002-12-13 20:15:29 +00001345 }
1346
Paul Jakma03292802008-06-07 20:37:10 +00001347 if (!LEN_LEFT)
1348 {
1349 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1350 __func__, peer->host);
1351 return -1;
1352 }
paul718e3742002-12-13 20:15:29 +00001353
Paul Jakma6e4ab122007-04-10 19:36:48 +00001354 {
1355 u_char val;
1356 if ((val = stream_getc (s)))
1357 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1358 peer->host, val);
1359 }
1360
1361 /* must have nrli_len, what is left of the attribute */
Paul Jakma03292802008-06-07 20:37:10 +00001362 nlri_len = LEN_LEFT;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001363 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
Paul Jakma03292802008-06-07 20:37:10 +00001364 {
1365 zlog_info ("%s: (%s) Failed to read NLRI",
1366 __func__, peer->host);
1367 return -1;
1368 }
paul718e3742002-12-13 20:15:29 +00001369
1370 if (safi != BGP_SAFI_VPNV4)
1371 {
1372 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
Paul Jakma03292802008-06-07 20:37:10 +00001373 if (ret < 0)
1374 {
1375 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1376 __func__, peer->host);
1377 return -1;
1378 }
paul718e3742002-12-13 20:15:29 +00001379 }
1380
1381 mp_update->afi = afi;
1382 mp_update->safi = safi;
1383 mp_update->nlri = stream_pnt (s);
1384 mp_update->length = nlri_len;
1385
paul9985f832005-02-09 15:51:56 +00001386 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001387
1388 return 0;
Paul Jakma03292802008-06-07 20:37:10 +00001389#undef LEN_LEFT
paul718e3742002-12-13 20:15:29 +00001390}
1391
1392/* Multiprotocol unreachable parse */
Paul Jakma03292802008-06-07 20:37:10 +00001393int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001394bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001395 struct bgp_nlri *mp_withdraw)
1396{
1397 struct stream *s;
1398 u_int16_t afi;
1399 u_char safi;
paul718e3742002-12-13 20:15:29 +00001400 u_int16_t withdraw_len;
1401 int ret;
1402
1403 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001404
1405#define BGP_MP_UNREACH_MIN_SIZE 3
1406 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1407 return -1;
1408
paul718e3742002-12-13 20:15:29 +00001409 afi = stream_getw (s);
1410 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001411
1412 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
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), withdraw_len);
1417 if (ret < 0)
1418 return -1;
1419 }
1420
1421 mp_withdraw->afi = afi;
1422 mp_withdraw->safi = safi;
1423 mp_withdraw->nlri = stream_pnt (s);
1424 mp_withdraw->length = withdraw_len;
1425
paul9985f832005-02-09 15:51:56 +00001426 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001427
1428 return 0;
1429}
1430
1431/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001432static int
paul718e3742002-12-13 20:15:29 +00001433bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1434 struct attr *attr, u_char flag)
1435{
1436 if (length == 0)
Paul Jakmafb982c22007-05-04 20:15:47 +00001437 {
1438 if (attr->extra)
1439 attr->extra->ecommunity = NULL;
1440 }
paul718e3742002-12-13 20:15:29 +00001441 else
1442 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001443 (bgp_attr_extra_get (attr))->ecommunity =
paul5228ad22004-06-04 17:58:18 +00001444 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001445 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001446 }
1447 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1448
1449 return 0;
1450}
1451
1452/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001453static int
paul718e3742002-12-13 20:15:29 +00001454bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1455 u_char type, bgp_size_t length, u_char *startp)
1456{
1457 bgp_size_t total;
1458 struct transit *transit;
Paul Jakmafb982c22007-05-04 20:15:47 +00001459 struct attr_extra *attre;
paul718e3742002-12-13 20:15:29 +00001460
hassof4184462005-02-01 20:13:16 +00001461 if (BGP_DEBUG (normal, NORMAL))
1462 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1463 peer->host, type, length);
1464
paul718e3742002-12-13 20:15:29 +00001465 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001466 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001467 "Unknown attribute type %d length %d is received", type, length);
1468
1469 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001470 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001471
1472 /* Adjest total length to include type and length. */
1473 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1474
1475 /* If any of the mandatory well-known attributes are not recognized,
1476 then the Error Subcode is set to Unrecognized Well-known
1477 Attribute. The Data field contains the unrecognized attribute
1478 (type, length and value). */
1479 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1480 {
1481 /* Adjust startp to do not include flag value. */
1482 bgp_notify_send_with_data (peer,
1483 BGP_NOTIFY_UPDATE_ERR,
1484 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1485 startp, total);
1486 return -1;
1487 }
1488
1489 /* Unrecognized non-transitive optional attributes must be quietly
1490 ignored and not passed along to other BGP peers. */
1491 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1492 return 0;
1493
1494 /* If a path with recognized transitive optional attribute is
1495 accepted and passed along to other BGP peers and the Partial bit
1496 in the Attribute Flags octet is set to 1 by some previous AS, it
1497 is not set back to 0 by the current AS. */
1498 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1499
1500 /* Store transitive attribute to the end of attr->transit. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001501 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
paul718e3742002-12-13 20:15:29 +00001502 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001503 attre->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1504 memset (attre->transit, 0, sizeof (struct transit));
paul718e3742002-12-13 20:15:29 +00001505 }
1506
Paul Jakmafb982c22007-05-04 20:15:47 +00001507 transit = attre->transit;
paul718e3742002-12-13 20:15:29 +00001508
1509 if (transit->val)
1510 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1511 transit->length + total);
1512 else
1513 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1514
1515 memcpy (transit->val + transit->length, startp, total);
1516 transit->length += total;
1517
1518 return 0;
1519}
1520
1521/* Read attribute of update packet. This function is called from
1522 bgp_update() in bgpd.c. */
1523int
1524bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1525 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1526{
1527 int ret;
1528 u_char flag;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001529 u_char type = 0;
paul718e3742002-12-13 20:15:29 +00001530 bgp_size_t length;
1531 u_char *startp, *endp;
1532 u_char *attr_endp;
1533 u_char seen[BGP_ATTR_BITMAP_SIZE];
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001534 /* we need the as4_path only until we have synthesized the as_path with it */
1535 /* same goes for as4_aggregator */
1536 struct aspath *as4_path = NULL;
1537 as_t as4_aggregator = 0;
1538 struct in_addr as4_aggregator_addr = { 0 };
paul718e3742002-12-13 20:15:29 +00001539
1540 /* Initialize bitmap. */
1541 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1542
1543 /* End pointer of BGP attribute. */
1544 endp = BGP_INPUT_PNT (peer) + size;
1545
1546 /* Get attributes to the end of attribute length. */
1547 while (BGP_INPUT_PNT (peer) < endp)
1548 {
1549 /* Check remaining length check.*/
1550 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1551 {
gdtc29fdba2004-12-09 14:46:46 +00001552 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001553 zlog (peer->log, LOG_WARNING,
Paul Jakma41367172007-08-06 15:24:51 +00001554 "%s error BGP attribute length %lu is smaller than min len",
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001555 peer->host,
1556 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
paul718e3742002-12-13 20:15:29 +00001557
1558 bgp_notify_send (peer,
1559 BGP_NOTIFY_UPDATE_ERR,
1560 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1561 return -1;
1562 }
1563
1564 /* Fetch attribute flag and type. */
1565 startp = BGP_INPUT_PNT (peer);
1566 flag = stream_getc (BGP_INPUT (peer));
1567 type = stream_getc (BGP_INPUT (peer));
1568
Paul Jakma370b64a2007-12-22 16:49:52 +00001569 /* Check whether Extended-Length applies and is in bounds */
1570 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1571 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1572 {
1573 zlog (peer->log, LOG_WARNING,
Paul Jakma851a1a52008-07-22 19:56:56 +00001574 "%s Extended length set, but just %lu bytes of attr header",
Paul Jakma370b64a2007-12-22 16:49:52 +00001575 peer->host,
1576 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1577
1578 bgp_notify_send (peer,
1579 BGP_NOTIFY_UPDATE_ERR,
1580 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1581 return -1;
1582 }
1583
paul718e3742002-12-13 20:15:29 +00001584 /* Check extended attribue length bit. */
1585 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1586 length = stream_getw (BGP_INPUT (peer));
1587 else
1588 length = stream_getc (BGP_INPUT (peer));
1589
1590 /* If any attribute appears more than once in the UPDATE
1591 message, then the Error Subcode is set to Malformed Attribute
1592 List. */
1593
1594 if (CHECK_BITMAP (seen, type))
1595 {
1596 zlog (peer->log, LOG_WARNING,
1597 "%s error BGP attribute type %d appears twice in a message",
1598 peer->host, type);
1599
1600 bgp_notify_send (peer,
1601 BGP_NOTIFY_UPDATE_ERR,
1602 BGP_NOTIFY_UPDATE_MAL_ATTR);
1603 return -1;
1604 }
1605
1606 /* Set type to bitmap to check duplicate attribute. `type' is
1607 unsigned char so it never overflow bitmap range. */
1608
1609 SET_BITMAP (seen, type);
1610
1611 /* Overflow check. */
1612 attr_endp = BGP_INPUT_PNT (peer) + length;
1613
1614 if (attr_endp > endp)
1615 {
1616 zlog (peer->log, LOG_WARNING,
1617 "%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);
1618 bgp_notify_send (peer,
1619 BGP_NOTIFY_UPDATE_ERR,
1620 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1621 return -1;
1622 }
1623
1624 /* OK check attribute and store it's value. */
1625 switch (type)
1626 {
1627 case BGP_ATTR_ORIGIN:
1628 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1629 break;
1630 case BGP_ATTR_AS_PATH:
1631 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1632 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001633 case BGP_ATTR_AS4_PATH:
1634 ret = bgp_attr_as4_path (peer, length, attr, &as4_path );
1635 break;
paul718e3742002-12-13 20:15:29 +00001636 case BGP_ATTR_NEXT_HOP:
1637 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1638 break;
1639 case BGP_ATTR_MULTI_EXIT_DISC:
1640 ret = bgp_attr_med (peer, length, attr, flag, startp);
1641 break;
1642 case BGP_ATTR_LOCAL_PREF:
1643 ret = bgp_attr_local_pref (peer, length, attr, flag);
1644 break;
1645 case BGP_ATTR_ATOMIC_AGGREGATE:
1646 ret = bgp_attr_atomic (peer, length, attr, flag);
1647 break;
1648 case BGP_ATTR_AGGREGATOR:
1649 ret = bgp_attr_aggregator (peer, length, attr, flag);
1650 break;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001651 case BGP_ATTR_AS4_AGGREGATOR:
1652 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1653 break;
paul718e3742002-12-13 20:15:29 +00001654 case BGP_ATTR_COMMUNITIES:
1655 ret = bgp_attr_community (peer, length, attr, flag);
1656 break;
1657 case BGP_ATTR_ORIGINATOR_ID:
1658 ret = bgp_attr_originator_id (peer, length, attr, flag);
1659 break;
1660 case BGP_ATTR_CLUSTER_LIST:
1661 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1662 break;
1663 case BGP_ATTR_MP_REACH_NLRI:
1664 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1665 break;
1666 case BGP_ATTR_MP_UNREACH_NLRI:
1667 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1668 break;
1669 case BGP_ATTR_EXT_COMMUNITIES:
1670 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1671 break;
Paul Jakma41367172007-08-06 15:24:51 +00001672 case BGP_ATTR_AS_PATHLIMIT:
1673 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1674 break;
paul718e3742002-12-13 20:15:29 +00001675 default:
1676 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1677 break;
1678 }
1679
1680 /* If error occured immediately return to the caller. */
1681 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001682 {
1683 zlog (peer->log, LOG_WARNING,
1684 "%s: Attribute %s, parse error",
1685 peer->host,
1686 LOOKUP (attr_str, type));
1687 bgp_notify_send (peer,
1688 BGP_NOTIFY_UPDATE_ERR,
1689 BGP_NOTIFY_UPDATE_MAL_ATTR);
1690 return ret;
1691 }
paul718e3742002-12-13 20:15:29 +00001692
1693 /* Check the fetched length. */
1694 if (BGP_INPUT_PNT (peer) != attr_endp)
1695 {
1696 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001697 "%s: BGP attribute %s, fetch error",
1698 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001699 bgp_notify_send (peer,
1700 BGP_NOTIFY_UPDATE_ERR,
1701 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1702 return -1;
1703 }
1704 }
1705
1706 /* Check final read pointer is same as end pointer. */
1707 if (BGP_INPUT_PNT (peer) != endp)
1708 {
1709 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001710 "%s BGP attribute %s, length mismatch",
1711 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001712 bgp_notify_send (peer,
1713 BGP_NOTIFY_UPDATE_ERR,
1714 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1715 return -1;
1716 }
1717
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001718 /*
1719 * At this place we can see whether we got AS4_PATH and/or
1720 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1721 * We can not do this before we've read all attributes because
1722 * the as4 handling does not say whether AS4_PATH has to be sent
1723 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1724 * in relationship to AGGREGATOR.
1725 * So, to be defensive, we are not relying on any order and read
1726 * all attributes first, including these 32bit ones, and now,
1727 * afterwards, we look what and if something is to be done for as4.
1728 */
1729 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1730 as4_aggregator, &as4_aggregator_addr))
1731 return -1;
1732
1733 /* At this stage, we have done all fiddling with as4, and the
1734 * resulting info is in attr->aggregator resp. attr->aspath
1735 * so we can chuck as4_aggregator and as4_path alltogether in
1736 * order to save memory
1737 */
1738 if ( as4_path )
1739 {
1740 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1741 as4_path = NULL;
1742 /* The flag that we got this is still there, but that does not
1743 * do any trouble
1744 */
1745 }
1746 /*
1747 * The "rest" of the code does nothing with as4_aggregator.
1748 * there is no memory attached specifically which is not part
1749 * of the attr.
1750 * so ignoring just means do nothing.
1751 */
1752 /*
1753 * Finally do the checks on the aspath we did not do yet
1754 * because we waited for a potentially synthesized aspath.
1755 */
1756 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1757 {
1758 ret = bgp_attr_aspath_check( peer, attr );
1759 if ( ret < 0 )
1760 return ret;
1761 }
1762
paul718e3742002-12-13 20:15:29 +00001763 /* Finally intern unknown attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00001764 if (attr->extra && attr->extra->transit)
1765 attr->extra->transit = transit_intern (attr->extra->transit);
paul718e3742002-12-13 20:15:29 +00001766
1767 return 0;
1768}
1769
1770/* Well-known attribute check. */
1771int
1772bgp_attr_check (struct peer *peer, struct attr *attr)
1773{
1774 u_char type = 0;
1775
1776 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1777 type = BGP_ATTR_ORIGIN;
1778
1779 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1780 type = BGP_ATTR_AS_PATH;
1781
1782 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1783 type = BGP_ATTR_NEXT_HOP;
1784
1785 if (peer_sort (peer) == BGP_PEER_IBGP
1786 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1787 type = BGP_ATTR_LOCAL_PREF;
1788
1789 if (type)
1790 {
1791 zlog (peer->log, LOG_WARNING,
1792 "%s Missing well-known attribute %d.",
1793 peer->host, type);
1794 bgp_notify_send_with_data (peer,
1795 BGP_NOTIFY_UPDATE_ERR,
1796 BGP_NOTIFY_UPDATE_MISS_ATTR,
1797 &type, 1);
1798 return -1;
1799 }
1800 return 0;
1801}
1802
1803int stream_put_prefix (struct stream *, struct prefix *);
1804
1805/* Make attribute packet. */
1806bgp_size_t
1807bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1808 struct stream *s, struct attr *attr, struct prefix *p,
1809 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001810 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001811{
paulfe69a502005-09-10 16:55:02 +00001812 size_t cp;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001813 size_t aspath_sizep;
paul718e3742002-12-13 20:15:29 +00001814 struct aspath *aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001815 int send_as4_path = 0;
1816 int send_as4_aggregator = 0;
1817 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
paul718e3742002-12-13 20:15:29 +00001818
1819 if (! bgp)
1820 bgp = bgp_get_default ();
1821
1822 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001823 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001824
1825 /* Origin attribute. */
1826 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1827 stream_putc (s, BGP_ATTR_ORIGIN);
1828 stream_putc (s, 1);
1829 stream_putc (s, attr->origin);
1830
1831 /* AS path attribute. */
1832
1833 /* If remote-peer is EBGP */
1834 if (peer_sort (peer) == BGP_PEER_EBGP
1835 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001836 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001837 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001838 {
1839 aspath = aspath_dup (attr->aspath);
1840
1841 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1842 {
1843 /* Strip the confed info, and then stuff our path CONFED_ID
1844 on the front */
1845 aspath = aspath_delete_confed_seq (aspath);
1846 aspath = aspath_add_seq (aspath, bgp->confed_id);
1847 }
1848 else
1849 {
1850 aspath = aspath_add_seq (aspath, peer->local_as);
1851 if (peer->change_local_as)
1852 aspath = aspath_add_seq (aspath, peer->change_local_as);
1853 }
1854 }
1855 else if (peer_sort (peer) == BGP_PEER_CONFED)
1856 {
1857 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1858 aspath = aspath_dup (attr->aspath);
1859 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1860 }
1861 else
1862 aspath = attr->aspath;
1863
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001864 /* If peer is not AS4 capable, then:
1865 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1866 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1867 * types are in it (i.e. exclude them if they are there)
1868 * AND do this only if there is at least one asnum > 65535 in the path!
1869 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1870 * all ASnums > 65535 to BGP_AS_TRANS
1871 */
paul718e3742002-12-13 20:15:29 +00001872
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001873 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1874 stream_putc (s, BGP_ATTR_AS_PATH);
1875 aspath_sizep = stream_get_endp (s);
1876 stream_putw (s, 0);
1877 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1878
1879 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1880 * in the path
1881 */
1882 if (!use32bit && aspath_has_as4 (aspath))
1883 send_as4_path = 1; /* we'll do this later, at the correct place */
1884
paul718e3742002-12-13 20:15:29 +00001885 /* Nexthop attribute. */
1886 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1887 {
1888 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1889 stream_putc (s, BGP_ATTR_NEXT_HOP);
1890 stream_putc (s, 4);
1891 if (safi == SAFI_MPLS_VPN)
1892 {
1893 if (attr->nexthop.s_addr == 0)
1894 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1895 else
1896 stream_put_ipv4 (s, attr->nexthop.s_addr);
1897 }
1898 else
1899 stream_put_ipv4 (s, attr->nexthop.s_addr);
1900 }
1901
1902 /* MED attribute. */
1903 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1904 {
1905 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1906 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1907 stream_putc (s, 4);
1908 stream_putl (s, attr->med);
1909 }
1910
1911 /* Local preference. */
1912 if (peer_sort (peer) == BGP_PEER_IBGP ||
1913 peer_sort (peer) == BGP_PEER_CONFED)
1914 {
1915 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1916 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1917 stream_putc (s, 4);
1918 stream_putl (s, attr->local_pref);
1919 }
1920
1921 /* Atomic aggregate. */
1922 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1923 {
1924 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1925 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1926 stream_putc (s, 0);
1927 }
1928
1929 /* Aggregator. */
1930 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1931 {
Paul Jakmafb982c22007-05-04 20:15:47 +00001932 assert (attr->extra);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001933
1934 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
paul718e3742002-12-13 20:15:29 +00001935 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1936 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00001937
1938 if (use32bit)
1939 {
1940 /* AS4 capable peer */
1941 stream_putc (s, 8);
1942 stream_putl (s, attr->extra->aggregator_as);
1943 }
1944 else
1945 {
1946 /* 2-byte AS peer */
1947 stream_putc (s, 6);
1948
1949 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1950 if ( attr->extra->aggregator_as > 65535 )
1951 {
1952 stream_putw (s, BGP_AS_TRANS);
1953
1954 /* we have to send AS4_AGGREGATOR, too.
1955 * we'll do that later in order to send attributes in ascending
1956 * order.
1957 */
1958 send_as4_aggregator = 1;
1959 }
1960 else
1961 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1962 }
Paul Jakmafb982c22007-05-04 20:15:47 +00001963 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00001964 }
1965
1966 /* Community attribute. */
1967 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1968 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1969 {
1970 if (attr->community->size * 4 > 255)
1971 {
1972 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1973 stream_putc (s, BGP_ATTR_COMMUNITIES);
1974 stream_putw (s, attr->community->size * 4);
1975 }
1976 else
1977 {
1978 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1979 stream_putc (s, BGP_ATTR_COMMUNITIES);
1980 stream_putc (s, attr->community->size * 4);
1981 }
1982 stream_put (s, attr->community->val, attr->community->size * 4);
1983 }
1984
1985 /* Route Reflector. */
1986 if (peer_sort (peer) == BGP_PEER_IBGP
1987 && from
1988 && peer_sort (from) == BGP_PEER_IBGP)
1989 {
1990 /* Originator ID. */
1991 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1992 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1993 stream_putc (s, 4);
1994
1995 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
Paul Jakmafb982c22007-05-04 20:15:47 +00001996 stream_put_in_addr (s, &attr->extra->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001997 else
1998 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001999
2000 /* Cluster list. */
2001 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2002 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2003
Paul Jakma9eda90c2007-08-30 13:36:17 +00002004 if (attr->extra && attr->extra->cluster)
paul718e3742002-12-13 20:15:29 +00002005 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002006 stream_putc (s, attr->extra->cluster->length + 4);
paul718e3742002-12-13 20:15:29 +00002007 /* If this peer configuration's parent BGP has cluster_id. */
2008 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2009 stream_put_in_addr (s, &bgp->cluster_id);
2010 else
2011 stream_put_in_addr (s, &bgp->router_id);
Paul Jakmafb982c22007-05-04 20:15:47 +00002012 stream_put (s, attr->extra->cluster->list,
2013 attr->extra->cluster->length);
paul718e3742002-12-13 20:15:29 +00002014 }
2015 else
2016 {
2017 stream_putc (s, 4);
2018 /* If this peer configuration's parent BGP has cluster_id. */
2019 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2020 stream_put_in_addr (s, &bgp->cluster_id);
2021 else
2022 stream_put_in_addr (s, &bgp->router_id);
2023 }
2024 }
2025
2026#ifdef HAVE_IPV6
2027 /* If p is IPv6 address put it into attribute. */
2028 if (p->family == AF_INET6)
2029 {
2030 unsigned long sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002031 struct attr_extra *attre = attr->extra;
2032
2033 assert (attr->extra);
2034
paul718e3742002-12-13 20:15:29 +00002035 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2036 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002037 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002038 stream_putc (s, 0); /* Marker: Attribute length. */
paul718e3742002-12-13 20:15:29 +00002039 stream_putw (s, AFI_IP6); /* AFI */
2040 stream_putc (s, safi); /* SAFI */
2041
Paul Jakmafb982c22007-05-04 20:15:47 +00002042 stream_putc (s, attre->mp_nexthop_len);
paul718e3742002-12-13 20:15:29 +00002043
Paul Jakmafb982c22007-05-04 20:15:47 +00002044 if (attre->mp_nexthop_len == 16)
2045 stream_put (s, &attre->mp_nexthop_global, 16);
2046 else if (attre->mp_nexthop_len == 32)
paul718e3742002-12-13 20:15:29 +00002047 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002048 stream_put (s, &attre->mp_nexthop_global, 16);
2049 stream_put (s, &attre->mp_nexthop_local, 16);
paul718e3742002-12-13 20:15:29 +00002050 }
2051
2052 /* SNPA */
2053 stream_putc (s, 0);
2054
paul718e3742002-12-13 20:15:29 +00002055 /* Prefix write. */
2056 stream_put_prefix (s, p);
2057
2058 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002059 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002060 }
2061#endif /* HAVE_IPV6 */
2062
2063 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2064 {
2065 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002066
2067 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2068 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002069 sizep = stream_get_endp (s);
Paul Jakmafb982c22007-05-04 20:15:47 +00002070 stream_putc (s, 0); /* Marker: Attribute Length. */
paul718e3742002-12-13 20:15:29 +00002071 stream_putw (s, AFI_IP); /* AFI */
2072 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2073
2074 stream_putc (s, 4);
2075 stream_put_ipv4 (s, attr->nexthop.s_addr);
2076
2077 /* SNPA */
2078 stream_putc (s, 0);
2079
paul718e3742002-12-13 20:15:29 +00002080 /* Prefix write. */
2081 stream_put_prefix (s, p);
2082
2083 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002084 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002085 }
2086
2087 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2088 {
2089 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00002090
2091 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2092 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002093 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002094 stream_putc (s, 0); /* Length of this attribute. */
2095 stream_putw (s, AFI_IP); /* AFI */
2096 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2097
2098 stream_putc (s, 12);
2099 stream_putl (s, 0);
2100 stream_putl (s, 0);
Paul Jakmafb982c22007-05-04 20:15:47 +00002101 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
paul718e3742002-12-13 20:15:29 +00002102
2103 /* SNPA */
2104 stream_putc (s, 0);
2105
paul718e3742002-12-13 20:15:29 +00002106 /* Tag, RD, Prefix write. */
2107 stream_putc (s, p->prefixlen + 88);
2108 stream_put (s, tag, 3);
2109 stream_put (s, prd->val, 8);
2110 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2111
2112 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002113 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00002114 }
2115
2116 /* Extended Communities attribute. */
2117 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2118 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2119 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002120 struct attr_extra *attre = attr->extra;
2121
2122 assert (attre);
2123
2124 if (peer_sort (peer) == BGP_PEER_IBGP
2125 || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00002126 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002127 if (attre->ecommunity->size * 8 > 255)
hasso4372df72004-05-20 10:20:02 +00002128 {
2129 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2130 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002131 stream_putw (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002132 }
2133 else
2134 {
2135 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2136 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
Paul Jakmafb982c22007-05-04 20:15:47 +00002137 stream_putc (s, attre->ecommunity->size * 8);
hasso4372df72004-05-20 10:20:02 +00002138 }
Paul Jakmafb982c22007-05-04 20:15:47 +00002139 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00002140 }
2141 else
2142 {
paul5228ad22004-06-04 17:58:18 +00002143 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00002144 int tbit;
2145 int ecom_tr_size = 0;
2146 int i;
2147
Paul Jakmafb982c22007-05-04 20:15:47 +00002148 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002149 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002150 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002151 tbit = *pnt;
2152
2153 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2154 continue;
2155
2156 ecom_tr_size++;
2157 }
2158
2159 if (ecom_tr_size)
2160 {
2161 if (ecom_tr_size * 8 > 255)
2162 {
2163 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2164 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2165 stream_putw (s, ecom_tr_size * 8);
2166 }
2167 else
2168 {
2169 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2170 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2171 stream_putc (s, ecom_tr_size * 8);
2172 }
2173
Paul Jakmafb982c22007-05-04 20:15:47 +00002174 for (i = 0; i < attre->ecommunity->size; i++)
hasso4372df72004-05-20 10:20:02 +00002175 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002176 pnt = attre->ecommunity->val + (i * 8);
hasso4372df72004-05-20 10:20:02 +00002177 tbit = *pnt;
2178
2179 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2180 continue;
2181
2182 stream_put (s, pnt, 8);
2183 }
2184 }
paul718e3742002-12-13 20:15:29 +00002185 }
paul718e3742002-12-13 20:15:29 +00002186 }
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002187
2188 if ( send_as4_path )
2189 {
2190 /* If the peer is NOT As4 capable, AND */
2191 /* there are ASnums > 65535 in path THEN
2192 * give out AS4_PATH */
2193
2194 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2195 * path segments!
2196 * Hm, I wonder... confederation things *should* only be at
2197 * the beginning of an aspath, right? Then we should use
2198 * aspath_delete_confed_seq for this, because it is already
2199 * there! (JK)
2200 * Folks, talk to me: what is reasonable here!?
2201 */
2202 aspath = aspath_delete_confed_seq (aspath);
2203
2204 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2205 stream_putc (s, BGP_ATTR_AS4_PATH);
2206 aspath_sizep = stream_get_endp (s);
2207 stream_putw (s, 0);
2208 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2209 }
2210
2211 if (aspath != attr->aspath)
2212 aspath_free (aspath);
2213
2214 if ( send_as4_aggregator )
2215 {
2216 assert (attr->extra);
2217
2218 /* send AS4_AGGREGATOR, at this place */
2219 /* this section of code moved here in order to ensure the correct
2220 * *ascending* order of attributes
2221 */
2222 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2223 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2224 stream_putc (s, 8);
2225 stream_putl (s, attr->extra->aggregator_as);
2226 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2227 }
Paul Jakma41367172007-08-06 15:24:51 +00002228
2229 /* AS-Pathlimit */
2230 if (attr->pathlimit.ttl)
2231 {
2232 u_int32_t as = attr->pathlimit.as;
2233
2234 /* should already have been done in announce_check(),
2235 * but just in case..
2236 */
2237 if (!as)
2238 as = peer->local_as;
2239
2240 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2241 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2242 stream_putc (s, 5);
2243 stream_putc (s, attr->pathlimit.ttl);
2244 stream_putl (s, as);
2245 }
2246
paul718e3742002-12-13 20:15:29 +00002247 /* Unknown transit attribute. */
Paul Jakmafb982c22007-05-04 20:15:47 +00002248 if (attr->extra && attr->extra->transit)
2249 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
paul718e3742002-12-13 20:15:29 +00002250
2251 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002252 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002253}
2254
2255bgp_size_t
2256bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2257 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00002258 u_char *tag)
paul718e3742002-12-13 20:15:29 +00002259{
2260 unsigned long cp;
2261 unsigned long attrlen_pnt;
2262 bgp_size_t size;
2263
paul9985f832005-02-09 15:51:56 +00002264 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002265
2266 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2267 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2268
paul9985f832005-02-09 15:51:56 +00002269 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002270 stream_putc (s, 0); /* Length of this attribute. */
2271
2272 stream_putw (s, family2afi (p->family));
2273
2274 if (safi == SAFI_MPLS_VPN)
2275 {
2276 /* SAFI */
2277 stream_putc (s, BGP_SAFI_VPNV4);
2278
2279 /* prefix. */
2280 stream_putc (s, p->prefixlen + 88);
2281 stream_put (s, tag, 3);
2282 stream_put (s, prd->val, 8);
2283 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2284 }
2285 else
2286 {
2287 /* SAFI */
2288 stream_putc (s, safi);
2289
2290 /* prefix */
2291 stream_put_prefix (s, p);
2292 }
2293
2294 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002295 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00002296 stream_putc_at (s, attrlen_pnt, size);
2297
paul9985f832005-02-09 15:51:56 +00002298 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00002299}
2300
2301/* Initialization of attribute. */
2302void
paulfe69a502005-09-10 16:55:02 +00002303bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00002304{
2305 void attrhash_init ();
2306
2307 aspath_init ();
2308 attrhash_init ();
2309 community_init ();
2310 ecommunity_init ();
2311 cluster_init ();
2312 transit_init ();
2313}
2314
2315/* Make attribute packet. */
2316void
paula3845922003-10-18 01:30:50 +00002317bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2318 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00002319{
2320 unsigned long cp;
2321 unsigned long len;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002322 size_t aspath_lenp;
paul718e3742002-12-13 20:15:29 +00002323 struct aspath *aspath;
2324
2325 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00002326 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00002327
2328 /* Place holder of length. */
2329 stream_putw (s, 0);
2330
2331 /* Origin attribute. */
2332 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2333 stream_putc (s, BGP_ATTR_ORIGIN);
2334 stream_putc (s, 1);
2335 stream_putc (s, attr->origin);
2336
2337 aspath = attr->aspath;
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002338
2339 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2340 stream_putc (s, BGP_ATTR_AS_PATH);
2341 aspath_lenp = stream_get_endp (s);
2342 stream_putw (s, 0);
2343
2344 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
paul718e3742002-12-13 20:15:29 +00002345
2346 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00002347 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2348 if(prefix != NULL
2349#ifdef HAVE_IPV6
2350 && prefix->family != AF_INET6
2351#endif /* HAVE_IPV6 */
2352 )
2353 {
2354 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2355 stream_putc (s, BGP_ATTR_NEXT_HOP);
2356 stream_putc (s, 4);
2357 stream_put_ipv4 (s, attr->nexthop.s_addr);
2358 }
paul718e3742002-12-13 20:15:29 +00002359
2360 /* MED attribute. */
2361 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2362 {
2363 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2364 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2365 stream_putc (s, 4);
2366 stream_putl (s, attr->med);
2367 }
2368
2369 /* Local preference. */
2370 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2371 {
2372 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2373 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2374 stream_putc (s, 4);
2375 stream_putl (s, attr->local_pref);
2376 }
2377
2378 /* Atomic aggregate. */
2379 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2380 {
2381 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2382 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2383 stream_putc (s, 0);
2384 }
2385
2386 /* Aggregator. */
2387 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2388 {
Paul Jakmafb982c22007-05-04 20:15:47 +00002389 assert (attr->extra);
paul718e3742002-12-13 20:15:29 +00002390 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2391 stream_putc (s, BGP_ATTR_AGGREGATOR);
Paul Jakma0b2aa3a2007-10-14 22:32:21 +00002392 stream_putc (s, 8);
2393 stream_putl (s, attr->extra->aggregator_as);
Paul Jakmafb982c22007-05-04 20:15:47 +00002394 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
paul718e3742002-12-13 20:15:29 +00002395 }
2396
2397 /* Community attribute. */
2398 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2399 {
2400 if (attr->community->size * 4 > 255)
2401 {
2402 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2403 stream_putc (s, BGP_ATTR_COMMUNITIES);
2404 stream_putw (s, attr->community->size * 4);
2405 }
2406 else
2407 {
2408 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2409 stream_putc (s, BGP_ATTR_COMMUNITIES);
2410 stream_putc (s, attr->community->size * 4);
2411 }
2412 stream_put (s, attr->community->val, attr->community->size * 4);
2413 }
2414
paula3845922003-10-18 01:30:50 +00002415#ifdef HAVE_IPV6
2416 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002417 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2418 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
paula3845922003-10-18 01:30:50 +00002419 {
2420 int sizep;
Paul Jakmafb982c22007-05-04 20:15:47 +00002421 struct attr_extra *attre = attr->extra;
2422
paula3845922003-10-18 01:30:50 +00002423 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2424 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00002425 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00002426
2427 /* MP header */
Paul Jakmafb982c22007-05-04 20:15:47 +00002428 stream_putc (s, 0); /* Marker: Attribute length. */
paula3845922003-10-18 01:30:50 +00002429 stream_putw(s, AFI_IP6); /* AFI */
2430 stream_putc(s, SAFI_UNICAST); /* SAFI */
2431
2432 /* Next hop */
Paul Jakmafb982c22007-05-04 20:15:47 +00002433 stream_putc(s, attre->mp_nexthop_len);
2434 stream_put(s, &attre->mp_nexthop_global, 16);
2435 if (attre->mp_nexthop_len == 32)
2436 stream_put(s, &attre->mp_nexthop_local, 16);
paula3845922003-10-18 01:30:50 +00002437
2438 /* SNPA */
2439 stream_putc(s, 0);
2440
2441 /* Prefix */
2442 stream_put_prefix(s, prefix);
2443
2444 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00002445 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00002446 }
2447#endif /* HAVE_IPV6 */
2448
Paul Jakma41367172007-08-06 15:24:51 +00002449 /* AS-Pathlimit */
2450 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2451 {
2452 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2453 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2454 stream_putc (s, 5);
2455 stream_putc (s, attr->pathlimit.ttl);
2456 stream_putl (s, attr->pathlimit.as);
2457 }
2458
paul718e3742002-12-13 20:15:29 +00002459 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00002460 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00002461 stream_putw_at (s, cp, len);
2462}