blob: 3b27517d7b48d7ca789ffa33699b413cb472eece [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. */
42struct message attr_str [] =
43{
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};
61
62struct hash *cluster_hash;
63
paul94f2b392005-06-28 12:44:16 +000064static void *
paul718e3742002-12-13 20:15:29 +000065cluster_hash_alloc (struct cluster_list *val)
66{
67 struct cluster_list *cluster;
68
69 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
70 cluster->length = val->length;
71
72 if (cluster->length)
73 {
74 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
75 memcpy (cluster->list, val->list, val->length);
76 }
77 else
78 cluster->list = NULL;
79
80 cluster->refcnt = 0;
81
82 return cluster;
83}
84
85/* Cluster list related functions. */
paul94f2b392005-06-28 12:44:16 +000086static struct cluster_list *
paul5228ad22004-06-04 17:58:18 +000087cluster_parse (struct in_addr * pnt, int length)
paul718e3742002-12-13 20:15:29 +000088{
89 struct cluster_list tmp;
90 struct cluster_list *cluster;
91
92 tmp.length = length;
paul5228ad22004-06-04 17:58:18 +000093 tmp.list = pnt;
paul718e3742002-12-13 20:15:29 +000094
95 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
96 cluster->refcnt++;
97 return cluster;
98}
99
100int
101cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
102{
103 int i;
104
105 for (i = 0; i < cluster->length / 4; i++)
106 if (cluster->list[i].s_addr == originator.s_addr)
107 return 1;
108 return 0;
109}
110
paul94f2b392005-06-28 12:44:16 +0000111static unsigned int
paul718e3742002-12-13 20:15:29 +0000112cluster_hash_key_make (struct cluster_list *cluster)
113{
114 unsigned int key = 0;
115 int length;
116 caddr_t pnt;
117
118 length = cluster->length;
119 pnt = (caddr_t) cluster->list;
120
121 while (length)
122 key += pnt[--length];
123
124 return key;
125}
126
paul94f2b392005-06-28 12:44:16 +0000127static int
paul718e3742002-12-13 20:15:29 +0000128cluster_hash_cmp (struct cluster_list *cluster1, struct cluster_list *cluster2)
129{
130 if (cluster1->length == cluster2->length &&
131 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0)
132 return 1;
133 return 0;
134}
135
paul94f2b392005-06-28 12:44:16 +0000136static void
paul718e3742002-12-13 20:15:29 +0000137cluster_free (struct cluster_list *cluster)
138{
139 if (cluster->list)
140 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
141 XFREE (MTYPE_CLUSTER, cluster);
142}
143
paul94f2b392005-06-28 12:44:16 +0000144static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000145cluster_dup (struct cluster_list *cluster)
146{
147 struct cluster_list *new;
148
149 new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
150 memset (new, 0, sizeof (struct cluster_list));
151 new->length = cluster->length;
152
153 if (cluster->length)
154 {
155 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
156 memcpy (new->list, cluster->list, cluster->length);
157 }
158 else
159 new->list = NULL;
160
161 return new;
162}
163
paul94f2b392005-06-28 12:44:16 +0000164static struct cluster_list *
paul718e3742002-12-13 20:15:29 +0000165cluster_intern (struct cluster_list *cluster)
166{
167 struct cluster_list *find;
168
169 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
170 find->refcnt++;
171
172 return find;
173}
174
175void
176cluster_unintern (struct cluster_list *cluster)
177{
178 struct cluster_list *ret;
179
180 if (cluster->refcnt)
181 cluster->refcnt--;
182
183 if (cluster->refcnt == 0)
184 {
185 ret = hash_release (cluster_hash, cluster);
186 cluster_free (cluster);
187 }
188}
189
paul94f2b392005-06-28 12:44:16 +0000190static void
191cluster_init (void)
paul718e3742002-12-13 20:15:29 +0000192{
193 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
194}
195
196/* Unknown transit attribute. */
197struct hash *transit_hash;
198
paul94f2b392005-06-28 12:44:16 +0000199static void
paul718e3742002-12-13 20:15:29 +0000200transit_free (struct transit *transit)
201{
202 if (transit->val)
203 XFREE (MTYPE_TRANSIT_VAL, transit->val);
204 XFREE (MTYPE_TRANSIT, transit);
205}
206
paul94f2b392005-06-28 12:44:16 +0000207static void *
paul718e3742002-12-13 20:15:29 +0000208transit_hash_alloc (struct transit *transit)
209{
210 /* Transit structure is already allocated. */
211 return transit;
212}
213
paul94f2b392005-06-28 12:44:16 +0000214static struct transit *
paul718e3742002-12-13 20:15:29 +0000215transit_intern (struct transit *transit)
216{
217 struct transit *find;
218
219 find = hash_get (transit_hash, transit, transit_hash_alloc);
220 if (find != transit)
221 transit_free (transit);
222 find->refcnt++;
223
224 return find;
225}
226
227void
228transit_unintern (struct transit *transit)
229{
230 struct transit *ret;
231
232 if (transit->refcnt)
233 transit->refcnt--;
234
235 if (transit->refcnt == 0)
236 {
237 ret = hash_release (transit_hash, transit);
238 transit_free (transit);
239 }
240}
241
paul94f2b392005-06-28 12:44:16 +0000242static unsigned int
paul718e3742002-12-13 20:15:29 +0000243transit_hash_key_make (struct transit *transit)
244{
245 unsigned int key = 0;
246 int length;
247 caddr_t pnt;
248
249 length = transit->length;
250 pnt = (caddr_t) transit->val;
251
252 while (length)
253 key += pnt[--length];
254
255 return key;
256}
257
paul94f2b392005-06-28 12:44:16 +0000258static int
paul718e3742002-12-13 20:15:29 +0000259transit_hash_cmp (struct transit *transit1, struct transit *transit2)
260{
261 if (transit1->length == transit2->length &&
262 memcmp (transit1->val, transit2->val, transit1->length) == 0)
263 return 1;
264 return 0;
265}
266
paul94f2b392005-06-28 12:44:16 +0000267static void
paul718e3742002-12-13 20:15:29 +0000268transit_init ()
269{
270 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
271}
272
273/* Attribute hash routines. */
274
275struct hash *attrhash;
276
277unsigned int
278attrhash_key_make (struct attr *attr)
279{
280 unsigned int key = 0;
281
282 key += attr->origin;
283 key += attr->nexthop.s_addr;
284 key += attr->med;
285 key += attr->local_pref;
286 key += attr->aggregator_as;
287 key += attr->aggregator_addr.s_addr;
288 key += attr->weight;
289
290 key += attr->mp_nexthop_global_in.s_addr;
291 if (attr->aspath)
292 key += aspath_key_make (attr->aspath);
293 if (attr->community)
294 key += community_hash_make (attr->community);
295 if (attr->ecommunity)
296 key += ecommunity_hash_make (attr->ecommunity);
297 if (attr->cluster)
298 key += cluster_hash_key_make (attr->cluster);
299 if (attr->transit)
300 key += transit_hash_key_make (attr->transit);
301
302#ifdef HAVE_IPV6
303 {
304 int i;
305
306 key += attr->mp_nexthop_len;
307 for (i = 0; i < 16; i++)
308 key += attr->mp_nexthop_global.s6_addr[i];
309 for (i = 0; i < 16; i++)
310 key += attr->mp_nexthop_local.s6_addr[i];
311 }
312#endif /* HAVE_IPV6 */
313
314 return key;
315}
316
317int
318attrhash_cmp (struct attr *attr1, struct attr *attr2)
319{
320 if (attr1->flag == attr2->flag
321 && attr1->origin == attr2->origin
322 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
323 && attr1->med == attr2->med
324 && attr1->local_pref == attr2->local_pref
325 && attr1->aggregator_as == attr2->aggregator_as
326 && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr
327 && attr1->weight == attr2->weight
328#ifdef HAVE_IPV6
329 && attr1->mp_nexthop_len == attr2->mp_nexthop_len
330 && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global)
331 && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local)
332#endif /* HAVE_IPV6 */
333 && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in)
334 && attr1->aspath == attr2->aspath
335 && attr1->community == attr2->community
336 && attr1->ecommunity == attr2->ecommunity
337 && attr1->cluster == attr2->cluster
338 && attr1->transit == attr2->transit)
339 return 1;
340 else
341 return 0;
342}
343
paul94f2b392005-06-28 12:44:16 +0000344static void
paul718e3742002-12-13 20:15:29 +0000345attrhash_init ()
346{
347 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
348}
349
paul94f2b392005-06-28 12:44:16 +0000350static void
paul718e3742002-12-13 20:15:29 +0000351attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
352{
353 struct attr *attr = backet->data;
354
355 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
356 inet_ntoa (attr->nexthop), VTY_NEWLINE);
357}
358
359void
360attr_show_all (struct vty *vty)
361{
362 hash_iterate (attrhash,
363 (void (*)(struct hash_backet *, void *))
364 attr_show_all_iterator,
365 vty);
366}
367
paul94f2b392005-06-28 12:44:16 +0000368static void *
paul718e3742002-12-13 20:15:29 +0000369bgp_attr_hash_alloc (struct attr *val)
370{
371 struct attr *attr;
372
373 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
374 *attr = *val;
375 attr->refcnt = 0;
376 return attr;
377}
378
379/* Internet argument attribute. */
380struct attr *
381bgp_attr_intern (struct attr *attr)
382{
383 struct attr *find;
384
385 /* Intern referenced strucutre. */
386 if (attr->aspath)
387 {
388 if (! attr->aspath->refcnt)
389 attr->aspath = aspath_intern (attr->aspath);
390 else
391 attr->aspath->refcnt++;
392 }
393 if (attr->community)
394 {
395 if (! attr->community->refcnt)
396 attr->community = community_intern (attr->community);
397 else
398 attr->community->refcnt++;
399 }
400 if (attr->ecommunity)
401 {
402 if (! attr->ecommunity->refcnt)
403 attr->ecommunity = ecommunity_intern (attr->ecommunity);
404 else
405 attr->ecommunity->refcnt++;
406 }
407 if (attr->cluster)
408 {
409 if (! attr->cluster->refcnt)
410 attr->cluster = cluster_intern (attr->cluster);
411 else
412 attr->cluster->refcnt++;
413 }
414 if (attr->transit)
415 {
416 if (! attr->transit->refcnt)
417 attr->transit = transit_intern (attr->transit);
418 else
419 attr->transit->refcnt++;
420 }
421
422 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
423 find->refcnt++;
424
425 return find;
426}
427
428/* Make network statement's attribute. */
429struct attr *
430bgp_attr_default_set (struct attr *attr, u_char origin)
431{
432 memset (attr, 0, sizeof (struct attr));
433
434 attr->origin = origin;
435 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
436 attr->aspath = aspath_empty ();
437 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
438 attr->weight = 32768;
439 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
440#ifdef HAVE_IPV6
441 attr->mp_nexthop_len = 16;
442#endif
443 return attr;
444}
445
446/* Make network statement's attribute. */
447struct attr *
448bgp_attr_default_intern (u_char origin)
449{
450 struct attr attr;
451 struct attr *new;
452
453 memset (&attr, 0, sizeof (struct attr));
454
455 attr.origin = origin;
456 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
457 attr.aspath = aspath_empty ();
458 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
459 attr.weight = 32768;
460 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
461#ifdef HAVE_IPV6
462 attr.mp_nexthop_len = 16;
463#endif
464
465 new = bgp_attr_intern (&attr);
466 aspath_unintern (new->aspath);
467 return new;
468}
469
470struct attr *
471bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
472 struct aspath *aspath,
473 struct community *community, int as_set)
474{
475 struct attr attr;
476 struct attr *new;
477
478 memset (&attr, 0, sizeof (struct attr));
479
480 /* Origin attribute. */
481 attr.origin = origin;
482 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
483
484 /* AS path attribute. */
485 if (aspath)
486 attr.aspath = aspath_intern (aspath);
487 else
488 attr.aspath = aspath_empty ();
489 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
490
491 /* Next hop attribute. */
492 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
493
494 if (community)
495 {
496 attr.community = community;
497 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
498 }
499
500 attr.weight = 32768;
501#ifdef HAVE_IPV6
502 attr.mp_nexthop_len = 16;
503#endif
504 if (! as_set)
505 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
506 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
507 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
508 attr.aggregator_as = bgp->confed_id;
509 else
510 attr.aggregator_as = bgp->as;
511 attr.aggregator_addr = bgp->router_id;
512
513 new = bgp_attr_intern (&attr);
514 aspath_unintern (new->aspath);
515 return new;
516}
517
518/* Free bgp attribute and aspath. */
519void
520bgp_attr_unintern (struct attr *attr)
521{
522 struct attr *ret;
523 struct aspath *aspath;
524 struct community *community;
525 struct ecommunity *ecommunity;
526 struct cluster_list *cluster;
527 struct transit *transit;
528
529 /* Decrement attribute reference. */
530 attr->refcnt--;
531 aspath = attr->aspath;
532 community = attr->community;
533 ecommunity = attr->ecommunity;
534 cluster = attr->cluster;
535 transit = attr->transit;
536
537 /* If reference becomes zero then free attribute object. */
538 if (attr->refcnt == 0)
539 {
540 ret = hash_release (attrhash, attr);
541 assert (ret != NULL);
542 XFREE (MTYPE_ATTR, attr);
543 }
544
545 /* aspath refcount shoud be decrement. */
546 if (aspath)
547 aspath_unintern (aspath);
548 if (community)
549 community_unintern (community);
550 if (ecommunity)
551 ecommunity_unintern (ecommunity);
552 if (cluster)
553 cluster_unintern (cluster);
554 if (transit)
555 transit_unintern (transit);
556}
557
558void
559bgp_attr_flush (struct attr *attr)
560{
561 if (attr->aspath && ! attr->aspath->refcnt)
562 aspath_free (attr->aspath);
563 if (attr->community && ! attr->community->refcnt)
564 community_free (attr->community);
565 if (attr->ecommunity && ! attr->ecommunity->refcnt)
566 ecommunity_free (attr->ecommunity);
567 if (attr->cluster && ! attr->cluster->refcnt)
568 cluster_free (attr->cluster);
569 if (attr->transit && ! attr->transit->refcnt)
570 transit_free (attr->transit);
571}
572
573/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000574static int
paul718e3742002-12-13 20:15:29 +0000575bgp_attr_origin (struct peer *peer, bgp_size_t length,
576 struct attr *attr, u_char flag, u_char *startp)
577{
578 bgp_size_t total;
579
580 /* total is entire attribute length include Attribute Flags (1),
581 Attribute Type code (1) and Attribute length (1 or 2). */
582 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
583
584 /* If any recognized attribute has Attribute Flags that conflict
585 with the Attribute Type Code, then the Error Subcode is set to
586 Attribute Flags Error. The Data field contains the erroneous
587 attribute (type, length and value). */
588 if (flag != BGP_ATTR_FLAG_TRANS)
589 {
590 zlog (peer->log, LOG_ERR,
591 "Origin attribute flag isn't transitive %d", flag);
592 bgp_notify_send_with_data (peer,
593 BGP_NOTIFY_UPDATE_ERR,
594 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
595 startp, total);
596 return -1;
597 }
598
599 /* If any recognized attribute has Attribute Length that conflicts
600 with the expected length (based on the attribute type code), then
601 the Error Subcode is set to Attribute Length Error. The Data
602 field contains the erroneous attribute (type, length and
603 value). */
604 if (length != 1)
605 {
606 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
607 length);
608 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
609 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
610 startp, total);
611 return -1;
612 }
613
614 /* Fetch origin attribute. */
615 attr->origin = stream_getc (BGP_INPUT (peer));
616
617 /* If the ORIGIN attribute has an undefined value, then the Error
618 Subcode is set to Invalid Origin Attribute. The Data field
619 contains the unrecognized attribute (type, length and value). */
620 if ((attr->origin != BGP_ORIGIN_IGP)
621 && (attr->origin != BGP_ORIGIN_EGP)
622 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
623 {
624 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
625 attr->origin);
626
627 bgp_notify_send_with_data (peer,
628 BGP_NOTIFY_UPDATE_ERR,
629 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
630 startp, total);
631 return -1;
632 }
633
634 /* Set oring attribute flag. */
635 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
636
637 return 0;
638}
639
640/* Parse AS path information. This function is wrapper of
641 aspath_parse. */
paul94f2b392005-06-28 12:44:16 +0000642static int
paul718e3742002-12-13 20:15:29 +0000643bgp_attr_aspath (struct peer *peer, bgp_size_t length,
644 struct attr *attr, u_char flag, u_char *startp)
645{
646 struct bgp *bgp;
647 struct aspath *aspath;
648 bgp_size_t total;
649
650 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
651
652 /* Flag check. */
653 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
654 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
655 {
656 zlog (peer->log, LOG_ERR,
657 "Origin attribute flag isn't transitive %d", flag);
658 bgp_notify_send_with_data (peer,
659 BGP_NOTIFY_UPDATE_ERR,
660 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
661 startp, total);
662 return -1;
663 }
664
665 /* In case of IBGP, length will be zero. */
paulfe69a502005-09-10 16:55:02 +0000666 attr->aspath = aspath_parse (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000667 if (! attr->aspath)
668 {
669 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
670 bgp_notify_send (peer,
671 BGP_NOTIFY_UPDATE_ERR,
672 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
673 return -1;
674 }
675
676 bgp = peer->bgp;
677
678 /* First AS check for EBGP. */
679 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
680 {
681 if (peer_sort (peer) == BGP_PEER_EBGP
682 && ! aspath_firstas_check (attr->aspath, peer->as))
683 {
684 zlog (peer->log, LOG_ERR,
685 "%s incorrect first AS (must be %d)", peer->host, peer->as);
686 bgp_notify_send (peer,
687 BGP_NOTIFY_UPDATE_ERR,
688 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
689 return -1;
690 }
691 }
692
693 /* local-as prepend */
694 if (peer->change_local_as &&
695 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
696 {
697 aspath = aspath_dup (attr->aspath);
698 aspath = aspath_add_seq (aspath, peer->change_local_as);
699 aspath_unintern (attr->aspath);
700 attr->aspath = aspath_intern (aspath);
701 }
702
703 /* Forward pointer. */
paulfe69a502005-09-10 16:55:02 +0000704/* stream_forward_getp (peer->ibuf, length);*/
paul718e3742002-12-13 20:15:29 +0000705
706 /* Set aspath attribute flag. */
707 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
708
709 return 0;
710}
711
712/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000713static int
paul718e3742002-12-13 20:15:29 +0000714bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
715 struct attr *attr, u_char flag, u_char *startp)
716{
717 bgp_size_t total;
718
719 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
720
721 /* Flag check. */
722 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
723 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
724 {
725 zlog (peer->log, LOG_ERR,
726 "Origin attribute flag isn't transitive %d", flag);
727 bgp_notify_send_with_data (peer,
728 BGP_NOTIFY_UPDATE_ERR,
729 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
730 startp, total);
731 return -1;
732 }
733
734 /* Check nexthop attribute length. */
735 if (length != 4)
736 {
737 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
738 length);
739
740 bgp_notify_send_with_data (peer,
741 BGP_NOTIFY_UPDATE_ERR,
742 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
743 startp, total);
744 return -1;
745 }
746
747 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
748 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
749
750 return 0;
751}
752
753/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000754static int
paul718e3742002-12-13 20:15:29 +0000755bgp_attr_med (struct peer *peer, bgp_size_t length,
756 struct attr *attr, u_char flag, u_char *startp)
757{
758 bgp_size_t total;
759
760 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
761
762 /* Length check. */
763 if (length != 4)
764 {
765 zlog (peer->log, LOG_ERR,
766 "MED attribute length isn't four [%d]", length);
767
768 bgp_notify_send_with_data (peer,
769 BGP_NOTIFY_UPDATE_ERR,
770 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
771 startp, total);
772 return -1;
773 }
774
775 attr->med = stream_getl (peer->ibuf);
776
777 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
778
779 return 0;
780}
781
782/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000783static int
paul718e3742002-12-13 20:15:29 +0000784bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
785 struct attr *attr, u_char flag)
786{
787 /* If it is contained in an UPDATE message that is received from an
788 external peer, then this attribute MUST be ignored by the
789 receiving speaker. */
790 if (peer_sort (peer) == BGP_PEER_EBGP)
791 {
paul9985f832005-02-09 15:51:56 +0000792 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000793 return 0;
794 }
795
796 if (length == 4)
797 attr->local_pref = stream_getl (peer->ibuf);
798 else
799 attr->local_pref = 0;
800
801 /* Set atomic aggregate flag. */
802 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
803
804 return 0;
805}
806
807/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000808static int
paul718e3742002-12-13 20:15:29 +0000809bgp_attr_atomic (struct peer *peer, bgp_size_t length,
810 struct attr *attr, u_char flag)
811{
812 if (length != 0)
813 {
814 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
815
816 bgp_notify_send (peer,
817 BGP_NOTIFY_UPDATE_ERR,
818 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
819 return -1;
820 }
821
822 /* Set atomic aggregate flag. */
823 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
824
825 return 0;
826}
827
828/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +0000829static int
paul718e3742002-12-13 20:15:29 +0000830bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
831 struct attr *attr, u_char flag)
832{
833 if (length != 6)
834 {
835 zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length);
836
837 bgp_notify_send (peer,
838 BGP_NOTIFY_UPDATE_ERR,
839 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
840 return -1;
841 }
842 attr->aggregator_as = stream_getw (peer->ibuf);
843 attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
844
845 /* Set atomic aggregate flag. */
846 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
847
848 return 0;
849}
850
851/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +0000852static int
paul718e3742002-12-13 20:15:29 +0000853bgp_attr_community (struct peer *peer, bgp_size_t length,
854 struct attr *attr, u_char flag)
855{
856 if (length == 0)
857 attr->community = NULL;
858 else
859 {
paul5228ad22004-06-04 17:58:18 +0000860 attr->community =
861 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +0000862 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000863 }
864
865 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
866
867 return 0;
868}
869
870/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +0000871static int
paul718e3742002-12-13 20:15:29 +0000872bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
873 struct attr *attr, u_char flag)
874{
875 if (length != 4)
876 {
877 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
878
879 bgp_notify_send (peer,
880 BGP_NOTIFY_UPDATE_ERR,
881 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
882 return -1;
883 }
884
885 attr->originator_id.s_addr = stream_get_ipv4 (peer->ibuf);
886
887 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
888
889 return 0;
890}
891
892/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +0000893static int
paul718e3742002-12-13 20:15:29 +0000894bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
895 struct attr *attr, u_char flag)
896{
897 /* Check length. */
898 if (length % 4)
899 {
900 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
901
902 bgp_notify_send (peer,
903 BGP_NOTIFY_UPDATE_ERR,
904 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
905 return -1;
906 }
907
paul5228ad22004-06-04 17:58:18 +0000908 attr->cluster = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf),
909 length);
paul718e3742002-12-13 20:15:29 +0000910
paul9985f832005-02-09 15:51:56 +0000911 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +0000912
913 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
914
915 return 0;
916}
917
918/* Multiprotocol reachability information parse. */
paul94f2b392005-06-28 12:44:16 +0000919static int
paul718e3742002-12-13 20:15:29 +0000920bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
921 struct bgp_nlri *mp_update)
922{
923 u_int16_t afi;
924 u_char safi;
925 u_char snpa_num;
926 u_char snpa_len;
927 u_char *lim;
928 bgp_size_t nlri_len;
929 int ret;
930 struct stream *s;
931
932 /* Set end of packet. */
933 s = peer->ibuf;
934 lim = stream_pnt (s) + length;
935
936 /* Load AFI, SAFI. */
937 afi = stream_getw (s);
938 safi = stream_getc (s);
939
940 /* Get nexthop length. */
941 attr->mp_nexthop_len = stream_getc (s);
942
943 /* Nexthop length check. */
944 switch (attr->mp_nexthop_len)
945 {
946 case 4:
947 stream_get (&attr->mp_nexthop_global_in, s, 4);
948 break;
949 case 12:
950 {
951 u_int32_t rd_high;
952 u_int32_t rd_low;
953
954 rd_high = stream_getl (s);
955 rd_low = stream_getl (s);
956 stream_get (&attr->mp_nexthop_global_in, s, 4);
957 }
958 break;
959#ifdef HAVE_IPV6
960 case 16:
961 stream_get (&attr->mp_nexthop_global, s, 16);
962 break;
963 case 32:
964 stream_get (&attr->mp_nexthop_global, s, 16);
965 stream_get (&attr->mp_nexthop_local, s, 16);
966 if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local))
967 {
968 char buf1[INET6_ADDRSTRLEN];
969 char buf2[INET6_ADDRSTRLEN];
970
971 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +0000972 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 +0000973 inet_ntop (AF_INET6, &attr->mp_nexthop_global,
974 buf1, INET6_ADDRSTRLEN),
975 inet_ntop (AF_INET6, &attr->mp_nexthop_local,
976 buf2, INET6_ADDRSTRLEN));
977
978 attr->mp_nexthop_len = 16;
979 }
980 break;
981#endif /* HAVE_IPV6 */
982 default:
983 zlog_info ("Wrong multiprotocol next hop length: %d",
984 attr->mp_nexthop_len);
985 return -1;
paul718e3742002-12-13 20:15:29 +0000986 }
987
988 snpa_num = stream_getc (s);
989
990 while (snpa_num--)
991 {
992 snpa_len = stream_getc (s);
paul9985f832005-02-09 15:51:56 +0000993 stream_forward_getp (s, (snpa_len + 1) >> 1);
paul718e3742002-12-13 20:15:29 +0000994 }
995
paul718e3742002-12-13 20:15:29 +0000996 nlri_len = lim - stream_pnt (s);
997
998 if (safi != BGP_SAFI_VPNV4)
999 {
1000 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1001 if (ret < 0)
1002 return -1;
1003 }
1004
1005 mp_update->afi = afi;
1006 mp_update->safi = safi;
1007 mp_update->nlri = stream_pnt (s);
1008 mp_update->length = nlri_len;
1009
paul9985f832005-02-09 15:51:56 +00001010 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001011
1012 return 0;
1013}
1014
1015/* Multiprotocol unreachable parse */
paul94f2b392005-06-28 12:44:16 +00001016static int
paul718e3742002-12-13 20:15:29 +00001017bgp_mp_unreach_parse (struct peer *peer, int length,
1018 struct bgp_nlri *mp_withdraw)
1019{
1020 struct stream *s;
1021 u_int16_t afi;
1022 u_char safi;
1023 u_char *lim;
1024 u_int16_t withdraw_len;
1025 int ret;
1026
1027 s = peer->ibuf;
1028 lim = stream_pnt (s) + length;
1029
1030 afi = stream_getw (s);
1031 safi = stream_getc (s);
1032
1033 withdraw_len = lim - stream_pnt (s);
1034
1035 if (safi != BGP_SAFI_VPNV4)
1036 {
1037 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1038 if (ret < 0)
1039 return -1;
1040 }
1041
1042 mp_withdraw->afi = afi;
1043 mp_withdraw->safi = safi;
1044 mp_withdraw->nlri = stream_pnt (s);
1045 mp_withdraw->length = withdraw_len;
1046
paul9985f832005-02-09 15:51:56 +00001047 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001048
1049 return 0;
1050}
1051
1052/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001053static int
paul718e3742002-12-13 20:15:29 +00001054bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1055 struct attr *attr, u_char flag)
1056{
1057 if (length == 0)
1058 attr->ecommunity = NULL;
1059 else
1060 {
paul5228ad22004-06-04 17:58:18 +00001061 attr->ecommunity =
1062 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001063 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001064 }
1065 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1066
1067 return 0;
1068}
1069
1070/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001071static int
paul718e3742002-12-13 20:15:29 +00001072bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1073 u_char type, bgp_size_t length, u_char *startp)
1074{
1075 bgp_size_t total;
1076 struct transit *transit;
1077
hassof4184462005-02-01 20:13:16 +00001078 if (BGP_DEBUG (normal, NORMAL))
1079 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1080 peer->host, type, length);
1081
paul718e3742002-12-13 20:15:29 +00001082 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001083 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001084 "Unknown attribute type %d length %d is received", type, length);
1085
1086 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001087 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001088
1089 /* Adjest total length to include type and length. */
1090 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1091
1092 /* If any of the mandatory well-known attributes are not recognized,
1093 then the Error Subcode is set to Unrecognized Well-known
1094 Attribute. The Data field contains the unrecognized attribute
1095 (type, length and value). */
1096 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1097 {
1098 /* Adjust startp to do not include flag value. */
1099 bgp_notify_send_with_data (peer,
1100 BGP_NOTIFY_UPDATE_ERR,
1101 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1102 startp, total);
1103 return -1;
1104 }
1105
1106 /* Unrecognized non-transitive optional attributes must be quietly
1107 ignored and not passed along to other BGP peers. */
1108 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1109 return 0;
1110
1111 /* If a path with recognized transitive optional attribute is
1112 accepted and passed along to other BGP peers and the Partial bit
1113 in the Attribute Flags octet is set to 1 by some previous AS, it
1114 is not set back to 0 by the current AS. */
1115 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1116
1117 /* Store transitive attribute to the end of attr->transit. */
1118 if (! attr->transit)
1119 {
1120 attr->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1121 memset (attr->transit, 0, sizeof (struct transit));
1122 }
1123
1124 transit = attr->transit;
1125
1126 if (transit->val)
1127 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1128 transit->length + total);
1129 else
1130 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1131
1132 memcpy (transit->val + transit->length, startp, total);
1133 transit->length += total;
1134
1135 return 0;
1136}
1137
1138/* Read attribute of update packet. This function is called from
1139 bgp_update() in bgpd.c. */
1140int
1141bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1142 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1143{
1144 int ret;
1145 u_char flag;
1146 u_char type;
1147 bgp_size_t length;
1148 u_char *startp, *endp;
1149 u_char *attr_endp;
1150 u_char seen[BGP_ATTR_BITMAP_SIZE];
1151
1152 /* Initialize bitmap. */
1153 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1154
1155 /* End pointer of BGP attribute. */
1156 endp = BGP_INPUT_PNT (peer) + size;
1157
1158 /* Get attributes to the end of attribute length. */
1159 while (BGP_INPUT_PNT (peer) < endp)
1160 {
1161 /* Check remaining length check.*/
1162 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1163 {
gdtc29fdba2004-12-09 14:46:46 +00001164 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001165 zlog (peer->log, LOG_WARNING,
paula2b1ecd2004-10-31 18:58:09 +00001166 "%s error BGP attribute length %ld is smaller than min len",
paul718e3742002-12-13 20:15:29 +00001167 peer->host, endp - STREAM_PNT (BGP_INPUT (peer)));
1168
1169 bgp_notify_send (peer,
1170 BGP_NOTIFY_UPDATE_ERR,
1171 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1172 return -1;
1173 }
1174
1175 /* Fetch attribute flag and type. */
1176 startp = BGP_INPUT_PNT (peer);
1177 flag = stream_getc (BGP_INPUT (peer));
1178 type = stream_getc (BGP_INPUT (peer));
1179
1180 /* Check extended attribue length bit. */
1181 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1182 length = stream_getw (BGP_INPUT (peer));
1183 else
1184 length = stream_getc (BGP_INPUT (peer));
1185
1186 /* If any attribute appears more than once in the UPDATE
1187 message, then the Error Subcode is set to Malformed Attribute
1188 List. */
1189
1190 if (CHECK_BITMAP (seen, type))
1191 {
1192 zlog (peer->log, LOG_WARNING,
1193 "%s error BGP attribute type %d appears twice in a message",
1194 peer->host, type);
1195
1196 bgp_notify_send (peer,
1197 BGP_NOTIFY_UPDATE_ERR,
1198 BGP_NOTIFY_UPDATE_MAL_ATTR);
1199 return -1;
1200 }
1201
1202 /* Set type to bitmap to check duplicate attribute. `type' is
1203 unsigned char so it never overflow bitmap range. */
1204
1205 SET_BITMAP (seen, type);
1206
1207 /* Overflow check. */
1208 attr_endp = BGP_INPUT_PNT (peer) + length;
1209
1210 if (attr_endp > endp)
1211 {
1212 zlog (peer->log, LOG_WARNING,
1213 "%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);
1214 bgp_notify_send (peer,
1215 BGP_NOTIFY_UPDATE_ERR,
1216 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1217 return -1;
1218 }
1219
1220 /* OK check attribute and store it's value. */
1221 switch (type)
1222 {
1223 case BGP_ATTR_ORIGIN:
1224 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1225 break;
1226 case BGP_ATTR_AS_PATH:
1227 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1228 break;
1229 case BGP_ATTR_NEXT_HOP:
1230 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1231 break;
1232 case BGP_ATTR_MULTI_EXIT_DISC:
1233 ret = bgp_attr_med (peer, length, attr, flag, startp);
1234 break;
1235 case BGP_ATTR_LOCAL_PREF:
1236 ret = bgp_attr_local_pref (peer, length, attr, flag);
1237 break;
1238 case BGP_ATTR_ATOMIC_AGGREGATE:
1239 ret = bgp_attr_atomic (peer, length, attr, flag);
1240 break;
1241 case BGP_ATTR_AGGREGATOR:
1242 ret = bgp_attr_aggregator (peer, length, attr, flag);
1243 break;
1244 case BGP_ATTR_COMMUNITIES:
1245 ret = bgp_attr_community (peer, length, attr, flag);
1246 break;
1247 case BGP_ATTR_ORIGINATOR_ID:
1248 ret = bgp_attr_originator_id (peer, length, attr, flag);
1249 break;
1250 case BGP_ATTR_CLUSTER_LIST:
1251 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1252 break;
1253 case BGP_ATTR_MP_REACH_NLRI:
1254 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1255 break;
1256 case BGP_ATTR_MP_UNREACH_NLRI:
1257 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1258 break;
1259 case BGP_ATTR_EXT_COMMUNITIES:
1260 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1261 break;
1262 default:
1263 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1264 break;
1265 }
1266
1267 /* If error occured immediately return to the caller. */
1268 if (ret < 0)
1269 return ret;
1270
1271 /* Check the fetched length. */
1272 if (BGP_INPUT_PNT (peer) != attr_endp)
1273 {
1274 zlog (peer->log, LOG_WARNING,
1275 "%s BGP attribute fetch error", peer->host);
1276 bgp_notify_send (peer,
1277 BGP_NOTIFY_UPDATE_ERR,
1278 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1279 return -1;
1280 }
1281 }
1282
1283 /* Check final read pointer is same as end pointer. */
1284 if (BGP_INPUT_PNT (peer) != endp)
1285 {
1286 zlog (peer->log, LOG_WARNING,
1287 "%s BGP attribute length mismatch", peer->host);
1288 bgp_notify_send (peer,
1289 BGP_NOTIFY_UPDATE_ERR,
1290 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1291 return -1;
1292 }
1293
1294 /* Finally intern unknown attribute. */
1295 if (attr->transit)
1296 attr->transit = transit_intern (attr->transit);
1297
1298 return 0;
1299}
1300
1301/* Well-known attribute check. */
1302int
1303bgp_attr_check (struct peer *peer, struct attr *attr)
1304{
1305 u_char type = 0;
1306
1307 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1308 type = BGP_ATTR_ORIGIN;
1309
1310 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1311 type = BGP_ATTR_AS_PATH;
1312
1313 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1314 type = BGP_ATTR_NEXT_HOP;
1315
1316 if (peer_sort (peer) == BGP_PEER_IBGP
1317 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1318 type = BGP_ATTR_LOCAL_PREF;
1319
1320 if (type)
1321 {
1322 zlog (peer->log, LOG_WARNING,
1323 "%s Missing well-known attribute %d.",
1324 peer->host, type);
1325 bgp_notify_send_with_data (peer,
1326 BGP_NOTIFY_UPDATE_ERR,
1327 BGP_NOTIFY_UPDATE_MISS_ATTR,
1328 &type, 1);
1329 return -1;
1330 }
1331 return 0;
1332}
1333
1334int stream_put_prefix (struct stream *, struct prefix *);
1335
1336/* Make attribute packet. */
1337bgp_size_t
1338bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1339 struct stream *s, struct attr *attr, struct prefix *p,
1340 afi_t afi, safi_t safi, struct peer *from,
paul5228ad22004-06-04 17:58:18 +00001341 struct prefix_rd *prd, char *tag)
paul718e3742002-12-13 20:15:29 +00001342{
paulfe69a502005-09-10 16:55:02 +00001343 size_t cp;
1344 unsigned int aspath_data_size;
paul718e3742002-12-13 20:15:29 +00001345 struct aspath *aspath;
1346
1347 if (! bgp)
1348 bgp = bgp_get_default ();
1349
1350 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001351 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001352
1353 /* Origin attribute. */
1354 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1355 stream_putc (s, BGP_ATTR_ORIGIN);
1356 stream_putc (s, 1);
1357 stream_putc (s, attr->origin);
1358
1359 /* AS path attribute. */
1360
1361 /* If remote-peer is EBGP */
1362 if (peer_sort (peer) == BGP_PEER_EBGP
1363 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001364 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001365 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001366 {
1367 aspath = aspath_dup (attr->aspath);
1368
1369 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1370 {
1371 /* Strip the confed info, and then stuff our path CONFED_ID
1372 on the front */
1373 aspath = aspath_delete_confed_seq (aspath);
1374 aspath = aspath_add_seq (aspath, bgp->confed_id);
1375 }
1376 else
1377 {
1378 aspath = aspath_add_seq (aspath, peer->local_as);
1379 if (peer->change_local_as)
1380 aspath = aspath_add_seq (aspath, peer->change_local_as);
1381 }
1382 }
1383 else if (peer_sort (peer) == BGP_PEER_CONFED)
1384 {
1385 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1386 aspath = aspath_dup (attr->aspath);
1387 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1388 }
1389 else
1390 aspath = attr->aspath;
1391
1392 /* AS path attribute extended length bit check. */
paulfe69a502005-09-10 16:55:02 +00001393 aspath_data_size = aspath_size (aspath);
1394 if (aspath_data_size > 255)
paul718e3742002-12-13 20:15:29 +00001395 {
1396 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1397 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001398 stream_putw (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001399 }
1400 else
1401 {
1402 stream_putc (s, BGP_ATTR_FLAG_TRANS);
paulfe69a502005-09-10 16:55:02 +00001403 stream_putc (s, BGP_ATTR_AS_PATH);
1404 stream_putc (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001405 }
paulfe69a502005-09-10 16:55:02 +00001406 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001407
1408 if (aspath != attr->aspath)
1409 aspath_free (aspath);
1410
1411 /* Nexthop attribute. */
1412 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1413 {
1414 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1415 stream_putc (s, BGP_ATTR_NEXT_HOP);
1416 stream_putc (s, 4);
1417 if (safi == SAFI_MPLS_VPN)
1418 {
1419 if (attr->nexthop.s_addr == 0)
1420 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1421 else
1422 stream_put_ipv4 (s, attr->nexthop.s_addr);
1423 }
1424 else
1425 stream_put_ipv4 (s, attr->nexthop.s_addr);
1426 }
1427
1428 /* MED attribute. */
1429 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1430 {
1431 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1432 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1433 stream_putc (s, 4);
1434 stream_putl (s, attr->med);
1435 }
1436
1437 /* Local preference. */
1438 if (peer_sort (peer) == BGP_PEER_IBGP ||
1439 peer_sort (peer) == BGP_PEER_CONFED)
1440 {
1441 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1442 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1443 stream_putc (s, 4);
1444 stream_putl (s, attr->local_pref);
1445 }
1446
1447 /* Atomic aggregate. */
1448 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1449 {
1450 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1451 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1452 stream_putc (s, 0);
1453 }
1454
1455 /* Aggregator. */
1456 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1457 {
1458 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1459 stream_putc (s, BGP_ATTR_AGGREGATOR);
1460 stream_putc (s, 6);
1461 stream_putw (s, attr->aggregator_as);
1462 stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
1463 }
1464
1465 /* Community attribute. */
1466 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1467 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1468 {
1469 if (attr->community->size * 4 > 255)
1470 {
1471 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1472 stream_putc (s, BGP_ATTR_COMMUNITIES);
1473 stream_putw (s, attr->community->size * 4);
1474 }
1475 else
1476 {
1477 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1478 stream_putc (s, BGP_ATTR_COMMUNITIES);
1479 stream_putc (s, attr->community->size * 4);
1480 }
1481 stream_put (s, attr->community->val, attr->community->size * 4);
1482 }
1483
1484 /* Route Reflector. */
1485 if (peer_sort (peer) == BGP_PEER_IBGP
1486 && from
1487 && peer_sort (from) == BGP_PEER_IBGP)
1488 {
1489 /* Originator ID. */
1490 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1491 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1492 stream_putc (s, 4);
1493
1494 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
1495 stream_put_in_addr (s, &attr->originator_id);
1496 else
1497 {
1498 if (from)
1499 stream_put_in_addr (s, &from->remote_id);
1500 else
1501 stream_put_in_addr (s, &attr->originator_id);
1502 }
1503
1504 /* Cluster list. */
1505 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1506 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1507
1508 if (attr->cluster)
1509 {
1510 stream_putc (s, attr->cluster->length + 4);
1511 /* If this peer configuration's parent BGP has cluster_id. */
1512 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1513 stream_put_in_addr (s, &bgp->cluster_id);
1514 else
1515 stream_put_in_addr (s, &bgp->router_id);
1516 stream_put (s, attr->cluster->list, attr->cluster->length);
1517 }
1518 else
1519 {
1520 stream_putc (s, 4);
1521 /* If this peer configuration's parent BGP has cluster_id. */
1522 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1523 stream_put_in_addr (s, &bgp->cluster_id);
1524 else
1525 stream_put_in_addr (s, &bgp->router_id);
1526 }
1527 }
1528
1529#ifdef HAVE_IPV6
1530 /* If p is IPv6 address put it into attribute. */
1531 if (p->family == AF_INET6)
1532 {
1533 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001534
1535 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1536 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001537 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001538 stream_putc (s, 0); /* Length of this attribute. */
1539 stream_putw (s, AFI_IP6); /* AFI */
1540 stream_putc (s, safi); /* SAFI */
1541
1542 stream_putc (s, attr->mp_nexthop_len);
1543
1544 if (attr->mp_nexthop_len == 16)
1545 stream_put (s, &attr->mp_nexthop_global, 16);
1546 else if (attr->mp_nexthop_len == 32)
1547 {
1548 stream_put (s, &attr->mp_nexthop_global, 16);
1549 stream_put (s, &attr->mp_nexthop_local, 16);
1550 }
1551
1552 /* SNPA */
1553 stream_putc (s, 0);
1554
paul718e3742002-12-13 20:15:29 +00001555 /* Prefix write. */
1556 stream_put_prefix (s, p);
1557
1558 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001559 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001560 }
1561#endif /* HAVE_IPV6 */
1562
1563 if (p->family == AF_INET && safi == SAFI_MULTICAST)
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_IP); /* AFI */
1572 stream_putc (s, SAFI_MULTICAST); /* SAFI */
1573
1574 stream_putc (s, 4);
1575 stream_put_ipv4 (s, attr->nexthop.s_addr);
1576
1577 /* SNPA */
1578 stream_putc (s, 0);
1579
paul718e3742002-12-13 20:15:29 +00001580 /* Prefix write. */
1581 stream_put_prefix (s, p);
1582
1583 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001584 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001585 }
1586
1587 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
1588 {
1589 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001590
1591 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1592 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001593 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001594 stream_putc (s, 0); /* Length of this attribute. */
1595 stream_putw (s, AFI_IP); /* AFI */
1596 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
1597
1598 stream_putc (s, 12);
1599 stream_putl (s, 0);
1600 stream_putl (s, 0);
1601 stream_put (s, &attr->mp_nexthop_global_in, 4);
1602
1603 /* SNPA */
1604 stream_putc (s, 0);
1605
paul718e3742002-12-13 20:15:29 +00001606 /* Tag, RD, Prefix write. */
1607 stream_putc (s, p->prefixlen + 88);
1608 stream_put (s, tag, 3);
1609 stream_put (s, prd->val, 8);
1610 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1611
1612 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001613 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001614 }
1615
1616 /* Extended Communities attribute. */
1617 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
1618 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
1619 {
hasso4372df72004-05-20 10:20:02 +00001620 if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00001621 {
hasso4372df72004-05-20 10:20:02 +00001622 if (attr->ecommunity->size * 8 > 255)
1623 {
1624 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1625 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1626 stream_putw (s, attr->ecommunity->size * 8);
1627 }
1628 else
1629 {
1630 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1631 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1632 stream_putc (s, attr->ecommunity->size * 8);
1633 }
1634 stream_put (s, attr->ecommunity->val, attr->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00001635 }
1636 else
1637 {
paul5228ad22004-06-04 17:58:18 +00001638 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00001639 int tbit;
1640 int ecom_tr_size = 0;
1641 int i;
1642
1643 for (i = 0; i < attr->ecommunity->size; i++)
1644 {
1645 pnt = attr->ecommunity->val + (i * 8);
1646 tbit = *pnt;
1647
1648 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1649 continue;
1650
1651 ecom_tr_size++;
1652 }
1653
1654 if (ecom_tr_size)
1655 {
1656 if (ecom_tr_size * 8 > 255)
1657 {
1658 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1659 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1660 stream_putw (s, ecom_tr_size * 8);
1661 }
1662 else
1663 {
1664 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1665 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1666 stream_putc (s, ecom_tr_size * 8);
1667 }
1668
1669 for (i = 0; i < attr->ecommunity->size; i++)
1670 {
1671 pnt = attr->ecommunity->val + (i * 8);
1672 tbit = *pnt;
1673
1674 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1675 continue;
1676
1677 stream_put (s, pnt, 8);
1678 }
1679 }
paul718e3742002-12-13 20:15:29 +00001680 }
paul718e3742002-12-13 20:15:29 +00001681 }
1682
1683 /* Unknown transit attribute. */
1684 if (attr->transit)
1685 stream_put (s, attr->transit->val, attr->transit->length);
1686
1687 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00001688 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001689}
1690
1691bgp_size_t
1692bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
1693 afi_t afi, safi_t safi, struct prefix_rd *prd,
paul5228ad22004-06-04 17:58:18 +00001694 char *tag)
paul718e3742002-12-13 20:15:29 +00001695{
1696 unsigned long cp;
1697 unsigned long attrlen_pnt;
1698 bgp_size_t size;
1699
paul9985f832005-02-09 15:51:56 +00001700 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001701
1702 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1703 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
1704
paul9985f832005-02-09 15:51:56 +00001705 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001706 stream_putc (s, 0); /* Length of this attribute. */
1707
1708 stream_putw (s, family2afi (p->family));
1709
1710 if (safi == SAFI_MPLS_VPN)
1711 {
1712 /* SAFI */
1713 stream_putc (s, BGP_SAFI_VPNV4);
1714
1715 /* prefix. */
1716 stream_putc (s, p->prefixlen + 88);
1717 stream_put (s, tag, 3);
1718 stream_put (s, prd->val, 8);
1719 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1720 }
1721 else
1722 {
1723 /* SAFI */
1724 stream_putc (s, safi);
1725
1726 /* prefix */
1727 stream_put_prefix (s, p);
1728 }
1729
1730 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001731 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00001732 stream_putc_at (s, attrlen_pnt, size);
1733
paul9985f832005-02-09 15:51:56 +00001734 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001735}
1736
1737/* Initialization of attribute. */
1738void
paulfe69a502005-09-10 16:55:02 +00001739bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00001740{
1741 void attrhash_init ();
1742
1743 aspath_init ();
1744 attrhash_init ();
1745 community_init ();
1746 ecommunity_init ();
1747 cluster_init ();
1748 transit_init ();
1749}
1750
1751/* Make attribute packet. */
1752void
paula3845922003-10-18 01:30:50 +00001753bgp_dump_routes_attr (struct stream *s, struct attr *attr,
1754 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00001755{
1756 unsigned long cp;
1757 unsigned long len;
paulfe69a502005-09-10 16:55:02 +00001758 unsigned int aspathlen;
paul718e3742002-12-13 20:15:29 +00001759 struct aspath *aspath;
1760
1761 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001762 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001763
1764 /* Place holder of length. */
1765 stream_putw (s, 0);
1766
1767 /* Origin attribute. */
1768 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1769 stream_putc (s, BGP_ATTR_ORIGIN);
1770 stream_putc (s, 1);
1771 stream_putc (s, attr->origin);
1772
1773 aspath = attr->aspath;
1774
paulfe69a502005-09-10 16:55:02 +00001775 if ( (aspathlen = aspath_size (aspath)) > 255 )
paul718e3742002-12-13 20:15:29 +00001776 {
1777 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1778 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001779 stream_putw (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001780 }
1781 else
1782 {
1783 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1784 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001785 stream_putc (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001786 }
paulfe69a502005-09-10 16:55:02 +00001787 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001788
1789 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00001790 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
1791 if(prefix != NULL
1792#ifdef HAVE_IPV6
1793 && prefix->family != AF_INET6
1794#endif /* HAVE_IPV6 */
1795 )
1796 {
1797 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1798 stream_putc (s, BGP_ATTR_NEXT_HOP);
1799 stream_putc (s, 4);
1800 stream_put_ipv4 (s, attr->nexthop.s_addr);
1801 }
paul718e3742002-12-13 20:15:29 +00001802
1803 /* MED attribute. */
1804 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1805 {
1806 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1807 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1808 stream_putc (s, 4);
1809 stream_putl (s, attr->med);
1810 }
1811
1812 /* Local preference. */
1813 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
1814 {
1815 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1816 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1817 stream_putc (s, 4);
1818 stream_putl (s, attr->local_pref);
1819 }
1820
1821 /* Atomic aggregate. */
1822 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1823 {
1824 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1825 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1826 stream_putc (s, 0);
1827 }
1828
1829 /* Aggregator. */
1830 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1831 {
1832 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1833 stream_putc (s, BGP_ATTR_AGGREGATOR);
1834 stream_putc (s, 6);
1835 stream_putw (s, attr->aggregator_as);
1836 stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
1837 }
1838
1839 /* Community attribute. */
1840 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
1841 {
1842 if (attr->community->size * 4 > 255)
1843 {
1844 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1845 stream_putc (s, BGP_ATTR_COMMUNITIES);
1846 stream_putw (s, attr->community->size * 4);
1847 }
1848 else
1849 {
1850 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1851 stream_putc (s, BGP_ATTR_COMMUNITIES);
1852 stream_putc (s, attr->community->size * 4);
1853 }
1854 stream_put (s, attr->community->val, attr->community->size * 4);
1855 }
1856
paula3845922003-10-18 01:30:50 +00001857#ifdef HAVE_IPV6
1858 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
1859 if(prefix != NULL && prefix->family == AF_INET6 &&
1860 (attr->mp_nexthop_len == 16 || attr->mp_nexthop_len == 32) )
1861 {
1862 int sizep;
1863
1864 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
1865 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001866 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00001867
1868 /* MP header */
1869 stream_putc (s, 0); /* Length of this attribute. */
1870 stream_putw(s, AFI_IP6); /* AFI */
1871 stream_putc(s, SAFI_UNICAST); /* SAFI */
1872
1873 /* Next hop */
1874 stream_putc(s, attr->mp_nexthop_len);
1875 stream_put(s, &attr->mp_nexthop_global, 16);
1876 if(attr->mp_nexthop_len == 32)
1877 stream_put(s, &attr->mp_nexthop_local, 16);
1878
1879 /* SNPA */
1880 stream_putc(s, 0);
1881
1882 /* Prefix */
1883 stream_put_prefix(s, prefix);
1884
1885 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001886 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00001887 }
1888#endif /* HAVE_IPV6 */
1889
paul718e3742002-12-13 20:15:29 +00001890 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00001891 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00001892 stream_putw_at (s, cp, len);
1893}