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

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

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