Annotation of embedaddon/quagga/bgpd/bgp_attr.c, revision 1.1.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>