Annotation of embedaddon/quagga/bgpd/bgp_attr.c, revision 1.1

1.1     ! misho       1: /* BGP attributes management routines.
        !             2:    Copyright (C) 1996, 97, 98, 1999 Kunihiro Ishiguro
        !             3: 
        !             4: This file is part of GNU Zebra.
        !             5: 
        !             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.
        !            10: 
        !            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.
        !            15: 
        !            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.  */
        !            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: #include "jhash.h"
        !            32: 
        !            33: #include "bgpd/bgpd.h"
        !            34: #include "bgpd/bgp_attr.h"
        !            35: #include "bgpd/bgp_route.h"
        !            36: #include "bgpd/bgp_aspath.h"
        !            37: #include "bgpd/bgp_community.h"
        !            38: #include "bgpd/bgp_debug.h"
        !            39: #include "bgpd/bgp_packet.h"
        !            40: #include "bgpd/bgp_ecommunity.h"
        !            41: 
        !            42: /* Attribute strings for logging. */
        !            43: static const struct message attr_str [] = 
        !            44: {
        !            45:   { BGP_ATTR_ORIGIN,           "ORIGIN" }, 
        !            46:   { BGP_ATTR_AS_PATH,          "AS_PATH" }, 
        !            47:   { BGP_ATTR_NEXT_HOP,         "NEXT_HOP" }, 
        !            48:   { BGP_ATTR_MULTI_EXIT_DISC,  "MULTI_EXIT_DISC" }, 
        !            49:   { BGP_ATTR_LOCAL_PREF,       "LOCAL_PREF" }, 
        !            50:   { BGP_ATTR_ATOMIC_AGGREGATE, "ATOMIC_AGGREGATE" }, 
        !            51:   { BGP_ATTR_AGGREGATOR,       "AGGREGATOR" }, 
        !            52:   { BGP_ATTR_COMMUNITIES,      "COMMUNITY" }, 
        !            53:   { BGP_ATTR_ORIGINATOR_ID,    "ORIGINATOR_ID" },
        !            54:   { BGP_ATTR_CLUSTER_LIST,     "CLUSTERLIST" }, 
        !            55:   { BGP_ATTR_DPA,              "DPA" },
        !            56:   { BGP_ATTR_ADVERTISER,       "ADVERTISER"} ,
        !            57:   { BGP_ATTR_RCID_PATH,        "RCID_PATH" },
        !            58:   { BGP_ATTR_MP_REACH_NLRI,    "MP_REACH_NLRI" },
        !            59:   { BGP_ATTR_MP_UNREACH_NLRI,  "MP_UNREACH_NLRI" },
        !            60:   { BGP_ATTR_EXT_COMMUNITIES,  "EXT_COMMUNITIES" },
        !            61:   { BGP_ATTR_AS4_PATH,         "AS4_PATH" }, 
        !            62:   { BGP_ATTR_AS4_AGGREGATOR,   "AS4_AGGREGATOR" }, 
        !            63:   { BGP_ATTR_AS_PATHLIMIT,     "AS_PATHLIMIT" },
        !            64: };
        !            65: static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);
        !            66: 
        !            67: static struct hash *cluster_hash;
        !            68: 
        !            69: static void *
        !            70: cluster_hash_alloc (void *p)
        !            71: {
        !            72:   struct cluster_list * val = (struct cluster_list *) p;
        !            73:   struct cluster_list *cluster;
        !            74: 
        !            75:   cluster = XMALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
        !            76:   cluster->length = val->length;
        !            77: 
        !            78:   if (cluster->length)
        !            79:     {
        !            80:       cluster->list = XMALLOC (MTYPE_CLUSTER_VAL, val->length);
        !            81:       memcpy (cluster->list, val->list, val->length);
        !            82:     }
        !            83:   else
        !            84:     cluster->list = NULL;
        !            85: 
        !            86:   cluster->refcnt = 0;
        !            87: 
        !            88:   return cluster;
        !            89: }
        !            90: 
        !            91: /* Cluster list related functions. */
        !            92: static struct cluster_list *
        !            93: cluster_parse (struct in_addr * pnt, int length)
        !            94: {
        !            95:   struct cluster_list tmp;
        !            96:   struct cluster_list *cluster;
        !            97: 
        !            98:   tmp.length = length;
        !            99:   tmp.list = pnt;
        !           100: 
        !           101:   cluster = hash_get (cluster_hash, &tmp, cluster_hash_alloc);
        !           102:   cluster->refcnt++;
        !           103:   return cluster;
        !           104: }
        !           105: 
        !           106: int
        !           107: cluster_loop_check (struct cluster_list *cluster, struct in_addr originator)
        !           108: {
        !           109:   int i;
        !           110:     
        !           111:   for (i = 0; i < cluster->length / 4; i++)
        !           112:     if (cluster->list[i].s_addr == originator.s_addr)
        !           113:       return 1;
        !           114:   return 0;
        !           115: }
        !           116: 
        !           117: static unsigned int
        !           118: cluster_hash_key_make (void *p)
        !           119: {
        !           120:   const struct cluster_list *cluster = p;
        !           121: 
        !           122:   return jhash(cluster->list, cluster->length, 0);
        !           123: }
        !           124: 
        !           125: static int
        !           126: cluster_hash_cmp (const void *p1, const void *p2)
        !           127: {
        !           128:   const struct cluster_list * cluster1 = p1;
        !           129:   const struct cluster_list * cluster2 = p2;
        !           130: 
        !           131:   return (cluster1->length == cluster2->length &&
        !           132:          memcmp (cluster1->list, cluster2->list, cluster1->length) == 0);
        !           133: }
        !           134: 
        !           135: static void
        !           136: cluster_free (struct cluster_list *cluster)
        !           137: {
        !           138:   if (cluster->list)
        !           139:     XFREE (MTYPE_CLUSTER_VAL, cluster->list);
        !           140:   XFREE (MTYPE_CLUSTER, cluster);
        !           141: }
        !           142: 
        !           143: #if 0
        !           144: static struct cluster_list *
        !           145: cluster_dup (struct cluster_list *cluster)
        !           146: {
        !           147:   struct cluster_list *new;
        !           148: 
        !           149:   new = XCALLOC (MTYPE_CLUSTER, sizeof (struct cluster_list));
        !           150:   new->length = cluster->length;
        !           151: 
        !           152:   if (cluster->length)
        !           153:     {
        !           154:       new->list = XMALLOC (MTYPE_CLUSTER_VAL, cluster->length);
        !           155:       memcpy (new->list, cluster->list, cluster->length);
        !           156:     }
        !           157:   else
        !           158:     new->list = NULL;
        !           159:   
        !           160:   return new;
        !           161: }
        !           162: #endif
        !           163: 
        !           164: static struct cluster_list *
        !           165: cluster_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: 
        !           175: void
        !           176: cluster_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: 
        !           190: static void
        !           191: cluster_init (void)
        !           192: {
        !           193:   cluster_hash = hash_create (cluster_hash_key_make, cluster_hash_cmp);
        !           194: }
        !           195: 
        !           196: static void
        !           197: cluster_finish (void)
        !           198: {
        !           199:   hash_free (cluster_hash);
        !           200:   cluster_hash = NULL;
        !           201: }
        !           202: 
        !           203: /* Unknown transit attribute. */
        !           204: static struct hash *transit_hash;
        !           205: 
        !           206: static void
        !           207: transit_free (struct transit *transit)
        !           208: {
        !           209:   if (transit->val)
        !           210:     XFREE (MTYPE_TRANSIT_VAL, transit->val);
        !           211:   XFREE (MTYPE_TRANSIT, transit);
        !           212: }
        !           213: 
        !           214: 
        !           215: static void *
        !           216: transit_hash_alloc (void *p)
        !           217: {
        !           218:   /* Transit structure is already allocated.  */
        !           219:   return p;
        !           220: }
        !           221: 
        !           222: static struct transit *
        !           223: transit_intern (struct transit *transit)
        !           224: {
        !           225:   struct transit *find;
        !           226: 
        !           227:   find = hash_get (transit_hash, transit, transit_hash_alloc);
        !           228:   if (find != transit)
        !           229:     transit_free (transit);
        !           230:   find->refcnt++;
        !           231: 
        !           232:   return find;
        !           233: }
        !           234: 
        !           235: void
        !           236: transit_unintern (struct transit *transit)
        !           237: {
        !           238:   struct transit *ret;
        !           239: 
        !           240:   if (transit->refcnt)
        !           241:     transit->refcnt--;
        !           242: 
        !           243:   if (transit->refcnt == 0)
        !           244:     {
        !           245:       ret = hash_release (transit_hash, transit);
        !           246:       transit_free (transit);
        !           247:     }
        !           248: }
        !           249: 
        !           250: static unsigned int
        !           251: transit_hash_key_make (void *p)
        !           252: {
        !           253:   const struct transit * transit = p;
        !           254: 
        !           255:   return jhash(transit->val, transit->length, 0);
        !           256: }
        !           257: 
        !           258: static int
        !           259: transit_hash_cmp (const void *p1, const void *p2)
        !           260: {
        !           261:   const struct transit * transit1 = p1;
        !           262:   const struct transit * transit2 = p2;
        !           263: 
        !           264:   return (transit1->length == transit2->length &&
        !           265:          memcmp (transit1->val, transit2->val, transit1->length) == 0);
        !           266: }
        !           267: 
        !           268: static void
        !           269: transit_init (void)
        !           270: {
        !           271:   transit_hash = hash_create (transit_hash_key_make, transit_hash_cmp);
        !           272: }
        !           273: 
        !           274: static void
        !           275: transit_finish (void)
        !           276: {
        !           277:   hash_free (transit_hash);
        !           278:   transit_hash = NULL;
        !           279: }
        !           280: 
        !           281: /* Attribute hash routines. */
        !           282: static struct hash *attrhash;
        !           283: 
        !           284: static struct attr_extra *
        !           285: bgp_attr_extra_new (void)
        !           286: {
        !           287:   return XCALLOC (MTYPE_ATTR_EXTRA, sizeof (struct attr_extra));
        !           288: }
        !           289: 
        !           290: void
        !           291: bgp_attr_extra_free (struct attr *attr)
        !           292: {
        !           293:   if (attr->extra)
        !           294:     {
        !           295:       XFREE (MTYPE_ATTR_EXTRA, attr->extra);
        !           296:       attr->extra = NULL;
        !           297:     }
        !           298: }
        !           299: 
        !           300: struct attr_extra *
        !           301: bgp_attr_extra_get (struct attr *attr)
        !           302: {
        !           303:   if (!attr->extra)
        !           304:     attr->extra = bgp_attr_extra_new();
        !           305:   return attr->extra;
        !           306: }
        !           307: 
        !           308: /* Shallow copy of an attribute
        !           309:  * Though, not so shallow that it doesn't copy the contents
        !           310:  * of the attr_extra pointed to by 'extra'
        !           311:  */
        !           312: void
        !           313: bgp_attr_dup (struct attr *new, struct attr *orig)
        !           314: {
        !           315:   *new = *orig;
        !           316:   if (orig->extra)
        !           317:     {
        !           318:       new->extra = bgp_attr_extra_new();
        !           319:       *new->extra = *orig->extra;
        !           320:     }
        !           321: }
        !           322: 
        !           323: unsigned long int
        !           324: attr_count (void)
        !           325: {
        !           326:   return attrhash->count;
        !           327: }
        !           328: 
        !           329: unsigned long int
        !           330: attr_unknown_count (void)
        !           331: {
        !           332:   return transit_hash->count;
        !           333: }
        !           334: 
        !           335: unsigned int
        !           336: attrhash_key_make (void *p)
        !           337: {
        !           338:   const struct attr * attr = (struct attr *) p;
        !           339:   uint32_t key = 0;
        !           340: #define MIX(val)       key = jhash_1word(val, key)
        !           341: 
        !           342:   MIX(attr->origin);
        !           343:   MIX(attr->nexthop.s_addr);
        !           344:   MIX(attr->med);
        !           345:   MIX(attr->local_pref);
        !           346: 
        !           347:   key += attr->origin;
        !           348:   key += attr->nexthop.s_addr;
        !           349:   key += attr->med;
        !           350:   key += attr->local_pref;
        !           351:   
        !           352:   if (attr->extra)
        !           353:     {
        !           354:       MIX(attr->extra->aggregator_as);
        !           355:       MIX(attr->extra->aggregator_addr.s_addr);
        !           356:       MIX(attr->extra->weight);
        !           357:       MIX(attr->extra->mp_nexthop_global_in.s_addr);
        !           358:     }
        !           359:   
        !           360:   if (attr->aspath)
        !           361:     MIX(aspath_key_make (attr->aspath));
        !           362:   if (attr->community)
        !           363:     MIX(community_hash_make (attr->community));
        !           364:   
        !           365:   if (attr->extra)
        !           366:     {
        !           367:       if (attr->extra->ecommunity)
        !           368:         MIX(ecommunity_hash_make (attr->extra->ecommunity));
        !           369:       if (attr->extra->cluster)
        !           370:         MIX(cluster_hash_key_make (attr->extra->cluster));
        !           371:       if (attr->extra->transit)
        !           372:         MIX(transit_hash_key_make (attr->extra->transit));
        !           373: 
        !           374: #ifdef HAVE_IPV6
        !           375:       MIX(attr->extra->mp_nexthop_len);
        !           376:       key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key);
        !           377:       key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key);
        !           378: #endif /* HAVE_IPV6 */
        !           379:     }
        !           380: 
        !           381:   return key;
        !           382: }
        !           383: 
        !           384: int
        !           385: attrhash_cmp (const void *p1, const void *p2)
        !           386: {
        !           387:   const struct attr * attr1 = p1;
        !           388:   const struct attr * attr2 = p2;
        !           389: 
        !           390:   if (attr1->flag == attr2->flag
        !           391:       && attr1->origin == attr2->origin
        !           392:       && attr1->nexthop.s_addr == attr2->nexthop.s_addr
        !           393:       && attr1->aspath == attr2->aspath
        !           394:       && attr1->community == attr2->community
        !           395:       && attr1->med == attr2->med
        !           396:       && attr1->local_pref == attr2->local_pref)
        !           397:     {
        !           398:       const struct attr_extra *ae1 = attr1->extra;
        !           399:       const struct attr_extra *ae2 = attr2->extra;
        !           400:       
        !           401:       if (ae1 && ae2
        !           402:           && ae1->aggregator_as == ae2->aggregator_as
        !           403:           && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
        !           404:           && ae1->weight == ae2->weight
        !           405: #ifdef HAVE_IPV6
        !           406:           && ae1->mp_nexthop_len == ae2->mp_nexthop_len
        !           407:           && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
        !           408:           && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
        !           409: #endif /* HAVE_IPV6 */
        !           410:           && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
        !           411:           && ae1->ecommunity == ae2->ecommunity
        !           412:           && ae1->cluster == ae2->cluster
        !           413:           && ae1->transit == ae2->transit)
        !           414:         return 1;
        !           415:       else if (ae1 || ae2)
        !           416:         return 0;
        !           417:       /* neither attribute has extra attributes, so they're same */
        !           418:       return 1;
        !           419:     }
        !           420:   else
        !           421:     return 0;
        !           422: }
        !           423: 
        !           424: static void
        !           425: attrhash_init (void)
        !           426: {
        !           427:   attrhash = hash_create (attrhash_key_make, attrhash_cmp);
        !           428: }
        !           429: 
        !           430: static void
        !           431: attrhash_finish (void)
        !           432: {
        !           433:   hash_free (attrhash);
        !           434:   attrhash = NULL;
        !           435: }
        !           436: 
        !           437: static void
        !           438: attr_show_all_iterator (struct hash_backet *backet, struct vty *vty)
        !           439: {
        !           440:   struct attr *attr = backet->data;
        !           441: 
        !           442:   vty_out (vty, "attr[%ld] nexthop %s%s", attr->refcnt, 
        !           443:           inet_ntoa (attr->nexthop), VTY_NEWLINE);
        !           444: }
        !           445: 
        !           446: void
        !           447: attr_show_all (struct vty *vty)
        !           448: {
        !           449:   hash_iterate (attrhash, 
        !           450:                (void (*)(struct hash_backet *, void *))
        !           451:                attr_show_all_iterator,
        !           452:                vty);
        !           453: }
        !           454: 
        !           455: static void *
        !           456: bgp_attr_hash_alloc (void *p)
        !           457: {
        !           458:   struct attr * val = (struct attr *) p;
        !           459:   struct attr *attr;
        !           460: 
        !           461:   attr = XMALLOC (MTYPE_ATTR, sizeof (struct attr));
        !           462:   *attr = *val;
        !           463:   if (val->extra)
        !           464:     {
        !           465:       attr->extra = bgp_attr_extra_new ();
        !           466:       *attr->extra = *val->extra;
        !           467:     }
        !           468:   attr->refcnt = 0;
        !           469:   return attr;
        !           470: }
        !           471: 
        !           472: /* Internet argument attribute. */
        !           473: struct attr *
        !           474: bgp_attr_intern (struct attr *attr)
        !           475: {
        !           476:   struct attr *find;
        !           477: 
        !           478:   /* Intern referenced strucutre. */
        !           479:   if (attr->aspath)
        !           480:     {
        !           481:       if (! attr->aspath->refcnt)
        !           482:        attr->aspath = aspath_intern (attr->aspath);
        !           483:       else
        !           484:        attr->aspath->refcnt++;
        !           485:     }
        !           486:   if (attr->community)
        !           487:     {
        !           488:       if (! attr->community->refcnt)
        !           489:        attr->community = community_intern (attr->community);
        !           490:       else
        !           491:        attr->community->refcnt++;
        !           492:     }
        !           493:   if (attr->extra)
        !           494:     {
        !           495:       struct attr_extra *attre = attr->extra;
        !           496:       
        !           497:       if (attre->ecommunity)
        !           498:         {
        !           499:           if (! attre->ecommunity->refcnt)
        !           500:             attre->ecommunity = ecommunity_intern (attre->ecommunity);
        !           501:           else
        !           502:             attre->ecommunity->refcnt++;
        !           503:           
        !           504:         }
        !           505:       if (attre->cluster)
        !           506:         {
        !           507:           if (! attre->cluster->refcnt)
        !           508:             attre->cluster = cluster_intern (attre->cluster);
        !           509:           else
        !           510:             attre->cluster->refcnt++;
        !           511:         }
        !           512:       if (attre->transit)
        !           513:         {
        !           514:           if (! attre->transit->refcnt)
        !           515:             attre->transit = transit_intern (attre->transit);
        !           516:           else
        !           517:             attre->transit->refcnt++;
        !           518:         }
        !           519:     }
        !           520:   
        !           521:   find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
        !           522:   find->refcnt++;
        !           523:   
        !           524:   return find;
        !           525: }
        !           526: 
        !           527: 
        !           528: /* Make network statement's attribute. */
        !           529: struct attr *
        !           530: bgp_attr_default_set (struct attr *attr, u_char origin)
        !           531: {
        !           532:   memset (attr, 0, sizeof (struct attr));
        !           533:   bgp_attr_extra_get (attr);
        !           534:   
        !           535:   attr->origin = origin;
        !           536:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
        !           537:   attr->aspath = aspath_empty ();
        !           538:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
        !           539:   attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
        !           540:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
        !           541: #ifdef HAVE_IPV6
        !           542:   attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
        !           543: #endif
        !           544: 
        !           545:   return attr;
        !           546: }
        !           547: 
        !           548: 
        !           549: /* Make network statement's attribute. */
        !           550: struct attr *
        !           551: bgp_attr_default_intern (u_char origin)
        !           552: {
        !           553:   struct attr attr;
        !           554:   struct attr *new;
        !           555:   struct attr_extra *attre;
        !           556:   
        !           557:   memset (&attr, 0, sizeof (struct attr));
        !           558:   attre = bgp_attr_extra_get (&attr);
        !           559:   
        !           560:   bgp_attr_default_set(&attr, origin);
        !           561: 
        !           562:   new = bgp_attr_intern (&attr);
        !           563:   bgp_attr_extra_free (&attr);
        !           564:   
        !           565:   aspath_unintern (&new->aspath);
        !           566:   return new;
        !           567: }
        !           568: 
        !           569: struct attr *
        !           570: bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,
        !           571:                           struct aspath *aspath,
        !           572:                           struct community *community, int as_set)
        !           573: {
        !           574:   struct attr attr;
        !           575:   struct attr *new;
        !           576:   struct attr_extra *attre;
        !           577: 
        !           578:   memset (&attr, 0, sizeof (struct attr));
        !           579:   attre = bgp_attr_extra_get (&attr);
        !           580:   
        !           581:   /* Origin attribute. */
        !           582:   attr.origin = origin;
        !           583:   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
        !           584: 
        !           585:   /* AS path attribute. */
        !           586:   if (aspath)
        !           587:     attr.aspath = aspath_intern (aspath);
        !           588:   else
        !           589:     attr.aspath = aspath_empty ();
        !           590:   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
        !           591: 
        !           592:   /* Next hop attribute.  */
        !           593:   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
        !           594: 
        !           595:   if (community)
        !           596:     {
        !           597:       attr.community = community;
        !           598:       attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
        !           599:     }
        !           600: 
        !           601:   attre->weight = BGP_ATTR_DEFAULT_WEIGHT;
        !           602: #ifdef HAVE_IPV6
        !           603:   attre->mp_nexthop_len = IPV6_MAX_BYTELEN;
        !           604: #endif
        !           605:   if (! as_set)
        !           606:     attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
        !           607:   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
        !           608:   if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
        !           609:     attre->aggregator_as = bgp->confed_id;
        !           610:   else
        !           611:     attre->aggregator_as = bgp->as;
        !           612:   attre->aggregator_addr = bgp->router_id;
        !           613: 
        !           614:   new = bgp_attr_intern (&attr);
        !           615:   bgp_attr_extra_free (&attr);
        !           616:   
        !           617:   aspath_unintern (&new->aspath);
        !           618:   return new;
        !           619: }
        !           620: 
        !           621: /* Unintern just the sub-components of the attr, but not the attr */
        !           622: void
        !           623: bgp_attr_unintern_sub (struct attr *attr)
        !           624: {
        !           625:   /* aspath refcount shoud be decrement. */
        !           626:   if (attr->aspath)
        !           627:     aspath_unintern (&attr->aspath);
        !           628:   UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);
        !           629:   
        !           630:   if (attr->community)
        !           631:     community_unintern (&attr->community);
        !           632:   UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);
        !           633:   
        !           634:   if (attr->extra)
        !           635:     {
        !           636:       if (attr->extra->ecommunity)
        !           637:         ecommunity_unintern (&attr->extra->ecommunity);
        !           638:       UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);
        !           639:       
        !           640:       if (attr->extra->cluster)
        !           641:         cluster_unintern (attr->extra->cluster);
        !           642:       UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);
        !           643:       
        !           644:       if (attr->extra->transit)
        !           645:         transit_unintern (attr->extra->transit);
        !           646:     }
        !           647: }
        !           648: 
        !           649: /* Free bgp attribute and aspath. */
        !           650: void
        !           651: bgp_attr_unintern (struct attr **attr)
        !           652: {
        !           653:   struct attr *ret;
        !           654:   struct attr tmp;
        !           655:   
        !           656:   /* Decrement attribute reference. */
        !           657:   (*attr)->refcnt--;
        !           658:   
        !           659:   tmp = *(*attr);
        !           660:   
        !           661:   if ((*attr)->extra)
        !           662:     {
        !           663:       tmp.extra = bgp_attr_extra_new ();
        !           664:       memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra));
        !           665:     }
        !           666:   
        !           667:   /* If reference becomes zero then free attribute object. */
        !           668:   if ((*attr)->refcnt == 0)
        !           669:     {    
        !           670:       ret = hash_release (attrhash, *attr);
        !           671:       assert (ret != NULL);
        !           672:       bgp_attr_extra_free (*attr);
        !           673:       XFREE (MTYPE_ATTR, *attr);
        !           674:       *attr = NULL;
        !           675:     }
        !           676: 
        !           677:   bgp_attr_unintern_sub (&tmp);
        !           678: }
        !           679: 
        !           680: void
        !           681: bgp_attr_flush (struct attr *attr)
        !           682: {
        !           683:   if (attr->aspath && ! attr->aspath->refcnt)
        !           684:     aspath_free (attr->aspath);
        !           685:   if (attr->community && ! attr->community->refcnt)
        !           686:     community_free (attr->community);
        !           687:   if (attr->extra)
        !           688:     {
        !           689:       struct attr_extra *attre = attr->extra;
        !           690: 
        !           691:       if (attre->ecommunity && ! attre->ecommunity->refcnt)
        !           692:         ecommunity_free (&attre->ecommunity);
        !           693:       if (attre->cluster && ! attre->cluster->refcnt)
        !           694:         cluster_free (attre->cluster);
        !           695:       if (attre->transit && ! attre->transit->refcnt)
        !           696:         transit_free (attre->transit);
        !           697:     }
        !           698: }
        !           699: 
        !           700: /* Implement draft-scudder-idr-optional-transitive behaviour and
        !           701:  * avoid resetting sessions for malformed attributes which are
        !           702:  * are partial/optional and hence where the error likely was not
        !           703:  * introduced by the sending neighbour.
        !           704:  */
        !           705: static bgp_attr_parse_ret_t
        !           706: bgp_attr_malformed (struct peer *peer, u_char type, u_char flag,
        !           707:                     u_char subcode, u_char *startp, bgp_size_t length)
        !           708: {
        !           709:   /* Only relax error handling for eBGP peers */
        !           710:   if (peer_sort (peer) != BGP_PEER_EBGP)
        !           711:     {
        !           712:       bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
        !           713:                                  startp, length);
        !           714:       return BGP_ATTR_PARSE_ERROR;
        !           715: 
        !           716:     }
        !           717:   
        !           718:   switch (type) {
        !           719:     /* where an optional attribute is inconsequential, e.g. it does not affect
        !           720:      * route selection, and can be safely ignored then any such attributes
        !           721:      * which are malformed should just be ignored and the route processed as
        !           722:      * normal.
        !           723:      */
        !           724:     case BGP_ATTR_AS4_AGGREGATOR:
        !           725:     case BGP_ATTR_AGGREGATOR:
        !           726:     case BGP_ATTR_ATOMIC_AGGREGATE:
        !           727:       return BGP_ATTR_PARSE_PROCEED;
        !           728:     
        !           729:     /* Core attributes, particularly ones which may influence route
        !           730:      * selection should always cause session resets
        !           731:      */
        !           732:     case BGP_ATTR_ORIGIN:
        !           733:     case BGP_ATTR_AS_PATH:
        !           734:     case BGP_ATTR_NEXT_HOP:
        !           735:     case BGP_ATTR_MULTI_EXIT_DISC:
        !           736:     case BGP_ATTR_LOCAL_PREF:
        !           737:     case BGP_ATTR_COMMUNITIES:
        !           738:     case BGP_ATTR_ORIGINATOR_ID:
        !           739:     case BGP_ATTR_CLUSTER_LIST:
        !           740:     case BGP_ATTR_MP_REACH_NLRI:
        !           741:     case BGP_ATTR_MP_UNREACH_NLRI:
        !           742:     case BGP_ATTR_EXT_COMMUNITIES:
        !           743:       bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
        !           744:                                  startp, length);
        !           745:       return BGP_ATTR_PARSE_ERROR;
        !           746:   }
        !           747:   
        !           748:   /* Partial optional attributes that are malformed should not cause
        !           749:    * the whole session to be reset. Instead treat it as a withdrawal
        !           750:    * of the routes, if possible.
        !           751:    */
        !           752:   if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)
        !           753:       && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
        !           754:       && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
        !           755:     return BGP_ATTR_PARSE_WITHDRAW;
        !           756:   
        !           757:   /* default to reset */
        !           758:   return BGP_ATTR_PARSE_ERROR;
        !           759: }
        !           760: 
        !           761: /* Get origin attribute of the update message. */
        !           762: static bgp_attr_parse_ret_t
        !           763: bgp_attr_origin (struct peer *peer, bgp_size_t length, 
        !           764:                 struct attr *attr, u_char flag, u_char *startp)
        !           765: {
        !           766:   bgp_size_t total;
        !           767: 
        !           768:   /* total is entire attribute length include Attribute Flags (1),
        !           769:      Attribute Type code (1) and Attribute length (1 or 2).  */
        !           770:   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
        !           771: 
        !           772:   /* If any recognized attribute has Attribute Flags that conflict
        !           773:      with the Attribute Type Code, then the Error Subcode is set to
        !           774:      Attribute Flags Error.  The Data field contains the erroneous
        !           775:      attribute (type, length and value). */
        !           776:   if (flag != BGP_ATTR_FLAG_TRANS)
        !           777:     {
        !           778:       zlog (peer->log, LOG_ERR, 
        !           779:            "Origin attribute flag isn't transitive %d", flag);
        !           780:       return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
        !           781:                                  BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
        !           782:                                  startp, total);
        !           783:     }
        !           784: 
        !           785:   /* If any recognized attribute has Attribute Length that conflicts
        !           786:      with the expected length (based on the attribute type code), then
        !           787:      the Error Subcode is set to Attribute Length Error.  The Data
        !           788:      field contains the erroneous attribute (type, length and
        !           789:      value). */
        !           790:   if (length != 1)
        !           791:     {
        !           792:       zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
        !           793:            length);
        !           794:       return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
        !           795:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
        !           796:                                  startp, total);
        !           797:     }
        !           798: 
        !           799:   /* Fetch origin attribute. */
        !           800:   attr->origin = stream_getc (BGP_INPUT (peer));
        !           801: 
        !           802:   /* If the ORIGIN attribute has an undefined value, then the Error
        !           803:      Subcode is set to Invalid Origin Attribute.  The Data field
        !           804:      contains the unrecognized attribute (type, length and value). */
        !           805:   if ((attr->origin != BGP_ORIGIN_IGP)
        !           806:       && (attr->origin != BGP_ORIGIN_EGP)
        !           807:       && (attr->origin != BGP_ORIGIN_INCOMPLETE))
        !           808:     {
        !           809:       zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
        !           810:              attr->origin);
        !           811:       return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,
        !           812:                                  BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
        !           813:                                  startp, total);
        !           814:     }
        !           815: 
        !           816:   /* Set oring attribute flag. */
        !           817:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
        !           818: 
        !           819:   return 0;
        !           820: }
        !           821: 
        !           822: /* Parse AS path information.  This function is wrapper of
        !           823:    aspath_parse. */
        !           824: static int
        !           825: bgp_attr_aspath (struct peer *peer, bgp_size_t length, 
        !           826:                 struct attr *attr, u_char flag, u_char *startp)
        !           827: {
        !           828:   bgp_size_t total;
        !           829: 
        !           830:   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
        !           831: 
        !           832:   /* Flag check. */
        !           833:   if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
        !           834:       || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
        !           835:     {
        !           836:       zlog (peer->log, LOG_ERR, 
        !           837:            "As-Path attribute flag isn't transitive %d", flag);
        !           838:       return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
        !           839:                                  BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
        !           840:                                  startp, total);
        !           841:     }
        !           842: 
        !           843:   /*
        !           844:    * peer with AS4 => will get 4Byte ASnums
        !           845:    * otherwise, will get 16 Bit
        !           846:    */
        !           847:   attr->aspath = aspath_parse (peer->ibuf, length, 
        !           848:                                CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
        !           849: 
        !           850:   /* In case of IBGP, length will be zero. */
        !           851:   if (! attr->aspath)
        !           852:     {
        !           853:       zlog (peer->log, LOG_ERR,
        !           854:             "Malformed AS path from %s, length is %d",
        !           855:             peer->host, length);
        !           856:       return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
        !           857:                                  BGP_NOTIFY_UPDATE_MAL_AS_PATH,
        !           858:                                  NULL, 0);
        !           859:     }
        !           860: 
        !           861:   /* Set aspath attribute flag. */
        !           862:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
        !           863: 
        !           864:   return BGP_ATTR_PARSE_PROCEED;
        !           865: }
        !           866: 
        !           867: static bgp_attr_parse_ret_t
        !           868: bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)
        !           869: {
        !           870:   /* These checks were part of bgp_attr_aspath, but with
        !           871:    * as4 we should to check aspath things when
        !           872:    * aspath synthesizing with as4_path has already taken place.
        !           873:    * Otherwise we check ASPATH and use the synthesized thing, and that is
        !           874:    * not right.
        !           875:    * So do the checks later, i.e. here
        !           876:    */
        !           877:   struct bgp *bgp = peer->bgp;
        !           878:   struct aspath *aspath;
        !           879: 
        !           880:   bgp = peer->bgp;
        !           881:     
        !           882:   /* Confederation sanity check. */
        !           883:   if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
        !           884:      (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
        !           885:     {
        !           886:       zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
        !           887:       return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
        !           888:                                  BGP_NOTIFY_UPDATE_MAL_AS_PATH,
        !           889:                                  NULL, 0);
        !           890:     }
        !           891: 
        !           892:   /* First AS check for EBGP. */
        !           893:   if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
        !           894:     {
        !           895:       if (peer_sort (peer) == BGP_PEER_EBGP 
        !           896:          && ! aspath_firstas_check (attr->aspath, peer->as))
        !           897:        {
        !           898:          zlog (peer->log, LOG_ERR,
        !           899:                "%s incorrect first AS (must be %u)", peer->host, peer->as);
        !           900:           return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
        !           901:                                      BGP_NOTIFY_UPDATE_MAL_AS_PATH,
        !           902:                                      NULL, 0);
        !           903:        }
        !           904:     }
        !           905: 
        !           906:   /* local-as prepend */
        !           907:   if (peer->change_local_as &&
        !           908:       ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND))
        !           909:     {
        !           910:       aspath = aspath_dup (attr->aspath);
        !           911:       aspath = aspath_add_seq (aspath, peer->change_local_as);
        !           912:       aspath_unintern (&attr->aspath);
        !           913:       attr->aspath = aspath_intern (aspath);
        !           914:     }
        !           915: 
        !           916:   return BGP_ATTR_PARSE_PROCEED;
        !           917: }
        !           918: 
        !           919: /* Parse AS4 path information.  This function is another wrapper of
        !           920:    aspath_parse. */
        !           921: static int
        !           922: bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
        !           923:                 struct attr *attr, u_char flag, u_char *startp,
        !           924:                 struct aspath **as4_path)
        !           925: {
        !           926:   bgp_size_t total;
        !           927: 
        !           928:   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
        !           929: 
        !           930:   /* Flag check. */
        !           931:   if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
        !           932:       || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
        !           933:     {
        !           934:       zlog (peer->log, LOG_ERR, 
        !           935:            "As4-Path attribute flag isn't optional/transitive %d", flag);
        !           936:       return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
        !           937:                                  BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
        !           938:                                  startp, total);
        !           939:     }
        !           940: 
        !           941:   *as4_path = aspath_parse (peer->ibuf, length, 1);
        !           942: 
        !           943:   /* In case of IBGP, length will be zero. */
        !           944:   if (!*as4_path)
        !           945:     {
        !           946:       zlog (peer->log, LOG_ERR,
        !           947:             "Malformed AS4 path from %s, length is %d",
        !           948:             peer->host, length);
        !           949:       return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
        !           950:                                  BGP_NOTIFY_UPDATE_MAL_AS_PATH,
        !           951:                                  NULL, 0);
        !           952:     }
        !           953: 
        !           954:   /* Set aspath attribute flag. */
        !           955:   if (as4_path)
        !           956:     attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH);
        !           957: 
        !           958:   return BGP_ATTR_PARSE_PROCEED;
        !           959: }
        !           960: 
        !           961: /* Nexthop attribute. */
        !           962: static bgp_attr_parse_ret_t
        !           963: bgp_attr_nexthop (struct peer *peer, bgp_size_t length, 
        !           964:                  struct attr *attr, u_char flag, u_char *startp)
        !           965: {
        !           966:   bgp_size_t total;
        !           967: 
        !           968:   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
        !           969: 
        !           970:   /* Flag check. */
        !           971:   if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
        !           972:       || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
        !           973:     {
        !           974:       zlog (peer->log, LOG_ERR, 
        !           975:            "Origin attribute flag isn't transitive %d", flag);
        !           976:       return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
        !           977:                                  BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
        !           978:                                  startp, total);
        !           979:     }
        !           980: 
        !           981:   /* Check nexthop attribute length. */
        !           982:   if (length != 4)
        !           983:     {
        !           984:       zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
        !           985:              length);
        !           986: 
        !           987:       return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
        !           988:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
        !           989:                                  startp, total);
        !           990:     }
        !           991: 
        !           992:   attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);
        !           993:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
        !           994: 
        !           995:   return BGP_ATTR_PARSE_PROCEED;
        !           996: }
        !           997: 
        !           998: /* MED atrribute. */
        !           999: static bgp_attr_parse_ret_t
        !          1000: bgp_attr_med (struct peer *peer, bgp_size_t length, 
        !          1001:              struct attr *attr, u_char flag, u_char *startp)
        !          1002: {
        !          1003:   bgp_size_t total;
        !          1004: 
        !          1005:   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
        !          1006: 
        !          1007:   /* Flag checks. */
        !          1008:   if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
        !          1009:     {
        !          1010:       zlog (peer->log, LOG_ERR,
        !          1011:            "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag);
        !          1012:       bgp_notify_send_with_data (peer,
        !          1013:                                 BGP_NOTIFY_UPDATE_ERR,
        !          1014:                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
        !          1015:                                 startp, total);
        !          1016:       return -1;
        !          1017:     }
        !          1018:   if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
        !          1019:     {
        !          1020:       zlog (peer->log, LOG_ERR,
        !          1021:            "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag);
        !          1022:       bgp_notify_send_with_data (peer,
        !          1023:                                 BGP_NOTIFY_UPDATE_ERR,
        !          1024:                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
        !          1025:                                 startp, total);
        !          1026:       return -1;
        !          1027:     }
        !          1028:   if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
        !          1029:     {
        !          1030:       zlog (peer->log, LOG_ERR,
        !          1031:            "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag);
        !          1032:       bgp_notify_send_with_data (peer,
        !          1033:                                 BGP_NOTIFY_UPDATE_ERR,
        !          1034:                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
        !          1035:                                 startp, total);
        !          1036:       return -1;
        !          1037:     }
        !          1038: 
        !          1039:   /* Length check. */
        !          1040:   if (length != 4)
        !          1041:     {
        !          1042:       zlog (peer->log, LOG_ERR, 
        !          1043:            "MED attribute length isn't four [%d]", length);
        !          1044: 
        !          1045:       return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
        !          1046:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
        !          1047:                                  startp, total);
        !          1048:     }
        !          1049: 
        !          1050:   attr->med = stream_getl (peer->ibuf);
        !          1051: 
        !          1052:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC);
        !          1053: 
        !          1054:   return BGP_ATTR_PARSE_PROCEED;
        !          1055: }
        !          1056: 
        !          1057: /* Local preference attribute. */
        !          1058: static bgp_attr_parse_ret_t
        !          1059: bgp_attr_local_pref (struct peer *peer, bgp_size_t length, 
        !          1060:                     struct attr *attr, u_char flag, u_char *startp)
        !          1061: {
        !          1062:   bgp_size_t total;
        !          1063: 
        !          1064:   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
        !          1065:   /* Flag checks. */
        !          1066:   if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
        !          1067:     {
        !          1068:       zlog (peer->log, LOG_ERR,
        !          1069:            "LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag);
        !          1070:       bgp_notify_send_with_data (peer,
        !          1071:                                 BGP_NOTIFY_UPDATE_ERR,
        !          1072:                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
        !          1073:                                 startp, total);
        !          1074:       return -1;
        !          1075:     }
        !          1076:   if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
        !          1077:     {
        !          1078:       zlog (peer->log, LOG_ERR,
        !          1079:            "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);
        !          1080:       bgp_notify_send_with_data (peer,
        !          1081:                                 BGP_NOTIFY_UPDATE_ERR,
        !          1082:                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
        !          1083:                                 startp, total);
        !          1084:       return -1;
        !          1085:     }
        !          1086: 
        !          1087:   /* If it is contained in an UPDATE message that is received from an
        !          1088:      external peer, then this attribute MUST be ignored by the
        !          1089:      receiving speaker. */
        !          1090:   if (peer_sort (peer) == BGP_PEER_EBGP)
        !          1091:     {
        !          1092:       stream_forward_getp (peer->ibuf, length);
        !          1093:       return BGP_ATTR_PARSE_PROCEED;
        !          1094:     }
        !          1095: 
        !          1096:   if (length == 4) 
        !          1097:     attr->local_pref = stream_getl (peer->ibuf);
        !          1098:   else 
        !          1099:     attr->local_pref = 0;
        !          1100: 
        !          1101:   /* Set atomic aggregate flag. */
        !          1102:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
        !          1103: 
        !          1104:   return BGP_ATTR_PARSE_PROCEED;
        !          1105: }
        !          1106: 
        !          1107: /* Atomic aggregate. */
        !          1108: static int
        !          1109: bgp_attr_atomic (struct peer *peer, bgp_size_t length, 
        !          1110:                 struct attr *attr, u_char flag, u_char *startp)
        !          1111: {
        !          1112:   bgp_size_t total;
        !          1113: 
        !          1114:   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
        !          1115:   /* Flag checks. */
        !          1116:   if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
        !          1117:     {
        !          1118:       zlog (peer->log, LOG_ERR,
        !          1119:            "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag);
        !          1120:       bgp_notify_send_with_data (peer,
        !          1121:                                 BGP_NOTIFY_UPDATE_ERR,
        !          1122:                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
        !          1123:                                 startp, total);
        !          1124:       return -1;
        !          1125:     }
        !          1126:   if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
        !          1127:     {
        !          1128:       zlog (peer->log, LOG_ERR,
        !          1129:            "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag);
        !          1130:       bgp_notify_send_with_data (peer,
        !          1131:                                 BGP_NOTIFY_UPDATE_ERR,
        !          1132:                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
        !          1133:                                 startp, total);
        !          1134:       return -1;
        !          1135:     }
        !          1136:   if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
        !          1137:     {
        !          1138:       zlog (peer->log, LOG_ERR,
        !          1139:            "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag);
        !          1140:       bgp_notify_send_with_data (peer,
        !          1141:                                 BGP_NOTIFY_UPDATE_ERR,
        !          1142:                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
        !          1143:                                 startp, total);
        !          1144:       return -1;
        !          1145:     }
        !          1146: 
        !          1147:   /* Length check. */
        !          1148:   if (length != 0)
        !          1149:     {
        !          1150:       zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);
        !          1151: 
        !          1152:       return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
        !          1153:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
        !          1154:                                  NULL, 0);
        !          1155:     }
        !          1156: 
        !          1157:   /* Set atomic aggregate flag. */
        !          1158:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
        !          1159: 
        !          1160:   return BGP_ATTR_PARSE_PROCEED;
        !          1161: }
        !          1162: 
        !          1163: /* Aggregator attribute */
        !          1164: static int
        !          1165: bgp_attr_aggregator (struct peer *peer, bgp_size_t length,
        !          1166:                     struct attr *attr, u_char flag)
        !          1167: {
        !          1168:   int wantedlen = 6;
        !          1169:   struct attr_extra *attre = bgp_attr_extra_get (attr);
        !          1170:   
        !          1171:   /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */
        !          1172:   if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
        !          1173:     wantedlen = 8;
        !          1174:   
        !          1175:   if (length != wantedlen)
        !          1176:     {
        !          1177:       zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);
        !          1178: 
        !          1179:       return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
        !          1180:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
        !          1181:                                  NULL, 0);
        !          1182:     }
        !          1183:   
        !          1184:   if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
        !          1185:     attre->aggregator_as = stream_getl (peer->ibuf);
        !          1186:   else
        !          1187:     attre->aggregator_as = stream_getw (peer->ibuf);
        !          1188:   attre->aggregator_addr.s_addr = stream_get_ipv4 (peer->ibuf);
        !          1189: 
        !          1190:   /* Set atomic aggregate flag. */
        !          1191:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
        !          1192: 
        !          1193:   return BGP_ATTR_PARSE_PROCEED;
        !          1194: }
        !          1195: 
        !          1196: /* New Aggregator attribute */
        !          1197: static bgp_attr_parse_ret_t
        !          1198: bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
        !          1199:                     struct attr *attr, u_char flag, 
        !          1200:                     as_t *as4_aggregator_as,
        !          1201:                     struct in_addr *as4_aggregator_addr)
        !          1202: {
        !          1203:   if (length != 8)
        !          1204:     {
        !          1205:       zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);
        !          1206:       return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
        !          1207:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
        !          1208:                                  NULL, 0);
        !          1209:     }
        !          1210:   *as4_aggregator_as = stream_getl (peer->ibuf);
        !          1211:   as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
        !          1212: 
        !          1213:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR);
        !          1214: 
        !          1215:   return BGP_ATTR_PARSE_PROCEED;
        !          1216: }
        !          1217: 
        !          1218: /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
        !          1219:  */
        !          1220: static bgp_attr_parse_ret_t
        !          1221: bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,
        !          1222:                           struct aspath *as4_path, as_t as4_aggregator,
        !          1223:                           struct in_addr *as4_aggregator_addr)
        !          1224: {
        !          1225:   int ignore_as4_path = 0;
        !          1226:   struct aspath *newpath;
        !          1227:   struct attr_extra *attre = attr->extra;
        !          1228:     
        !          1229:   if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
        !          1230:     {
        !          1231:       /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
        !          1232:        * if given.
        !          1233:        * It is worth a warning though, because the peer really
        !          1234:        * should not send them
        !          1235:        */
        !          1236:       if (BGP_DEBUG(as4, AS4))
        !          1237:         {
        !          1238:           if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))
        !          1239:             zlog_debug ("[AS4] %s %s AS4_PATH",
        !          1240:                         peer->host, "AS4 capable peer, yet it sent");
        !          1241:           
        !          1242:           if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_AGGREGATOR)))
        !          1243:             zlog_debug ("[AS4] %s %s AS4_AGGREGATOR",
        !          1244:                         peer->host, "AS4 capable peer, yet it sent");
        !          1245:         }
        !          1246:       
        !          1247:       return BGP_ATTR_PARSE_PROCEED;
        !          1248:     }
        !          1249:   
        !          1250:   if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))
        !          1251:       && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))
        !          1252:     {
        !          1253:       /* Hu? This is not supposed to happen at all!
        !          1254:        * got as4_path and no aspath,
        !          1255:        *   This should already
        !          1256:        *   have been handled by 'well known attributes missing'
        !          1257:        *   But... yeah, paranoia
        !          1258:        * Take this as a "malformed attribute"
        !          1259:        */
        !          1260:       zlog (peer->log, LOG_ERR, 
        !          1261:             "%s BGP not AS4 capable peer sent AS4_PATH but"
        !          1262:             " no AS_PATH, cant do anything here", peer->host);
        !          1263:       return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
        !          1264:                                  BGP_NOTIFY_UPDATE_MAL_ATTR,
        !          1265:                                  NULL, 0);
        !          1266:     }
        !          1267: 
        !          1268:   /* We have a asn16 peer.  First, look for AS4_AGGREGATOR
        !          1269:    * because that may override AS4_PATH
        !          1270:    */
        !          1271:   if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )
        !          1272:     {
        !          1273:       if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )
        !          1274:         {
        !          1275:           assert (attre);
        !          1276:           
        !          1277:           /* received both.
        !          1278:            * if the as_number in aggregator is not AS_TRANS,
        !          1279:            *  then AS4_AGGREGATOR and AS4_PATH shall be ignored
        !          1280:            *        and the Aggregator shall be taken as 
        !          1281:            *        info on the aggregating node, and the AS_PATH
        !          1282:            *        shall be taken as the AS_PATH
        !          1283:            *  otherwise
        !          1284:            *        the Aggregator shall be ignored and the
        !          1285:            *        AS4_AGGREGATOR shall be taken as the
        !          1286:            *        Aggregating node and the AS_PATH is to be
        !          1287:            *        constructed "as in all other cases"
        !          1288:            */
        !          1289:           if (attre->aggregator_as != BGP_AS_TRANS)
        !          1290:             {
        !          1291:               /* ignore */
        !          1292:               if ( BGP_DEBUG(as4, AS4))
        !          1293:                 zlog_debug ("[AS4] %s BGP not AS4 capable peer" 
        !          1294:                             " send AGGREGATOR != AS_TRANS and"
        !          1295:                             " AS4_AGGREGATOR, so ignore"
        !          1296:                             " AS4_AGGREGATOR and AS4_PATH", peer->host);
        !          1297:               ignore_as4_path = 1;
        !          1298:             }
        !          1299:           else
        !          1300:             {
        !          1301:               /* "New_aggregator shall be taken as aggregator" */
        !          1302:               attre->aggregator_as = as4_aggregator;
        !          1303:               attre->aggregator_addr.s_addr = as4_aggregator_addr->s_addr;
        !          1304:             }
        !          1305:         }
        !          1306:       else
        !          1307:         {
        !          1308:           /* We received a AS4_AGGREGATOR but no AGGREGATOR.
        !          1309:            * That is bogus - but reading the conditions
        !          1310:            * we have to handle AS4_AGGREGATOR as if it were
        !          1311:            * AGGREGATOR in that case
        !          1312:            */
        !          1313:           if ( BGP_DEBUG(as4, AS4))
        !          1314:             zlog_debug ("[AS4] %s BGP not AS4 capable peer send"
        !          1315:                         " AS4_AGGREGATOR but no AGGREGATOR, will take"
        !          1316:                         " it as if AGGREGATOR with AS_TRANS had been there", peer->host);
        !          1317:           (attre = bgp_attr_extra_get (attr))->aggregator_as = as4_aggregator;
        !          1318:           /* sweep it under the carpet and simulate a "good" AGGREGATOR */
        !          1319:           attr->flag |= (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR));
        !          1320:         }
        !          1321:     }
        !          1322: 
        !          1323:   /* need to reconcile NEW_AS_PATH and AS_PATH */
        !          1324:   if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
        !          1325:     {
        !          1326:        newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
        !          1327:        aspath_unintern (&attr->aspath);
        !          1328:        attr->aspath = aspath_intern (newpath);
        !          1329:     }
        !          1330:   return BGP_ATTR_PARSE_PROCEED;
        !          1331: }
        !          1332: 
        !          1333: /* Community attribute. */
        !          1334: static bgp_attr_parse_ret_t
        !          1335: bgp_attr_community (struct peer *peer, bgp_size_t length, 
        !          1336:                    struct attr *attr, u_char flag, u_char *startp)
        !          1337: {
        !          1338:   bgp_size_t total
        !          1339:     = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
        !          1340:   
        !          1341:   if (length == 0)
        !          1342:     {
        !          1343:       attr->community = NULL;
        !          1344:       return BGP_ATTR_PARSE_PROCEED;
        !          1345:     }
        !          1346:   
        !          1347:   attr->community =
        !          1348:     community_parse ((u_int32_t *)stream_pnt (peer->ibuf), length);
        !          1349:   
        !          1350:   /* XXX: fix community_parse to use stream API and remove this */
        !          1351:   stream_forward_getp (peer->ibuf, length);
        !          1352: 
        !          1353:   if (!attr->community)
        !          1354:     return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
        !          1355:                                BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
        !          1356:                                startp, total);
        !          1357:   
        !          1358:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
        !          1359: 
        !          1360:   return BGP_ATTR_PARSE_PROCEED;
        !          1361: }
        !          1362: 
        !          1363: /* Originator ID attribute. */
        !          1364: static bgp_attr_parse_ret_t
        !          1365: bgp_attr_originator_id (struct peer *peer, bgp_size_t length, 
        !          1366:                        struct attr *attr, u_char flag)
        !          1367: {
        !          1368:   if (length != 4)
        !          1369:     {
        !          1370:       zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
        !          1371: 
        !          1372:       return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
        !          1373:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
        !          1374:                                  NULL, 0);
        !          1375:     }
        !          1376: 
        !          1377:   (bgp_attr_extra_get (attr))->originator_id.s_addr 
        !          1378:     = stream_get_ipv4 (peer->ibuf);
        !          1379: 
        !          1380:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
        !          1381: 
        !          1382:   return BGP_ATTR_PARSE_PROCEED;
        !          1383: }
        !          1384: 
        !          1385: /* Cluster list attribute. */
        !          1386: static bgp_attr_parse_ret_t
        !          1387: bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, 
        !          1388:                       struct attr *attr, u_char flag)
        !          1389: {
        !          1390:   /* Check length. */
        !          1391:   if (length % 4)
        !          1392:     {
        !          1393:       zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
        !          1394: 
        !          1395:       return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
        !          1396:                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
        !          1397:                                  NULL, 0);
        !          1398:     }
        !          1399: 
        !          1400:   (bgp_attr_extra_get (attr))->cluster 
        !          1401:     = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length);
        !          1402:   
        !          1403:   /* XXX: Fix cluster_parse to use stream API and then remove this */
        !          1404:   stream_forward_getp (peer->ibuf, length);
        !          1405: 
        !          1406:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST);
        !          1407: 
        !          1408:   return BGP_ATTR_PARSE_PROCEED;
        !          1409: }
        !          1410: 
        !          1411: /* Multiprotocol reachability information parse. */
        !          1412: int
        !          1413: bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,
        !          1414:                    struct bgp_nlri *mp_update)
        !          1415: {
        !          1416:   afi_t afi;
        !          1417:   safi_t safi;
        !          1418:   bgp_size_t nlri_len;
        !          1419:   size_t start;
        !          1420:   int ret;
        !          1421:   struct stream *s;
        !          1422:   struct attr_extra *attre = bgp_attr_extra_get(attr);
        !          1423:   
        !          1424:   /* Set end of packet. */
        !          1425:   s = BGP_INPUT(peer);
        !          1426:   start = stream_get_getp(s);
        !          1427:   
        !          1428:   /* safe to read statically sized header? */
        !          1429: #define BGP_MP_REACH_MIN_SIZE 5
        !          1430: #define LEN_LEFT       (length - (stream_get_getp(s) - start))
        !          1431:   if ((length > STREAM_READABLE(s)) || (length < BGP_MP_REACH_MIN_SIZE))
        !          1432:     {
        !          1433:       zlog_info ("%s: %s sent invalid length, %lu", 
        !          1434:                 __func__, peer->host, (unsigned long)length);
        !          1435:       return BGP_ATTR_PARSE_ERROR;
        !          1436:     }
        !          1437:   
        !          1438:   /* Load AFI, SAFI. */
        !          1439:   afi = stream_getw (s);
        !          1440:   safi = stream_getc (s);
        !          1441: 
        !          1442:   /* Get nexthop length. */
        !          1443:   attre->mp_nexthop_len = stream_getc (s);
        !          1444:   
        !          1445:   if (LEN_LEFT < attre->mp_nexthop_len)
        !          1446:     {
        !          1447:       zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", 
        !          1448:                 __func__, peer->host, attre->mp_nexthop_len);
        !          1449:       return BGP_ATTR_PARSE_ERROR;
        !          1450:     }
        !          1451:   
        !          1452:   /* Nexthop length check. */
        !          1453:   switch (attre->mp_nexthop_len)
        !          1454:     {
        !          1455:     case 4:
        !          1456:       stream_get (&attre->mp_nexthop_global_in, s, 4);
        !          1457:       /* Probably needed for RFC 2283 */
        !          1458:       if (attr->nexthop.s_addr == 0)
        !          1459:         memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
        !          1460:       break;
        !          1461:     case 12:
        !          1462:       {
        !          1463:        u_int32_t rd_high;
        !          1464:        u_int32_t rd_low;
        !          1465: 
        !          1466:        rd_high = stream_getl (s);
        !          1467:        rd_low = stream_getl (s);
        !          1468:        stream_get (&attre->mp_nexthop_global_in, s, 4);
        !          1469:       }
        !          1470:       break;
        !          1471: #ifdef HAVE_IPV6
        !          1472:     case 16:
        !          1473:       stream_get (&attre->mp_nexthop_global, s, 16);
        !          1474:       break;
        !          1475:     case 32:
        !          1476:       stream_get (&attre->mp_nexthop_global, s, 16);
        !          1477:       stream_get (&attre->mp_nexthop_local, s, 16);
        !          1478:       if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
        !          1479:        {
        !          1480:          char buf1[INET6_ADDRSTRLEN];
        !          1481:          char buf2[INET6_ADDRSTRLEN];
        !          1482: 
        !          1483:          if (BGP_DEBUG (update, UPDATE_IN))
        !          1484:            zlog_debug ("%s got two nexthop %s %s but second one is not a link-local nexthop", peer->host,
        !          1485:                       inet_ntop (AF_INET6, &attre->mp_nexthop_global,
        !          1486:                                  buf1, INET6_ADDRSTRLEN),
        !          1487:                       inet_ntop (AF_INET6, &attre->mp_nexthop_local,
        !          1488:                                  buf2, INET6_ADDRSTRLEN));
        !          1489: 
        !          1490:          attre->mp_nexthop_len = 16;
        !          1491:        }
        !          1492:       break;
        !          1493: #endif /* HAVE_IPV6 */
        !          1494:     default:
        !          1495:       zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", 
        !          1496:                 __func__, peer->host, attre->mp_nexthop_len);
        !          1497:       return BGP_ATTR_PARSE_ERROR;
        !          1498:     }
        !          1499: 
        !          1500:   if (!LEN_LEFT)
        !          1501:     {
        !          1502:       zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
        !          1503:                  __func__, peer->host);
        !          1504:       return BGP_ATTR_PARSE_ERROR;
        !          1505:     }
        !          1506:   
        !          1507:   {
        !          1508:     u_char val; 
        !          1509:     if ((val = stream_getc (s)))
        !          1510:     zlog_warn ("%s sent non-zero value, %u, for defunct SNPA-length field",
        !          1511:                 peer->host, val);
        !          1512:   }
        !          1513:   
        !          1514:   /* must have nrli_len, what is left of the attribute */
        !          1515:   nlri_len = LEN_LEFT;
        !          1516:   if ((!nlri_len) || (nlri_len > STREAM_READABLE(s)))
        !          1517:     {
        !          1518:       zlog_info ("%s: (%s) Failed to read NLRI",
        !          1519:                  __func__, peer->host);
        !          1520:       return BGP_ATTR_PARSE_ERROR;
        !          1521:     }
        !          1522:  
        !          1523:   if (safi != BGP_SAFI_VPNV4)
        !          1524:     {
        !          1525:       ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
        !          1526:       if (ret < 0) 
        !          1527:         {
        !          1528:           zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
        !          1529:                      __func__, peer->host);
        !          1530:          return BGP_ATTR_PARSE_ERROR;
        !          1531:        }
        !          1532:     }
        !          1533: 
        !          1534:   mp_update->afi = afi;
        !          1535:   mp_update->safi = safi;
        !          1536:   mp_update->nlri = stream_pnt (s);
        !          1537:   mp_update->length = nlri_len;
        !          1538: 
        !          1539:   stream_forward_getp (s, nlri_len);
        !          1540: 
        !          1541:   return BGP_ATTR_PARSE_PROCEED;
        !          1542: #undef LEN_LEFT
        !          1543: }
        !          1544: 
        !          1545: /* Multiprotocol unreachable parse */
        !          1546: int
        !          1547: bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, 
        !          1548:                      struct bgp_nlri *mp_withdraw)
        !          1549: {
        !          1550:   struct stream *s;
        !          1551:   afi_t afi;
        !          1552:   safi_t safi;
        !          1553:   u_int16_t withdraw_len;
        !          1554:   int ret;
        !          1555: 
        !          1556:   s = peer->ibuf;
        !          1557:   
        !          1558: #define BGP_MP_UNREACH_MIN_SIZE 3
        !          1559:   if ((length > STREAM_READABLE(s)) || (length <  BGP_MP_UNREACH_MIN_SIZE))
        !          1560:     return BGP_ATTR_PARSE_ERROR;
        !          1561:   
        !          1562:   afi = stream_getw (s);
        !          1563:   safi = stream_getc (s);
        !          1564:   
        !          1565:   withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
        !          1566: 
        !          1567:   if (safi != BGP_SAFI_VPNV4)
        !          1568:     {
        !          1569:       ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
        !          1570:       if (ret < 0)
        !          1571:        return BGP_ATTR_PARSE_ERROR;
        !          1572:     }
        !          1573: 
        !          1574:   mp_withdraw->afi = afi;
        !          1575:   mp_withdraw->safi = safi;
        !          1576:   mp_withdraw->nlri = stream_pnt (s);
        !          1577:   mp_withdraw->length = withdraw_len;
        !          1578: 
        !          1579:   stream_forward_getp (s, withdraw_len);
        !          1580: 
        !          1581:   return BGP_ATTR_PARSE_PROCEED;
        !          1582: }
        !          1583: 
        !          1584: /* Extended Community attribute. */
        !          1585: static bgp_attr_parse_ret_t
        !          1586: bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, 
        !          1587:                          struct attr *attr, u_char flag, u_char *startp)
        !          1588: {
        !          1589:   bgp_size_t total
        !          1590:     = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
        !          1591:   
        !          1592:   if (length == 0)
        !          1593:     {
        !          1594:       if (attr->extra)
        !          1595:         attr->extra->ecommunity = NULL;
        !          1596:       /* Empty extcomm doesn't seem to be invalid per se */
        !          1597:       return BGP_ATTR_PARSE_PROCEED;
        !          1598:     }
        !          1599: 
        !          1600:   (bgp_attr_extra_get (attr))->ecommunity =
        !          1601:     ecommunity_parse ((u_int8_t *)stream_pnt (peer->ibuf), length);
        !          1602:   /* XXX: fix ecommunity_parse to use stream API */
        !          1603:   stream_forward_getp (peer->ibuf, length);
        !          1604:   
        !          1605:   if (!attr->extra->ecommunity)
        !          1606:     return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
        !          1607:                                flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
        !          1608:                                startp, total);
        !          1609:   
        !          1610:   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
        !          1611: 
        !          1612:   return BGP_ATTR_PARSE_PROCEED;
        !          1613: }
        !          1614: 
        !          1615: /* BGP unknown attribute treatment. */
        !          1616: static bgp_attr_parse_ret_t
        !          1617: bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
        !          1618:                  u_char type, bgp_size_t length, u_char *startp)
        !          1619: {
        !          1620:   bgp_size_t total;
        !          1621:   struct transit *transit;
        !          1622:   struct attr_extra *attre;
        !          1623: 
        !          1624:   if (BGP_DEBUG (normal, NORMAL))
        !          1625:   zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
        !          1626:              peer->host, type, length);
        !          1627:   
        !          1628:   if (BGP_DEBUG (events, EVENTS))
        !          1629:     zlog (peer->log, LOG_DEBUG, 
        !          1630:          "Unknown attribute type %d length %d is received", type, length);
        !          1631: 
        !          1632:   /* Forward read pointer of input stream. */
        !          1633:   stream_forward_getp (peer->ibuf, length);
        !          1634: 
        !          1635:   /* Adjest total length to include type and length. */
        !          1636:   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
        !          1637: 
        !          1638:   /* If any of the mandatory well-known attributes are not recognized,
        !          1639:      then the Error Subcode is set to Unrecognized Well-known
        !          1640:      Attribute.  The Data field contains the unrecognized attribute
        !          1641:      (type, length and value). */
        !          1642:   if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
        !          1643:     {
        !          1644:       return bgp_attr_malformed (peer, type, flag,
        !          1645:                                  BGP_NOTIFY_UPDATE_UNREC_ATTR,
        !          1646:                                  startp, total);
        !          1647:     }
        !          1648: 
        !          1649:   /* Unrecognized non-transitive optional attributes must be quietly
        !          1650:      ignored and not passed along to other BGP peers. */
        !          1651:   if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
        !          1652:     return BGP_ATTR_PARSE_PROCEED;
        !          1653: 
        !          1654:   /* If a path with recognized transitive optional attribute is
        !          1655:      accepted and passed along to other BGP peers and the Partial bit
        !          1656:      in the Attribute Flags octet is set to 1 by some previous AS, it
        !          1657:      is not set back to 0 by the current AS. */
        !          1658:   SET_FLAG (*startp, BGP_ATTR_FLAG_PARTIAL);
        !          1659: 
        !          1660:   /* Store transitive attribute to the end of attr->transit. */
        !          1661:   if (! ((attre = bgp_attr_extra_get(attr))->transit) )
        !          1662:       attre->transit = XCALLOC (MTYPE_TRANSIT, sizeof (struct transit));
        !          1663: 
        !          1664:   transit = attre->transit;
        !          1665: 
        !          1666:   if (transit->val)
        !          1667:     transit->val = XREALLOC (MTYPE_TRANSIT_VAL, transit->val, 
        !          1668:                             transit->length + total);
        !          1669:   else
        !          1670:     transit->val = XMALLOC (MTYPE_TRANSIT_VAL, total);
        !          1671: 
        !          1672:   memcpy (transit->val + transit->length, startp, total);
        !          1673:   transit->length += total;
        !          1674: 
        !          1675:   return BGP_ATTR_PARSE_PROCEED;
        !          1676: }
        !          1677: 
        !          1678: /* Read attribute of update packet.  This function is called from
        !          1679:    bgp_update() in bgpd.c.  */
        !          1680: bgp_attr_parse_ret_t
        !          1681: bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
        !          1682:                struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
        !          1683: {
        !          1684:   int ret;
        !          1685:   u_char flag = 0;
        !          1686:   u_char type = 0;
        !          1687:   bgp_size_t length;
        !          1688:   u_char *startp, *endp;
        !          1689:   u_char *attr_endp;
        !          1690:   u_char seen[BGP_ATTR_BITMAP_SIZE];
        !          1691:   /* we need the as4_path only until we have synthesized the as_path with it */
        !          1692:   /* same goes for as4_aggregator */
        !          1693:   struct aspath *as4_path = NULL;
        !          1694:   as_t as4_aggregator = 0;
        !          1695:   struct in_addr as4_aggregator_addr = { 0 };
        !          1696: 
        !          1697:   /* Initialize bitmap. */
        !          1698:   memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
        !          1699: 
        !          1700:   /* End pointer of BGP attribute. */
        !          1701:   endp = BGP_INPUT_PNT (peer) + size;
        !          1702:   
        !          1703:   /* Get attributes to the end of attribute length. */
        !          1704:   while (BGP_INPUT_PNT (peer) < endp)
        !          1705:     {
        !          1706:       /* Check remaining length check.*/
        !          1707:       if (endp - BGP_INPUT_PNT (peer) < BGP_ATTR_MIN_LEN)
        !          1708:        {
        !          1709:          /* XXX warning: long int format, int arg (arg 5) */
        !          1710:          zlog (peer->log, LOG_WARNING, 
        !          1711:                "%s: error BGP attribute length %lu is smaller than min len",
        !          1712:                peer->host,
        !          1713:                (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
        !          1714: 
        !          1715:          bgp_notify_send (peer, 
        !          1716:                           BGP_NOTIFY_UPDATE_ERR, 
        !          1717:                           BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
        !          1718:          return BGP_ATTR_PARSE_ERROR;
        !          1719:        }
        !          1720: 
        !          1721:       /* Fetch attribute flag and type. */
        !          1722:       startp = BGP_INPUT_PNT (peer);
        !          1723:       flag = stream_getc (BGP_INPUT (peer));
        !          1724:       type = stream_getc (BGP_INPUT (peer));
        !          1725: 
        !          1726:       /* Check whether Extended-Length applies and is in bounds */
        !          1727:       if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN)
        !          1728:           && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))
        !          1729:        {
        !          1730:          zlog (peer->log, LOG_WARNING, 
        !          1731:                "%s: Extended length set, but just %lu bytes of attr header",
        !          1732:                peer->host,
        !          1733:                (unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));
        !          1734: 
        !          1735:          bgp_notify_send (peer, 
        !          1736:                           BGP_NOTIFY_UPDATE_ERR, 
        !          1737:                           BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
        !          1738:          return BGP_ATTR_PARSE_ERROR;
        !          1739:        }
        !          1740: 
        !          1741:       /* Check extended attribue length bit. */
        !          1742:       if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
        !          1743:        length = stream_getw (BGP_INPUT (peer));
        !          1744:       else
        !          1745:        length = stream_getc (BGP_INPUT (peer));
        !          1746:       
        !          1747:       /* If any attribute appears more than once in the UPDATE
        !          1748:         message, then the Error Subcode is set to Malformed Attribute
        !          1749:         List. */
        !          1750: 
        !          1751:       if (CHECK_BITMAP (seen, type))
        !          1752:        {
        !          1753:          zlog (peer->log, LOG_WARNING,
        !          1754:                "%s: error BGP attribute type %d appears twice in a message",
        !          1755:                peer->host, type);
        !          1756: 
        !          1757:          bgp_notify_send (peer, 
        !          1758:                           BGP_NOTIFY_UPDATE_ERR, 
        !          1759:                           BGP_NOTIFY_UPDATE_MAL_ATTR);
        !          1760:          return BGP_ATTR_PARSE_ERROR;
        !          1761:        }
        !          1762: 
        !          1763:       /* Set type to bitmap to check duplicate attribute.  `type' is
        !          1764:         unsigned char so it never overflow bitmap range. */
        !          1765: 
        !          1766:       SET_BITMAP (seen, type);
        !          1767: 
        !          1768:       /* Overflow check. */
        !          1769:       attr_endp =  BGP_INPUT_PNT (peer) + length;
        !          1770: 
        !          1771:       if (attr_endp > endp)
        !          1772:        {
        !          1773:          zlog (peer->log, LOG_WARNING, 
        !          1774:                "%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);
        !          1775:          bgp_notify_send (peer, 
        !          1776:                           BGP_NOTIFY_UPDATE_ERR, 
        !          1777:                           BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
        !          1778:          return BGP_ATTR_PARSE_ERROR;
        !          1779:        }
        !          1780: 
        !          1781:       /* OK check attribute and store it's value. */
        !          1782:       switch (type)
        !          1783:        {
        !          1784:        case BGP_ATTR_ORIGIN:
        !          1785:          ret = bgp_attr_origin (peer, length, attr, flag, startp);
        !          1786:          break;
        !          1787:        case BGP_ATTR_AS_PATH:
        !          1788:          ret = bgp_attr_aspath (peer, length, attr, flag, startp);
        !          1789:          break;
        !          1790:        case BGP_ATTR_AS4_PATH:
        !          1791:          ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);
        !          1792:          break;
        !          1793:        case BGP_ATTR_NEXT_HOP: 
        !          1794:          ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
        !          1795:          break;
        !          1796:        case BGP_ATTR_MULTI_EXIT_DISC:
        !          1797:          ret = bgp_attr_med (peer, length, attr, flag, startp);
        !          1798:          break;
        !          1799:        case BGP_ATTR_LOCAL_PREF:
        !          1800:          ret = bgp_attr_local_pref (peer, length, attr, flag, startp);
        !          1801:          break;
        !          1802:        case BGP_ATTR_ATOMIC_AGGREGATE:
        !          1803:          ret = bgp_attr_atomic (peer, length, attr, flag, startp);
        !          1804:          break;
        !          1805:        case BGP_ATTR_AGGREGATOR:
        !          1806:          ret = bgp_attr_aggregator (peer, length, attr, flag);
        !          1807:          break;
        !          1808:        case BGP_ATTR_AS4_AGGREGATOR:
        !          1809:          ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
        !          1810:                                         &as4_aggregator, 
        !          1811:                                         &as4_aggregator_addr);
        !          1812:          break;
        !          1813:        case BGP_ATTR_COMMUNITIES:
        !          1814:          ret = bgp_attr_community (peer, length, attr, flag, startp);
        !          1815:          break;
        !          1816:        case BGP_ATTR_ORIGINATOR_ID:
        !          1817:          ret = bgp_attr_originator_id (peer, length, attr, flag);
        !          1818:          break;
        !          1819:        case BGP_ATTR_CLUSTER_LIST:
        !          1820:          ret = bgp_attr_cluster_list (peer, length, attr, flag);
        !          1821:          break;
        !          1822:        case BGP_ATTR_MP_REACH_NLRI:
        !          1823:          ret = bgp_mp_reach_parse (peer, length, attr, mp_update);
        !          1824:          break;
        !          1825:        case BGP_ATTR_MP_UNREACH_NLRI:
        !          1826:          ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);
        !          1827:          break;
        !          1828:        case BGP_ATTR_EXT_COMMUNITIES:
        !          1829:          ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
        !          1830:          break;
        !          1831:        default:
        !          1832:          ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
        !          1833:          break;
        !          1834:        }
        !          1835:       
        !          1836:       /* If hard error occured immediately return to the caller. */
        !          1837:       if (ret == BGP_ATTR_PARSE_ERROR)
        !          1838:         {
        !          1839:           zlog (peer->log, LOG_WARNING,
        !          1840:                 "%s: Attribute %s, parse error", 
        !          1841:                 peer->host, 
        !          1842:                 LOOKUP (attr_str, type));
        !          1843:           bgp_notify_send (peer, 
        !          1844:                            BGP_NOTIFY_UPDATE_ERR,
        !          1845:                            BGP_NOTIFY_UPDATE_MAL_ATTR);
        !          1846:           if (as4_path)
        !          1847:             aspath_unintern (&as4_path);
        !          1848:           return ret;
        !          1849:         }
        !          1850:       if (ret == BGP_ATTR_PARSE_WITHDRAW)
        !          1851:         {
        !          1852:           
        !          1853:           zlog (peer->log, LOG_WARNING,
        !          1854:                 "%s: Attribute %s, parse error - treating as withdrawal",
        !          1855:                 peer->host,
        !          1856:                 LOOKUP (attr_str, type));
        !          1857:           if (as4_path)
        !          1858:             aspath_unintern (&as4_path);
        !          1859:           return ret;
        !          1860:         }
        !          1861:       
        !          1862:       /* Check the fetched length. */
        !          1863:       if (BGP_INPUT_PNT (peer) != attr_endp)
        !          1864:        {
        !          1865:          zlog (peer->log, LOG_WARNING, 
        !          1866:                "%s: BGP attribute %s, fetch error", 
        !          1867:                 peer->host, LOOKUP (attr_str, type));
        !          1868:          bgp_notify_send (peer, 
        !          1869:                           BGP_NOTIFY_UPDATE_ERR, 
        !          1870:                           BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
        !          1871:           if (as4_path)
        !          1872:             aspath_unintern (&as4_path);
        !          1873:          return BGP_ATTR_PARSE_ERROR;
        !          1874:        }
        !          1875:     }
        !          1876: 
        !          1877:   /* Check final read pointer is same as end pointer. */
        !          1878:   if (BGP_INPUT_PNT (peer) != endp)
        !          1879:     {
        !          1880:       zlog (peer->log, LOG_WARNING, 
        !          1881:            "%s: BGP attribute %s, length mismatch",
        !          1882:            peer->host, LOOKUP (attr_str, type));
        !          1883:       bgp_notify_send (peer, 
        !          1884:                       BGP_NOTIFY_UPDATE_ERR, 
        !          1885:                       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
        !          1886:       if (as4_path)
        !          1887:         aspath_unintern (&as4_path);
        !          1888:       return BGP_ATTR_PARSE_ERROR;
        !          1889:     }
        !          1890: 
        !          1891:   /* 
        !          1892:    * At this place we can see whether we got AS4_PATH and/or
        !          1893:    * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
        !          1894:    * We can not do this before we've read all attributes because
        !          1895:    * the as4 handling does not say whether AS4_PATH has to be sent
        !          1896:    * after AS_PATH or not - and when AS4_AGGREGATOR will be send
        !          1897:    * in relationship to AGGREGATOR.
        !          1898:    * So, to be defensive, we are not relying on any order and read
        !          1899:    * all attributes first, including these 32bit ones, and now,
        !          1900:    * afterwards, we look what and if something is to be done for as4.
        !          1901:    */
        !          1902:   if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,
        !          1903:                                 as4_aggregator, &as4_aggregator_addr))
        !          1904:     {
        !          1905:       if (as4_path)
        !          1906:         aspath_unintern (&as4_path);
        !          1907:       return BGP_ATTR_PARSE_ERROR;
        !          1908:     }
        !          1909: 
        !          1910:   /* At this stage, we have done all fiddling with as4, and the
        !          1911:    * resulting info is in attr->aggregator resp. attr->aspath
        !          1912:    * so we can chuck as4_aggregator and as4_path alltogether in
        !          1913:    * order to save memory
        !          1914:    */
        !          1915:   if (as4_path)
        !          1916:     {
        !          1917:       aspath_unintern (&as4_path); /* unintern - it is in the hash */
        !          1918:       /* The flag that we got this is still there, but that does not
        !          1919:        * do any trouble
        !          1920:        */
        !          1921:     }
        !          1922:   /*
        !          1923:    * The "rest" of the code does nothing with as4_aggregator.
        !          1924:    * there is no memory attached specifically which is not part
        !          1925:    * of the attr.
        !          1926:    * so ignoring just means do nothing.
        !          1927:    */
        !          1928:   /*
        !          1929:    * Finally do the checks on the aspath we did not do yet
        !          1930:    * because we waited for a potentially synthesized aspath.
        !          1931:    */
        !          1932:   if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
        !          1933:     {
        !          1934:       ret = bgp_attr_aspath_check (peer, attr, flag);
        !          1935:       if (ret != BGP_ATTR_PARSE_PROCEED)
        !          1936:        return ret;
        !          1937:     }
        !          1938: 
        !          1939:   /* Finally intern unknown attribute. */
        !          1940:   if (attr->extra && attr->extra->transit)
        !          1941:     attr->extra->transit = transit_intern (attr->extra->transit);
        !          1942: 
        !          1943:   return BGP_ATTR_PARSE_PROCEED;
        !          1944: }
        !          1945: 
        !          1946: /* Well-known attribute check. */
        !          1947: int
        !          1948: bgp_attr_check (struct peer *peer, struct attr *attr)
        !          1949: {
        !          1950:   u_char type = 0;
        !          1951:   
        !          1952:   if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
        !          1953:     type = BGP_ATTR_ORIGIN;
        !          1954: 
        !          1955:   if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
        !          1956:     type = BGP_ATTR_AS_PATH;
        !          1957: 
        !          1958:   if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
        !          1959:     type = BGP_ATTR_NEXT_HOP;
        !          1960: 
        !          1961:   if (peer_sort (peer) == BGP_PEER_IBGP
        !          1962:       && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
        !          1963:     type = BGP_ATTR_LOCAL_PREF;
        !          1964: 
        !          1965:   if (type)
        !          1966:     {
        !          1967:       zlog (peer->log, LOG_WARNING, 
        !          1968:            "%s Missing well-known attribute %d.",
        !          1969:            peer->host, type);
        !          1970:       bgp_notify_send_with_data (peer, 
        !          1971:                                 BGP_NOTIFY_UPDATE_ERR, 
        !          1972:                                 BGP_NOTIFY_UPDATE_MISS_ATTR,
        !          1973:                                 &type, 1);
        !          1974:       return BGP_ATTR_PARSE_ERROR;
        !          1975:     }
        !          1976:   return BGP_ATTR_PARSE_PROCEED;
        !          1977: }
        !          1978: 
        !          1979: int stream_put_prefix (struct stream *, struct prefix *);
        !          1980: 
        !          1981: /* Make attribute packet. */
        !          1982: bgp_size_t
        !          1983: bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
        !          1984:                      struct stream *s, struct attr *attr, struct prefix *p,
        !          1985:                      afi_t afi, safi_t safi, struct peer *from,
        !          1986:                      struct prefix_rd *prd, u_char *tag)
        !          1987: {
        !          1988:   size_t cp;
        !          1989:   size_t aspath_sizep;
        !          1990:   struct aspath *aspath;
        !          1991:   int send_as4_path = 0;
        !          1992:   int send_as4_aggregator = 0;
        !          1993:   int use32bit = (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)) ? 1 : 0;
        !          1994: 
        !          1995:   if (! bgp)
        !          1996:     bgp = bgp_get_default ();
        !          1997: 
        !          1998:   /* Remember current pointer. */
        !          1999:   cp = stream_get_endp (s);
        !          2000: 
        !          2001:   /* Origin attribute. */
        !          2002:   stream_putc (s, BGP_ATTR_FLAG_TRANS);
        !          2003:   stream_putc (s, BGP_ATTR_ORIGIN);
        !          2004:   stream_putc (s, 1);
        !          2005:   stream_putc (s, attr->origin);
        !          2006: 
        !          2007:   /* AS path attribute. */
        !          2008: 
        !          2009:   /* If remote-peer is EBGP */
        !          2010:   if (peer_sort (peer) == BGP_PEER_EBGP
        !          2011:       && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
        !          2012:          || attr->aspath->segments == NULL)
        !          2013:       && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
        !          2014:     {    
        !          2015:       aspath = aspath_dup (attr->aspath);
        !          2016: 
        !          2017:       if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION))
        !          2018:        {
        !          2019:          /* Strip the confed info, and then stuff our path CONFED_ID
        !          2020:             on the front */
        !          2021:          aspath = aspath_delete_confed_seq (aspath);
        !          2022:          aspath = aspath_add_seq (aspath, bgp->confed_id);
        !          2023:        }
        !          2024:       else
        !          2025:        {
        !          2026:          aspath = aspath_add_seq (aspath, peer->local_as);
        !          2027:          if (peer->change_local_as)
        !          2028:            aspath = aspath_add_seq (aspath, peer->change_local_as);
        !          2029:        }
        !          2030:     }
        !          2031:   else if (peer_sort (peer) == BGP_PEER_CONFED)
        !          2032:     {
        !          2033:       /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
        !          2034:       aspath = aspath_dup (attr->aspath);
        !          2035:       aspath = aspath_add_confed_seq (aspath, peer->local_as);
        !          2036:     }
        !          2037:   else
        !          2038:     aspath = attr->aspath;
        !          2039: 
        !          2040:   /* If peer is not AS4 capable, then:
        !          2041:    * - send the created AS_PATH out as AS4_PATH (optional, transitive),
        !          2042:    *   but ensure that no AS_CONFED_SEQUENCE and AS_CONFED_SET path segment
        !          2043:    *   types are in it (i.e. exclude them if they are there)
        !          2044:    *   AND do this only if there is at least one asnum > 65535 in the path!
        !          2045:    * - send an AS_PATH out, but put 16Bit ASnums in it, not 32bit, and change
        !          2046:    *   all ASnums > 65535 to BGP_AS_TRANS
        !          2047:    */
        !          2048: 
        !          2049:   stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
        !          2050:   stream_putc (s, BGP_ATTR_AS_PATH);
        !          2051:   aspath_sizep = stream_get_endp (s);
        !          2052:   stream_putw (s, 0);
        !          2053:   stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, use32bit));
        !          2054:   
        !          2055:   /* OLD session may need NEW_AS_PATH sent, if there are 4-byte ASNs 
        !          2056:    * in the path
        !          2057:    */
        !          2058:   if (!use32bit && aspath_has_as4 (aspath))
        !          2059:       send_as4_path = 1; /* we'll do this later, at the correct place */
        !          2060:   
        !          2061:   /* Nexthop attribute. */
        !          2062:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)
        !          2063:     {
        !          2064:       stream_putc (s, BGP_ATTR_FLAG_TRANS);
        !          2065:       stream_putc (s, BGP_ATTR_NEXT_HOP);
        !          2066:       stream_putc (s, 4);
        !          2067:       if (safi == SAFI_MPLS_VPN)
        !          2068:        {
        !          2069:          if (attr->nexthop.s_addr == 0)
        !          2070:            stream_put_ipv4 (s, peer->nexthop.v4.s_addr);
        !          2071:          else
        !          2072:            stream_put_ipv4 (s, attr->nexthop.s_addr);
        !          2073:        }
        !          2074:       else
        !          2075:        stream_put_ipv4 (s, attr->nexthop.s_addr);
        !          2076:     }
        !          2077: 
        !          2078:   /* MED attribute. */
        !          2079:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
        !          2080:     {
        !          2081:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
        !          2082:       stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
        !          2083:       stream_putc (s, 4);
        !          2084:       stream_putl (s, attr->med);
        !          2085:     }
        !          2086: 
        !          2087:   /* Local preference. */
        !          2088:   if (peer_sort (peer) == BGP_PEER_IBGP ||
        !          2089:       peer_sort (peer) == BGP_PEER_CONFED)
        !          2090:     {
        !          2091:       stream_putc (s, BGP_ATTR_FLAG_TRANS);
        !          2092:       stream_putc (s, BGP_ATTR_LOCAL_PREF);
        !          2093:       stream_putc (s, 4);
        !          2094:       stream_putl (s, attr->local_pref);
        !          2095:     }
        !          2096: 
        !          2097:   /* Atomic aggregate. */
        !          2098:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
        !          2099:     {
        !          2100:       stream_putc (s, BGP_ATTR_FLAG_TRANS);
        !          2101:       stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
        !          2102:       stream_putc (s, 0);
        !          2103:     }
        !          2104: 
        !          2105:   /* Aggregator. */
        !          2106:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
        !          2107:     {
        !          2108:       assert (attr->extra);
        !          2109:       
        !          2110:       /* Common to BGP_ATTR_AGGREGATOR, regardless of ASN size */
        !          2111:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
        !          2112:       stream_putc (s, BGP_ATTR_AGGREGATOR);
        !          2113:       
        !          2114:       if (use32bit)
        !          2115:         {
        !          2116:           /* AS4 capable peer */
        !          2117:           stream_putc (s, 8);
        !          2118:           stream_putl (s, attr->extra->aggregator_as);
        !          2119:         }
        !          2120:       else
        !          2121:         {
        !          2122:           /* 2-byte AS peer */
        !          2123:           stream_putc (s, 6);
        !          2124:           
        !          2125:           /* Is ASN representable in 2-bytes? Or must AS_TRANS be used? */
        !          2126:           if ( attr->extra->aggregator_as > 65535 )
        !          2127:             {
        !          2128:               stream_putw (s, BGP_AS_TRANS);
        !          2129:               
        !          2130:               /* we have to send AS4_AGGREGATOR, too.
        !          2131:                * we'll do that later in order to send attributes in ascending
        !          2132:                * order.
        !          2133:                */
        !          2134:               send_as4_aggregator = 1;
        !          2135:             }
        !          2136:           else
        !          2137:             stream_putw (s, (u_int16_t) attr->extra->aggregator_as);
        !          2138:         }
        !          2139:       stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
        !          2140:     }
        !          2141: 
        !          2142:   /* Community attribute. */
        !          2143:   if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) 
        !          2144:       && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES)))
        !          2145:     {
        !          2146:       if (attr->community->size * 4 > 255)
        !          2147:        {
        !          2148:          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
        !          2149:          stream_putc (s, BGP_ATTR_COMMUNITIES);
        !          2150:          stream_putw (s, attr->community->size * 4);
        !          2151:        }
        !          2152:       else
        !          2153:        {
        !          2154:          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
        !          2155:          stream_putc (s, BGP_ATTR_COMMUNITIES);
        !          2156:          stream_putc (s, attr->community->size * 4);
        !          2157:        }
        !          2158:       stream_put (s, attr->community->val, attr->community->size * 4);
        !          2159:     }
        !          2160: 
        !          2161:   /* Route Reflector. */
        !          2162:   if (peer_sort (peer) == BGP_PEER_IBGP
        !          2163:       && from
        !          2164:       && peer_sort (from) == BGP_PEER_IBGP)
        !          2165:     {
        !          2166:       /* Originator ID. */
        !          2167:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
        !          2168:       stream_putc (s, BGP_ATTR_ORIGINATOR_ID);
        !          2169:       stream_putc (s, 4);
        !          2170: 
        !          2171:       if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
        !          2172:        stream_put_in_addr (s, &attr->extra->originator_id);
        !          2173:       else 
        !          2174:         stream_put_in_addr (s, &from->remote_id);
        !          2175: 
        !          2176:       /* Cluster list. */
        !          2177:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
        !          2178:       stream_putc (s, BGP_ATTR_CLUSTER_LIST);
        !          2179:       
        !          2180:       if (attr->extra && attr->extra->cluster)
        !          2181:        {
        !          2182:          stream_putc (s, attr->extra->cluster->length + 4);
        !          2183:          /* If this peer configuration's parent BGP has cluster_id. */
        !          2184:          if (bgp->config & BGP_CONFIG_CLUSTER_ID)
        !          2185:            stream_put_in_addr (s, &bgp->cluster_id);
        !          2186:          else
        !          2187:            stream_put_in_addr (s, &bgp->router_id);
        !          2188:          stream_put (s, attr->extra->cluster->list, 
        !          2189:                      attr->extra->cluster->length);
        !          2190:        }
        !          2191:       else
        !          2192:        {
        !          2193:          stream_putc (s, 4);
        !          2194:          /* If this peer configuration's parent BGP has cluster_id. */
        !          2195:          if (bgp->config & BGP_CONFIG_CLUSTER_ID)
        !          2196:            stream_put_in_addr (s, &bgp->cluster_id);
        !          2197:          else
        !          2198:            stream_put_in_addr (s, &bgp->router_id);
        !          2199:        }
        !          2200:     }
        !          2201: 
        !          2202: #ifdef HAVE_IPV6
        !          2203:   /* If p is IPv6 address put it into attribute. */
        !          2204:   if (p->family == AF_INET6)
        !          2205:     {
        !          2206:       unsigned long sizep;
        !          2207:       struct attr_extra *attre = attr->extra;
        !          2208:       
        !          2209:       assert (attr->extra);
        !          2210:       
        !          2211:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
        !          2212:       stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
        !          2213:       sizep = stream_get_endp (s);
        !          2214:       stream_putc (s, 0);      /* Marker: Attribute length. */
        !          2215:       stream_putw (s, AFI_IP6);        /* AFI */
        !          2216:       stream_putc (s, safi);   /* SAFI */
        !          2217: 
        !          2218:       stream_putc (s, attre->mp_nexthop_len);
        !          2219: 
        !          2220:       if (attre->mp_nexthop_len == 16)
        !          2221:        stream_put (s, &attre->mp_nexthop_global, 16);
        !          2222:       else if (attre->mp_nexthop_len == 32)
        !          2223:        {
        !          2224:          stream_put (s, &attre->mp_nexthop_global, 16);
        !          2225:          stream_put (s, &attre->mp_nexthop_local, 16);
        !          2226:        }
        !          2227:       
        !          2228:       /* SNPA */
        !          2229:       stream_putc (s, 0);
        !          2230: 
        !          2231:       /* Prefix write. */
        !          2232:       stream_put_prefix (s, p);
        !          2233: 
        !          2234:       /* Set MP attribute length. */
        !          2235:       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
        !          2236:     }
        !          2237: #endif /* HAVE_IPV6 */
        !          2238: 
        !          2239:   if (p->family == AF_INET && safi == SAFI_MULTICAST)
        !          2240:     {
        !          2241:       unsigned long sizep;
        !          2242: 
        !          2243:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
        !          2244:       stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
        !          2245:       sizep = stream_get_endp (s);
        !          2246:       stream_putc (s, 0);      /* Marker: Attribute Length. */
        !          2247:       stream_putw (s, AFI_IP); /* AFI */
        !          2248:       stream_putc (s, SAFI_MULTICAST); /* SAFI */
        !          2249: 
        !          2250:       stream_putc (s, 4);
        !          2251:       stream_put_ipv4 (s, attr->nexthop.s_addr);
        !          2252: 
        !          2253:       /* SNPA */
        !          2254:       stream_putc (s, 0);
        !          2255: 
        !          2256:       /* Prefix write. */
        !          2257:       stream_put_prefix (s, p);
        !          2258: 
        !          2259:       /* Set MP attribute length. */
        !          2260:       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
        !          2261:     }
        !          2262: 
        !          2263:   if (p->family == AF_INET && safi == SAFI_MPLS_VPN)
        !          2264:     {
        !          2265:       unsigned long sizep;
        !          2266: 
        !          2267:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
        !          2268:       stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
        !          2269:       sizep = stream_get_endp (s);
        !          2270:       stream_putc (s, 0);      /* Length of this attribute. */
        !          2271:       stream_putw (s, AFI_IP); /* AFI */
        !          2272:       stream_putc (s, BGP_SAFI_VPNV4); /* SAFI */
        !          2273: 
        !          2274:       stream_putc (s, 12);
        !          2275:       stream_putl (s, 0);
        !          2276:       stream_putl (s, 0);
        !          2277:       stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
        !          2278: 
        !          2279:       /* SNPA */
        !          2280:       stream_putc (s, 0);
        !          2281: 
        !          2282:       /* Tag, RD, Prefix write. */
        !          2283:       stream_putc (s, p->prefixlen + 88);
        !          2284:       stream_put (s, tag, 3);
        !          2285:       stream_put (s, prd->val, 8);
        !          2286:       stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
        !          2287: 
        !          2288:       /* Set MP attribute length. */
        !          2289:       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
        !          2290:     }
        !          2291: 
        !          2292:   /* Extended Communities attribute. */
        !          2293:   if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) 
        !          2294:       && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
        !          2295:     {
        !          2296:       struct attr_extra *attre = attr->extra;
        !          2297:       
        !          2298:       assert (attre);
        !          2299:       
        !          2300:       if (peer_sort (peer) == BGP_PEER_IBGP 
        !          2301:           || peer_sort (peer) == BGP_PEER_CONFED)
        !          2302:        {
        !          2303:          if (attre->ecommunity->size * 8 > 255)
        !          2304:            {
        !          2305:              stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
        !          2306:              stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
        !          2307:              stream_putw (s, attre->ecommunity->size * 8);
        !          2308:            }
        !          2309:          else
        !          2310:            {
        !          2311:              stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
        !          2312:              stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
        !          2313:              stream_putc (s, attre->ecommunity->size * 8);
        !          2314:            }
        !          2315:          stream_put (s, attre->ecommunity->val, attre->ecommunity->size * 8);
        !          2316:        }
        !          2317:       else
        !          2318:        {
        !          2319:          u_int8_t *pnt;
        !          2320:          int tbit;
        !          2321:          int ecom_tr_size = 0;
        !          2322:          int i;
        !          2323: 
        !          2324:          for (i = 0; i < attre->ecommunity->size; i++)
        !          2325:            {
        !          2326:              pnt = attre->ecommunity->val + (i * 8);
        !          2327:              tbit = *pnt;
        !          2328: 
        !          2329:              if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
        !          2330:                continue;
        !          2331: 
        !          2332:              ecom_tr_size++;
        !          2333:            }
        !          2334: 
        !          2335:          if (ecom_tr_size)
        !          2336:            {
        !          2337:              if (ecom_tr_size * 8 > 255)
        !          2338:                {
        !          2339:                  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
        !          2340:                  stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
        !          2341:                  stream_putw (s, ecom_tr_size * 8);
        !          2342:                }
        !          2343:              else
        !          2344:                {
        !          2345:                  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
        !          2346:                  stream_putc (s, BGP_ATTR_EXT_COMMUNITIES);
        !          2347:                  stream_putc (s, ecom_tr_size * 8);
        !          2348:                }
        !          2349: 
        !          2350:              for (i = 0; i < attre->ecommunity->size; i++)
        !          2351:                {
        !          2352:                  pnt = attre->ecommunity->val + (i * 8);
        !          2353:                  tbit = *pnt;
        !          2354: 
        !          2355:                  if (CHECK_FLAG (tbit, ECOMMUNITY_FLAG_NON_TRANSITIVE))
        !          2356:                    continue;
        !          2357: 
        !          2358:                  stream_put (s, pnt, 8);
        !          2359:                }
        !          2360:            }
        !          2361:        }
        !          2362:     }
        !          2363: 
        !          2364:   if ( send_as4_path )
        !          2365:     {
        !          2366:       /* If the peer is NOT As4 capable, AND */
        !          2367:       /* there are ASnums > 65535 in path  THEN
        !          2368:        * give out AS4_PATH */
        !          2369: 
        !          2370:       /* Get rid of all AS_CONFED_SEQUENCE and AS_CONFED_SET
        !          2371:        * path segments!
        !          2372:        * Hm, I wonder...  confederation things *should* only be at
        !          2373:        * the beginning of an aspath, right?  Then we should use
        !          2374:        * aspath_delete_confed_seq for this, because it is already
        !          2375:        * there! (JK) 
        !          2376:        * Folks, talk to me: what is reasonable here!?
        !          2377:        */
        !          2378:       aspath = aspath_delete_confed_seq (aspath);
        !          2379: 
        !          2380:       stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
        !          2381:       stream_putc (s, BGP_ATTR_AS4_PATH);
        !          2382:       aspath_sizep = stream_get_endp (s);
        !          2383:       stream_putw (s, 0);
        !          2384:       stream_putw_at (s, aspath_sizep, aspath_put (s, aspath, 1));
        !          2385:     }
        !          2386: 
        !          2387:   if (aspath != attr->aspath)
        !          2388:     aspath_free (aspath);
        !          2389: 
        !          2390:   if ( send_as4_aggregator ) 
        !          2391:     {
        !          2392:       assert (attr->extra);
        !          2393: 
        !          2394:       /* send AS4_AGGREGATOR, at this place */
        !          2395:       /* this section of code moved here in order to ensure the correct
        !          2396:        * *ascending* order of attributes
        !          2397:        */
        !          2398:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
        !          2399:       stream_putc (s, BGP_ATTR_AS4_AGGREGATOR);
        !          2400:       stream_putc (s, 8);
        !          2401:       stream_putl (s, attr->extra->aggregator_as);
        !          2402:       stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
        !          2403:     }
        !          2404:   
        !          2405:   /* Unknown transit attribute. */
        !          2406:   if (attr->extra && attr->extra->transit)
        !          2407:     stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
        !          2408: 
        !          2409:   /* Return total size of attribute. */
        !          2410:   return stream_get_endp (s) - cp;
        !          2411: }
        !          2412: 
        !          2413: bgp_size_t
        !          2414: bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,
        !          2415:                     afi_t afi, safi_t safi, struct prefix_rd *prd,
        !          2416:                     u_char *tag)
        !          2417: {
        !          2418:   unsigned long cp;
        !          2419:   unsigned long attrlen_pnt;
        !          2420:   bgp_size_t size;
        !          2421: 
        !          2422:   cp = stream_get_endp (s);
        !          2423: 
        !          2424:   stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
        !          2425:   stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
        !          2426: 
        !          2427:   attrlen_pnt = stream_get_endp (s);
        !          2428:   stream_putc (s, 0);          /* Length of this attribute. */
        !          2429: 
        !          2430:   stream_putw (s, family2afi (p->family));
        !          2431: 
        !          2432:   if (safi == SAFI_MPLS_VPN)
        !          2433:     {
        !          2434:       /* SAFI */
        !          2435:       stream_putc (s, BGP_SAFI_VPNV4);
        !          2436: 
        !          2437:       /* prefix. */
        !          2438:       stream_putc (s, p->prefixlen + 88);
        !          2439:       stream_put (s, tag, 3);
        !          2440:       stream_put (s, prd->val, 8);
        !          2441:       stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
        !          2442:     }
        !          2443:   else
        !          2444:     {
        !          2445:       /* SAFI */
        !          2446:       stream_putc (s, safi);
        !          2447: 
        !          2448:       /* prefix */
        !          2449:       stream_put_prefix (s, p);
        !          2450:     }
        !          2451: 
        !          2452:   /* Set MP attribute length. */
        !          2453:   size = stream_get_endp (s) - attrlen_pnt - 1;
        !          2454:   stream_putc_at (s, attrlen_pnt, size);
        !          2455: 
        !          2456:   return stream_get_endp (s) - cp;
        !          2457: }
        !          2458: 
        !          2459: /* Initialization of attribute. */
        !          2460: void
        !          2461: bgp_attr_init (void)
        !          2462: {
        !          2463:   aspath_init ();
        !          2464:   attrhash_init ();
        !          2465:   community_init ();
        !          2466:   ecommunity_init ();
        !          2467:   cluster_init ();
        !          2468:   transit_init ();
        !          2469: }
        !          2470: 
        !          2471: void
        !          2472: bgp_attr_finish (void)
        !          2473: {
        !          2474:   aspath_finish ();
        !          2475:   attrhash_finish ();
        !          2476:   community_finish ();
        !          2477:   ecommunity_finish ();
        !          2478:   cluster_finish ();
        !          2479:   transit_finish ();
        !          2480: }
        !          2481: 
        !          2482: /* Make attribute packet. */
        !          2483: void
        !          2484: bgp_dump_routes_attr (struct stream *s, struct attr *attr, 
        !          2485:                       struct prefix *prefix)
        !          2486: {
        !          2487:   unsigned long cp;
        !          2488:   unsigned long len;
        !          2489:   size_t aspath_lenp;
        !          2490:   struct aspath *aspath;
        !          2491: 
        !          2492:   /* Remember current pointer. */
        !          2493:   cp = stream_get_endp (s);
        !          2494: 
        !          2495:   /* Place holder of length. */
        !          2496:   stream_putw (s, 0);
        !          2497: 
        !          2498:   /* Origin attribute. */
        !          2499:   stream_putc (s, BGP_ATTR_FLAG_TRANS);
        !          2500:   stream_putc (s, BGP_ATTR_ORIGIN);
        !          2501:   stream_putc (s, 1);
        !          2502:   stream_putc (s, attr->origin);
        !          2503: 
        !          2504:   aspath = attr->aspath;
        !          2505:   
        !          2506:   stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
        !          2507:   stream_putc (s, BGP_ATTR_AS_PATH);
        !          2508:   aspath_lenp = stream_get_endp (s);
        !          2509:   stream_putw (s, 0);
        !          2510:   
        !          2511:   stream_putw_at (s, aspath_lenp, aspath_put (s, aspath, 1));
        !          2512: 
        !          2513:   /* Nexthop attribute. */
        !          2514:   /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
        !          2515:   if(prefix != NULL
        !          2516: #ifdef HAVE_IPV6
        !          2517:      && prefix->family != AF_INET6
        !          2518: #endif /* HAVE_IPV6 */
        !          2519:      )
        !          2520:     {
        !          2521:       stream_putc (s, BGP_ATTR_FLAG_TRANS);
        !          2522:       stream_putc (s, BGP_ATTR_NEXT_HOP);
        !          2523:       stream_putc (s, 4);
        !          2524:       stream_put_ipv4 (s, attr->nexthop.s_addr);
        !          2525:     }
        !          2526: 
        !          2527:   /* MED attribute. */
        !          2528:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC))
        !          2529:     {
        !          2530:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
        !          2531:       stream_putc (s, BGP_ATTR_MULTI_EXIT_DISC);
        !          2532:       stream_putc (s, 4);
        !          2533:       stream_putl (s, attr->med);
        !          2534:     }
        !          2535: 
        !          2536:   /* Local preference. */
        !          2537:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF))
        !          2538:     {
        !          2539:       stream_putc (s, BGP_ATTR_FLAG_TRANS);
        !          2540:       stream_putc (s, BGP_ATTR_LOCAL_PREF);
        !          2541:       stream_putc (s, 4);
        !          2542:       stream_putl (s, attr->local_pref);
        !          2543:     }
        !          2544: 
        !          2545:   /* Atomic aggregate. */
        !          2546:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE))
        !          2547:     {
        !          2548:       stream_putc (s, BGP_ATTR_FLAG_TRANS);
        !          2549:       stream_putc (s, BGP_ATTR_ATOMIC_AGGREGATE);
        !          2550:       stream_putc (s, 0);
        !          2551:     }
        !          2552: 
        !          2553:   /* Aggregator. */
        !          2554:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR))
        !          2555:     {
        !          2556:       assert (attr->extra);
        !          2557:       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
        !          2558:       stream_putc (s, BGP_ATTR_AGGREGATOR);
        !          2559:       stream_putc (s, 8);
        !          2560:       stream_putl (s, attr->extra->aggregator_as);
        !          2561:       stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
        !          2562:     }
        !          2563: 
        !          2564:   /* Community attribute. */
        !          2565:   if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES))
        !          2566:     {
        !          2567:       if (attr->community->size * 4 > 255)
        !          2568:        {
        !          2569:          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_EXTLEN);
        !          2570:          stream_putc (s, BGP_ATTR_COMMUNITIES);
        !          2571:          stream_putw (s, attr->community->size * 4);
        !          2572:        }
        !          2573:       else
        !          2574:        {
        !          2575:          stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_TRANS);
        !          2576:          stream_putc (s, BGP_ATTR_COMMUNITIES);
        !          2577:          stream_putc (s, attr->community->size * 4);
        !          2578:        }
        !          2579:       stream_put (s, attr->community->val, attr->community->size * 4);
        !          2580:     }
        !          2581: 
        !          2582: #ifdef HAVE_IPV6
        !          2583:   /* Add a MP_NLRI attribute to dump the IPv6 next hop */
        !          2584:   if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
        !          2585:      (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
        !          2586:     {
        !          2587:       int sizep;
        !          2588:       struct attr_extra *attre = attr->extra;
        !          2589:       
        !          2590:       stream_putc(s, BGP_ATTR_FLAG_OPTIONAL);
        !          2591:       stream_putc(s, BGP_ATTR_MP_REACH_NLRI);
        !          2592:       sizep = stream_get_endp (s);
        !          2593: 
        !          2594:       /* MP header */
        !          2595:       stream_putc (s, 0);              /* Marker: Attribute length. */
        !          2596:       stream_putw(s, AFI_IP6);         /* AFI */
        !          2597:       stream_putc(s, SAFI_UNICAST);    /* SAFI */
        !          2598: 
        !          2599:       /* Next hop */
        !          2600:       stream_putc(s, attre->mp_nexthop_len);
        !          2601:       stream_put(s, &attre->mp_nexthop_global, 16);
        !          2602:       if (attre->mp_nexthop_len == 32)
        !          2603:         stream_put(s, &attre->mp_nexthop_local, 16);
        !          2604: 
        !          2605:       /* SNPA */
        !          2606:       stream_putc(s, 0);
        !          2607: 
        !          2608:       /* Prefix */
        !          2609:       stream_put_prefix(s, prefix);
        !          2610: 
        !          2611:       /* Set MP attribute length. */
        !          2612:       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
        !          2613:     }
        !          2614: #endif /* HAVE_IPV6 */
        !          2615: 
        !          2616:   /* Return total size of attribute. */
        !          2617:   len = stream_get_endp (s) - cp - 2;
        !          2618:   stream_putw_at (s, cp, len);
        !          2619: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>