[bgpd] AS4 bugfix by Chris Caputo <ccaputo@alt.net>
[jleu-quagga.git] / bgpd / bgp_attr.c
blobf38db4149e57009d833bea2e883743b7dcd23155
1 /* BGP attributes management routines.
2 Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
4 This file is part of GNU Zebra.
6 GNU Zebra is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
11 GNU Zebra is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Zebra; see the file COPYING. If not, write to the Free
18 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA. */
21 #include <zebra.h>
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"
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"
41 /* Attribute strings for logging. */
42 static struct message attr_str [] =
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 { BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES" },
60 { BGP_ATTR_AS4_PATH, "AS4_PATH" },
61 { BGP_ATTR_AS4_AGGREGATOR, "AS4_AGGREGATOR" },
62 { BGP_ATTR_AS_PATHLIMIT, "AS_PATHLIMIT" },
64 int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
66 struct hash *cluster_hash;
68 static void *
69 cluster_hash_alloc (void *p)
71 struct cluster_list * val = (struct cluster_list *) p;
72 struct cluster_list *cluster;
74 cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
75 cluster->length = val->length;
77 if (cluster->length)
79 cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
80 memcpy (cluster->list, val->list, val->length);
82 else
83 cluster->list = NULL;
85 cluster->refcnt = 0;
87 return cluster;
90 /* Cluster list related functions. */
91 static struct cluster_list *
92 cluster_parse (struct in_addr * pnt, int length)
94 struct cluster_list tmp;
95 struct cluster_list *cluster;
97 tmp.length = length;
98 tmp.list = pnt;
100 cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
101 cluster->refcnt++;
102 return cluster;
106 cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
108 int i;
110 for (i = 0; i < cluster->length / 4; i++)
111 if (cluster->list[i].s_addr == originator.s_addr)
112 return 1;
113 return 0;
116 static unsigned int
117 cluster_hash_key_make (void *p)
119 struct cluster_list * cluster = (struct cluster_list *) p;
120 unsigned int key = 0;
121 int length;
122 caddr_t pnt;
124 length = cluster->length;
125 pnt = (caddr_t) cluster->list;
127 while (length)
128 key += pnt[--length];
130 return key;
133 static int
134 cluster_hash_cmp (const void *p1, const void *p2)
136 const struct cluster_list * cluster1 = p1;
137 const struct cluster_list * cluster2 = p2;
139 return (cluster1->length == cluster2->length &&
140 memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
143 static void
144 cluster_free (struct cluster_list *cluster)
146 if (cluster->list)
147 XFREE (MTYPE_CLUSTER_VAL, cluster->list);
148 XFREE (MTYPE_CLUSTER, cluster);
151 static struct cluster_list *
152 cluster_dup (struct cluster_list *cluster)
154 struct cluster_list *new;
156 new = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
157 memset (new, 0, sizeof (struct cluster_list));
158 new->length = cluster->length;
160 if (cluster->length)
162 new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
163 memcpy (new->list, cluster->list, cluster->length);
165 else
166 new->list = NULL;
168 return new;
171 static struct cluster_list *
172 cluster_intern (struct cluster_list *cluster)
174 struct cluster_list *find;
176 find = hash_get (cluster_hash, cluster, cluster_hash_alloc);
177 find->refcnt++;
179 return find;
182 void
183 cluster_unintern (struct cluster_list *cluster)
185 struct cluster_list *ret;
187 if (cluster->refcnt)
188 cluster->refcnt--;
190 if (cluster->refcnt == 0)
192 ret = hash_release (cluster_hash, cluster);
193 cluster_free (cluster);
197 static void
198 cluster_init (void)
200 cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
203 /* Unknown transit attribute. */
204 struct hash *transit_hash;
206 static void
207 transit_free (struct transit *transit)
209 if (transit->val)
210 XFREE (MTYPE_TRANSIT_VAL, transit->val);
211 XFREE (MTYPE_TRANSIT, transit);
215 static void *
216 transit_hash_alloc (void *p)
218 /* Transit structure is already allocated. */
219 return p;
222 static struct transit *
223 transit_intern (struct transit *transit)
225 struct transit *find;
227 find = hash_get (transit_hash, transit, transit_hash_alloc);
228 if (find != transit)
229 transit_free (transit);
230 find->refcnt++;
232 return find;
235 void
236 transit_unintern (struct transit *transit)
238 struct transit *ret;
240 if (transit->refcnt)
241 transit->refcnt--;
243 if (transit->refcnt == 0)
245 ret = hash_release (transit_hash, transit);
246 transit_free (transit);
250 static unsigned int
251 transit_hash_key_make (void *p)
253 struct transit * transit = (struct transit *) p;
254 unsigned int key = 0;
255 int length;
256 caddr_t pnt;
258 length = transit->length;
259 pnt = (caddr_t) transit->val;
261 while (length)
262 key += pnt[--length];
264 return key;
267 static int
268 transit_hash_cmp (const void *p1, const void *p2)
270 const struct transit * transit1 = p1;
271 const struct transit * transit2 = p2;
273 return (transit1->length == transit2->length &&
274 memcmp (transit1->val, transit2->val, transit1->length) == 0);
277 static void
278 transit_init ()
280 transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
283 /* Attribute hash routines. */
284 struct hash *attrhash;
286 static struct attr_extra *
287 bgp_attr_extra_new (void)
289 return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
292 void
293 bgp_attr_extra_free (struct attr *attr)
295 if (attr->extra)
297 XFREE (MTYPE_ATTR_EXTRA, attr->extra);
298 attr->extra = NULL;
302 struct attr_extra *
303 bgp_attr_extra_get (struct attr *attr)
305 if (!attr->extra)
306 attr->extra = bgp_attr_extra_new();
307 return attr->extra;
310 /* Shallow copy of an attribute
311 * Though, not so shallow that it doesn't copy the contents
312 * of the attr_extra pointed to by 'extra'
314 void
315 bgp_attr_dup (struct attr *new, struct attr *orig)
317 *new = *orig;
318 if (orig->extra)
320 new->extra = bgp_attr_extra_new();
321 *new->extra = *orig->extra;
325 unsigned long int
326 attr_count (void)
328 return attrhash->count;
331 unsigned long int
332 attr_unknown_count (void)
334 return transit_hash->count;
337 unsigned int
338 attrhash_key_make (void *p)
340 struct attr * attr = (struct attr *) p;
341 unsigned int key = 0;
343 key += attr->origin;
344 key += attr->nexthop.s_addr;
345 key += attr->med;
346 key += attr->local_pref;
347 if (attr->pathlimit.as)
349 key += attr->pathlimit.ttl;
350 key += attr->pathlimit.as;
353 if (attr->extra)
355 key += attr->extra->aggregator_as;
356 key += attr->extra->aggregator_addr.s_addr;
357 key += attr->extra->weight;
358 key += attr->extra->mp_nexthop_global_in.s_addr;
361 if (attr->aspath)
362 key += aspath_key_make (attr->aspath);
363 if (attr->community)
364 key += community_hash_make (attr->community);
366 if (attr->extra)
368 if (attr->extra->ecommunity)
369 key += ecommunity_hash_make (attr->extra->ecommunity);
370 if (attr->extra->cluster)
371 key += cluster_hash_key_make (attr->extra->cluster);
372 if (attr->extra->transit)
373 key += transit_hash_key_make (attr->extra->transit);
375 #ifdef HAVE_IPV6
377 int i;
379 key += attr->extra->mp_nexthop_len;
380 for (i = 0; i < 16; i++)
381 key += attr->extra->mp_nexthop_global.s6_addr[i];
382 for (i = 0; i < 16; i++)
383 key += attr->extra->mp_nexthop_local.s6_addr[i];
385 #endif /* HAVE_IPV6 */
388 return key;
392 attrhash_cmp (const void *p1, const void *p2)
394 const struct attr * attr1 = p1;
395 const struct attr * attr2 = p2;
397 if (attr1->flag == attr2->flag
398 && attr1->origin == attr2->origin
399 && attr1->nexthop.s_addr == attr2->nexthop.s_addr
400 && attr1->aspath == attr2->aspath
401 && attr1->community == attr2->community
402 && attr1->med == attr2->med
403 && attr1->local_pref == attr2->local_pref
404 && attr1->pathlimit.ttl == attr2->pathlimit.ttl
405 && attr1->pathlimit.as == attr2->pathlimit.as)
407 const struct attr_extra *ae1 = attr1->extra;
408 const struct attr_extra *ae2 = attr2->extra;
410 if (ae1 && ae2
411 && ae1->aggregator_as == ae2->aggregator_as
412 && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
413 && ae1->weight == ae2->weight
414 #ifdef HAVE_IPV6
415 && ae1->mp_nexthop_len == ae2->mp_nexthop_len
416 && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
417 && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
418 #endif /* HAVE_IPV6 */
419 && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
420 && ae1->ecommunity == ae2->ecommunity
421 && ae1->cluster == ae2->cluster
422 && ae1->transit == ae2->transit)
423 return 1;
424 else if (ae1 || ae2)
425 return 0;
426 /* neither attribute has extra attributes, so they're same */
427 return 1;
429 else
430 return 0;
433 static void
434 attrhash_init (void)
436 attrhash = hash_create (attrhash_key_make, attrhash_cmp);
439 static void
440 attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
442 struct attr *attr = backet->data;
444 vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt,
445 inet_ntoa (attr->nexthop), VTY_NEWLINE);
448 void
449 attr_show_all (struct vty *vty)
451 hash_iterate (attrhash,
452 (void (*)(struct hash_backet *, void *))
453 attr_show_all_iterator,
454 vty);
457 static void *
458 bgp_attr_hash_alloc (void *p)
460 struct attr * val = (struct attr *) p;
461 struct attr *attr;
463 attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
464 *attr = *val;
465 if (val->extra)
467 attr->extra = bgp_attr_extra_new ();
468 *attr->extra = *val->extra;
470 attr->refcnt = 0;
471 return attr;
474 /* Internet argument attribute. */
475 struct attr *
476 bgp_attr_intern (struct attr *attr)
478 struct attr *find;
480 /* Intern referenced strucutre. */
481 if (attr->aspath)
483 if (! attr->aspath->refcnt)
484 attr->aspath = aspath_intern (attr->aspath);
485 else
486 attr->aspath->refcnt++;
488 if (attr->community)
490 if (! attr->community->refcnt)
491 attr->community = community_intern (attr->community);
492 else
493 attr->community->refcnt++;
495 if (attr->extra)
497 struct attr_extra *attre = attr->extra;
499 if (attre->ecommunity)
501 if (! attre->ecommunity->refcnt)
502 attre->ecommunity = ecommunity_intern (attre->ecommunity);
503 else
504 attre->ecommunity->refcnt++;
506 if (attre->cluster)
508 if (! attre->cluster->refcnt)
509 attre->cluster = cluster_intern (attre->cluster);
510 else
511 attre->cluster->refcnt++;
513 if (attre->transit)
515 if (! attre->transit->refcnt)
516 attre->transit = transit_intern (attre->transit);
517 else
518 attre->transit->refcnt++;
522 find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
523 find->refcnt++;
525 return find;
529 /* Make network statement's attribute. */
530 struct attr *
531 bgp_attr_default_set (struct attr *attr, u_char origin)
533 memset (attr, 0, sizeof (struct attr));
534 bgp_attr_extra_get (attr);
536 attr->origin = origin;
537 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
538 attr->aspath = aspath_empty ();
539 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
540 attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
541 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
542 #ifdef HAVE_IPV6
543 attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
544 #endif
546 return attr;
550 /* Make network statement's attribute. */
551 struct attr *
552 bgp_attr_default_intern (u_char origin)
554 struct attr attr;
555 struct attr *new;
556 struct attr_extra *attre;
558 memset (&attr, 0, sizeof (struct attr));
559 attre = bgp_attr_extra_get (&attr);
561 bgp_attr_default_set(&attr, origin);
563 new = bgp_attr_intern (&attr);
564 bgp_attr_extra_free (&attr);
566 aspath_unintern (new->aspath);
567 return new;
570 struct attr *
571 bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
572 struct aspath *aspath,
573 struct community *community, int as_set)
575 struct attr attr;
576 struct attr *new;
577 struct attr_extra *attre;
579 memset (&attr, 0, sizeof (struct attr));
580 attre = bgp_attr_extra_get (&attr);
582 /* Origin attribute. */
583 attr.origin = origin;
584 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
586 /* AS path attribute. */
587 if (aspath)
588 attr.aspath = aspath_intern (aspath);
589 else
590 attr.aspath = aspath_empty ();
591 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
593 /* Next hop attribute. */
594 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
596 if (community)
598 attr.community = community;
599 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
602 attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
603 #ifdef HAVE_IPV6
604 attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
605 #endif
606 if (! as_set)
607 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
608 attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
609 if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
610 attre->aggregator_as = bgp->confed_id;
611 else
612 attre->aggregator_as = bgp->as;
613 attre->aggregator_addr = bgp->router_id;
615 new = bgp_attr_intern (&attr);
616 bgp_attr_extra_free (&attr);
618 aspath_unintern (new->aspath);
619 return new;
622 /* Free bgp attribute and aspath. */
623 void
624 bgp_attr_unintern (struct attr *attr)
626 struct attr *ret;
627 struct aspath *aspath;
628 struct community *community;
629 struct ecommunity *ecommunity = NULL;
630 struct cluster_list *cluster = NULL;
631 struct transit *transit = NULL;
633 /* Decrement attribute reference. */
634 attr->refcnt--;
635 aspath = attr->aspath;
636 community = attr->community;
637 if (attr->extra)
639 ecommunity = attr->extra->ecommunity;
640 cluster = attr->extra->cluster;
641 transit = attr->extra->transit;
644 /* If reference becomes zero then free attribute object. */
645 if (attr->refcnt == 0)
647 ret = hash_release (attrhash, attr);
648 assert (ret != NULL);
649 bgp_attr_extra_free (attr);
650 XFREE (MTYPE_ATTR, attr);
653 /* aspath refcount shoud be decrement. */
654 if (aspath)
655 aspath_unintern (aspath);
656 if (community)
657 community_unintern (community);
658 if (ecommunity)
659 ecommunity_unintern (ecommunity);
660 if (cluster)
661 cluster_unintern (cluster);
662 if (transit)
663 transit_unintern (transit);
666 void
667 bgp_attr_flush (struct attr *attr)
669 if (attr->aspath && ! attr->aspath->refcnt)
670 aspath_free (attr->aspath);
671 if (attr->community && ! attr->community->refcnt)
672 community_free (attr->community);
673 if (attr->extra)
675 struct attr_extra *attre = attr->extra;
676 if (attre->ecommunity && ! attre->ecommunity->refcnt)
677 ecommunity_free (attre->ecommunity);
678 if (attre->cluster && ! attre->cluster->refcnt)
679 cluster_free (attre->cluster);
680 if (attre->transit && ! attre->transit->refcnt)
681 transit_free (attre->transit);
685 /* Parse AS_PATHLIMIT attribute in an UPDATE */
686 static int
687 bgp_attr_aspathlimit (struct peer *peer, bgp_size_t length,
688 struct attr *attr, u_char flag, u_char *startp)
690 bgp_size_t total;
692 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
694 if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
695 || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
697 zlog (peer->log, LOG_ERR,
698 "AS-Pathlimit attribute flag isn't transitive %d", flag);
699 bgp_notify_send_with_data (peer,
700 BGP_NOTIFY_UPDATE_ERR,
701 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
702 startp, total);
703 return -1;
706 if (length != 5)
708 zlog (peer->log, LOG_ERR,
709 "AS-Pathlimit length, %u, is not 5", length);
710 bgp_notify_send_with_data (peer,
711 BGP_NOTIFY_UPDATE_ERR,
712 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
713 startp, total);
714 return -1;
717 attr->pathlimit.ttl = stream_getc (BGP_INPUT(peer));
718 attr->pathlimit.as = stream_getl (BGP_INPUT(peer));
719 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT);
720 return 0;
722 /* Get origin attribute of the update message. */
723 static int
724 bgp_attr_origin (struct peer *peer, bgp_size_t length,
725 struct attr *attr, u_char flag, u_char *startp)
727 bgp_size_t total;
729 /* total is entire attribute length include Attribute Flags (1),
730 Attribute Type code (1) and Attribute length (1 or 2). */
731 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
733 /* If any recognized attribute has Attribute Flags that conflict
734 with the Attribute Type Code, then the Error Subcode is set to
735 Attribute Flags Error. The Data field contains the erroneous
736 attribute (type, length and value). */
737 if (flag != BGP_ATTR_FLAG_TRANS)
739 zlog (peer->log, LOG_ERR,
740 "Origin attribute flag isn't transitive %d", flag);
741 bgp_notify_send_with_data (peer,
742 BGP_NOTIFY_UPDATE_ERR,
743 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
744 startp, total);
745 return -1;
748 /* If any recognized attribute has Attribute Length that conflicts
749 with the expected length (based on the attribute type code), then
750 the Error Subcode is set to Attribute Length Error. The Data
751 field contains the erroneous attribute (type, length and
752 value). */
753 if (length != 1)
755 zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
756 length);
757 bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,
758 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
759 startp, total);
760 return -1;
763 /* Fetch origin attribute. */
764 attr->origin = stream_getc (BGP_INPUT (peer));
766 /* If the ORIGIN attribute has an undefined value, then the Error
767 Subcode is set to Invalid Origin Attribute. The Data field
768 contains the unrecognized attribute (type, length and value). */
769 if ((attr->origin != BGP_ORIGIN_IGP)
770 && (attr->origin != BGP_ORIGIN_EGP)
771 && (attr->origin != BGP_ORIGIN_INCOMPLETE))
773 zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
774 attr->origin);
776 bgp_notify_send_with_data (peer,
777 BGP_NOTIFY_UPDATE_ERR,
778 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
779 startp, total);
780 return -1;
783 /* Set oring attribute flag. */
784 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
786 return 0;
789 /* Parse AS path information. This function is wrapper of
790 aspath_parse. */
791 static int
792 bgp_attr_aspath (struct peer *peer, bgp_size_t length,
793 struct attr *attr, u_char flag, u_char *startp)
795 bgp_size_t total;
797 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
799 /* Flag check. */
800 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
801 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
803 zlog (peer->log, LOG_ERR,
804 "As-Path attribute flag isn't transitive %d", flag);
805 bgp_notify_send_with_data (peer,
806 BGP_NOTIFY_UPDATE_ERR,
807 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
808 startp, total);
809 return -1;
813 * peer with AS4 => will get 4Byte ASnums
814 * otherwise, will get 16 Bit
816 attr->aspath = aspath_parse (peer->ibuf, length,
817 CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
819 /* In case of IBGP, length will be zero. */
820 if (! attr->aspath)
822 zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
823 bgp_notify_send (peer,
824 BGP_NOTIFY_UPDATE_ERR,
825 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
826 return -1;
829 /* Forward pointer. */
830 /* stream_forward_getp (peer->ibuf, length);*/
832 /* Set aspath attribute flag. */
833 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
835 return 0;
838 static int bgp_attr_aspath_check( struct peer *peer,
839 struct attr *attr)
841 /* These checks were part of bgp_attr_aspath, but with
842 * as4 we should to check aspath things when
843 * aspath synthesizing with as4_path has already taken place.
844 * Otherwise we check ASPATH and use the synthesized thing, and that is
845 * not right.
846 * So do the checks later, i.e. here
848 struct bgp *bgp = peer->bgp;
849 struct aspath *aspath;
851 bgp = peer->bgp;
853 /* First AS check for EBGP. */
854 if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
856 if (peer_sort (peer) == BGP_PEER_EBGP
857 && ! aspath_firstas_check (attr->aspath, peer->as))
859 zlog (peer->log, LOG_ERR,
860 "%s incorrect first AS (must be %u)", peer->host, peer->as);
861 bgp_notify_send (peer,
862 BGP_NOTIFY_UPDATE_ERR,
863 BGP_NOTIFY_UPDATE_MAL_AS_PATH);
864 return -1;
868 /* local-as prepend */
869 if (peer->change_local_as &&
870 ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
872 aspath = aspath_dup (attr->aspath);
873 aspath = aspath_add_seq (aspath, peer->change_local_as);
874 aspath_unintern (attr->aspath);
875 attr->aspath = aspath_intern (aspath);
878 return 0;
882 /* Parse AS4 path information. This function is another wrapper of
883 aspath_parse. */
884 static int
885 bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
886 struct attr *attr, struct aspath **as4_path)
888 *as4_path = aspath_parse (peer->ibuf, length, 1);
890 /* Set aspath attribute flag. */
891 if (as4_path)
892 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
894 return 0;
897 /* Nexthop attribute. */
898 static int
899 bgp_attr_nexthop (struct peer *peer, bgp_size_t length,
900 struct attr *attr, u_char flag, u_char *startp)
902 bgp_size_t total;
904 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
906 /* Flag check. */
907 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
908 || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
910 zlog (peer->log, LOG_ERR,
911 "Origin attribute flag isn't transitive %d", flag);
912 bgp_notify_send_with_data (peer,
913 BGP_NOTIFY_UPDATE_ERR,
914 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
915 startp, total);
916 return -1;
919 /* Check nexthop attribute length. */
920 if (length != 4)
922 zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
923 length);
925 bgp_notify_send_with_data (peer,
926 BGP_NOTIFY_UPDATE_ERR,
927 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
928 startp, total);
929 return -1;
932 attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
933 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
935 return 0;
938 /* MED atrribute. */
939 static int
940 bgp_attr_med (struct peer *peer, bgp_size_t length,
941 struct attr *attr, u_char flag, u_char *startp)
943 bgp_size_t total;
945 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
947 /* Length check. */
948 if (length != 4)
950 zlog (peer->log, LOG_ERR,
951 "MED attribute length isn't four [%d]", length);
953 bgp_notify_send_with_data (peer,
954 BGP_NOTIFY_UPDATE_ERR,
955 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
956 startp, total);
957 return -1;
960 attr->med = stream_getl (peer->ibuf);
962 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
964 return 0;
967 /* Local preference attribute. */
968 static int
969 bgp_attr_local_pref (struct peer *peer, bgp_size_t length,
970 struct attr *attr, u_char flag)
972 /* If it is contained in an UPDATE message that is received from an
973 external peer, then this attribute MUST be ignored by the
974 receiving speaker. */
975 if (peer_sort (peer) == BGP_PEER_EBGP)
977 stream_forward_getp (peer->ibuf, length);
978 return 0;
981 if (length == 4)
982 attr->local_pref = stream_getl (peer->ibuf);
983 else
984 attr->local_pref = 0;
986 /* Set atomic aggregate flag. */
987 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
989 return 0;
992 /* Atomic aggregate. */
993 static int
994 bgp_attr_atomic (struct peer *peer, bgp_size_t length,
995 struct attr *attr, u_char flag)
997 if (length != 0)
999 zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
1001 bgp_notify_send (peer,
1002 BGP_NOTIFY_UPDATE_ERR,
1003 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1004 return -1;
1007 /* Set atomic aggregate flag. */
1008 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
1010 return 0;
1013 /* Aggregator attribute */
1014 static int
1015 bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
1016 struct attr *attr, u_char flag)
1018 int wantedlen = 6;
1019 struct attr_extra *attre = bgp_attr_extra_get (attr);
1021 /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
1022 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1023 wantedlen = 8;
1025 if (length != wantedlen)
1027 zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
1029 bgp_notify_send (peer,
1030 BGP_NOTIFY_UPDATE_ERR,
1031 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1032 return -1;
1035 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
1036 attre->aggregator_as = stream_getl (peer->ibuf);
1037 else
1038 attre->aggregator_as = stream_getw (peer->ibuf);
1039 attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
1041 /* Set atomic aggregate flag. */
1042 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
1044 return 0;
1047 /* New Aggregator attribute */
1048 static int
1049 bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
1050 struct attr *attr, as_t *as4_aggregator_as,
1051 struct in_addr *as4_aggregator_addr)
1053 if (length != 8)
1055 zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
1057 bgp_notify_send (peer,
1058 BGP_NOTIFY_UPDATE_ERR,
1059 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1060 return -1;
1062 *as4_aggregator_as = stream_getl (peer->ibuf);
1063 as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
1065 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
1067 return 0;
1070 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
1072 static int
1073 bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,
1074 struct aspath *as4_path, as_t as4_aggregator,
1075 struct in_addr *as4_aggregator_addr)
1077 int ignore_as4_path = 0;
1078 struct aspath *newpath;
1079 struct attr_extra *attre = attr->extra;
1081 if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV) )
1083 /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
1084 * if given.
1085 * It is worth a warning though, because the peer really
1086 * should not send them
1088 if (BGP_DEBUG(as4, AS4))
1090 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
1091 zlog_debug ("[AS4] %s %s AS4_PATH",
1092 peer->host, "AS4 capable peer, yet it sent");
1094 if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
1095 zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
1096 peer->host, "AS4 capable peer, yet it sent");
1099 return 0;
1102 if (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))
1103 && !(attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH))))
1105 /* Hu? This is not supposed to happen at all!
1106 * got as4_path and no aspath,
1107 * This should already
1108 * have been handled by 'well known attributes missing'
1109 * But... yeah, paranoia
1110 * Take this as a "malformed attribute"
1112 zlog (peer->log, LOG_ERR,
1113 "%s BGP not AS4 capable peer sent AS4_PATH but"
1114 " no AS_PATH, cant do anything here", peer->host);
1115 bgp_notify_send (peer,
1116 BGP_NOTIFY_UPDATE_ERR,
1117 BGP_NOTIFY_UPDATE_MAL_ATTR);
1118 return -1;
1121 /* We have a asn16 peer. First, look for AS4_AGGREGATOR
1122 * because that may override AS4_PATH
1124 if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
1126 if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
1128 assert (attre);
1130 /* received both.
1131 * if the as_number in aggregator is not AS_TRANS,
1132 * then AS4_AGGREGATOR and AS4_PATH shall be ignored
1133 * and the Aggregator shall be taken as
1134 * info on the aggregating node, and the AS_PATH
1135 * shall be taken as the AS_PATH
1136 * otherwise
1137 * the Aggregator shall be ignored and the
1138 * AS4_AGGREGATOR shall be taken as the
1139 * Aggregating node and the AS_PATH is to be
1140 * constructed "as in all other cases"
1142 if ( attre->aggregator_as != BGP_AS_TRANS )
1144 /* ignore */
1145 if ( BGP_DEBUG(as4, AS4))
1146 zlog_debug ("[AS4] %s BGP not AS4 capable peer"
1147 " send AGGREGATOR != AS_TRANS and"
1148 " AS4_AGGREGATOR, so ignore"
1149 " AS4_AGGREGATOR and AS4_PATH", peer->host);
1150 ignore_as4_path = 1;
1152 else
1154 /* "New_aggregator shall be taken as aggregator" */
1155 attre->aggregator_as = as4_aggregator;
1156 attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
1159 else
1161 /* We received a AS4_AGGREGATOR but no AGGREGATOR.
1162 * That is bogus - but reading the conditions
1163 * we have to handle AS4_AGGREGATOR as if it were
1164 * AGGREGATOR in that case
1166 if ( BGP_DEBUG(as4, AS4))
1167 zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
1168 " AS4_AGGREGATOR but no AGGREGATOR, will take"
1169 " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
1170 (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
1171 /* sweep it under the carpet and simulate a "good" AGGREGATOR */
1172 attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
1176 /* need to reconcile NEW_AS_PATH and AS_PATH */
1177 if ( !ignore_as4_path && (attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))) )
1179 newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
1180 aspath_unintern (attr->aspath);
1181 attr->aspath = aspath_intern (newpath);
1183 return 0;
1186 /* Community attribute. */
1187 static int
1188 bgp_attr_community (struct peer *peer, bgp_size_t length,
1189 struct attr *attr, u_char flag)
1191 if (length == 0)
1193 attr->community = NULL;
1194 return 0;
1196 else
1198 attr->community =
1199 community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
1200 stream_forward_getp (peer->ibuf, length);
1203 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
1205 return 0;
1208 /* Originator ID attribute. */
1209 static int
1210 bgp_attr_originator_id (struct peer *peer, bgp_size_t length,
1211 struct attr *attr, u_char flag)
1213 if (length != 4)
1215 zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
1217 bgp_notify_send (peer,
1218 BGP_NOTIFY_UPDATE_ERR,
1219 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1220 return -1;
1223 (bgp_attr_extra_get (attr))->originator_id.s_addr
1224 = stream_get_ipv4 (peer->ibuf);
1226 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
1228 return 0;
1231 /* Cluster list attribute. */
1232 static int
1233 bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,
1234 struct attr *attr, u_char flag)
1236 /* Check length. */
1237 if (length % 4)
1239 zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
1241 bgp_notify_send (peer,
1242 BGP_NOTIFY_UPDATE_ERR,
1243 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1244 return -1;
1247 (bgp_attr_extra_get (attr))->cluster
1248 = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
1250 stream_forward_getp (peer->ibuf, length);;
1252 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
1254 return 0;
1257 /* Multiprotocol reachability information parse. */
1259 bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
1260 struct bgp_nlri *mp_update)
1262 u_int16_t afi;
1263 u_char safi;
1264 bgp_size_t nlri_len;
1265 size_t start;
1266 int ret;
1267 struct stream *s;
1268 struct attr_extra *attre = bgp_attr_extra_get(attr);
1270 /* Set end of packet. */
1271 s = BGP_INPUT(peer);
1272 start = stream_get_getp(s);
1274 /* safe to read statically sized header? */
1275 #define BGP_MP_REACH_MIN_SIZE 5
1276 #define LEN_LEFT (length - (stream_get_getp(s) - start))
1277 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
1279 zlog_info ("%s: %s sent invalid length, %lu",
1280 __func__, peer->host, (unsigned long)length);
1281 return -1;
1284 /* Load AFI, SAFI. */
1285 afi = stream_getw (s);
1286 safi = stream_getc (s);
1288 /* Get nexthop length. */
1289 attre->mp_nexthop_len = stream_getc (s);
1291 if (LEN_LEFT < attre->mp_nexthop_len)
1293 zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",
1294 __func__, peer->host, attre->mp_nexthop_len);
1295 return -1;
1298 /* Nexthop length check. */
1299 switch (attre->mp_nexthop_len)
1301 case 4:
1302 stream_get (&attre->mp_nexthop_global_in, s, 4);
1303 break;
1304 case 12:
1306 u_int32_t rd_high;
1307 u_int32_t rd_low;
1309 rd_high = stream_getl (s);
1310 rd_low = stream_getl (s);
1311 stream_get (&attre->mp_nexthop_global_in, s, 4);
1313 break;
1314 #ifdef HAVE_IPV6
1315 case 16:
1316 stream_get (&attre->mp_nexthop_global, s, 16);
1317 break;
1318 case 32:
1319 stream_get (&attre->mp_nexthop_global, s, 16);
1320 stream_get (&attre->mp_nexthop_local, s, 16);
1321 if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
1323 char buf1[INET6_ADDRSTRLEN];
1324 char buf2[INET6_ADDRSTRLEN];
1326 if (BGP_DEBUG (update, UPDATE_IN))
1327 zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
1328 inet_ntop (AF_INET6, &attre->mp_nexthop_global,
1329 buf1, INET6_ADDRSTRLEN),
1330 inet_ntop (AF_INET6, &attre->mp_nexthop_local,
1331 buf2, INET6_ADDRSTRLEN));
1333 attre->mp_nexthop_len = 16;
1335 break;
1336 #endif /* HAVE_IPV6 */
1337 default:
1338 zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",
1339 __func__, peer->host, attre->mp_nexthop_len);
1340 return -1;
1343 if (!LEN_LEFT)
1345 zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
1346 __func__, peer->host);
1347 return -1;
1351 u_char val;
1352 if ((val = stream_getc (s)))
1353 zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
1354 peer->host, val);
1357 /* must have nrli_len, what is left of the attribute */
1358 nlri_len = LEN_LEFT;
1359 if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
1361 zlog_info ("%s: (%s) Failed to read NLRI",
1362 __func__, peer->host);
1363 return -1;
1366 if (safi != BGP_SAFI_VPNV4)
1368 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
1369 if (ret < 0)
1371 zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
1372 __func__, peer->host);
1373 return -1;
1377 mp_update->afi = afi;
1378 mp_update->safi = safi;
1379 mp_update->nlri = stream_pnt (s);
1380 mp_update->length = nlri_len;
1382 stream_forward_getp (s, nlri_len);
1384 return 0;
1385 #undef LEN_LEFT
1388 /* Multiprotocol unreachable parse */
1390 bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,
1391 struct bgp_nlri *mp_withdraw)
1393 struct stream *s;
1394 u_int16_t afi;
1395 u_char safi;
1396 u_int16_t withdraw_len;
1397 int ret;
1399 s = peer->ibuf;
1401 #define BGP_MP_UNREACH_MIN_SIZE 3
1402 if ((length > STREAM_READABLE(s)) || (length < BGP_MP_UNREACH_MIN_SIZE))
1403 return -1;
1405 afi = stream_getw (s);
1406 safi = stream_getc (s);
1408 withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
1410 if (safi != BGP_SAFI_VPNV4)
1412 ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
1413 if (ret < 0)
1414 return -1;
1417 mp_withdraw->afi = afi;
1418 mp_withdraw->safi = safi;
1419 mp_withdraw->nlri = stream_pnt (s);
1420 mp_withdraw->length = withdraw_len;
1422 stream_forward_getp (s, withdraw_len);
1424 return 0;
1427 /* Extended Community attribute. */
1428 static int
1429 bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,
1430 struct attr *attr, u_char flag)
1432 if (length == 0)
1434 if (attr->extra)
1435 attr->extra->ecommunity = NULL;
1437 else
1439 (bgp_attr_extra_get (attr))->ecommunity =
1440 ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
1441 stream_forward_getp (peer->ibuf, length);
1443 attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
1445 return 0;
1448 /* BGP unknown attribute treatment. */
1449 static int
1450 bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
1451 u_char type, bgp_size_t length, u_char *startp)
1453 bgp_size_t total;
1454 struct transit *transit;
1455 struct attr_extra *attre;
1457 if (BGP_DEBUG (normal, NORMAL))
1458 zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
1459 peer->host, type, length);
1461 if (BGP_DEBUG (events, EVENTS))
1462 zlog (peer->log, LOG_DEBUG,
1463 "Unknown attribute type %d length %d is received", type, length);
1465 /* Forward read pointer of input stream. */
1466 stream_forward_getp (peer->ibuf, length);
1468 /* Adjest total length to include type and length. */
1469 total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
1471 /* If any of the mandatory well-known attributes are not recognized,
1472 then the Error Subcode is set to Unrecognized Well-known
1473 Attribute. The Data field contains the unrecognized attribute
1474 (type, length and value). */
1475 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
1477 /* Adjust startp to do not include flag value. */
1478 bgp_notify_send_with_data (peer,
1479 BGP_NOTIFY_UPDATE_ERR,
1480 BGP_NOTIFY_UPDATE_UNREC_ATTR,
1481 startp, total);
1482 return -1;
1485 /* Unrecognized non-transitive optional attributes must be quietly
1486 ignored and not passed along to other BGP peers. */
1487 if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
1488 return 0;
1490 /* If a path with recognized transitive optional attribute is
1491 accepted and passed along to other BGP peers and the Partial bit
1492 in the Attribute Flags octet is set to 1 by some previous AS, it
1493 is not set back to 0 by the current AS. */
1494 SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
1496 /* Store transitive attribute to the end of attr->transit. */
1497 if (! ((attre = bgp_attr_extra_get(attr))->transit) )
1499 attre->transit = XMALLOC (MTYPE_TRANSIT, sizeof (struct transit));
1500 memset (attre->transit, 0, sizeof (struct transit));
1503 transit = attre->transit;
1505 if (transit->val)
1506 transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val,
1507 transit->length + total);
1508 else
1509 transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
1511 memcpy (transit->val + transit->length, startp, total);
1512 transit->length += total;
1514 return 0;
1517 /* Read attribute of update packet. This function is called from
1518 bgp_update() in bgpd.c. */
1520 bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
1521 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
1523 int ret;
1524 u_char flag;
1525 u_char type = 0;
1526 bgp_size_t length;
1527 u_char *startp, *endp;
1528 u_char *attr_endp;
1529 u_char seen[BGP_ATTR_BITMAP_SIZE];
1530 /* we need the as4_path only until we have synthesized the as_path with it */
1531 /* same goes for as4_aggregator */
1532 struct aspath *as4_path = NULL;
1533 as_t as4_aggregator = 0;
1534 struct in_addr as4_aggregator_addr = { 0 };
1536 /* Initialize bitmap. */
1537 memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
1539 /* End pointer of BGP attribute. */
1540 endp = BGP_INPUT_PNT (peer) + size;
1542 /* Get attributes to the end of attribute length. */
1543 while (BGP_INPUT_PNT (peer) < endp)
1545 /* Check remaining length check.*/
1546 if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
1548 /* XXX warning: long int format, int arg (arg 5) */
1549 zlog (peer->log, LOG_WARNING,
1550 "%s error BGP attribute length %lu is smaller than min len",
1551 peer->host,
1552 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1554 bgp_notify_send (peer,
1555 BGP_NOTIFY_UPDATE_ERR,
1556 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1557 return -1;
1560 /* Fetch attribute flag and type. */
1561 startp = BGP_INPUT_PNT (peer);
1562 flag = stream_getc (BGP_INPUT (peer));
1563 type = stream_getc (BGP_INPUT (peer));
1565 /* Check whether Extended-Length applies and is in bounds */
1566 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
1567 && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
1569 zlog (peer->log, LOG_WARNING,
1570 "%s Extended length set, but just %lu bytes of attr header",
1571 peer->host,
1572 (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
1574 bgp_notify_send (peer,
1575 BGP_NOTIFY_UPDATE_ERR,
1576 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1577 return -1;
1580 /* Check extended attribue length bit. */
1581 if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
1582 length = stream_getw (BGP_INPUT (peer));
1583 else
1584 length = stream_getc (BGP_INPUT (peer));
1586 /* If any attribute appears more than once in the UPDATE
1587 message, then the Error Subcode is set to Malformed Attribute
1588 List. */
1590 if (CHECK_BITMAP (seen, type))
1592 zlog (peer->log, LOG_WARNING,
1593 "%s error BGP attribute type %d appears twice in a message",
1594 peer->host, type);
1596 bgp_notify_send (peer,
1597 BGP_NOTIFY_UPDATE_ERR,
1598 BGP_NOTIFY_UPDATE_MAL_ATTR);
1599 return -1;
1602 /* Set type to bitmap to check duplicate attribute. `type' is
1603 unsigned char so it never overflow bitmap range. */
1605 SET_BITMAP (seen, type);
1607 /* Overflow check. */
1608 attr_endp = BGP_INPUT_PNT (peer) + length;
1610 if (attr_endp > endp)
1612 zlog (peer->log, LOG_WARNING,
1613 "%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);
1614 bgp_notify_send (peer,
1615 BGP_NOTIFY_UPDATE_ERR,
1616 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1617 return -1;
1620 /* OK check attribute and store it's value. */
1621 switch (type)
1623 case BGP_ATTR_ORIGIN:
1624 ret = bgp_attr_origin (peer, length, attr, flag, startp);
1625 break;
1626 case BGP_ATTR_AS_PATH:
1627 ret = bgp_attr_aspath (peer, length, attr, flag, startp);
1628 break;
1629 case BGP_ATTR_AS4_PATH:
1630 ret = bgp_attr_as4_path (peer, length, attr, &as4_path );
1631 break;
1632 case BGP_ATTR_NEXT_HOP:
1633 ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
1634 break;
1635 case BGP_ATTR_MULTI_EXIT_DISC:
1636 ret = bgp_attr_med (peer, length, attr, flag, startp);
1637 break;
1638 case BGP_ATTR_LOCAL_PREF:
1639 ret = bgp_attr_local_pref (peer, length, attr, flag);
1640 break;
1641 case BGP_ATTR_ATOMIC_AGGREGATE:
1642 ret = bgp_attr_atomic (peer, length, attr, flag);
1643 break;
1644 case BGP_ATTR_AGGREGATOR:
1645 ret = bgp_attr_aggregator (peer, length, attr, flag);
1646 break;
1647 case BGP_ATTR_AS4_AGGREGATOR:
1648 ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
1649 break;
1650 case BGP_ATTR_COMMUNITIES:
1651 ret = bgp_attr_community (peer, length, attr, flag);
1652 break;
1653 case BGP_ATTR_ORIGINATOR_ID:
1654 ret = bgp_attr_originator_id (peer, length, attr, flag);
1655 break;
1656 case BGP_ATTR_CLUSTER_LIST:
1657 ret = bgp_attr_cluster_list (peer, length, attr, flag);
1658 break;
1659 case BGP_ATTR_MP_REACH_NLRI:
1660 ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
1661 break;
1662 case BGP_ATTR_MP_UNREACH_NLRI:
1663 ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
1664 break;
1665 case BGP_ATTR_EXT_COMMUNITIES:
1666 ret = bgp_attr_ext_communities (peer, length, attr, flag);
1667 break;
1668 case BGP_ATTR_AS_PATHLIMIT:
1669 ret = bgp_attr_aspathlimit (peer, length, attr, flag, startp);
1670 break;
1671 default:
1672 ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
1673 break;
1676 /* If error occured immediately return to the caller. */
1677 if (ret < 0)
1679 zlog (peer->log, LOG_WARNING,
1680 "%s: Attribute %s, parse error",
1681 peer->host,
1682 LOOKUP (attr_str, type));
1683 bgp_notify_send (peer,
1684 BGP_NOTIFY_UPDATE_ERR,
1685 BGP_NOTIFY_UPDATE_MAL_ATTR);
1686 return ret;
1689 /* Check the fetched length. */
1690 if (BGP_INPUT_PNT (peer) != attr_endp)
1692 zlog (peer->log, LOG_WARNING,
1693 "%s: BGP attribute %s, fetch error",
1694 peer->host, LOOKUP (attr_str, type));
1695 bgp_notify_send (peer,
1696 BGP_NOTIFY_UPDATE_ERR,
1697 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1698 return -1;
1702 /* Check final read pointer is same as end pointer. */
1703 if (BGP_INPUT_PNT (peer) != endp)
1705 zlog (peer->log, LOG_WARNING,
1706 "%s BGP attribute %s, length mismatch",
1707 peer->host, LOOKUP (attr_str, type));
1708 bgp_notify_send (peer,
1709 BGP_NOTIFY_UPDATE_ERR,
1710 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
1711 return -1;
1715 * At this place we can see whether we got AS4_PATH and/or
1716 * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
1717 * We can not do this before we've read all attributes because
1718 * the as4 handling does not say whether AS4_PATH has to be sent
1719 * after AS_PATH or not - and when AS4_AGGREGATOR will be send
1720 * in relationship to AGGREGATOR.
1721 * So, to be defensive, we are not relying on any order and read
1722 * all attributes first, including these 32bit ones, and now,
1723 * afterwards, we look what and if something is to be done for as4.
1725 if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
1726 as4_aggregator, &as4_aggregator_addr))
1727 return -1;
1729 /* At this stage, we have done all fiddling with as4, and the
1730 * resulting info is in attr->aggregator resp. attr->aspath
1731 * so we can chuck as4_aggregator and as4_path alltogether in
1732 * order to save memory
1734 if ( as4_path )
1736 aspath_unintern( as4_path ); /* unintern - it is in the hash */
1737 as4_path = NULL;
1738 /* The flag that we got this is still there, but that does not
1739 * do any trouble
1743 * The "rest" of the code does nothing with as4_aggregator.
1744 * there is no memory attached specifically which is not part
1745 * of the attr.
1746 * so ignoring just means do nothing.
1749 * Finally do the checks on the aspath we did not do yet
1750 * because we waited for a potentially synthesized aspath.
1752 if ( attr->flag & ( ATTR_FLAG_BIT( BGP_ATTR_AS_PATH)))
1754 ret = bgp_attr_aspath_check( peer, attr );
1755 if ( ret < 0 )
1756 return ret;
1759 /* Finally intern unknown attribute. */
1760 if (attr->extra && attr->extra->transit)
1761 attr->extra->transit = transit_intern (attr->extra->transit);
1763 return 0;
1766 /* Well-known attribute check. */
1768 bgp_attr_check (struct peer *peer, struct attr *attr)
1770 u_char type = 0;
1772 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
1773 type = BGP_ATTR_ORIGIN;
1775 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
1776 type = BGP_ATTR_AS_PATH;
1778 if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
1779 type = BGP_ATTR_NEXT_HOP;
1781 if (peer_sort (peer) == BGP_PEER_IBGP
1782 && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
1783 type = BGP_ATTR_LOCAL_PREF;
1785 if (type)
1787 zlog (peer->log, LOG_WARNING,
1788 "%s Missing well-known attribute %d.",
1789 peer->host, type);
1790 bgp_notify_send_with_data (peer,
1791 BGP_NOTIFY_UPDATE_ERR,
1792 BGP_NOTIFY_UPDATE_MISS_ATTR,
1793 &type, 1);
1794 return -1;
1796 return 0;
1799 int stream_put_prefix (struct stream *, struct prefix *);
1801 /* Make attribute packet. */
1802 bgp_size_t
1803 bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
1804 struct stream *s, struct attr *attr, struct prefix *p,
1805 afi_t afi, safi_t safi, struct peer *from,
1806 struct prefix_rd *prd, u_char *tag)
1808 size_t cp;
1809 size_t aspath_sizep;
1810 struct aspath *aspath;
1811 int send_as4_path = 0;
1812 int send_as4_aggregator = 0;
1813 int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
1815 if (! bgp)
1816 bgp = bgp_get_default ();
1818 /* Remember current pointer. */
1819 cp = stream_get_endp (s);
1821 /* Origin attribute. */
1822 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1823 stream_putc (s, BGP_ATTR_ORIGIN);
1824 stream_putc (s, 1);
1825 stream_putc (s, attr->origin);
1827 /* AS path attribute. */
1829 /* If remote-peer is EBGP */
1830 if (peer_sort (peer) == BGP_PEER_EBGP
1831 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
1832 || attr->aspath->segments == NULL)
1833 && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
1835 aspath = aspath_dup (attr->aspath);
1837 if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
1839 /* Strip the confed info, and then stuff our path CONFED_ID
1840 on the front */
1841 aspath = aspath_delete_confed_seq (aspath);
1842 aspath = aspath_add_seq (aspath, bgp->confed_id);
1844 else
1846 aspath = aspath_add_seq (aspath, peer->local_as);
1847 if (peer->change_local_as)
1848 aspath = aspath_add_seq (aspath, peer->change_local_as);
1851 else if (peer_sort (peer) == BGP_PEER_CONFED)
1853 /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
1854 aspath = aspath_dup (attr->aspath);
1855 aspath = aspath_add_confed_seq (aspath, peer->local_as);
1857 else
1858 aspath = attr->aspath;
1860 /* If peer is not AS4 capable, then:
1861 * - send the created AS_PATH out as AS4_PATH (optional, transitive),
1862 * but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
1863 * types are in it (i.e. exclude them if they are there)
1864 * AND do this only if there is at least one asnum > 65535 in the path!
1865 * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
1866 * all ASnums > 65535 to BGP_AS_TRANS
1869 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1870 stream_putc (s, BGP_ATTR_AS_PATH);
1871 aspath_sizep = stream_get_endp (s);
1872 stream_putw (s, 0);
1873 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
1875 /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs
1876 * in the path
1878 if (!use32bit && aspath_has_as4 (aspath))
1879 send_as4_path = 1; /* we'll do this later, at the correct place */
1881 /* Nexthop attribute. */
1882 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
1884 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1885 stream_putc (s, BGP_ATTR_NEXT_HOP);
1886 stream_putc (s, 4);
1887 if (safi == SAFI_MPLS_VPN)
1889 if (attr->nexthop.s_addr == 0)
1890 stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
1891 else
1892 stream_put_ipv4 (s, attr->nexthop.s_addr);
1894 else
1895 stream_put_ipv4 (s, attr->nexthop.s_addr);
1898 /* MED attribute. */
1899 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
1901 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1902 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
1903 stream_putc (s, 4);
1904 stream_putl (s, attr->med);
1907 /* Local preference. */
1908 if (peer_sort (peer) == BGP_PEER_IBGP ||
1909 peer_sort (peer) == BGP_PEER_CONFED)
1911 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1912 stream_putc (s, BGP_ATTR_LOCAL_PREF);
1913 stream_putc (s, 4);
1914 stream_putl (s, attr->local_pref);
1917 /* Atomic aggregate. */
1918 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
1920 stream_putc (s, BGP_ATTR_FLAG_TRANS);
1921 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
1922 stream_putc (s, 0);
1925 /* Aggregator. */
1926 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
1928 assert (attr->extra);
1930 /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
1931 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1932 stream_putc (s, BGP_ATTR_AGGREGATOR);
1934 if (use32bit)
1936 /* AS4 capable peer */
1937 stream_putc (s, 8);
1938 stream_putl (s, attr->extra->aggregator_as);
1940 else
1942 /* 2-byte AS peer */
1943 stream_putc (s, 6);
1945 /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
1946 if ( attr->extra->aggregator_as > 65535 )
1948 stream_putw (s, BGP_AS_TRANS);
1950 /* we have to send AS4_AGGREGATOR, too.
1951 * we'll do that later in order to send attributes in ascending
1952 * order.
1954 send_as4_aggregator = 1;
1956 else
1957 stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
1959 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
1962 /* Community attribute. */
1963 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY)
1964 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
1966 if (attr->community->size * 4 > 255)
1968 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
1969 stream_putc (s, BGP_ATTR_COMMUNITIES);
1970 stream_putw (s, attr->community->size * 4);
1972 else
1974 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
1975 stream_putc (s, BGP_ATTR_COMMUNITIES);
1976 stream_putc (s, attr->community->size * 4);
1978 stream_put (s, attr->community->val, attr->community->size * 4);
1981 /* Route Reflector. */
1982 if (peer_sort (peer) == BGP_PEER_IBGP
1983 && from
1984 && peer_sort (from) == BGP_PEER_IBGP)
1986 /* Originator ID. */
1987 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1988 stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
1989 stream_putc (s, 4);
1991 if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
1992 stream_put_in_addr (s, &attr->extra->originator_id);
1993 else
1994 stream_put_in_addr (s, &from->remote_id);
1996 /* Cluster list. */
1997 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
1998 stream_putc (s, BGP_ATTR_CLUSTER_LIST);
2000 if (attr->extra && attr->extra->cluster)
2002 stream_putc (s, attr->extra->cluster->length + 4);
2003 /* If this peer configuration's parent BGP has cluster_id. */
2004 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2005 stream_put_in_addr (s, &bgp->cluster_id);
2006 else
2007 stream_put_in_addr (s, &bgp->router_id);
2008 stream_put (s, attr->extra->cluster->list,
2009 attr->extra->cluster->length);
2011 else
2013 stream_putc (s, 4);
2014 /* If this peer configuration's parent BGP has cluster_id. */
2015 if (bgp->config & BGP_CONFIG_CLUSTER_ID)
2016 stream_put_in_addr (s, &bgp->cluster_id);
2017 else
2018 stream_put_in_addr (s, &bgp->router_id);
2022 #ifdef HAVE_IPV6
2023 /* If p is IPv6 address put it into attribute. */
2024 if (p->family == AF_INET6)
2026 unsigned long sizep;
2027 struct attr_extra *attre = attr->extra;
2029 assert (attr->extra);
2031 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2032 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
2033 sizep = stream_get_endp (s);
2034 stream_putc (s, 0); /* Marker: Attribute length. */
2035 stream_putw (s, AFI_IP6); /* AFI */
2036 stream_putc (s, safi); /* SAFI */
2038 stream_putc (s, attre->mp_nexthop_len);
2040 if (attre->mp_nexthop_len == 16)
2041 stream_put (s, &attre->mp_nexthop_global, 16);
2042 else if (attre->mp_nexthop_len == 32)
2044 stream_put (s, &attre->mp_nexthop_global, 16);
2045 stream_put (s, &attre->mp_nexthop_local, 16);
2048 /* SNPA */
2049 stream_putc (s, 0);
2051 /* Prefix write. */
2052 stream_put_prefix (s, p);
2054 /* Set MP attribute length. */
2055 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
2057 #endif /* HAVE_IPV6 */
2059 if (p->family == AF_INET && safi == SAFI_MULTICAST)
2061 unsigned long sizep;
2063 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2064 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
2065 sizep = stream_get_endp (s);
2066 stream_putc (s, 0); /* Marker: Attribute Length. */
2067 stream_putw (s, AFI_IP); /* AFI */
2068 stream_putc (s, SAFI_MULTICAST); /* SAFI */
2070 stream_putc (s, 4);
2071 stream_put_ipv4 (s, attr->nexthop.s_addr);
2073 /* SNPA */
2074 stream_putc (s, 0);
2076 /* Prefix write. */
2077 stream_put_prefix (s, p);
2079 /* Set MP attribute length. */
2080 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
2083 if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
2085 unsigned long sizep;
2087 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2088 stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
2089 sizep = stream_get_endp (s);
2090 stream_putc (s, 0); /* Length of this attribute. */
2091 stream_putw (s, AFI_IP); /* AFI */
2092 stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
2094 stream_putc (s, 12);
2095 stream_putl (s, 0);
2096 stream_putl (s, 0);
2097 stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
2099 /* SNPA */
2100 stream_putc (s, 0);
2102 /* Tag, RD, Prefix write. */
2103 stream_putc (s, p->prefixlen + 88);
2104 stream_put (s, tag, 3);
2105 stream_put (s, prd->val, 8);
2106 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2108 /* Set MP attribute length. */
2109 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
2112 /* Extended Communities attribute. */
2113 if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)
2114 && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
2116 struct attr_extra *attre = attr->extra;
2118 assert (attre);
2120 if (peer_sort (peer) == BGP_PEER_IBGP
2121 || peer_sort (peer) == BGP_PEER_CONFED)
2123 if (attre->ecommunity->size * 8 > 255)
2125 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2126 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2127 stream_putw (s, attre->ecommunity->size * 8);
2129 else
2131 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2132 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2133 stream_putc (s, attre->ecommunity->size * 8);
2135 stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
2137 else
2139 u_int8_t *pnt;
2140 int tbit;
2141 int ecom_tr_size = 0;
2142 int i;
2144 for (i = 0; i < attre->ecommunity->size; i++)
2146 pnt = attre->ecommunity->val + (i * 8);
2147 tbit = *pnt;
2149 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2150 continue;
2152 ecom_tr_size++;
2155 if (ecom_tr_size)
2157 if (ecom_tr_size * 8 > 255)
2159 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2160 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2161 stream_putw (s, ecom_tr_size * 8);
2163 else
2165 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2166 stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
2167 stream_putc (s, ecom_tr_size * 8);
2170 for (i = 0; i < attre->ecommunity->size; i++)
2172 pnt = attre->ecommunity->val + (i * 8);
2173 tbit = *pnt;
2175 if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
2176 continue;
2178 stream_put (s, pnt, 8);
2184 if ( send_as4_path )
2186 /* If the peer is NOT As4 capable, AND */
2187 /* there are ASnums > 65535 in path THEN
2188 * give out AS4_PATH */
2190 /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
2191 * path segments!
2192 * Hm, I wonder... confederation things *should* only be at
2193 * the beginning of an aspath, right? Then we should use
2194 * aspath_delete_confed_seq for this, because it is already
2195 * there! (JK)
2196 * Folks, talk to me: what is reasonable here!?
2198 aspath = aspath_delete_confed_seq (aspath);
2200 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
2201 stream_putc (s, BGP_ATTR_AS4_PATH);
2202 aspath_sizep = stream_get_endp (s);
2203 stream_putw (s, 0);
2204 stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
2207 if (aspath != attr->aspath)
2208 aspath_free (aspath);
2210 if ( send_as4_aggregator )
2212 assert (attr->extra);
2214 /* send AS4_AGGREGATOR, at this place */
2215 /* this section of code moved here in order to ensure the correct
2216 * *ascending* order of attributes
2218 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2219 stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
2220 stream_putc (s, 8);
2221 stream_putl (s, attr->extra->aggregator_as);
2222 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2225 /* AS-Pathlimit */
2226 if (attr->pathlimit.ttl)
2228 u_int32_t as = attr->pathlimit.as;
2230 /* should already have been done in announce_check(),
2231 * but just in case..
2233 if (!as)
2234 as = peer->local_as;
2236 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2237 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2238 stream_putc (s, 5);
2239 stream_putc (s, attr->pathlimit.ttl);
2240 stream_putl (s, as);
2243 /* Unknown transit attribute. */
2244 if (attr->extra && attr->extra->transit)
2245 stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
2247 /* Return total size of attribute. */
2248 return stream_get_endp (s) - cp;
2251 bgp_size_t
2252 bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
2253 afi_t afi, safi_t safi, struct prefix_rd *prd,
2254 u_char *tag)
2256 unsigned long cp;
2257 unsigned long attrlen_pnt;
2258 bgp_size_t size;
2260 cp = stream_get_endp (s);
2262 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2263 stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
2265 attrlen_pnt = stream_get_endp (s);
2266 stream_putc (s, 0); /* Length of this attribute. */
2268 stream_putw (s, family2afi (p->family));
2270 if (safi == SAFI_MPLS_VPN)
2272 /* SAFI */
2273 stream_putc (s, BGP_SAFI_VPNV4);
2275 /* prefix. */
2276 stream_putc (s, p->prefixlen + 88);
2277 stream_put (s, tag, 3);
2278 stream_put (s, prd->val, 8);
2279 stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
2281 else
2283 /* SAFI */
2284 stream_putc (s, safi);
2286 /* prefix */
2287 stream_put_prefix (s, p);
2290 /* Set MP attribute length. */
2291 size = stream_get_endp (s) - attrlen_pnt - 1;
2292 stream_putc_at (s, attrlen_pnt, size);
2294 return stream_get_endp (s) - cp;
2297 /* Initialization of attribute. */
2298 void
2299 bgp_attr_init (void)
2301 aspath_init ();
2302 attrhash_init ();
2303 community_init ();
2304 ecommunity_init ();
2305 cluster_init ();
2306 transit_init ();
2309 /* Make attribute packet. */
2310 void
2311 bgp_dump_routes_attr (struct stream *s, struct attr *attr,
2312 struct prefix *prefix)
2314 unsigned long cp;
2315 unsigned long len;
2316 size_t aspath_lenp;
2317 struct aspath *aspath;
2319 /* Remember current pointer. */
2320 cp = stream_get_endp (s);
2322 /* Place holder of length. */
2323 stream_putw (s, 0);
2325 /* Origin attribute. */
2326 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2327 stream_putc (s, BGP_ATTR_ORIGIN);
2328 stream_putc (s, 1);
2329 stream_putc (s, attr->origin);
2331 aspath = attr->aspath;
2333 stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2334 stream_putc (s, BGP_ATTR_AS_PATH);
2335 aspath_lenp = stream_get_endp (s);
2336 stream_putw (s, 0);
2338 stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
2340 /* Nexthop attribute. */
2341 /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
2342 if(prefix != NULL
2343 #ifdef HAVE_IPV6
2344 && prefix->family != AF_INET6
2345 #endif /* HAVE_IPV6 */
2348 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2349 stream_putc (s, BGP_ATTR_NEXT_HOP);
2350 stream_putc (s, 4);
2351 stream_put_ipv4 (s, attr->nexthop.s_addr);
2354 /* MED attribute. */
2355 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
2357 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
2358 stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
2359 stream_putc (s, 4);
2360 stream_putl (s, attr->med);
2363 /* Local preference. */
2364 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
2366 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2367 stream_putc (s, BGP_ATTR_LOCAL_PREF);
2368 stream_putc (s, 4);
2369 stream_putl (s, attr->local_pref);
2372 /* Atomic aggregate. */
2373 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
2375 stream_putc (s, BGP_ATTR_FLAG_TRANS);
2376 stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
2377 stream_putc (s, 0);
2380 /* Aggregator. */
2381 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
2383 assert (attr->extra);
2384 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2385 stream_putc (s, BGP_ATTR_AGGREGATOR);
2386 stream_putc (s, 8);
2387 stream_putl (s, attr->extra->aggregator_as);
2388 stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
2391 /* Community attribute. */
2392 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
2394 if (attr->community->size * 4 > 255)
2396 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
2397 stream_putc (s, BGP_ATTR_COMMUNITIES);
2398 stream_putw (s, attr->community->size * 4);
2400 else
2402 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2403 stream_putc (s, BGP_ATTR_COMMUNITIES);
2404 stream_putc (s, attr->community->size * 4);
2406 stream_put (s, attr->community->val, attr->community->size * 4);
2409 #ifdef HAVE_IPV6
2410 /* Add a MP_NLRI attribute to dump the IPv6 next hop */
2411 if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
2412 (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
2414 int sizep;
2415 struct attr_extra *attre = attr->extra;
2417 stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
2418 stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
2419 sizep = stream_get_endp (s);
2421 /* MP header */
2422 stream_putc (s, 0); /* Marker: Attribute length. */
2423 stream_putw(s, AFI_IP6); /* AFI */
2424 stream_putc(s, SAFI_UNICAST); /* SAFI */
2426 /* Next hop */
2427 stream_putc(s, attre->mp_nexthop_len);
2428 stream_put(s, &attre->mp_nexthop_global, 16);
2429 if (attre->mp_nexthop_len == 32)
2430 stream_put(s, &attre->mp_nexthop_local, 16);
2432 /* SNPA */
2433 stream_putc(s, 0);
2435 /* Prefix */
2436 stream_put_prefix(s, prefix);
2438 /* Set MP attribute length. */
2439 stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
2441 #endif /* HAVE_IPV6 */
2443 /* AS-Pathlimit */
2444 if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AS_PATHLIMIT))
2446 stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
2447 stream_putc (s, BGP_ATTR_AS_PATHLIMIT);
2448 stream_putc (s, 5);
2449 stream_putc (s, attr->pathlimit.ttl);
2450 stream_putl (s, attr->pathlimit.as);
2453 /* Return total size of attribute. */
2454 len = stream_get_endp (s) - cp - 2;
2455 stream_putw_at (s, cp, len);