blob: fc25d213079eacaa90f42f55295f1d1d73d00d82 [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" },
59 { 0, NULL }
60};
Paul Jakma6e4ab122007-04-10 19:36:48 +000061int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
paul718e3742002-12-13 20:15:29 +000062
63struct hash *cluster_hash;
64
paul94f2b392005-06-28 12:44:16 +000065static void *
paul718e3742002-12-13 20:15:29 +000066cluster_hash_alloc (struct cluster_list *val)
67{
68 struct cluster_list *cluster;
69
70 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
71 cluster->length = val->length;
72
73 if (cluster->length)
74 {
75 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
76 memcpy (cluster->list, val->list, val->length);
77 }
78 else
79 cluster->list = NULL;
80
81 cluster->refcnt = 0;
82
83 return cluster;
84}
85
86/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000087static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000088cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000089{
90 struct cluster_list tmp;
91 struct cluster_list *cluster;
92
93 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000094 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +000095
96 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
97 cluster->refcnt++;
98 return cluster;
99}
100
101int
102cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
103{
104 int i;
105
106 for (i = 0; i < cluster->length / 4; i++)
107 if (cluster->list[i].s_addr == originator.s_addr)
108 return 1;
109 return 0;
110}
111
paul94f2b392005-06-28 12:44:16 +0000112static unsigned int
paul718e3742002-12-13 20:15:29 +0000113cluster_hash_key_make (struct cluster_list *cluster)
114{
115 unsigned int key = 0;
116 int length;
117 caddr_t pnt;
118
119 length = cluster->length;
120 pnt = (caddr_t) cluster->list;
121
122 while (length)
123 key += pnt[--length];
124
125 return key;
126}
127
paul94f2b392005-06-28 12:44:16 +0000128static int
paul718e3742002-12-13 20:15:29 +0000129cluster_hash_cmp (struct cluster_list *cluster1, struct cluster_list *cluster2)
130{
131 if (cluster1->length == cluster2->length &&
132 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0)
133 return 1;
134 return 0;
135}
136
paul94f2b392005-06-28 12:44:16 +0000137static void
paul718e3742002-12-13 20:15:29 +0000138cluster_free (struct cluster_list *cluster)
139{
140 if (cluster->list)
141 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
142 XFREE (MTYPE_CLUSTER, cluster);
143}
144
paul94f2b392005-06-28 12:44:16 +0000145static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000146cluster_dup (struct cluster_list *cluster)
147{
148 struct cluster_list *new;
149
150 new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
151 memset (new, 0, sizeof (struct cluster_list));
152 new->length = cluster->length;
153
154 if (cluster->length)
155 {
156 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
157 memcpy (new->list, cluster->list, cluster->length);
158 }
159 else
160 new->list = NULL;
161
162 return new;
163}
164
paul94f2b392005-06-28 12:44:16 +0000165static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000166cluster_intern (struct cluster_list *cluster)
167{
168 struct cluster_list *find;
169
170 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
171 find->refcnt++;
172
173 return find;
174}
175
176void
177cluster_unintern (struct cluster_list *cluster)
178{
179 struct cluster_list *ret;
180
181 if (cluster->refcnt)
182 cluster->refcnt--;
183
184 if (cluster->refcnt == 0)
185 {
186 ret = hash_release (cluster_hash, cluster);
187 cluster_free (cluster);
188 }
189}
190
paul94f2b392005-06-28 12:44:16 +0000191static void
192cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000193{
194 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
195}
196
197/* Unknown transit attribute. */
198struct hash *transit_hash;
199
paul94f2b392005-06-28 12:44:16 +0000200static void
paul718e3742002-12-13 20:15:29 +0000201transit_free (struct transit *transit)
202{
203 if (transit->val)
204 XFREE (MTYPE_TRANSIT_VAL, transit->val);
205 XFREE (MTYPE_TRANSIT, transit);
206}
207
paul94f2b392005-06-28 12:44:16 +0000208static void *
paul718e3742002-12-13 20:15:29 +0000209transit_hash_alloc (struct transit *transit)
210{
211 /* Transit structure is already allocated. */
212 return transit;
213}
214
paul94f2b392005-06-28 12:44:16 +0000215static struct transit *
paul718e3742002-12-13 20:15:29 +0000216transit_intern (struct transit *transit)
217{
218 struct transit *find;
219
220 find = hash_get (transit_hash, transit, transit_hash_alloc);
221 if (find != transit)
222 transit_free (transit);
223 find->refcnt++;
224
225 return find;
226}
227
228void
229transit_unintern (struct transit *transit)
230{
231 struct transit *ret;
232
233 if (transit->refcnt)
234 transit->refcnt--;
235
236 if (transit->refcnt == 0)
237 {
238 ret = hash_release (transit_hash, transit);
239 transit_free (transit);
240 }
241}
242
paul94f2b392005-06-28 12:44:16 +0000243static unsigned int
paul718e3742002-12-13 20:15:29 +0000244transit_hash_key_make (struct transit *transit)
245{
246 unsigned int key = 0;
247 int length;
248 caddr_t pnt;
249
250 length = transit->length;
251 pnt = (caddr_t) transit->val;
252
253 while (length)
254 key += pnt[--length];
255
256 return key;
257}
258
paul94f2b392005-06-28 12:44:16 +0000259static int
paul718e3742002-12-13 20:15:29 +0000260transit_hash_cmp (struct transit *transit1, struct transit *transit2)
261{
262 if (transit1->length == transit2->length &&
263 memcmp (transit1->val, transit2->val, transit1->length) == 0)
264 return 1;
265 return 0;
266}
267
paul94f2b392005-06-28 12:44:16 +0000268static void
paul718e3742002-12-13 20:15:29 +0000269transit_init ()
270{
271 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
272}
273
274/* Attribute hash routines. */
275
276struct hash *attrhash;
277
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000278unsigned long int
279attr_count (void)
280{
281 return attrhash->count;
282}
283
284unsigned long int
285attr_unknown_count (void)
286{
287 return transit_hash->count;
288}
289
paul718e3742002-12-13 20:15:29 +0000290unsigned int
291attrhash_key_make (struct attr *attr)
292{
293 unsigned int key = 0;
294
295 key += attr->origin;
296 key += attr->nexthop.s_addr;
297 key += attr->med;
298 key += attr->local_pref;
299 key += attr->aggregator_as;
300 key += attr->aggregator_addr.s_addr;
301 key += attr->weight;
302
303 key += attr->mp_nexthop_global_in.s_addr;
304 if (attr->aspath)
305 key += aspath_key_make (attr->aspath);
306 if (attr->community)
307 key += community_hash_make (attr->community);
308 if (attr->ecommunity)
309 key += ecommunity_hash_make (attr->ecommunity);
310 if (attr->cluster)
311 key += cluster_hash_key_make (attr->cluster);
312 if (attr->transit)
313 key += transit_hash_key_make (attr->transit);
314
315#ifdef HAVE_IPV6
316 {
317 int i;
318
319 key += attr->mp_nexthop_len;
320 for (i = 0; i < 16; i++)
321 key += attr->mp_nexthop_global.s6_addr[i];
322 for (i = 0; i < 16; i++)
323 key += attr->mp_nexthop_local.s6_addr[i];
324 }
325#endif /* HAVE_IPV6 */
326
327 return key;
328}
329
330int
331attrhash_cmp (struct attr *attr1, struct attr *attr2)
332{
333 if (attr1->flag == attr2->flag
334 && attr1->origin == attr2->origin
335 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
336 && attr1->med == attr2->med
337 && attr1->local_pref == attr2->local_pref
338 && attr1->aggregator_as == attr2->aggregator_as
339 && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr
340 && attr1->weight == attr2->weight
341#ifdef HAVE_IPV6
342 && attr1->mp_nexthop_len == attr2->mp_nexthop_len
343 && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global)
344 && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local)
345#endif /* HAVE_IPV6 */
346 && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in)
347 && attr1->aspath == attr2->aspath
348 && attr1->community == attr2->community
349 && attr1->ecommunity == attr2->ecommunity
350 && attr1->cluster == attr2->cluster
351 && attr1->transit == attr2->transit)
352 return 1;
353 else
354 return 0;
355}
356
paul94f2b392005-06-28 12:44:16 +0000357static void
paul718e3742002-12-13 20:15:29 +0000358attrhash_init ()
359{
360 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
361}
362
paul94f2b392005-06-28 12:44:16 +0000363static void
paul718e3742002-12-13 20:15:29 +0000364attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
365{
366 struct attr *attr = backet->data;
367
368 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
369 inet_ntoa (attr->nexthop), VTY_NEWLINE);
370}
371
372void
373attr_show_all (struct vty *vty)
374{
375 hash_iterate (attrhash,
376 (void (*)(struct hash_backet *, void *))
377 attr_show_all_iterator,
378 vty);
379}
380
paul94f2b392005-06-28 12:44:16 +0000381static void *
paul718e3742002-12-13 20:15:29 +0000382bgp_attr_hash_alloc (struct attr *val)
383{
384 struct attr *attr;
385
386 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
387 *attr = *val;
388 attr->refcnt = 0;
389 return attr;
390}
391
392/* Internet argument attribute. */
393struct attr *
394bgp_attr_intern (struct attr *attr)
395{
396 struct attr *find;
397
398 /* Intern referenced strucutre. */
399 if (attr->aspath)
400 {
401 if (! attr->aspath->refcnt)
402 attr->aspath = aspath_intern (attr->aspath);
403 else
404 attr->aspath->refcnt++;
405 }
406 if (attr->community)
407 {
408 if (! attr->community->refcnt)
409 attr->community = community_intern (attr->community);
410 else
411 attr->community->refcnt++;
412 }
413 if (attr->ecommunity)
414 {
415 if (! attr->ecommunity->refcnt)
416 attr->ecommunity = ecommunity_intern (attr->ecommunity);
417 else
418 attr->ecommunity->refcnt++;
419 }
420 if (attr->cluster)
421 {
422 if (! attr->cluster->refcnt)
423 attr->cluster = cluster_intern (attr->cluster);
424 else
425 attr->cluster->refcnt++;
426 }
427 if (attr->transit)
428 {
429 if (! attr->transit->refcnt)
430 attr->transit = transit_intern (attr->transit);
431 else
432 attr->transit->refcnt++;
433 }
434
435 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
436 find->refcnt++;
437
438 return find;
439}
440
441/* Make network statement's attribute. */
442struct attr *
443bgp_attr_default_set (struct attr *attr, u_char origin)
444{
445 memset (attr, 0, sizeof (struct attr));
446
447 attr->origin = origin;
448 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
449 attr->aspath = aspath_empty ();
450 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
451 attr->weight = 32768;
452 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
453#ifdef HAVE_IPV6
454 attr->mp_nexthop_len = 16;
455#endif
456 return attr;
457}
458
459/* Make network statement's attribute. */
460struct attr *
461bgp_attr_default_intern (u_char origin)
462{
463 struct attr attr;
464 struct attr *new;
465
466 memset (&attr, 0, sizeof (struct attr));
467
468 attr.origin = origin;
469 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
470 attr.aspath = aspath_empty ();
471 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
472 attr.weight = 32768;
473 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
474#ifdef HAVE_IPV6
475 attr.mp_nexthop_len = 16;
476#endif
477
478 new = bgp_attr_intern (&attr);
479 aspath_unintern (new->aspath);
480 return new;
481}
482
483struct attr *
484bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
485 struct aspath *aspath,
486 struct community *community, int as_set)
487{
488 struct attr attr;
489 struct attr *new;
490
491 memset (&attr, 0, sizeof (struct attr));
492
493 /* Origin attribute. */
494 attr.origin = origin;
495 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
496
497 /* AS path attribute. */
498 if (aspath)
499 attr.aspath = aspath_intern (aspath);
500 else
501 attr.aspath = aspath_empty ();
502 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
503
504 /* Next hop attribute. */
505 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
506
507 if (community)
508 {
509 attr.community = community;
510 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
511 }
512
513 attr.weight = 32768;
514#ifdef HAVE_IPV6
515 attr.mp_nexthop_len = 16;
516#endif
517 if (! as_set)
518 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
519 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
520 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
521 attr.aggregator_as = bgp->confed_id;
522 else
523 attr.aggregator_as = bgp->as;
524 attr.aggregator_addr = bgp->router_id;
525
526 new = bgp_attr_intern (&attr);
527 aspath_unintern (new->aspath);
528 return new;
529}
530
531/* Free bgp attribute and aspath. */
532void
533bgp_attr_unintern (struct attr *attr)
534{
535 struct attr *ret;
536 struct aspath *aspath;
537 struct community *community;
538 struct ecommunity *ecommunity;
539 struct cluster_list *cluster;
540 struct transit *transit;
541
542 /* Decrement attribute reference. */
543 attr->refcnt--;
544 aspath = attr->aspath;
545 community = attr->community;
546 ecommunity = attr->ecommunity;
547 cluster = attr->cluster;
548 transit = attr->transit;
549
550 /* If reference becomes zero then free attribute object. */
551 if (attr->refcnt == 0)
552 {
553 ret = hash_release (attrhash, attr);
554 assert (ret != NULL);
555 XFREE (MTYPE_ATTR, attr);
556 }
557
558 /* aspath refcount shoud be decrement. */
559 if (aspath)
560 aspath_unintern (aspath);
561 if (community)
562 community_unintern (community);
563 if (ecommunity)
564 ecommunity_unintern (ecommunity);
565 if (cluster)
566 cluster_unintern (cluster);
567 if (transit)
568 transit_unintern (transit);
569}
570
571void
572bgp_attr_flush (struct attr *attr)
573{
574 if (attr->aspath && ! attr->aspath->refcnt)
575 aspath_free (attr->aspath);
576 if (attr->community && ! attr->community->refcnt)
577 community_free (attr->community);
578 if (attr->ecommunity && ! attr->ecommunity->refcnt)
579 ecommunity_free (attr->ecommunity);
580 if (attr->cluster && ! attr->cluster->refcnt)
581 cluster_free (attr->cluster);
582 if (attr->transit && ! attr->transit->refcnt)
583 transit_free (attr->transit);
584}
585
586/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000587static int
paul718e3742002-12-13 20:15:29 +0000588bgp_attr_origin (struct peer *peer, bgp_size_t length,
589 struct attr *attr, u_char flag, u_char *startp)
590{
591 bgp_size_t total;
592
593 /* total is entire attribute length include Attribute Flags (1),
594 Attribute Type code (1) and Attribute length (1 or 2). */
595 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
596
597 /* If any recognized attribute has Attribute Flags that conflict
598 with the Attribute Type Code, then the Error Subcode is set to
599 Attribute Flags Error. The Data field contains the erroneous
600 attribute (type, length and value). */
601 if (flag != BGP_ATTR_FLAG_TRANS)
602 {
603 zlog (peer->log, LOG_ERR,
604 "Origin attribute flag isn't transitive %d", flag);
605 bgp_notify_send_with_data (peer,
606 BGP_NOTIFY_UPDATE_ERR,
607 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
608 startp, total);
609 return -1;
610 }
611
612 /* If any recognized attribute has Attribute Length that conflicts
613 with the expected length (based on the attribute type code), then
614 the Error Subcode is set to Attribute Length Error. The Data
615 field contains the erroneous attribute (type, length and
616 value). */
617 if (length != 1)
618 {
619 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
620 length);
621 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
622 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
623 startp, total);
624 return -1;
625 }
626
627 /* Fetch origin attribute. */
628 attr->origin = stream_getc (BGP_INPUT (peer));
629
630 /* If the ORIGIN attribute has an undefined value, then the Error
631 Subcode is set to Invalid Origin Attribute. The Data field
632 contains the unrecognized attribute (type, length and value). */
633 if ((attr->origin != BGP_ORIGIN_IGP)
634 && (attr->origin != BGP_ORIGIN_EGP)
635 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
636 {
637 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
638 attr->origin);
639
640 bgp_notify_send_with_data (peer,
641 BGP_NOTIFY_UPDATE_ERR,
642 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
643 startp, total);
644 return -1;
645 }
646
647 /* Set oring attribute flag. */
648 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
649
650 return 0;
651}
652
653/* Parse AS path information. This function is wrapper of
654 aspath_parse. */
paul94f2b392005-06-28 12:44:16 +0000655static int
paul718e3742002-12-13 20:15:29 +0000656bgp_attr_aspath (struct peer *peer, bgp_size_t length,
657 struct attr *attr, u_char flag, u_char *startp)
658{
659 struct bgp *bgp;
660 struct aspath *aspath;
661 bgp_size_t total;
662
663 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
664
665 /* Flag check. */
666 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
667 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
668 {
669 zlog (peer->log, LOG_ERR,
670 "Origin attribute flag isn't transitive %d", flag);
671 bgp_notify_send_with_data (peer,
672 BGP_NOTIFY_UPDATE_ERR,
673 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
674 startp, total);
675 return -1;
676 }
677
678 /* In case of IBGP, length will be zero. */
paulfe69a502005-09-10 16:55:02 +0000679 attr->aspath = aspath_parse (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000680 if (! attr->aspath)
681 {
682 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
683 bgp_notify_send (peer,
684 BGP_NOTIFY_UPDATE_ERR,
685 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
686 return -1;
687 }
688
689 bgp = peer->bgp;
690
691 /* First AS check for EBGP. */
692 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
693 {
694 if (peer_sort (peer) == BGP_PEER_EBGP
695 && ! aspath_firstas_check (attr->aspath, peer->as))
696 {
697 zlog (peer->log, LOG_ERR,
698 "%s incorrect first AS (must be %d)", peer->host, peer->as);
699 bgp_notify_send (peer,
700 BGP_NOTIFY_UPDATE_ERR,
701 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
702 return -1;
703 }
704 }
705
706 /* local-as prepend */
707 if (peer->change_local_as &&
708 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
709 {
710 aspath = aspath_dup (attr->aspath);
711 aspath = aspath_add_seq (aspath, peer->change_local_as);
712 aspath_unintern (attr->aspath);
713 attr->aspath = aspath_intern (aspath);
714 }
715
716 /* Forward pointer. */
paulfe69a502005-09-10 16:55:02 +0000717/* stream_forward_getp (peer->ibuf, length);*/
paul718e3742002-12-13 20:15:29 +0000718
719 /* Set aspath attribute flag. */
720 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
721
722 return 0;
723}
724
725/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000726static int
paul718e3742002-12-13 20:15:29 +0000727bgp_attr_nexthop (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 = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
733
734 /* Flag check. */
735 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
736 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
737 {
738 zlog (peer->log, LOG_ERR,
739 "Origin attribute flag isn't transitive %d", flag);
740 bgp_notify_send_with_data (peer,
741 BGP_NOTIFY_UPDATE_ERR,
742 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
743 startp, total);
744 return -1;
745 }
746
747 /* Check nexthop attribute length. */
748 if (length != 4)
749 {
750 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
751 length);
752
753 bgp_notify_send_with_data (peer,
754 BGP_NOTIFY_UPDATE_ERR,
755 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
756 startp, total);
757 return -1;
758 }
759
760 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
761 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
762
763 return 0;
764}
765
766/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000767static int
paul718e3742002-12-13 20:15:29 +0000768bgp_attr_med (struct peer *peer, bgp_size_t length,
769 struct attr *attr, u_char flag, u_char *startp)
770{
771 bgp_size_t total;
772
773 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
774
775 /* Length check. */
776 if (length != 4)
777 {
778 zlog (peer->log, LOG_ERR,
779 "MED attribute length isn't four [%d]", length);
780
781 bgp_notify_send_with_data (peer,
782 BGP_NOTIFY_UPDATE_ERR,
783 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
784 startp, total);
785 return -1;
786 }
787
788 attr->med = stream_getl (peer->ibuf);
789
790 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
791
792 return 0;
793}
794
795/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000796static int
paul718e3742002-12-13 20:15:29 +0000797bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
798 struct attr *attr, u_char flag)
799{
800 /* If it is contained in an UPDATE message that is received from an
801 external peer, then this attribute MUST be ignored by the
802 receiving speaker. */
803 if (peer_sort (peer) == BGP_PEER_EBGP)
804 {
paul9985f832005-02-09 15:51:56 +0000805 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000806 return 0;
807 }
808
809 if (length == 4)
810 attr->local_pref = stream_getl (peer->ibuf);
811 else
812 attr->local_pref = 0;
813
814 /* Set atomic aggregate flag. */
815 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
816
817 return 0;
818}
819
820/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000821static int
paul718e3742002-12-13 20:15:29 +0000822bgp_attr_atomic (struct peer *peer, bgp_size_t length,
823 struct attr *attr, u_char flag)
824{
825 if (length != 0)
826 {
827 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
828
829 bgp_notify_send (peer,
830 BGP_NOTIFY_UPDATE_ERR,
831 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
832 return -1;
833 }
834
835 /* Set atomic aggregate flag. */
836 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
837
838 return 0;
839}
840
841/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +0000842static int
paul718e3742002-12-13 20:15:29 +0000843bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
844 struct attr *attr, u_char flag)
845{
846 if (length != 6)
847 {
848 zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length);
849
850 bgp_notify_send (peer,
851 BGP_NOTIFY_UPDATE_ERR,
852 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
853 return -1;
854 }
855 attr->aggregator_as = stream_getw (peer->ibuf);
856 attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
857
858 /* Set atomic aggregate flag. */
859 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
860
861 return 0;
862}
863
864/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +0000865static int
paul718e3742002-12-13 20:15:29 +0000866bgp_attr_community (struct peer *peer, bgp_size_t length,
867 struct attr *attr, u_char flag)
868{
869 if (length == 0)
870 attr->community = NULL;
871 else
872 {
paul5228ad22004-06-04 17:58:18 +0000873 attr->community =
874 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +0000875 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000876 }
877
878 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
879
880 return 0;
881}
882
883/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +0000884static int
paul718e3742002-12-13 20:15:29 +0000885bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
886 struct attr *attr, u_char flag)
887{
888 if (length != 4)
889 {
890 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
891
892 bgp_notify_send (peer,
893 BGP_NOTIFY_UPDATE_ERR,
894 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
895 return -1;
896 }
897
898 attr->originator_id.s_addr = stream_get_ipv4 (peer->ibuf);
899
900 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
901
902 return 0;
903}
904
905/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +0000906static int
paul718e3742002-12-13 20:15:29 +0000907bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
908 struct attr *attr, u_char flag)
909{
910 /* Check length. */
911 if (length % 4)
912 {
913 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
914
915 bgp_notify_send (peer,
916 BGP_NOTIFY_UPDATE_ERR,
917 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
918 return -1;
919 }
920
paul5228ad22004-06-04 17:58:18 +0000921 attr->cluster = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf),
922 length);
paul718e3742002-12-13 20:15:29 +0000923
paul9985f832005-02-09 15:51:56 +0000924 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +0000925
926 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
927
928 return 0;
929}
930
931/* Multiprotocol reachability information parse. */
paul94f2b392005-06-28 12:44:16 +0000932static int
paul718e3742002-12-13 20:15:29 +0000933bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
934 struct bgp_nlri *mp_update)
935{
936 u_int16_t afi;
937 u_char safi;
paul718e3742002-12-13 20:15:29 +0000938 bgp_size_t nlri_len;
Paul Jakma6e4ab122007-04-10 19:36:48 +0000939 size_t start;
paul718e3742002-12-13 20:15:29 +0000940 int ret;
941 struct stream *s;
942
943 /* Set end of packet. */
Paul Jakma6e4ab122007-04-10 19:36:48 +0000944 s = BGP_INPUT(peer);
945 start = stream_get_getp(s);
946
947 /* safe to read statically sized header? */
948#define BGP_MP_REACH_MIN_SIZE 5
949 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
950 return -1;
951
paul718e3742002-12-13 20:15:29 +0000952 /* Load AFI, SAFI. */
953 afi = stream_getw (s);
954 safi = stream_getc (s);
955
956 /* Get nexthop length. */
957 attr->mp_nexthop_len = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +0000958
959 if (STREAM_READABLE(s) < attr->mp_nexthop_len)
960 return -1;
961
paul718e3742002-12-13 20:15:29 +0000962 /* Nexthop length check. */
963 switch (attr->mp_nexthop_len)
964 {
965 case 4:
966 stream_get (&attr->mp_nexthop_global_in, s, 4);
967 break;
968 case 12:
969 {
970 u_int32_t rd_high;
971 u_int32_t rd_low;
972
973 rd_high = stream_getl (s);
974 rd_low = stream_getl (s);
975 stream_get (&attr->mp_nexthop_global_in, s, 4);
976 }
977 break;
978#ifdef HAVE_IPV6
979 case 16:
980 stream_get (&attr->mp_nexthop_global, s, 16);
981 break;
982 case 32:
983 stream_get (&attr->mp_nexthop_global, s, 16);
984 stream_get (&attr->mp_nexthop_local, s, 16);
985 if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local))
986 {
987 char buf1[INET6_ADDRSTRLEN];
988 char buf2[INET6_ADDRSTRLEN];
989
990 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +0000991 zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
paul718e3742002-12-13 20:15:29 +0000992 inet_ntop (AF_INET6, &attr->mp_nexthop_global,
993 buf1, INET6_ADDRSTRLEN),
994 inet_ntop (AF_INET6, &attr->mp_nexthop_local,
995 buf2, INET6_ADDRSTRLEN));
996
997 attr->mp_nexthop_len = 16;
998 }
999 break;
1000#endif /* HAVE_IPV6 */
1001 default:
1002 zlog_info ("Wrong multiprotocol next hop length: %d",
1003 attr->mp_nexthop_len);
1004 return -1;
paul718e3742002-12-13 20:15:29 +00001005 }
1006
Paul Jakma6e4ab122007-04-10 19:36:48 +00001007 if (!STREAM_READABLE(s))
1008 return -1;
paul718e3742002-12-13 20:15:29 +00001009
Paul Jakma6e4ab122007-04-10 19:36:48 +00001010 {
1011 u_char val;
1012 if ((val = stream_getc (s)))
1013 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1014 peer->host, val);
1015 }
1016
1017 /* must have nrli_len, what is left of the attribute */
1018 nlri_len = length - (stream_get_getp(s) - start);
1019 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
1020 return -1;
paul718e3742002-12-13 20:15:29 +00001021
1022 if (safi != BGP_SAFI_VPNV4)
1023 {
1024 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1025 if (ret < 0)
1026 return -1;
1027 }
1028
1029 mp_update->afi = afi;
1030 mp_update->safi = safi;
1031 mp_update->nlri = stream_pnt (s);
1032 mp_update->length = nlri_len;
1033
paul9985f832005-02-09 15:51:56 +00001034 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001035
1036 return 0;
1037}
1038
1039/* Multiprotocol unreachable parse */
paul94f2b392005-06-28 12:44:16 +00001040static int
Paul Jakma6e4ab122007-04-10 19:36:48 +00001041bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
paul718e3742002-12-13 20:15:29 +00001042 struct bgp_nlri *mp_withdraw)
1043{
1044 struct stream *s;
1045 u_int16_t afi;
1046 u_char safi;
paul718e3742002-12-13 20:15:29 +00001047 u_int16_t withdraw_len;
1048 int ret;
1049
1050 s = peer->ibuf;
Paul Jakma6e4ab122007-04-10 19:36:48 +00001051
1052#define BGP_MP_UNREACH_MIN_SIZE 3
1053 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1054 return -1;
1055
paul718e3742002-12-13 20:15:29 +00001056 afi = stream_getw (s);
1057 safi = stream_getc (s);
Paul Jakma6e4ab122007-04-10 19:36:48 +00001058
1059 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
paul718e3742002-12-13 20:15:29 +00001060
1061 if (safi != BGP_SAFI_VPNV4)
1062 {
1063 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1064 if (ret < 0)
1065 return -1;
1066 }
1067
1068 mp_withdraw->afi = afi;
1069 mp_withdraw->safi = safi;
1070 mp_withdraw->nlri = stream_pnt (s);
1071 mp_withdraw->length = withdraw_len;
1072
paul9985f832005-02-09 15:51:56 +00001073 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001074
1075 return 0;
1076}
1077
1078/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001079static int
paul718e3742002-12-13 20:15:29 +00001080bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1081 struct attr *attr, u_char flag)
1082{
1083 if (length == 0)
1084 attr->ecommunity = NULL;
1085 else
1086 {
paul5228ad22004-06-04 17:58:18 +00001087 attr->ecommunity =
1088 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001089 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001090 }
1091 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1092
1093 return 0;
1094}
1095
1096/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001097static int
paul718e3742002-12-13 20:15:29 +00001098bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1099 u_char type, bgp_size_t length, u_char *startp)
1100{
1101 bgp_size_t total;
1102 struct transit *transit;
1103
hassof4184462005-02-01 20:13:16 +00001104 if (BGP_DEBUG (normal, NORMAL))
1105 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1106 peer->host, type, length);
1107
paul718e3742002-12-13 20:15:29 +00001108 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001109 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001110 "Unknown attribute type %d length %d is received", type, length);
1111
1112 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001113 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001114
1115 /* Adjest total length to include type and length. */
1116 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1117
1118 /* If any of the mandatory well-known attributes are not recognized,
1119 then the Error Subcode is set to Unrecognized Well-known
1120 Attribute. The Data field contains the unrecognized attribute
1121 (type, length and value). */
1122 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1123 {
1124 /* Adjust startp to do not include flag value. */
1125 bgp_notify_send_with_data (peer,
1126 BGP_NOTIFY_UPDATE_ERR,
1127 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1128 startp, total);
1129 return -1;
1130 }
1131
1132 /* Unrecognized non-transitive optional attributes must be quietly
1133 ignored and not passed along to other BGP peers. */
1134 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1135 return 0;
1136
1137 /* If a path with recognized transitive optional attribute is
1138 accepted and passed along to other BGP peers and the Partial bit
1139 in the Attribute Flags octet is set to 1 by some previous AS, it
1140 is not set back to 0 by the current AS. */
1141 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1142
1143 /* Store transitive attribute to the end of attr->transit. */
1144 if (! attr->transit)
1145 {
1146 attr->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1147 memset (attr->transit, 0, sizeof (struct transit));
1148 }
1149
1150 transit = attr->transit;
1151
1152 if (transit->val)
1153 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1154 transit->length + total);
1155 else
1156 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1157
1158 memcpy (transit->val + transit->length, startp, total);
1159 transit->length += total;
1160
1161 return 0;
1162}
1163
1164/* Read attribute of update packet. This function is called from
1165 bgp_update() in bgpd.c. */
1166int
1167bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1168 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1169{
1170 int ret;
1171 u_char flag;
1172 u_char type;
1173 bgp_size_t length;
1174 u_char *startp, *endp;
1175 u_char *attr_endp;
1176 u_char seen[BGP_ATTR_BITMAP_SIZE];
1177
1178 /* Initialize bitmap. */
1179 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1180
1181 /* End pointer of BGP attribute. */
1182 endp = BGP_INPUT_PNT (peer) + size;
1183
1184 /* Get attributes to the end of attribute length. */
1185 while (BGP_INPUT_PNT (peer) < endp)
1186 {
1187 /* Check remaining length check.*/
1188 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1189 {
gdtc29fdba2004-12-09 14:46:46 +00001190 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001191 zlog (peer->log, LOG_WARNING,
paula2b1ecd2004-10-31 18:58:09 +00001192 "%s error BGP attribute length %ld is smaller than min len",
paul718e3742002-12-13 20:15:29 +00001193 peer->host, endp - STREAM_PNT (BGP_INPUT (peer)));
1194
1195 bgp_notify_send (peer,
1196 BGP_NOTIFY_UPDATE_ERR,
1197 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1198 return -1;
1199 }
1200
1201 /* Fetch attribute flag and type. */
1202 startp = BGP_INPUT_PNT (peer);
1203 flag = stream_getc (BGP_INPUT (peer));
1204 type = stream_getc (BGP_INPUT (peer));
1205
1206 /* Check extended attribue length bit. */
1207 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1208 length = stream_getw (BGP_INPUT (peer));
1209 else
1210 length = stream_getc (BGP_INPUT (peer));
1211
1212 /* If any attribute appears more than once in the UPDATE
1213 message, then the Error Subcode is set to Malformed Attribute
1214 List. */
1215
1216 if (CHECK_BITMAP (seen, type))
1217 {
1218 zlog (peer->log, LOG_WARNING,
1219 "%s error BGP attribute type %d appears twice in a message",
1220 peer->host, type);
1221
1222 bgp_notify_send (peer,
1223 BGP_NOTIFY_UPDATE_ERR,
1224 BGP_NOTIFY_UPDATE_MAL_ATTR);
1225 return -1;
1226 }
1227
1228 /* Set type to bitmap to check duplicate attribute. `type' is
1229 unsigned char so it never overflow bitmap range. */
1230
1231 SET_BITMAP (seen, type);
1232
1233 /* Overflow check. */
1234 attr_endp = BGP_INPUT_PNT (peer) + length;
1235
1236 if (attr_endp > endp)
1237 {
1238 zlog (peer->log, LOG_WARNING,
1239 "%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);
1240 bgp_notify_send (peer,
1241 BGP_NOTIFY_UPDATE_ERR,
1242 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1243 return -1;
1244 }
1245
1246 /* OK check attribute and store it's value. */
1247 switch (type)
1248 {
1249 case BGP_ATTR_ORIGIN:
1250 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1251 break;
1252 case BGP_ATTR_AS_PATH:
1253 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1254 break;
1255 case BGP_ATTR_NEXT_HOP:
1256 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1257 break;
1258 case BGP_ATTR_MULTI_EXIT_DISC:
1259 ret = bgp_attr_med (peer, length, attr, flag, startp);
1260 break;
1261 case BGP_ATTR_LOCAL_PREF:
1262 ret = bgp_attr_local_pref (peer, length, attr, flag);
1263 break;
1264 case BGP_ATTR_ATOMIC_AGGREGATE:
1265 ret = bgp_attr_atomic (peer, length, attr, flag);
1266 break;
1267 case BGP_ATTR_AGGREGATOR:
1268 ret = bgp_attr_aggregator (peer, length, attr, flag);
1269 break;
1270 case BGP_ATTR_COMMUNITIES:
1271 ret = bgp_attr_community (peer, length, attr, flag);
1272 break;
1273 case BGP_ATTR_ORIGINATOR_ID:
1274 ret = bgp_attr_originator_id (peer, length, attr, flag);
1275 break;
1276 case BGP_ATTR_CLUSTER_LIST:
1277 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1278 break;
1279 case BGP_ATTR_MP_REACH_NLRI:
1280 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1281 break;
1282 case BGP_ATTR_MP_UNREACH_NLRI:
1283 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1284 break;
1285 case BGP_ATTR_EXT_COMMUNITIES:
1286 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1287 break;
1288 default:
1289 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1290 break;
1291 }
1292
1293 /* If error occured immediately return to the caller. */
1294 if (ret < 0)
Paul Jakma6e4ab122007-04-10 19:36:48 +00001295 {
1296 zlog (peer->log, LOG_WARNING,
1297 "%s: Attribute %s, parse error",
1298 peer->host,
1299 LOOKUP (attr_str, type));
1300 bgp_notify_send (peer,
1301 BGP_NOTIFY_UPDATE_ERR,
1302 BGP_NOTIFY_UPDATE_MAL_ATTR);
1303 return ret;
1304 }
paul718e3742002-12-13 20:15:29 +00001305
1306 /* Check the fetched length. */
1307 if (BGP_INPUT_PNT (peer) != attr_endp)
1308 {
1309 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001310 "%s: BGP attribute %s, fetch error",
1311 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001312 bgp_notify_send (peer,
1313 BGP_NOTIFY_UPDATE_ERR,
1314 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1315 return -1;
1316 }
1317 }
1318
1319 /* Check final read pointer is same as end pointer. */
1320 if (BGP_INPUT_PNT (peer) != endp)
1321 {
1322 zlog (peer->log, LOG_WARNING,
Paul Jakma6e4ab122007-04-10 19:36:48 +00001323 "%s BGP attribute %s, length mismatch",
1324 peer->host, LOOKUP (attr_str, type));
paul718e3742002-12-13 20:15:29 +00001325 bgp_notify_send (peer,
1326 BGP_NOTIFY_UPDATE_ERR,
1327 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1328 return -1;
1329 }
1330
1331 /* Finally intern unknown attribute. */
1332 if (attr->transit)
1333 attr->transit = transit_intern (attr->transit);
1334
1335 return 0;
1336}
1337
1338/* Well-known attribute check. */
1339int
1340bgp_attr_check (struct peer *peer, struct attr *attr)
1341{
1342 u_char type = 0;
1343
1344 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1345 type = BGP_ATTR_ORIGIN;
1346
1347 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1348 type = BGP_ATTR_AS_PATH;
1349
1350 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1351 type = BGP_ATTR_NEXT_HOP;
1352
1353 if (peer_sort (peer) == BGP_PEER_IBGP
1354 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1355 type = BGP_ATTR_LOCAL_PREF;
1356
1357 if (type)
1358 {
1359 zlog (peer->log, LOG_WARNING,
1360 "%s Missing well-known attribute %d.",
1361 peer->host, type);
1362 bgp_notify_send_with_data (peer,
1363 BGP_NOTIFY_UPDATE_ERR,
1364 BGP_NOTIFY_UPDATE_MISS_ATTR,
1365 &type, 1);
1366 return -1;
1367 }
1368 return 0;
1369}
1370
1371int stream_put_prefix (struct stream *, struct prefix *);
1372
1373/* Make attribute packet. */
1374bgp_size_t
1375bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1376 struct stream *s, struct attr *attr, struct prefix *p,
1377 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001378 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001379{
paulfe69a502005-09-10 16:55:02 +00001380 size_t cp;
1381 unsigned int aspath_data_size;
paul718e3742002-12-13 20:15:29 +00001382 struct aspath *aspath;
1383
1384 if (! bgp)
1385 bgp = bgp_get_default ();
1386
1387 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001388 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001389
1390 /* Origin attribute. */
1391 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1392 stream_putc (s, BGP_ATTR_ORIGIN);
1393 stream_putc (s, 1);
1394 stream_putc (s, attr->origin);
1395
1396 /* AS path attribute. */
1397
1398 /* If remote-peer is EBGP */
1399 if (peer_sort (peer) == BGP_PEER_EBGP
1400 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001401 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001402 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001403 {
1404 aspath = aspath_dup (attr->aspath);
1405
1406 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1407 {
1408 /* Strip the confed info, and then stuff our path CONFED_ID
1409 on the front */
1410 aspath = aspath_delete_confed_seq (aspath);
1411 aspath = aspath_add_seq (aspath, bgp->confed_id);
1412 }
1413 else
1414 {
1415 aspath = aspath_add_seq (aspath, peer->local_as);
1416 if (peer->change_local_as)
1417 aspath = aspath_add_seq (aspath, peer->change_local_as);
1418 }
1419 }
1420 else if (peer_sort (peer) == BGP_PEER_CONFED)
1421 {
1422 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1423 aspath = aspath_dup (attr->aspath);
1424 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1425 }
1426 else
1427 aspath = attr->aspath;
1428
1429 /* AS path attribute extended length bit check. */
paulfe69a502005-09-10 16:55:02 +00001430 aspath_data_size = aspath_size (aspath);
1431 if (aspath_data_size > 255)
paul718e3742002-12-13 20:15:29 +00001432 {
1433 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1434 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001435 stream_putw (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001436 }
1437 else
1438 {
1439 stream_putc (s, BGP_ATTR_FLAG_TRANS);
paulfe69a502005-09-10 16:55:02 +00001440 stream_putc (s, BGP_ATTR_AS_PATH);
1441 stream_putc (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001442 }
paulfe69a502005-09-10 16:55:02 +00001443 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001444
1445 if (aspath != attr->aspath)
1446 aspath_free (aspath);
1447
1448 /* Nexthop attribute. */
1449 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1450 {
1451 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1452 stream_putc (s, BGP_ATTR_NEXT_HOP);
1453 stream_putc (s, 4);
1454 if (safi == SAFI_MPLS_VPN)
1455 {
1456 if (attr->nexthop.s_addr == 0)
1457 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1458 else
1459 stream_put_ipv4 (s, attr->nexthop.s_addr);
1460 }
1461 else
1462 stream_put_ipv4 (s, attr->nexthop.s_addr);
1463 }
1464
1465 /* MED attribute. */
1466 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1467 {
1468 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1469 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1470 stream_putc (s, 4);
1471 stream_putl (s, attr->med);
1472 }
1473
1474 /* Local preference. */
1475 if (peer_sort (peer) == BGP_PEER_IBGP ||
1476 peer_sort (peer) == BGP_PEER_CONFED)
1477 {
1478 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1479 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1480 stream_putc (s, 4);
1481 stream_putl (s, attr->local_pref);
1482 }
1483
1484 /* Atomic aggregate. */
1485 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1486 {
1487 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1488 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1489 stream_putc (s, 0);
1490 }
1491
1492 /* Aggregator. */
1493 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1494 {
1495 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1496 stream_putc (s, BGP_ATTR_AGGREGATOR);
1497 stream_putc (s, 6);
1498 stream_putw (s, attr->aggregator_as);
1499 stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
1500 }
1501
1502 /* Community attribute. */
1503 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1504 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1505 {
1506 if (attr->community->size * 4 > 255)
1507 {
1508 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1509 stream_putc (s, BGP_ATTR_COMMUNITIES);
1510 stream_putw (s, attr->community->size * 4);
1511 }
1512 else
1513 {
1514 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1515 stream_putc (s, BGP_ATTR_COMMUNITIES);
1516 stream_putc (s, attr->community->size * 4);
1517 }
1518 stream_put (s, attr->community->val, attr->community->size * 4);
1519 }
1520
1521 /* Route Reflector. */
1522 if (peer_sort (peer) == BGP_PEER_IBGP
1523 && from
1524 && peer_sort (from) == BGP_PEER_IBGP)
1525 {
1526 /* Originator ID. */
1527 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1528 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1529 stream_putc (s, 4);
1530
1531 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
1532 stream_put_in_addr (s, &attr->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001533 else
1534 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001535
1536 /* Cluster list. */
1537 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1538 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1539
1540 if (attr->cluster)
1541 {
1542 stream_putc (s, attr->cluster->length + 4);
1543 /* If this peer configuration's parent BGP has cluster_id. */
1544 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1545 stream_put_in_addr (s, &bgp->cluster_id);
1546 else
1547 stream_put_in_addr (s, &bgp->router_id);
1548 stream_put (s, attr->cluster->list, attr->cluster->length);
1549 }
1550 else
1551 {
1552 stream_putc (s, 4);
1553 /* If this peer configuration's parent BGP has cluster_id. */
1554 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1555 stream_put_in_addr (s, &bgp->cluster_id);
1556 else
1557 stream_put_in_addr (s, &bgp->router_id);
1558 }
1559 }
1560
1561#ifdef HAVE_IPV6
1562 /* If p is IPv6 address put it into attribute. */
1563 if (p->family == AF_INET6)
1564 {
1565 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001566
1567 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1568 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001569 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001570 stream_putc (s, 0); /* Length of this attribute. */
1571 stream_putw (s, AFI_IP6); /* AFI */
1572 stream_putc (s, safi); /* SAFI */
1573
1574 stream_putc (s, attr->mp_nexthop_len);
1575
1576 if (attr->mp_nexthop_len == 16)
1577 stream_put (s, &attr->mp_nexthop_global, 16);
1578 else if (attr->mp_nexthop_len == 32)
1579 {
1580 stream_put (s, &attr->mp_nexthop_global, 16);
1581 stream_put (s, &attr->mp_nexthop_local, 16);
1582 }
1583
1584 /* SNPA */
1585 stream_putc (s, 0);
1586
paul718e3742002-12-13 20:15:29 +00001587 /* Prefix write. */
1588 stream_put_prefix (s, p);
1589
1590 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001591 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001592 }
1593#endif /* HAVE_IPV6 */
1594
1595 if (p->family == AF_INET && safi == SAFI_MULTICAST)
1596 {
1597 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001598
1599 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1600 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001601 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001602 stream_putc (s, 0); /* Length of this attribute. */
1603 stream_putw (s, AFI_IP); /* AFI */
1604 stream_putc (s, SAFI_MULTICAST); /* SAFI */
1605
1606 stream_putc (s, 4);
1607 stream_put_ipv4 (s, attr->nexthop.s_addr);
1608
1609 /* SNPA */
1610 stream_putc (s, 0);
1611
paul718e3742002-12-13 20:15:29 +00001612 /* Prefix write. */
1613 stream_put_prefix (s, p);
1614
1615 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001616 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001617 }
1618
1619 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
1620 {
1621 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001622
1623 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1624 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001625 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001626 stream_putc (s, 0); /* Length of this attribute. */
1627 stream_putw (s, AFI_IP); /* AFI */
1628 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
1629
1630 stream_putc (s, 12);
1631 stream_putl (s, 0);
1632 stream_putl (s, 0);
1633 stream_put (s, &attr->mp_nexthop_global_in, 4);
1634
1635 /* SNPA */
1636 stream_putc (s, 0);
1637
paul718e3742002-12-13 20:15:29 +00001638 /* Tag, RD, Prefix write. */
1639 stream_putc (s, p->prefixlen + 88);
1640 stream_put (s, tag, 3);
1641 stream_put (s, prd->val, 8);
1642 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1643
1644 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001645 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001646 }
1647
1648 /* Extended Communities attribute. */
1649 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
1650 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
1651 {
hasso4372df72004-05-20 10:20:02 +00001652 if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00001653 {
hasso4372df72004-05-20 10:20:02 +00001654 if (attr->ecommunity->size * 8 > 255)
1655 {
1656 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1657 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1658 stream_putw (s, attr->ecommunity->size * 8);
1659 }
1660 else
1661 {
1662 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1663 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1664 stream_putc (s, attr->ecommunity->size * 8);
1665 }
1666 stream_put (s, attr->ecommunity->val, attr->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00001667 }
1668 else
1669 {
paul5228ad22004-06-04 17:58:18 +00001670 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00001671 int tbit;
1672 int ecom_tr_size = 0;
1673 int i;
1674
1675 for (i = 0; i < attr->ecommunity->size; i++)
1676 {
1677 pnt = attr->ecommunity->val + (i * 8);
1678 tbit = *pnt;
1679
1680 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1681 continue;
1682
1683 ecom_tr_size++;
1684 }
1685
1686 if (ecom_tr_size)
1687 {
1688 if (ecom_tr_size * 8 > 255)
1689 {
1690 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1691 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1692 stream_putw (s, ecom_tr_size * 8);
1693 }
1694 else
1695 {
1696 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1697 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1698 stream_putc (s, ecom_tr_size * 8);
1699 }
1700
1701 for (i = 0; i < attr->ecommunity->size; i++)
1702 {
1703 pnt = attr->ecommunity->val + (i * 8);
1704 tbit = *pnt;
1705
1706 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1707 continue;
1708
1709 stream_put (s, pnt, 8);
1710 }
1711 }
paul718e3742002-12-13 20:15:29 +00001712 }
paul718e3742002-12-13 20:15:29 +00001713 }
1714
1715 /* Unknown transit attribute. */
1716 if (attr->transit)
1717 stream_put (s, attr->transit->val, attr->transit->length);
1718
1719 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00001720 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001721}
1722
1723bgp_size_t
1724bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
1725 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001726 u_char *tag)
paul718e3742002-12-13 20:15:29 +00001727{
1728 unsigned long cp;
1729 unsigned long attrlen_pnt;
1730 bgp_size_t size;
1731
paul9985f832005-02-09 15:51:56 +00001732 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001733
1734 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1735 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
1736
paul9985f832005-02-09 15:51:56 +00001737 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001738 stream_putc (s, 0); /* Length of this attribute. */
1739
1740 stream_putw (s, family2afi (p->family));
1741
1742 if (safi == SAFI_MPLS_VPN)
1743 {
1744 /* SAFI */
1745 stream_putc (s, BGP_SAFI_VPNV4);
1746
1747 /* prefix. */
1748 stream_putc (s, p->prefixlen + 88);
1749 stream_put (s, tag, 3);
1750 stream_put (s, prd->val, 8);
1751 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1752 }
1753 else
1754 {
1755 /* SAFI */
1756 stream_putc (s, safi);
1757
1758 /* prefix */
1759 stream_put_prefix (s, p);
1760 }
1761
1762 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001763 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00001764 stream_putc_at (s, attrlen_pnt, size);
1765
paul9985f832005-02-09 15:51:56 +00001766 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001767}
1768
1769/* Initialization of attribute. */
1770void
paulfe69a502005-09-10 16:55:02 +00001771bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00001772{
1773 void attrhash_init ();
1774
1775 aspath_init ();
1776 attrhash_init ();
1777 community_init ();
1778 ecommunity_init ();
1779 cluster_init ();
1780 transit_init ();
1781}
1782
1783/* Make attribute packet. */
1784void
paula3845922003-10-18 01:30:50 +00001785bgp_dump_routes_attr (struct stream *s, struct attr *attr,
1786 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00001787{
1788 unsigned long cp;
1789 unsigned long len;
paulfe69a502005-09-10 16:55:02 +00001790 unsigned int aspathlen;
paul718e3742002-12-13 20:15:29 +00001791 struct aspath *aspath;
1792
1793 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001794 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001795
1796 /* Place holder of length. */
1797 stream_putw (s, 0);
1798
1799 /* Origin attribute. */
1800 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1801 stream_putc (s, BGP_ATTR_ORIGIN);
1802 stream_putc (s, 1);
1803 stream_putc (s, attr->origin);
1804
1805 aspath = attr->aspath;
1806
paulfe69a502005-09-10 16:55:02 +00001807 if ( (aspathlen = aspath_size (aspath)) > 255 )
paul718e3742002-12-13 20:15:29 +00001808 {
1809 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1810 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001811 stream_putw (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001812 }
1813 else
1814 {
1815 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1816 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001817 stream_putc (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001818 }
paulfe69a502005-09-10 16:55:02 +00001819 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001820
1821 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00001822 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
1823 if(prefix != NULL
1824#ifdef HAVE_IPV6
1825 && prefix->family != AF_INET6
1826#endif /* HAVE_IPV6 */
1827 )
1828 {
1829 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1830 stream_putc (s, BGP_ATTR_NEXT_HOP);
1831 stream_putc (s, 4);
1832 stream_put_ipv4 (s, attr->nexthop.s_addr);
1833 }
paul718e3742002-12-13 20:15:29 +00001834
1835 /* MED attribute. */
1836 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1837 {
1838 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1839 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1840 stream_putc (s, 4);
1841 stream_putl (s, attr->med);
1842 }
1843
1844 /* Local preference. */
1845 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
1846 {
1847 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1848 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1849 stream_putc (s, 4);
1850 stream_putl (s, attr->local_pref);
1851 }
1852
1853 /* Atomic aggregate. */
1854 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1855 {
1856 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1857 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1858 stream_putc (s, 0);
1859 }
1860
1861 /* Aggregator. */
1862 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1863 {
1864 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1865 stream_putc (s, BGP_ATTR_AGGREGATOR);
1866 stream_putc (s, 6);
1867 stream_putw (s, attr->aggregator_as);
1868 stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
1869 }
1870
1871 /* Community attribute. */
1872 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
1873 {
1874 if (attr->community->size * 4 > 255)
1875 {
1876 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1877 stream_putc (s, BGP_ATTR_COMMUNITIES);
1878 stream_putw (s, attr->community->size * 4);
1879 }
1880 else
1881 {
1882 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1883 stream_putc (s, BGP_ATTR_COMMUNITIES);
1884 stream_putc (s, attr->community->size * 4);
1885 }
1886 stream_put (s, attr->community->val, attr->community->size * 4);
1887 }
1888
paula3845922003-10-18 01:30:50 +00001889#ifdef HAVE_IPV6
1890 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
1891 if(prefix != NULL && prefix->family == AF_INET6 &&
1892 (attr->mp_nexthop_len == 16 || attr->mp_nexthop_len == 32) )
1893 {
1894 int sizep;
1895
1896 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
1897 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001898 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00001899
1900 /* MP header */
1901 stream_putc (s, 0); /* Length of this attribute. */
1902 stream_putw(s, AFI_IP6); /* AFI */
1903 stream_putc(s, SAFI_UNICAST); /* SAFI */
1904
1905 /* Next hop */
1906 stream_putc(s, attr->mp_nexthop_len);
1907 stream_put(s, &attr->mp_nexthop_global, 16);
1908 if(attr->mp_nexthop_len == 32)
1909 stream_put(s, &attr->mp_nexthop_local, 16);
1910
1911 /* SNPA */
1912 stream_putc(s, 0);
1913
1914 /* Prefix */
1915 stream_put_prefix(s, prefix);
1916
1917 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001918 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00001919 }
1920#endif /* HAVE_IPV6 */
1921
paul718e3742002-12-13 20:15:29 +00001922 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00001923 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00001924 stream_putw_at (s, cp, len);
1925}