LCOV - code coverage report
Current view: top level - bgpd - bgp_attr.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 226 1147 19.7 %
Date: 2015-11-19 Functions: 16 66 24.2 %

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

Generated by: LCOV version 1.10