blob: 4c72d80ab7579851821bc287b86b71be04f936e5 [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
Paul Jakmacbdfbaa2006-03-30 13:20:48 +0000277unsigned long int
278attr_count (void)
279{
280 return attrhash->count;
281}
282
283unsigned long int
284attr_unknown_count (void)
285{
286 return transit_hash->count;
287}
288
paul718e3742002-12-13 20:15:29 +0000289unsigned int
290attrhash_key_make (struct attr *attr)
291{
292 unsigned int key = 0;
293
294 key += attr->origin;
295 key += attr->nexthop.s_addr;
296 key += attr->med;
297 key += attr->local_pref;
298 key += attr->aggregator_as;
299 key += attr->aggregator_addr.s_addr;
300 key += attr->weight;
301
302 key += attr->mp_nexthop_global_in.s_addr;
303 if (attr->aspath)
304 key += aspath_key_make (attr->aspath);
305 if (attr->community)
306 key += community_hash_make (attr->community);
307 if (attr->ecommunity)
308 key += ecommunity_hash_make (attr->ecommunity);
309 if (attr->cluster)
310 key += cluster_hash_key_make (attr->cluster);
311 if (attr->transit)
312 key += transit_hash_key_make (attr->transit);
313
314#ifdef HAVE_IPV6
315 {
316 int i;
317
318 key += attr->mp_nexthop_len;
319 for (i = 0; i < 16; i++)
320 key += attr->mp_nexthop_global.s6_addr[i];
321 for (i = 0; i < 16; i++)
322 key += attr->mp_nexthop_local.s6_addr[i];
323 }
324#endif /* HAVE_IPV6 */
325
326 return key;
327}
328
329int
330attrhash_cmp (struct attr *attr1, struct attr *attr2)
331{
332 if (attr1->flag == attr2->flag
333 && attr1->origin == attr2->origin
334 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
335 && attr1->med == attr2->med
336 && attr1->local_pref == attr2->local_pref
337 && attr1->aggregator_as == attr2->aggregator_as
338 && attr1->aggregator_addr.s_addr == attr2->aggregator_addr.s_addr
339 && attr1->weight == attr2->weight
340#ifdef HAVE_IPV6
341 && attr1->mp_nexthop_len == attr2->mp_nexthop_len
342 && IPV6_ADDR_SAME (&attr1->mp_nexthop_global, &attr2->mp_nexthop_global)
343 && IPV6_ADDR_SAME (&attr1->mp_nexthop_local, &attr2->mp_nexthop_local)
344#endif /* HAVE_IPV6 */
345 && IPV4_ADDR_SAME (&attr1->mp_nexthop_global_in, &attr2->mp_nexthop_global_in)
346 && attr1->aspath == attr2->aspath
347 && attr1->community == attr2->community
348 && attr1->ecommunity == attr2->ecommunity
349 && attr1->cluster == attr2->cluster
350 && attr1->transit == attr2->transit)
351 return 1;
352 else
353 return 0;
354}
355
paul94f2b392005-06-28 12:44:16 +0000356static void
paul718e3742002-12-13 20:15:29 +0000357attrhash_init ()
358{
359 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
360}
361
paul94f2b392005-06-28 12:44:16 +0000362static void
paul718e3742002-12-13 20:15:29 +0000363attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
364{
365 struct attr *attr = backet->data;
366
367 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
368 inet_ntoa (attr->nexthop), VTY_NEWLINE);
369}
370
371void
372attr_show_all (struct vty *vty)
373{
374 hash_iterate (attrhash,
375 (void (*)(struct hash_backet *, void *))
376 attr_show_all_iterator,
377 vty);
378}
379
paul94f2b392005-06-28 12:44:16 +0000380static void *
paul718e3742002-12-13 20:15:29 +0000381bgp_attr_hash_alloc (struct attr *val)
382{
383 struct attr *attr;
384
385 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
386 *attr = *val;
387 attr->refcnt = 0;
388 return attr;
389}
390
391/* Internet argument attribute. */
392struct attr *
393bgp_attr_intern (struct attr *attr)
394{
395 struct attr *find;
396
397 /* Intern referenced strucutre. */
398 if (attr->aspath)
399 {
400 if (! attr->aspath->refcnt)
401 attr->aspath = aspath_intern (attr->aspath);
402 else
403 attr->aspath->refcnt++;
404 }
405 if (attr->community)
406 {
407 if (! attr->community->refcnt)
408 attr->community = community_intern (attr->community);
409 else
410 attr->community->refcnt++;
411 }
412 if (attr->ecommunity)
413 {
414 if (! attr->ecommunity->refcnt)
415 attr->ecommunity = ecommunity_intern (attr->ecommunity);
416 else
417 attr->ecommunity->refcnt++;
418 }
419 if (attr->cluster)
420 {
421 if (! attr->cluster->refcnt)
422 attr->cluster = cluster_intern (attr->cluster);
423 else
424 attr->cluster->refcnt++;
425 }
426 if (attr->transit)
427 {
428 if (! attr->transit->refcnt)
429 attr->transit = transit_intern (attr->transit);
430 else
431 attr->transit->refcnt++;
432 }
433
434 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
435 find->refcnt++;
436
437 return find;
438}
439
440/* Make network statement's attribute. */
441struct attr *
442bgp_attr_default_set (struct attr *attr, u_char origin)
443{
444 memset (attr, 0, sizeof (struct attr));
445
446 attr->origin = origin;
447 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
448 attr->aspath = aspath_empty ();
449 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
450 attr->weight = 32768;
451 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
452#ifdef HAVE_IPV6
453 attr->mp_nexthop_len = 16;
454#endif
455 return attr;
456}
457
458/* Make network statement's attribute. */
459struct attr *
460bgp_attr_default_intern (u_char origin)
461{
462 struct attr attr;
463 struct attr *new;
464
465 memset (&attr, 0, sizeof (struct attr));
466
467 attr.origin = origin;
468 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
469 attr.aspath = aspath_empty ();
470 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
471 attr.weight = 32768;
472 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
473#ifdef HAVE_IPV6
474 attr.mp_nexthop_len = 16;
475#endif
476
477 new = bgp_attr_intern (&attr);
478 aspath_unintern (new->aspath);
479 return new;
480}
481
482struct attr *
483bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
484 struct aspath *aspath,
485 struct community *community, int as_set)
486{
487 struct attr attr;
488 struct attr *new;
489
490 memset (&attr, 0, sizeof (struct attr));
491
492 /* Origin attribute. */
493 attr.origin = origin;
494 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
495
496 /* AS path attribute. */
497 if (aspath)
498 attr.aspath = aspath_intern (aspath);
499 else
500 attr.aspath = aspath_empty ();
501 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
502
503 /* Next hop attribute. */
504 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
505
506 if (community)
507 {
508 attr.community = community;
509 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
510 }
511
512 attr.weight = 32768;
513#ifdef HAVE_IPV6
514 attr.mp_nexthop_len = 16;
515#endif
516 if (! as_set)
517 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
518 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
519 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
520 attr.aggregator_as = bgp->confed_id;
521 else
522 attr.aggregator_as = bgp->as;
523 attr.aggregator_addr = bgp->router_id;
524
525 new = bgp_attr_intern (&attr);
526 aspath_unintern (new->aspath);
527 return new;
528}
529
530/* Free bgp attribute and aspath. */
531void
532bgp_attr_unintern (struct attr *attr)
533{
534 struct attr *ret;
535 struct aspath *aspath;
536 struct community *community;
537 struct ecommunity *ecommunity;
538 struct cluster_list *cluster;
539 struct transit *transit;
540
541 /* Decrement attribute reference. */
542 attr->refcnt--;
543 aspath = attr->aspath;
544 community = attr->community;
545 ecommunity = attr->ecommunity;
546 cluster = attr->cluster;
547 transit = attr->transit;
548
549 /* If reference becomes zero then free attribute object. */
550 if (attr->refcnt == 0)
551 {
552 ret = hash_release (attrhash, attr);
553 assert (ret != NULL);
554 XFREE (MTYPE_ATTR, attr);
555 }
556
557 /* aspath refcount shoud be decrement. */
558 if (aspath)
559 aspath_unintern (aspath);
560 if (community)
561 community_unintern (community);
562 if (ecommunity)
563 ecommunity_unintern (ecommunity);
564 if (cluster)
565 cluster_unintern (cluster);
566 if (transit)
567 transit_unintern (transit);
568}
569
570void
571bgp_attr_flush (struct attr *attr)
572{
573 if (attr->aspath && ! attr->aspath->refcnt)
574 aspath_free (attr->aspath);
575 if (attr->community && ! attr->community->refcnt)
576 community_free (attr->community);
577 if (attr->ecommunity && ! attr->ecommunity->refcnt)
578 ecommunity_free (attr->ecommunity);
579 if (attr->cluster && ! attr->cluster->refcnt)
580 cluster_free (attr->cluster);
581 if (attr->transit && ! attr->transit->refcnt)
582 transit_free (attr->transit);
583}
584
585/* Get origin attribute of the update message. */
paul94f2b392005-06-28 12:44:16 +0000586static int
paul718e3742002-12-13 20:15:29 +0000587bgp_attr_origin (struct peer *peer, bgp_size_t length,
588 struct attr *attr, u_char flag, u_char *startp)
589{
590 bgp_size_t total;
591
592 /* total is entire attribute length include Attribute Flags (1),
593 Attribute Type code (1) and Attribute length (1 or 2). */
594 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
595
596 /* If any recognized attribute has Attribute Flags that conflict
597 with the Attribute Type Code, then the Error Subcode is set to
598 Attribute Flags Error. The Data field contains the erroneous
599 attribute (type, length and value). */
600 if (flag != BGP_ATTR_FLAG_TRANS)
601 {
602 zlog (peer->log, LOG_ERR,
603 "Origin attribute flag isn't transitive %d", flag);
604 bgp_notify_send_with_data (peer,
605 BGP_NOTIFY_UPDATE_ERR,
606 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
607 startp, total);
608 return -1;
609 }
610
611 /* If any recognized attribute has Attribute Length that conflicts
612 with the expected length (based on the attribute type code), then
613 the Error Subcode is set to Attribute Length Error. The Data
614 field contains the erroneous attribute (type, length and
615 value). */
616 if (length != 1)
617 {
618 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
619 length);
620 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
621 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
622 startp, total);
623 return -1;
624 }
625
626 /* Fetch origin attribute. */
627 attr->origin = stream_getc (BGP_INPUT (peer));
628
629 /* If the ORIGIN attribute has an undefined value, then the Error
630 Subcode is set to Invalid Origin Attribute. The Data field
631 contains the unrecognized attribute (type, length and value). */
632 if ((attr->origin != BGP_ORIGIN_IGP)
633 && (attr->origin != BGP_ORIGIN_EGP)
634 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
635 {
636 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
637 attr->origin);
638
639 bgp_notify_send_with_data (peer,
640 BGP_NOTIFY_UPDATE_ERR,
641 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
642 startp, total);
643 return -1;
644 }
645
646 /* Set oring attribute flag. */
647 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
648
649 return 0;
650}
651
652/* Parse AS path information. This function is wrapper of
653 aspath_parse. */
paul94f2b392005-06-28 12:44:16 +0000654static int
paul718e3742002-12-13 20:15:29 +0000655bgp_attr_aspath (struct peer *peer, bgp_size_t length,
656 struct attr *attr, u_char flag, u_char *startp)
657{
658 struct bgp *bgp;
659 struct aspath *aspath;
660 bgp_size_t total;
661
662 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
663
664 /* Flag check. */
665 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
666 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
667 {
668 zlog (peer->log, LOG_ERR,
669 "Origin attribute flag isn't transitive %d", flag);
670 bgp_notify_send_with_data (peer,
671 BGP_NOTIFY_UPDATE_ERR,
672 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
673 startp, total);
674 return -1;
675 }
676
677 /* In case of IBGP, length will be zero. */
paulfe69a502005-09-10 16:55:02 +0000678 attr->aspath = aspath_parse (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000679 if (! attr->aspath)
680 {
681 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
682 bgp_notify_send (peer,
683 BGP_NOTIFY_UPDATE_ERR,
684 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
685 return -1;
686 }
687
688 bgp = peer->bgp;
689
690 /* First AS check for EBGP. */
691 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
692 {
693 if (peer_sort (peer) == BGP_PEER_EBGP
694 && ! aspath_firstas_check (attr->aspath, peer->as))
695 {
696 zlog (peer->log, LOG_ERR,
697 "%s incorrect first AS (must be %d)", peer->host, peer->as);
698 bgp_notify_send (peer,
699 BGP_NOTIFY_UPDATE_ERR,
700 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
701 return -1;
702 }
703 }
704
705 /* local-as prepend */
706 if (peer->change_local_as &&
707 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
708 {
709 aspath = aspath_dup (attr->aspath);
710 aspath = aspath_add_seq (aspath, peer->change_local_as);
711 aspath_unintern (attr->aspath);
712 attr->aspath = aspath_intern (aspath);
713 }
714
715 /* Forward pointer. */
paulfe69a502005-09-10 16:55:02 +0000716/* stream_forward_getp (peer->ibuf, length);*/
paul718e3742002-12-13 20:15:29 +0000717
718 /* Set aspath attribute flag. */
719 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
720
721 return 0;
722}
723
724/* Nexthop attribute. */
paul94f2b392005-06-28 12:44:16 +0000725static int
paul718e3742002-12-13 20:15:29 +0000726bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
727 struct attr *attr, u_char flag, u_char *startp)
728{
729 bgp_size_t total;
730
731 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
732
733 /* Flag check. */
734 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
735 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
736 {
737 zlog (peer->log, LOG_ERR,
738 "Origin attribute flag isn't transitive %d", flag);
739 bgp_notify_send_with_data (peer,
740 BGP_NOTIFY_UPDATE_ERR,
741 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
742 startp, total);
743 return -1;
744 }
745
746 /* Check nexthop attribute length. */
747 if (length != 4)
748 {
749 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
750 length);
751
752 bgp_notify_send_with_data (peer,
753 BGP_NOTIFY_UPDATE_ERR,
754 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
755 startp, total);
756 return -1;
757 }
758
759 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
760 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
761
762 return 0;
763}
764
765/* MED atrribute. */
paul94f2b392005-06-28 12:44:16 +0000766static int
paul718e3742002-12-13 20:15:29 +0000767bgp_attr_med (struct peer *peer, bgp_size_t length,
768 struct attr *attr, u_char flag, u_char *startp)
769{
770 bgp_size_t total;
771
772 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
773
774 /* Length check. */
775 if (length != 4)
776 {
777 zlog (peer->log, LOG_ERR,
778 "MED attribute length isn't four [%d]", length);
779
780 bgp_notify_send_with_data (peer,
781 BGP_NOTIFY_UPDATE_ERR,
782 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
783 startp, total);
784 return -1;
785 }
786
787 attr->med = stream_getl (peer->ibuf);
788
789 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
790
791 return 0;
792}
793
794/* Local preference attribute. */
paul94f2b392005-06-28 12:44:16 +0000795static int
paul718e3742002-12-13 20:15:29 +0000796bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
797 struct attr *attr, u_char flag)
798{
799 /* If it is contained in an UPDATE message that is received from an
800 external peer, then this attribute MUST be ignored by the
801 receiving speaker. */
802 if (peer_sort (peer) == BGP_PEER_EBGP)
803 {
paul9985f832005-02-09 15:51:56 +0000804 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000805 return 0;
806 }
807
808 if (length == 4)
809 attr->local_pref = stream_getl (peer->ibuf);
810 else
811 attr->local_pref = 0;
812
813 /* Set atomic aggregate flag. */
814 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
815
816 return 0;
817}
818
819/* Atomic aggregate. */
paul94f2b392005-06-28 12:44:16 +0000820static int
paul718e3742002-12-13 20:15:29 +0000821bgp_attr_atomic (struct peer *peer, bgp_size_t length,
822 struct attr *attr, u_char flag)
823{
824 if (length != 0)
825 {
826 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
827
828 bgp_notify_send (peer,
829 BGP_NOTIFY_UPDATE_ERR,
830 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
831 return -1;
832 }
833
834 /* Set atomic aggregate flag. */
835 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
836
837 return 0;
838}
839
840/* Aggregator attribute */
paul94f2b392005-06-28 12:44:16 +0000841static int
paul718e3742002-12-13 20:15:29 +0000842bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
843 struct attr *attr, u_char flag)
844{
845 if (length != 6)
846 {
847 zlog (peer->log, LOG_ERR, "Aggregator length is not 6 [%d]", length);
848
849 bgp_notify_send (peer,
850 BGP_NOTIFY_UPDATE_ERR,
851 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
852 return -1;
853 }
854 attr->aggregator_as = stream_getw (peer->ibuf);
855 attr->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
856
857 /* Set atomic aggregate flag. */
858 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
859
860 return 0;
861}
862
863/* Community attribute. */
paul94f2b392005-06-28 12:44:16 +0000864static int
paul718e3742002-12-13 20:15:29 +0000865bgp_attr_community (struct peer *peer, bgp_size_t length,
866 struct attr *attr, u_char flag)
867{
868 if (length == 0)
869 attr->community = NULL;
870 else
871 {
paul5228ad22004-06-04 17:58:18 +0000872 attr->community =
873 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +0000874 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +0000875 }
876
877 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
878
879 return 0;
880}
881
882/* Originator ID attribute. */
paul94f2b392005-06-28 12:44:16 +0000883static int
paul718e3742002-12-13 20:15:29 +0000884bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
885 struct attr *attr, u_char flag)
886{
887 if (length != 4)
888 {
889 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
890
891 bgp_notify_send (peer,
892 BGP_NOTIFY_UPDATE_ERR,
893 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
894 return -1;
895 }
896
897 attr->originator_id.s_addr = stream_get_ipv4 (peer->ibuf);
898
899 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
900
901 return 0;
902}
903
904/* Cluster list attribute. */
paul94f2b392005-06-28 12:44:16 +0000905static int
paul718e3742002-12-13 20:15:29 +0000906bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
907 struct attr *attr, u_char flag)
908{
909 /* Check length. */
910 if (length % 4)
911 {
912 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
913
914 bgp_notify_send (peer,
915 BGP_NOTIFY_UPDATE_ERR,
916 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
917 return -1;
918 }
919
paul5228ad22004-06-04 17:58:18 +0000920 attr->cluster = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf),
921 length);
paul718e3742002-12-13 20:15:29 +0000922
paul9985f832005-02-09 15:51:56 +0000923 stream_forward_getp (peer->ibuf, length);;
paul718e3742002-12-13 20:15:29 +0000924
925 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
926
927 return 0;
928}
929
930/* Multiprotocol reachability information parse. */
paul94f2b392005-06-28 12:44:16 +0000931static int
paul718e3742002-12-13 20:15:29 +0000932bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
933 struct bgp_nlri *mp_update)
934{
935 u_int16_t afi;
936 u_char safi;
937 u_char snpa_num;
938 u_char snpa_len;
939 u_char *lim;
940 bgp_size_t nlri_len;
941 int ret;
942 struct stream *s;
943
944 /* Set end of packet. */
945 s = peer->ibuf;
946 lim = stream_pnt (s) + length;
947
948 /* Load AFI, SAFI. */
949 afi = stream_getw (s);
950 safi = stream_getc (s);
951
952 /* Get nexthop length. */
953 attr->mp_nexthop_len = stream_getc (s);
954
955 /* Nexthop length check. */
956 switch (attr->mp_nexthop_len)
957 {
958 case 4:
959 stream_get (&attr->mp_nexthop_global_in, s, 4);
960 break;
961 case 12:
962 {
963 u_int32_t rd_high;
964 u_int32_t rd_low;
965
966 rd_high = stream_getl (s);
967 rd_low = stream_getl (s);
968 stream_get (&attr->mp_nexthop_global_in, s, 4);
969 }
970 break;
971#ifdef HAVE_IPV6
972 case 16:
973 stream_get (&attr->mp_nexthop_global, s, 16);
974 break;
975 case 32:
976 stream_get (&attr->mp_nexthop_global, s, 16);
977 stream_get (&attr->mp_nexthop_local, s, 16);
978 if (! IN6_IS_ADDR_LINKLOCAL (&attr->mp_nexthop_local))
979 {
980 char buf1[INET6_ADDRSTRLEN];
981 char buf2[INET6_ADDRSTRLEN];
982
983 if (BGP_DEBUG (update, UPDATE_IN))
ajs557865c2004-12-08 19:59:11 +0000984 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 +0000985 inet_ntop (AF_INET6, &attr->mp_nexthop_global,
986 buf1, INET6_ADDRSTRLEN),
987 inet_ntop (AF_INET6, &attr->mp_nexthop_local,
988 buf2, INET6_ADDRSTRLEN));
989
990 attr->mp_nexthop_len = 16;
991 }
992 break;
993#endif /* HAVE_IPV6 */
994 default:
995 zlog_info ("Wrong multiprotocol next hop length: %d",
996 attr->mp_nexthop_len);
997 return -1;
paul718e3742002-12-13 20:15:29 +0000998 }
999
1000 snpa_num = stream_getc (s);
1001
1002 while (snpa_num--)
1003 {
1004 snpa_len = stream_getc (s);
paul9985f832005-02-09 15:51:56 +00001005 stream_forward_getp (s, (snpa_len + 1) >> 1);
paul718e3742002-12-13 20:15:29 +00001006 }
1007
paul718e3742002-12-13 20:15:29 +00001008 nlri_len = lim - stream_pnt (s);
1009
1010 if (safi != BGP_SAFI_VPNV4)
1011 {
1012 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1013 if (ret < 0)
1014 return -1;
1015 }
1016
1017 mp_update->afi = afi;
1018 mp_update->safi = safi;
1019 mp_update->nlri = stream_pnt (s);
1020 mp_update->length = nlri_len;
1021
paul9985f832005-02-09 15:51:56 +00001022 stream_forward_getp (s, nlri_len);
paul718e3742002-12-13 20:15:29 +00001023
1024 return 0;
1025}
1026
1027/* Multiprotocol unreachable parse */
paul94f2b392005-06-28 12:44:16 +00001028static int
paul718e3742002-12-13 20:15:29 +00001029bgp_mp_unreach_parse (struct peer *peer, int length,
1030 struct bgp_nlri *mp_withdraw)
1031{
1032 struct stream *s;
1033 u_int16_t afi;
1034 u_char safi;
1035 u_char *lim;
1036 u_int16_t withdraw_len;
1037 int ret;
1038
1039 s = peer->ibuf;
1040 lim = stream_pnt (s) + length;
1041
1042 afi = stream_getw (s);
1043 safi = stream_getc (s);
1044
1045 withdraw_len = lim - stream_pnt (s);
1046
1047 if (safi != BGP_SAFI_VPNV4)
1048 {
1049 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1050 if (ret < 0)
1051 return -1;
1052 }
1053
1054 mp_withdraw->afi = afi;
1055 mp_withdraw->safi = safi;
1056 mp_withdraw->nlri = stream_pnt (s);
1057 mp_withdraw->length = withdraw_len;
1058
paul9985f832005-02-09 15:51:56 +00001059 stream_forward_getp (s, withdraw_len);
paul718e3742002-12-13 20:15:29 +00001060
1061 return 0;
1062}
1063
1064/* Extended Community attribute. */
paul94f2b392005-06-28 12:44:16 +00001065static int
paul718e3742002-12-13 20:15:29 +00001066bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1067 struct attr *attr, u_char flag)
1068{
1069 if (length == 0)
1070 attr->ecommunity = NULL;
1071 else
1072 {
paul5228ad22004-06-04 17:58:18 +00001073 attr->ecommunity =
1074 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
paul9985f832005-02-09 15:51:56 +00001075 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001076 }
1077 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1078
1079 return 0;
1080}
1081
1082/* BGP unknown attribute treatment. */
paul94f2b392005-06-28 12:44:16 +00001083static int
paul718e3742002-12-13 20:15:29 +00001084bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1085 u_char type, bgp_size_t length, u_char *startp)
1086{
1087 bgp_size_t total;
1088 struct transit *transit;
1089
hassof4184462005-02-01 20:13:16 +00001090 if (BGP_DEBUG (normal, NORMAL))
1091 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1092 peer->host, type, length);
1093
paul718e3742002-12-13 20:15:29 +00001094 if (BGP_DEBUG (events, EVENTS))
ajs557865c2004-12-08 19:59:11 +00001095 zlog (peer->log, LOG_DEBUG,
paul718e3742002-12-13 20:15:29 +00001096 "Unknown attribute type %d length %d is received", type, length);
1097
1098 /* Forward read pointer of input stream. */
paul9985f832005-02-09 15:51:56 +00001099 stream_forward_getp (peer->ibuf, length);
paul718e3742002-12-13 20:15:29 +00001100
1101 /* Adjest total length to include type and length. */
1102 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1103
1104 /* If any of the mandatory well-known attributes are not recognized,
1105 then the Error Subcode is set to Unrecognized Well-known
1106 Attribute. The Data field contains the unrecognized attribute
1107 (type, length and value). */
1108 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1109 {
1110 /* Adjust startp to do not include flag value. */
1111 bgp_notify_send_with_data (peer,
1112 BGP_NOTIFY_UPDATE_ERR,
1113 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1114 startp, total);
1115 return -1;
1116 }
1117
1118 /* Unrecognized non-transitive optional attributes must be quietly
1119 ignored and not passed along to other BGP peers. */
1120 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1121 return 0;
1122
1123 /* If a path with recognized transitive optional attribute is
1124 accepted and passed along to other BGP peers and the Partial bit
1125 in the Attribute Flags octet is set to 1 by some previous AS, it
1126 is not set back to 0 by the current AS. */
1127 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1128
1129 /* Store transitive attribute to the end of attr->transit. */
1130 if (! attr->transit)
1131 {
1132 attr->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1133 memset (attr->transit, 0, sizeof (struct transit));
1134 }
1135
1136 transit = attr->transit;
1137
1138 if (transit->val)
1139 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1140 transit->length + total);
1141 else
1142 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1143
1144 memcpy (transit->val + transit->length, startp, total);
1145 transit->length += total;
1146
1147 return 0;
1148}
1149
1150/* Read attribute of update packet. This function is called from
1151 bgp_update() in bgpd.c. */
1152int
1153bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1154 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1155{
1156 int ret;
1157 u_char flag;
1158 u_char type;
1159 bgp_size_t length;
1160 u_char *startp, *endp;
1161 u_char *attr_endp;
1162 u_char seen[BGP_ATTR_BITMAP_SIZE];
1163
1164 /* Initialize bitmap. */
1165 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1166
1167 /* End pointer of BGP attribute. */
1168 endp = BGP_INPUT_PNT (peer) + size;
1169
1170 /* Get attributes to the end of attribute length. */
1171 while (BGP_INPUT_PNT (peer) < endp)
1172 {
1173 /* Check remaining length check.*/
1174 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1175 {
gdtc29fdba2004-12-09 14:46:46 +00001176 /* XXX warning: long int format, int arg (arg 5) */
paul718e3742002-12-13 20:15:29 +00001177 zlog (peer->log, LOG_WARNING,
paula2b1ecd2004-10-31 18:58:09 +00001178 "%s error BGP attribute length %ld is smaller than min len",
paul718e3742002-12-13 20:15:29 +00001179 peer->host, endp - STREAM_PNT (BGP_INPUT (peer)));
1180
1181 bgp_notify_send (peer,
1182 BGP_NOTIFY_UPDATE_ERR,
1183 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1184 return -1;
1185 }
1186
1187 /* Fetch attribute flag and type. */
1188 startp = BGP_INPUT_PNT (peer);
1189 flag = stream_getc (BGP_INPUT (peer));
1190 type = stream_getc (BGP_INPUT (peer));
1191
1192 /* Check extended attribue length bit. */
1193 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1194 length = stream_getw (BGP_INPUT (peer));
1195 else
1196 length = stream_getc (BGP_INPUT (peer));
1197
1198 /* If any attribute appears more than once in the UPDATE
1199 message, then the Error Subcode is set to Malformed Attribute
1200 List. */
1201
1202 if (CHECK_BITMAP (seen, type))
1203 {
1204 zlog (peer->log, LOG_WARNING,
1205 "%s error BGP attribute type %d appears twice in a message",
1206 peer->host, type);
1207
1208 bgp_notify_send (peer,
1209 BGP_NOTIFY_UPDATE_ERR,
1210 BGP_NOTIFY_UPDATE_MAL_ATTR);
1211 return -1;
1212 }
1213
1214 /* Set type to bitmap to check duplicate attribute. `type' is
1215 unsigned char so it never overflow bitmap range. */
1216
1217 SET_BITMAP (seen, type);
1218
1219 /* Overflow check. */
1220 attr_endp = BGP_INPUT_PNT (peer) + length;
1221
1222 if (attr_endp > endp)
1223 {
1224 zlog (peer->log, LOG_WARNING,
1225 "%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);
1226 bgp_notify_send (peer,
1227 BGP_NOTIFY_UPDATE_ERR,
1228 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1229 return -1;
1230 }
1231
1232 /* OK check attribute and store it's value. */
1233 switch (type)
1234 {
1235 case BGP_ATTR_ORIGIN:
1236 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1237 break;
1238 case BGP_ATTR_AS_PATH:
1239 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1240 break;
1241 case BGP_ATTR_NEXT_HOP:
1242 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1243 break;
1244 case BGP_ATTR_MULTI_EXIT_DISC:
1245 ret = bgp_attr_med (peer, length, attr, flag, startp);
1246 break;
1247 case BGP_ATTR_LOCAL_PREF:
1248 ret = bgp_attr_local_pref (peer, length, attr, flag);
1249 break;
1250 case BGP_ATTR_ATOMIC_AGGREGATE:
1251 ret = bgp_attr_atomic (peer, length, attr, flag);
1252 break;
1253 case BGP_ATTR_AGGREGATOR:
1254 ret = bgp_attr_aggregator (peer, length, attr, flag);
1255 break;
1256 case BGP_ATTR_COMMUNITIES:
1257 ret = bgp_attr_community (peer, length, attr, flag);
1258 break;
1259 case BGP_ATTR_ORIGINATOR_ID:
1260 ret = bgp_attr_originator_id (peer, length, attr, flag);
1261 break;
1262 case BGP_ATTR_CLUSTER_LIST:
1263 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1264 break;
1265 case BGP_ATTR_MP_REACH_NLRI:
1266 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1267 break;
1268 case BGP_ATTR_MP_UNREACH_NLRI:
1269 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1270 break;
1271 case BGP_ATTR_EXT_COMMUNITIES:
1272 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1273 break;
1274 default:
1275 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1276 break;
1277 }
1278
1279 /* If error occured immediately return to the caller. */
1280 if (ret < 0)
1281 return ret;
1282
1283 /* Check the fetched length. */
1284 if (BGP_INPUT_PNT (peer) != attr_endp)
1285 {
1286 zlog (peer->log, LOG_WARNING,
1287 "%s BGP attribute fetch error", 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
1295 /* Check final read pointer is same as end pointer. */
1296 if (BGP_INPUT_PNT (peer) != endp)
1297 {
1298 zlog (peer->log, LOG_WARNING,
1299 "%s BGP attribute length mismatch", peer->host);
1300 bgp_notify_send (peer,
1301 BGP_NOTIFY_UPDATE_ERR,
1302 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1303 return -1;
1304 }
1305
1306 /* Finally intern unknown attribute. */
1307 if (attr->transit)
1308 attr->transit = transit_intern (attr->transit);
1309
1310 return 0;
1311}
1312
1313/* Well-known attribute check. */
1314int
1315bgp_attr_check (struct peer *peer, struct attr *attr)
1316{
1317 u_char type = 0;
1318
1319 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1320 type = BGP_ATTR_ORIGIN;
1321
1322 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1323 type = BGP_ATTR_AS_PATH;
1324
1325 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1326 type = BGP_ATTR_NEXT_HOP;
1327
1328 if (peer_sort (peer) == BGP_PEER_IBGP
1329 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1330 type = BGP_ATTR_LOCAL_PREF;
1331
1332 if (type)
1333 {
1334 zlog (peer->log, LOG_WARNING,
1335 "%s Missing well-known attribute %d.",
1336 peer->host, type);
1337 bgp_notify_send_with_data (peer,
1338 BGP_NOTIFY_UPDATE_ERR,
1339 BGP_NOTIFY_UPDATE_MISS_ATTR,
1340 &type, 1);
1341 return -1;
1342 }
1343 return 0;
1344}
1345
1346int stream_put_prefix (struct stream *, struct prefix *);
1347
1348/* Make attribute packet. */
1349bgp_size_t
1350bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1351 struct stream *s, struct attr *attr, struct prefix *p,
1352 afi_t afi, safi_t safi, struct peer *from,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001353 struct prefix_rd *prd, u_char *tag)
paul718e3742002-12-13 20:15:29 +00001354{
paulfe69a502005-09-10 16:55:02 +00001355 size_t cp;
1356 unsigned int aspath_data_size;
paul718e3742002-12-13 20:15:29 +00001357 struct aspath *aspath;
1358
1359 if (! bgp)
1360 bgp = bgp_get_default ();
1361
1362 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001363 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001364
1365 /* Origin attribute. */
1366 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1367 stream_putc (s, BGP_ATTR_ORIGIN);
1368 stream_putc (s, 1);
1369 stream_putc (s, attr->origin);
1370
1371 /* AS path attribute. */
1372
1373 /* If remote-peer is EBGP */
1374 if (peer_sort (peer) == BGP_PEER_EBGP
1375 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
paulfe69a502005-09-10 16:55:02 +00001376 || attr->aspath->segments == NULL)
paulfee0f4c2004-09-13 05:12:46 +00001377 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
paul718e3742002-12-13 20:15:29 +00001378 {
1379 aspath = aspath_dup (attr->aspath);
1380
1381 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1382 {
1383 /* Strip the confed info, and then stuff our path CONFED_ID
1384 on the front */
1385 aspath = aspath_delete_confed_seq (aspath);
1386 aspath = aspath_add_seq (aspath, bgp->confed_id);
1387 }
1388 else
1389 {
1390 aspath = aspath_add_seq (aspath, peer->local_as);
1391 if (peer->change_local_as)
1392 aspath = aspath_add_seq (aspath, peer->change_local_as);
1393 }
1394 }
1395 else if (peer_sort (peer) == BGP_PEER_CONFED)
1396 {
1397 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1398 aspath = aspath_dup (attr->aspath);
1399 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1400 }
1401 else
1402 aspath = attr->aspath;
1403
1404 /* AS path attribute extended length bit check. */
paulfe69a502005-09-10 16:55:02 +00001405 aspath_data_size = aspath_size (aspath);
1406 if (aspath_data_size > 255)
paul718e3742002-12-13 20:15:29 +00001407 {
1408 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1409 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001410 stream_putw (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001411 }
1412 else
1413 {
1414 stream_putc (s, BGP_ATTR_FLAG_TRANS);
paulfe69a502005-09-10 16:55:02 +00001415 stream_putc (s, BGP_ATTR_AS_PATH);
1416 stream_putc (s, aspath_data_size);
paul718e3742002-12-13 20:15:29 +00001417 }
paulfe69a502005-09-10 16:55:02 +00001418 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001419
1420 if (aspath != attr->aspath)
1421 aspath_free (aspath);
1422
1423 /* Nexthop attribute. */
1424 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1425 {
1426 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1427 stream_putc (s, BGP_ATTR_NEXT_HOP);
1428 stream_putc (s, 4);
1429 if (safi == SAFI_MPLS_VPN)
1430 {
1431 if (attr->nexthop.s_addr == 0)
1432 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1433 else
1434 stream_put_ipv4 (s, attr->nexthop.s_addr);
1435 }
1436 else
1437 stream_put_ipv4 (s, attr->nexthop.s_addr);
1438 }
1439
1440 /* MED attribute. */
1441 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1442 {
1443 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1444 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1445 stream_putc (s, 4);
1446 stream_putl (s, attr->med);
1447 }
1448
1449 /* Local preference. */
1450 if (peer_sort (peer) == BGP_PEER_IBGP ||
1451 peer_sort (peer) == BGP_PEER_CONFED)
1452 {
1453 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1454 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1455 stream_putc (s, 4);
1456 stream_putl (s, attr->local_pref);
1457 }
1458
1459 /* Atomic aggregate. */
1460 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1461 {
1462 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1463 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1464 stream_putc (s, 0);
1465 }
1466
1467 /* Aggregator. */
1468 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1469 {
1470 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1471 stream_putc (s, BGP_ATTR_AGGREGATOR);
1472 stream_putc (s, 6);
1473 stream_putw (s, attr->aggregator_as);
1474 stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
1475 }
1476
1477 /* Community attribute. */
1478 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1479 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1480 {
1481 if (attr->community->size * 4 > 255)
1482 {
1483 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1484 stream_putc (s, BGP_ATTR_COMMUNITIES);
1485 stream_putw (s, attr->community->size * 4);
1486 }
1487 else
1488 {
1489 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1490 stream_putc (s, BGP_ATTR_COMMUNITIES);
1491 stream_putc (s, attr->community->size * 4);
1492 }
1493 stream_put (s, attr->community->val, attr->community->size * 4);
1494 }
1495
1496 /* Route Reflector. */
1497 if (peer_sort (peer) == BGP_PEER_IBGP
1498 && from
1499 && peer_sort (from) == BGP_PEER_IBGP)
1500 {
1501 /* Originator ID. */
1502 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1503 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1504 stream_putc (s, 4);
1505
1506 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
1507 stream_put_in_addr (s, &attr->originator_id);
Paul Jakma34c3f812006-05-12 23:25:37 +00001508 else
1509 stream_put_in_addr (s, &from->remote_id);
paul718e3742002-12-13 20:15:29 +00001510
1511 /* Cluster list. */
1512 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1513 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
1514
1515 if (attr->cluster)
1516 {
1517 stream_putc (s, attr->cluster->length + 4);
1518 /* If this peer configuration's parent BGP has cluster_id. */
1519 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1520 stream_put_in_addr (s, &bgp->cluster_id);
1521 else
1522 stream_put_in_addr (s, &bgp->router_id);
1523 stream_put (s, attr->cluster->list, attr->cluster->length);
1524 }
1525 else
1526 {
1527 stream_putc (s, 4);
1528 /* If this peer configuration's parent BGP has cluster_id. */
1529 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
1530 stream_put_in_addr (s, &bgp->cluster_id);
1531 else
1532 stream_put_in_addr (s, &bgp->router_id);
1533 }
1534 }
1535
1536#ifdef HAVE_IPV6
1537 /* If p is IPv6 address put it into attribute. */
1538 if (p->family == AF_INET6)
1539 {
1540 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001541
1542 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1543 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001544 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001545 stream_putc (s, 0); /* Length of this attribute. */
1546 stream_putw (s, AFI_IP6); /* AFI */
1547 stream_putc (s, safi); /* SAFI */
1548
1549 stream_putc (s, attr->mp_nexthop_len);
1550
1551 if (attr->mp_nexthop_len == 16)
1552 stream_put (s, &attr->mp_nexthop_global, 16);
1553 else if (attr->mp_nexthop_len == 32)
1554 {
1555 stream_put (s, &attr->mp_nexthop_global, 16);
1556 stream_put (s, &attr->mp_nexthop_local, 16);
1557 }
1558
1559 /* SNPA */
1560 stream_putc (s, 0);
1561
paul718e3742002-12-13 20:15:29 +00001562 /* Prefix write. */
1563 stream_put_prefix (s, p);
1564
1565 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001566 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001567 }
1568#endif /* HAVE_IPV6 */
1569
1570 if (p->family == AF_INET && safi == SAFI_MULTICAST)
1571 {
1572 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001573
1574 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1575 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001576 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001577 stream_putc (s, 0); /* Length of this attribute. */
1578 stream_putw (s, AFI_IP); /* AFI */
1579 stream_putc (s, SAFI_MULTICAST); /* SAFI */
1580
1581 stream_putc (s, 4);
1582 stream_put_ipv4 (s, attr->nexthop.s_addr);
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
1594 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
1595 {
1596 unsigned long sizep;
paul718e3742002-12-13 20:15:29 +00001597
1598 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1599 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001600 sizep = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001601 stream_putc (s, 0); /* Length of this attribute. */
1602 stream_putw (s, AFI_IP); /* AFI */
1603 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
1604
1605 stream_putc (s, 12);
1606 stream_putl (s, 0);
1607 stream_putl (s, 0);
1608 stream_put (s, &attr->mp_nexthop_global_in, 4);
1609
1610 /* SNPA */
1611 stream_putc (s, 0);
1612
paul718e3742002-12-13 20:15:29 +00001613 /* Tag, RD, Prefix write. */
1614 stream_putc (s, p->prefixlen + 88);
1615 stream_put (s, tag, 3);
1616 stream_put (s, prd->val, 8);
1617 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1618
1619 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001620 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paul718e3742002-12-13 20:15:29 +00001621 }
1622
1623 /* Extended Communities attribute. */
1624 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
1625 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
1626 {
hasso4372df72004-05-20 10:20:02 +00001627 if (peer_sort (peer) == BGP_PEER_IBGP || peer_sort (peer) == BGP_PEER_CONFED)
paul718e3742002-12-13 20:15:29 +00001628 {
hasso4372df72004-05-20 10:20:02 +00001629 if (attr->ecommunity->size * 8 > 255)
1630 {
1631 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1632 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1633 stream_putw (s, attr->ecommunity->size * 8);
1634 }
1635 else
1636 {
1637 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1638 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1639 stream_putc (s, attr->ecommunity->size * 8);
1640 }
1641 stream_put (s, attr->ecommunity->val, attr->ecommunity->size * 8);
paul718e3742002-12-13 20:15:29 +00001642 }
1643 else
1644 {
paul5228ad22004-06-04 17:58:18 +00001645 u_int8_t *pnt;
hasso4372df72004-05-20 10:20:02 +00001646 int tbit;
1647 int ecom_tr_size = 0;
1648 int i;
1649
1650 for (i = 0; i < attr->ecommunity->size; i++)
1651 {
1652 pnt = attr->ecommunity->val + (i * 8);
1653 tbit = *pnt;
1654
1655 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1656 continue;
1657
1658 ecom_tr_size++;
1659 }
1660
1661 if (ecom_tr_size)
1662 {
1663 if (ecom_tr_size * 8 > 255)
1664 {
1665 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1666 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1667 stream_putw (s, ecom_tr_size * 8);
1668 }
1669 else
1670 {
1671 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1672 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
1673 stream_putc (s, ecom_tr_size * 8);
1674 }
1675
1676 for (i = 0; i < attr->ecommunity->size; i++)
1677 {
1678 pnt = attr->ecommunity->val + (i * 8);
1679 tbit = *pnt;
1680
1681 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
1682 continue;
1683
1684 stream_put (s, pnt, 8);
1685 }
1686 }
paul718e3742002-12-13 20:15:29 +00001687 }
paul718e3742002-12-13 20:15:29 +00001688 }
1689
1690 /* Unknown transit attribute. */
1691 if (attr->transit)
1692 stream_put (s, attr->transit->val, attr->transit->length);
1693
1694 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00001695 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001696}
1697
1698bgp_size_t
1699bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
1700 afi_t afi, safi_t safi, struct prefix_rd *prd,
Paul Jakmaa3b6ea52006-05-04 07:52:12 +00001701 u_char *tag)
paul718e3742002-12-13 20:15:29 +00001702{
1703 unsigned long cp;
1704 unsigned long attrlen_pnt;
1705 bgp_size_t size;
1706
paul9985f832005-02-09 15:51:56 +00001707 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001708
1709 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1710 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
1711
paul9985f832005-02-09 15:51:56 +00001712 attrlen_pnt = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001713 stream_putc (s, 0); /* Length of this attribute. */
1714
1715 stream_putw (s, family2afi (p->family));
1716
1717 if (safi == SAFI_MPLS_VPN)
1718 {
1719 /* SAFI */
1720 stream_putc (s, BGP_SAFI_VPNV4);
1721
1722 /* prefix. */
1723 stream_putc (s, p->prefixlen + 88);
1724 stream_put (s, tag, 3);
1725 stream_put (s, prd->val, 8);
1726 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
1727 }
1728 else
1729 {
1730 /* SAFI */
1731 stream_putc (s, safi);
1732
1733 /* prefix */
1734 stream_put_prefix (s, p);
1735 }
1736
1737 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001738 size = stream_get_endp (s) - attrlen_pnt - 1;
paul718e3742002-12-13 20:15:29 +00001739 stream_putc_at (s, attrlen_pnt, size);
1740
paul9985f832005-02-09 15:51:56 +00001741 return stream_get_endp (s) - cp;
paul718e3742002-12-13 20:15:29 +00001742}
1743
1744/* Initialization of attribute. */
1745void
paulfe69a502005-09-10 16:55:02 +00001746bgp_attr_init (void)
paul718e3742002-12-13 20:15:29 +00001747{
1748 void attrhash_init ();
1749
1750 aspath_init ();
1751 attrhash_init ();
1752 community_init ();
1753 ecommunity_init ();
1754 cluster_init ();
1755 transit_init ();
1756}
1757
1758/* Make attribute packet. */
1759void
paula3845922003-10-18 01:30:50 +00001760bgp_dump_routes_attr (struct stream *s, struct attr *attr,
1761 struct prefix *prefix)
paul718e3742002-12-13 20:15:29 +00001762{
1763 unsigned long cp;
1764 unsigned long len;
paulfe69a502005-09-10 16:55:02 +00001765 unsigned int aspathlen;
paul718e3742002-12-13 20:15:29 +00001766 struct aspath *aspath;
1767
1768 /* Remember current pointer. */
paul9985f832005-02-09 15:51:56 +00001769 cp = stream_get_endp (s);
paul718e3742002-12-13 20:15:29 +00001770
1771 /* Place holder of length. */
1772 stream_putw (s, 0);
1773
1774 /* Origin attribute. */
1775 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1776 stream_putc (s, BGP_ATTR_ORIGIN);
1777 stream_putc (s, 1);
1778 stream_putc (s, attr->origin);
1779
1780 aspath = attr->aspath;
1781
paulfe69a502005-09-10 16:55:02 +00001782 if ( (aspathlen = aspath_size (aspath)) > 255 )
paul718e3742002-12-13 20:15:29 +00001783 {
1784 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1785 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001786 stream_putw (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001787 }
1788 else
1789 {
1790 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1791 stream_putc (s, BGP_ATTR_AS_PATH);
paulfe69a502005-09-10 16:55:02 +00001792 stream_putc (s, aspathlen);
paul718e3742002-12-13 20:15:29 +00001793 }
paulfe69a502005-09-10 16:55:02 +00001794 aspath_put (s, aspath);
paul718e3742002-12-13 20:15:29 +00001795
1796 /* Nexthop attribute. */
paula3845922003-10-18 01:30:50 +00001797 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
1798 if(prefix != NULL
1799#ifdef HAVE_IPV6
1800 && prefix->family != AF_INET6
1801#endif /* HAVE_IPV6 */
1802 )
1803 {
1804 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1805 stream_putc (s, BGP_ATTR_NEXT_HOP);
1806 stream_putc (s, 4);
1807 stream_put_ipv4 (s, attr->nexthop.s_addr);
1808 }
paul718e3742002-12-13 20:15:29 +00001809
1810 /* MED attribute. */
1811 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1812 {
1813 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1814 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1815 stream_putc (s, 4);
1816 stream_putl (s, attr->med);
1817 }
1818
1819 /* Local preference. */
1820 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
1821 {
1822 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1823 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1824 stream_putc (s, 4);
1825 stream_putl (s, attr->local_pref);
1826 }
1827
1828 /* Atomic aggregate. */
1829 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1830 {
1831 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1832 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1833 stream_putc (s, 0);
1834 }
1835
1836 /* Aggregator. */
1837 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1838 {
1839 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1840 stream_putc (s, BGP_ATTR_AGGREGATOR);
1841 stream_putc (s, 6);
1842 stream_putw (s, attr->aggregator_as);
1843 stream_put_ipv4 (s, attr->aggregator_addr.s_addr);
1844 }
1845
1846 /* Community attribute. */
1847 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
1848 {
1849 if (attr->community->size * 4 > 255)
1850 {
1851 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1852 stream_putc (s, BGP_ATTR_COMMUNITIES);
1853 stream_putw (s, attr->community->size * 4);
1854 }
1855 else
1856 {
1857 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1858 stream_putc (s, BGP_ATTR_COMMUNITIES);
1859 stream_putc (s, attr->community->size * 4);
1860 }
1861 stream_put (s, attr->community->val, attr->community->size * 4);
1862 }
1863
paula3845922003-10-18 01:30:50 +00001864#ifdef HAVE_IPV6
1865 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
1866 if(prefix != NULL && prefix->family == AF_INET6 &&
1867 (attr->mp_nexthop_len == 16 || attr->mp_nexthop_len == 32) )
1868 {
1869 int sizep;
1870
1871 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
1872 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
paul9985f832005-02-09 15:51:56 +00001873 sizep = stream_get_endp (s);
paula3845922003-10-18 01:30:50 +00001874
1875 /* MP header */
1876 stream_putc (s, 0); /* Length of this attribute. */
1877 stream_putw(s, AFI_IP6); /* AFI */
1878 stream_putc(s, SAFI_UNICAST); /* SAFI */
1879
1880 /* Next hop */
1881 stream_putc(s, attr->mp_nexthop_len);
1882 stream_put(s, &attr->mp_nexthop_global, 16);
1883 if(attr->mp_nexthop_len == 32)
1884 stream_put(s, &attr->mp_nexthop_local, 16);
1885
1886 /* SNPA */
1887 stream_putc(s, 0);
1888
1889 /* Prefix */
1890 stream_put_prefix(s, prefix);
1891
1892 /* Set MP attribute length. */
paul9985f832005-02-09 15:51:56 +00001893 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
paula3845922003-10-18 01:30:50 +00001894 }
1895#endif /* HAVE_IPV6 */
1896
paul718e3742002-12-13 20:15:29 +00001897 /* Return total size of attribute. */
paul9985f832005-02-09 15:51:56 +00001898 len = stream_get_endp (s) - cp - 2;
paul718e3742002-12-13 20:15:29 +00001899 stream_putw_at (s, cp, len);
1900}