Diff for /embedaddon/quagga/bgpd/bgp_attr.c between versions 1.1.1.1 and 1.1.1.3

version 1.1.1.1, 2012/02/21 17:26:12 version 1.1.1.3, 2013/07/21 23:54:37
Line 51  static const struct message attr_str [] =  Line 51  static const struct message attr_str [] = 
   { BGP_ATTR_AGGREGATOR,       "AGGREGATOR" },     { BGP_ATTR_AGGREGATOR,       "AGGREGATOR" }, 
   { BGP_ATTR_COMMUNITIES,      "COMMUNITY" },     { BGP_ATTR_COMMUNITIES,      "COMMUNITY" }, 
   { BGP_ATTR_ORIGINATOR_ID,    "ORIGINATOR_ID" },    { BGP_ATTR_ORIGINATOR_ID,    "ORIGINATOR_ID" },
  { BGP_ATTR_CLUSTER_LIST,     "CLUSTERLIST" },   { BGP_ATTR_CLUSTER_LIST,     "CLUSTER_LIST" }, 
   { BGP_ATTR_DPA,              "DPA" },    { BGP_ATTR_DPA,              "DPA" },
   { BGP_ATTR_ADVERTISER,       "ADVERTISER"} ,    { BGP_ATTR_ADVERTISER,       "ADVERTISER"} ,
   { BGP_ATTR_RCID_PATH,        "RCID_PATH" },    { BGP_ATTR_RCID_PATH,        "RCID_PATH" },
Line 62  static const struct message attr_str [] =  Line 62  static const struct message attr_str [] = 
   { BGP_ATTR_AS4_AGGREGATOR,   "AS4_AGGREGATOR" },     { BGP_ATTR_AS4_AGGREGATOR,   "AS4_AGGREGATOR" }, 
   { BGP_ATTR_AS_PATHLIMIT,     "AS_PATHLIMIT" },    { BGP_ATTR_AS_PATHLIMIT,     "AS_PATHLIMIT" },
 };  };
static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]);static const int attr_str_max = array_size(attr_str);
 
 static const struct message attr_flag_str[] =
 {
   { BGP_ATTR_FLAG_OPTIONAL, "Optional" },
   { BGP_ATTR_FLAG_TRANS,    "Transitive" },
   { BGP_ATTR_FLAG_PARTIAL,  "Partial" },
   /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
   { BGP_ATTR_FLAG_EXTLEN,   "Extended Length" },
 };
 static const size_t attr_flag_str_max = array_size(attr_flag_str);
   
 static struct hash *cluster_hash;  static struct hash *cluster_hash;
   
Line 175  cluster_intern (struct cluster_list *cluster) Line 185  cluster_intern (struct cluster_list *cluster)
 void  void
 cluster_unintern (struct cluster_list *cluster)  cluster_unintern (struct cluster_list *cluster)
 {  {
   struct cluster_list *ret;  
   
   if (cluster->refcnt)    if (cluster->refcnt)
     cluster->refcnt--;      cluster->refcnt--;
   
   if (cluster->refcnt == 0)    if (cluster->refcnt == 0)
     {      {
      ret = hash_release (cluster_hash, cluster);      hash_release (cluster_hash, cluster);
       cluster_free (cluster);        cluster_free (cluster);
     }      }
 }  }
Line 235  transit_intern (struct transit *transit) Line 243  transit_intern (struct transit *transit)
 void  void
 transit_unintern (struct transit *transit)  transit_unintern (struct transit *transit)
 {  {
   struct transit *ret;  
   
   if (transit->refcnt)    if (transit->refcnt)
     transit->refcnt--;      transit->refcnt--;
   
   if (transit->refcnt == 0)    if (transit->refcnt == 0)
     {      {
      ret = hash_release (transit_hash, transit);      hash_release (transit_hash, transit);
       transit_free (transit);        transit_free (transit);
     }      }
 }  }
Line 312  bgp_attr_extra_get (struct attr *attr) Line 318  bgp_attr_extra_get (struct attr *attr)
 void  void
 bgp_attr_dup (struct attr *new, struct attr *orig)  bgp_attr_dup (struct attr *new, struct attr *orig)
 {  {
     struct attr_extra *extra = new->extra;
   
   *new = *orig;    *new = *orig;
  if (orig->extra)  /* if caller provided attr_extra space, use it in any case.
    *
    * This is neccesary even if orig->extra equals NULL, because otherwise
    * memory may be later allocated on the heap by bgp_attr_extra_get.
    *
    * That memory would eventually be leaked, because the caller must not
    * call bgp_attr_extra_free if he provided attr_extra on the stack.
    */
   if (extra)
     {      {
         new->extra = extra;
         memset(new->extra, 0, sizeof(struct attr_extra));
         if (orig->extra)
           *new->extra = *orig->extra;
       }
     else if (orig->extra)
       {
       new->extra = bgp_attr_extra_new();        new->extra = bgp_attr_extra_new();
       *new->extra = *orig->extra;        *new->extra = *orig->extra;
     }      }
Line 335  attr_unknown_count (void) Line 358  attr_unknown_count (void)
 unsigned int  unsigned int
 attrhash_key_make (void *p)  attrhash_key_make (void *p)
 {  {
  const struct attr * attr = (struct attr *) p;  const struct attr *attr = (struct attr *) p;
   const struct attr_extra *extra = attr->extra;
   uint32_t key = 0;    uint32_t key = 0;
 #define MIX(val)        key = jhash_1word(val, key)  #define MIX(val)        key = jhash_1word(val, key)
   
Line 349  attrhash_key_make (void *p) Line 373  attrhash_key_make (void *p)
   key += attr->med;    key += attr->med;
   key += attr->local_pref;    key += attr->local_pref;
       
  if (attr->extra)  if (extra)
     {      {
      MIX(attr->extra->aggregator_as);      MIX(extra->aggregator_as);
      MIX(attr->extra->aggregator_addr.s_addr);      MIX(extra->aggregator_addr.s_addr);
      MIX(attr->extra->weight);      MIX(extra->weight);
      MIX(attr->extra->mp_nexthop_global_in.s_addr);      MIX(extra->mp_nexthop_global_in.s_addr);
     }      }
       
   if (attr->aspath)    if (attr->aspath)
Line 362  attrhash_key_make (void *p) Line 386  attrhash_key_make (void *p)
   if (attr->community)    if (attr->community)
     MIX(community_hash_make (attr->community));      MIX(community_hash_make (attr->community));
       
  if (attr->extra)  if (extra)
     {      {
      if (attr->extra->ecommunity)      if (extra->ecommunity)
        MIX(ecommunity_hash_make (attr->extra->ecommunity));        MIX(ecommunity_hash_make (extra->ecommunity));
      if (attr->extra->cluster)      if (extra->cluster)
        MIX(cluster_hash_key_make (attr->extra->cluster));        MIX(cluster_hash_key_make (extra->cluster));
      if (attr->extra->transit)      if (extra->transit)
        MIX(transit_hash_key_make (attr->extra->transit));        MIX(transit_hash_key_make (extra->transit));
   
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
      MIX(attr->extra->mp_nexthop_len);      MIX(extra->mp_nexthop_len);
      key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key);      key = jhash(extra->mp_nexthop_global.s6_addr, 16, key);
      key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key);      key = jhash(extra->mp_nexthop_local.s6_addr, 16, key);
 #endif /* HAVE_IPV6 */  #endif /* HAVE_IPV6 */
     }      }
   
Line 552  bgp_attr_default_intern (u_char origin) Line 576  bgp_attr_default_intern (u_char origin)
 {  {
   struct attr attr;    struct attr attr;
   struct attr *new;    struct attr *new;
  struct attr_extra *attre;
   
  memset (&attr, 0, sizeof (struct attr)); 
  attre = bgp_attr_extra_get (&attr); 
   
   bgp_attr_default_set(&attr, origin);    bgp_attr_default_set(&attr, origin);
   
   new = bgp_attr_intern (&attr);    new = bgp_attr_intern (&attr);
Line 573  bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori Line 593  bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori
 {  {
   struct attr attr;    struct attr attr;
   struct attr *new;    struct attr *new;
  struct attr_extra *attre;  struct attr_extra attre;
   
   memset (&attr, 0, sizeof (struct attr));    memset (&attr, 0, sizeof (struct attr));
  attre = bgp_attr_extra_get (&attr);  memset (&attre, 0, sizeof (struct attr_extra));
    attr.extra = &attre;
 
   /* Origin attribute. */    /* Origin attribute. */
   attr.origin = origin;    attr.origin = origin;
   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);    attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGIN);
Line 598  bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori Line 619  bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori
       attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);        attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
     }      }
   
  attre->weight = BGP_ATTR_DEFAULT_WEIGHT;  attre.weight = BGP_ATTR_DEFAULT_WEIGHT;
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
  attre->mp_nexthop_len = IPV6_MAX_BYTELEN;  attre.mp_nexthop_len = IPV6_MAX_BYTELEN;
 #endif  #endif
   if (! as_set)    if (! as_set)
     attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);      attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
   attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);    attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
   if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))    if (CHECK_FLAG (bgp->config, BGP_CONFIG_CONFEDERATION))
    attre->aggregator_as = bgp->confed_id;    attre.aggregator_as = bgp->confed_id;
   else    else
    attre->aggregator_as = bgp->as;    attre.aggregator_as = bgp->as;
  attre->aggregator_addr = bgp->router_id;  attre.aggregator_addr = bgp->router_id;
   
   new = bgp_attr_intern (&attr);    new = bgp_attr_intern (&attr);
  bgp_attr_extra_free (&attr);
   
   aspath_unintern (&new->aspath);    aspath_unintern (&new->aspath);
   return new;    return new;
 }  }
Line 648  bgp_attr_unintern_sub (struct attr *attr) Line 668  bgp_attr_unintern_sub (struct attr *attr)
   
 /* Free bgp attribute and aspath. */  /* Free bgp attribute and aspath. */
 void  void
bgp_attr_unintern (struct attr **attr)bgp_attr_unintern (struct attr **pattr)
 {  {
     struct attr *attr = *pattr;
   struct attr *ret;    struct attr *ret;
   struct attr tmp;    struct attr tmp;
     struct attr_extra tmp_extra;
       
   /* Decrement attribute reference. */    /* Decrement attribute reference. */
  (*attr)->refcnt--;  attr->refcnt--;
       
  tmp = *(*attr);  tmp = *attr;
       
  if ((*attr)->extra)  if (attr->extra)
     {      {
      tmp.extra = bgp_attr_extra_new ();      tmp.extra = &tmp_extra;
      memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra));      memcpy (tmp.extra, attr->extra, sizeof (struct attr_extra));
     }      }
       
   /* If reference becomes zero then free attribute object. */    /* If reference becomes zero then free attribute object. */
  if ((*attr)->refcnt == 0)  if (attr->refcnt == 0)
    {        {
      ret = hash_release (attrhash, *attr);      ret = hash_release (attrhash, attr);
       assert (ret != NULL);        assert (ret != NULL);
      bgp_attr_extra_free (*attr);      bgp_attr_extra_free (attr);
      XFREE (MTYPE_ATTR, *attr);      XFREE (MTYPE_ATTR, attr);
      *attr = NULL;      *pattr = NULL;
     }      }
   
   bgp_attr_unintern_sub (&tmp);    bgp_attr_unintern_sub (&tmp);
Line 703  bgp_attr_flush (struct attr *attr) Line 725  bgp_attr_flush (struct attr *attr)
  * introduced by the sending neighbour.   * introduced by the sending neighbour.
  */   */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_malformed (struct peer *peer, u_char type, u_char flag,bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode,
                    u_char subcode, u_char *startp, bgp_size_t length)                    bgp_size_t length)
 {  {
     struct peer *const peer = args->peer; 
     const u_int8_t flags = args->flags;
     /* startp and length must be special-cased, as whether or not to
      * send the attribute data with the NOTIFY depends on the error,
      * the caller therefore signals this with the seperate length argument
      */
     u_char *notify_datap = (length > 0 ? args->startp : NULL);
     
   /* Only relax error handling for eBGP peers */    /* Only relax error handling for eBGP peers */
  if (peer_sort (peer) != BGP_PEER_EBGP)  if (peer->sort != BGP_PEER_EBGP)
     {      {
       bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,        bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
                                 startp, length);                                 notify_datap, length);
       return BGP_ATTR_PARSE_ERROR;        return BGP_ATTR_PARSE_ERROR;
   
     }      }
       
  switch (type) {  /* Adjust the stream getp to the end of the attribute, in case we can
    /* where an optional attribute is inconsequential, e.g. it does not affect   * still proceed but the caller hasn't read all the attribute.
     * route selection, and can be safely ignored then any such attributes   */
     * which are malformed should just be ignored and the route processed as  stream_set_getp (BGP_INPUT (peer),
     * normal.                   (args->startp - STREAM_DATA (BGP_INPUT (peer)))
                     + args->total);
   
   switch (args->type) {
     /* where an attribute is relatively inconsequential, e.g. it does not
      * affect route selection, and can be safely ignored, then any such
      * attributes which are malformed should just be ignored and the route
      * processed as normal.
      */       */
     case BGP_ATTR_AS4_AGGREGATOR:      case BGP_ATTR_AS4_AGGREGATOR:
     case BGP_ATTR_AGGREGATOR:      case BGP_ATTR_AGGREGATOR:
Line 727  bgp_attr_malformed (struct peer *peer, u_char type, u_ Line 764  bgp_attr_malformed (struct peer *peer, u_char type, u_
       return BGP_ATTR_PARSE_PROCEED;        return BGP_ATTR_PARSE_PROCEED;
           
     /* Core attributes, particularly ones which may influence route      /* Core attributes, particularly ones which may influence route
     * selection should always cause session resets     * selection, should always cause session resets
      */       */
     case BGP_ATTR_ORIGIN:      case BGP_ATTR_ORIGIN:
     case BGP_ATTR_AS_PATH:      case BGP_ATTR_AS_PATH:
Line 741  bgp_attr_malformed (struct peer *peer, u_char type, u_ Line 778  bgp_attr_malformed (struct peer *peer, u_char type, u_
     case BGP_ATTR_MP_UNREACH_NLRI:      case BGP_ATTR_MP_UNREACH_NLRI:
     case BGP_ATTR_EXT_COMMUNITIES:      case BGP_ATTR_EXT_COMMUNITIES:
       bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,        bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode,
                                 startp, length);                                 notify_datap, length);
       return BGP_ATTR_PARSE_ERROR;        return BGP_ATTR_PARSE_ERROR;
   }    }
       
Line 749  bgp_attr_malformed (struct peer *peer, u_char type, u_ Line 786  bgp_attr_malformed (struct peer *peer, u_char type, u_
    * the whole session to be reset. Instead treat it as a withdrawal     * the whole session to be reset. Instead treat it as a withdrawal
    * of the routes, if possible.     * of the routes, if possible.
    */     */
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)  if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS)
      && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)      && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
      && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))      && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
     return BGP_ATTR_PARSE_WITHDRAW;      return BGP_ATTR_PARSE_WITHDRAW;
       
   /* default to reset */    /* default to reset */
   return BGP_ATTR_PARSE_ERROR;    return BGP_ATTR_PARSE_ERROR;
 }  }
   
/* Get origin attribute of the update message. *//* Find out what is wrong with the path attribute flag bits and log the error.
static bgp_attr_parse_ret_t   "Flag bits" here stand for Optional, Transitive and Partial, but not for
bgp_attr_origin (struct peer *peer, bgp_size_t length,    Extended Length. Checking O/T/P bits at once implies, that the attribute
                 struct attr *attr, u_char flag, u_char *startp)   being diagnosed is defined by RFC as either a "well-known" or an "optional,
    non-transitive" attribute. */
 static void
 bgp_attr_flags_diagnose (struct bgp_attr_parser_args *args,
                          u_int8_t desired_flags /* how RFC says it must be */
 )
 {  {
  bgp_size_t total;  u_char seen = 0, i;
   u_char real_flags = args->flags;
   const u_int8_t attr_code = args->type;
   
   desired_flags &= ~BGP_ATTR_FLAG_EXTLEN;
   real_flags &= ~BGP_ATTR_FLAG_EXTLEN;
   for (i = 0; i <= 2; i++) /* O,T,P, but not E */
     if
     (
       CHECK_FLAG (desired_flags, attr_flag_str[i].key) !=
       CHECK_FLAG (real_flags,    attr_flag_str[i].key)
     )
     {
       zlog (args->peer->log, LOG_ERR, "%s attribute must%s be flagged as \"%s\"",
             LOOKUP (attr_str, attr_code),
             CHECK_FLAG (desired_flags, attr_flag_str[i].key) ? "" : " not",
             attr_flag_str[i].str);
       seen = 1;
     }
   if (!seen)
     {
       zlog (args->peer->log, LOG_DEBUG,
             "Strange, %s called for attr %s, but no problem found with flags"
             " (real flags 0x%x, desired 0x%x)",
             __func__, LOOKUP (attr_str, attr_code),
             real_flags, desired_flags);
     }
 }
   
  /* total is entire attribute length include Attribute Flags (1),/* Required flags for attributes. EXTLEN will be masked off when testing,
     Attribute Type code (1) and Attribute length (1 or 2).  */ * as will PARTIAL for optional+transitive attributes.
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); */
 const u_int8_t attr_flags_values [] = {
   [BGP_ATTR_ORIGIN] =           BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_AS_PATH] =          BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_NEXT_HOP] =         BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_MULTI_EXIT_DISC] =  BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_LOCAL_PREF] =       BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_ATOMIC_AGGREGATE] = BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_AGGREGATOR] =       BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_COMMUNITIES] =      BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_ORIGINATOR_ID] =    BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_CLUSTER_LIST] =     BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_MP_REACH_NLRI] =    BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_MP_UNREACH_NLRI] =  BGP_ATTR_FLAG_OPTIONAL,
   [BGP_ATTR_EXT_COMMUNITIES] =  BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_AS4_PATH] =         BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
   [BGP_ATTR_AS4_AGGREGATOR] =   BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
 };
 static const size_t attr_flags_values_max =
   sizeof (attr_flags_values) / sizeof (attr_flags_values[0]);
   
  /* If any recognized attribute has Attribute Flags that conflictstatic int
     with the Attribute Type Code, then the Error Subcode is set tobgp_attr_flag_invalid (struct bgp_attr_parser_args *args)
     Attribute Flags Error.  The Data field contains the erroneous{
     attribute (type, length and value). */  u_int8_t mask = BGP_ATTR_FLAG_EXTLEN;
  if (flag != BGP_ATTR_FLAG_TRANS)  const u_int8_t flags = args->flags;
   const u_int8_t attr_code = args->type;
   struct peer *const peer = args->peer; 
   
   /* there may be attributes we don't know about */
   if (attr_code > attr_flags_values_max)
     return 0;
   if (attr_flags_values[attr_code] == 0)
     return 0;
   
   /* RFC4271, "For well-known attributes, the Transitive bit MUST be set to
    * 1."
    */
   if (!CHECK_FLAG (BGP_ATTR_FLAG_OPTIONAL, flags)
       && !CHECK_FLAG (BGP_ATTR_FLAG_TRANS, flags))
     {      {
      zlog (peer->log, LOG_ERR,       zlog (peer->log, LOG_ERR,
            "Origin attribute flag isn't transitive %d", flag);            "%s well-known attributes must have transitive flag set (%x)",
      return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,            LOOKUP (attr_str, attr_code), flags);
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,      return 1;
                                 startp, total); 
     }      }
     
     /* "For well-known attributes and for optional non-transitive attributes,
      *  the Partial bit MUST be set to 0." 
      */
     if (CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL))
       {
         if (!CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL))
           {
             zlog (peer->log, LOG_ERR,
                   "%s well-known attribute "
                   "must NOT have the partial flag set (%x)",
                    LOOKUP (attr_str, attr_code), flags);
             return 1;
           }
         if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
             && !CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
           {
             zlog (peer->log, LOG_ERR,
                   "%s optional + transitive attribute "
                   "must NOT have the partial flag set (%x)",
                    LOOKUP (attr_str, attr_code), flags);
             return 1;
           }
       }
     
     /* Optional transitive attributes may go through speakers that don't
      * reocgnise them and set the Partial bit.
      */
     if (CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL)
         && CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS))
       SET_FLAG (mask, BGP_ATTR_FLAG_PARTIAL);
     
     if ((flags & ~mask)
         == attr_flags_values[attr_code])
       return 0;
     
     bgp_attr_flags_diagnose (args, attr_flags_values[attr_code]);
     return 1;
   }
   
   /* Get origin attribute of the update message. */
   static bgp_attr_parse_ret_t
   bgp_attr_origin (struct bgp_attr_parser_args *args)
   {
     struct peer *const peer = args->peer;
     struct attr *const attr = args->attr;
     const bgp_size_t length = args->length;
     
   /* If any recognized attribute has Attribute Length that conflicts    /* If any recognized attribute has Attribute Length that conflicts
      with the expected length (based on the attribute type code), then       with the expected length (based on the attribute type code), then
      the Error Subcode is set to Attribute Length Error.  The Data       the Error Subcode is set to Attribute Length Error.  The Data
Line 791  bgp_attr_origin (struct peer *peer, bgp_size_t length, Line 939  bgp_attr_origin (struct peer *peer, bgp_size_t length,
     {      {
       zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",        zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",
             length);              length);
      return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 startp, total);                                 args->total);
     }      }
   
   /* Fetch origin attribute. */    /* Fetch origin attribute. */
Line 808  bgp_attr_origin (struct peer *peer, bgp_size_t length, Line 956  bgp_attr_origin (struct peer *peer, bgp_size_t length,
     {      {
       zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",        zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",
               attr->origin);                attr->origin);
      return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_INVAL_ORIGIN,                                   BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
                                 startp, total);                                 args->total);
     }      }
   
   /* Set oring attribute flag. */    /* Set oring attribute flag. */
Line 822  bgp_attr_origin (struct peer *peer, bgp_size_t length, Line 970  bgp_attr_origin (struct peer *peer, bgp_size_t length,
 /* Parse AS path information.  This function is wrapper of  /* Parse AS path information.  This function is wrapper of
    aspath_parse. */     aspath_parse. */
 static int  static int
bgp_attr_aspath (struct peer *peer, bgp_size_t length, bgp_attr_aspath (struct bgp_attr_parser_args *args)
                 struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total;  struct attr *const attr = args->attr;
  struct peer *const peer = args->peer; 
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  const bgp_size_t length = args->length;
  
  /* Flag check. */ 
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) 
      || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) 
    { 
      zlog (peer->log, LOG_ERR,  
            "As-Path attribute flag isn't transitive %d", flag); 
      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
    } 
 
   /*    /*
    * peer with AS4 => will get 4Byte ASnums     * peer with AS4 => will get 4Byte ASnums
    * otherwise, will get 16 Bit     * otherwise, will get 16 Bit
Line 853  bgp_attr_aspath (struct peer *peer, bgp_size_t length, Line 989  bgp_attr_aspath (struct peer *peer, bgp_size_t length,
       zlog (peer->log, LOG_ERR,        zlog (peer->log, LOG_ERR,
             "Malformed AS path from %s, length is %d",              "Malformed AS path from %s, length is %d",
             peer->host, length);              peer->host, length);
      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,      return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);
                                 BGP_NOTIFY_UPDATE_MAL_AS_PATH, 
                                 NULL, 0); 
     }      }
   
   /* Set aspath attribute flag. */    /* Set aspath attribute flag. */
Line 865  bgp_attr_aspath (struct peer *peer, bgp_size_t length, Line 999  bgp_attr_aspath (struct peer *peer, bgp_size_t length,
 }  }
   
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_aspath_check (struct peer *peer, struct attr *attr, u_char flag)bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)
 {  {
   /* These checks were part of bgp_attr_aspath, but with    /* These checks were part of bgp_attr_aspath, but with
    * as4 we should to check aspath things when     * as4 we should to check aspath things when
Line 877  bgp_attr_aspath_check (struct peer *peer, struct attr  Line 1011  bgp_attr_aspath_check (struct peer *peer, struct attr 
   struct bgp *bgp = peer->bgp;    struct bgp *bgp = peer->bgp;
   struct aspath *aspath;    struct aspath *aspath;
   
   bgp = peer->bgp;  
       
   /* Confederation sanity check. */    /* Confederation sanity check. */
  if ((peer_sort (peer) == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||  if ((peer->sort == BGP_PEER_CONFED && ! aspath_left_confed_check (attr->aspath)) ||
     (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))     (peer->sort == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))
     {      {
       zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);        zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host);
      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
                                 BGP_NOTIFY_UPDATE_MAL_AS_PATH,                       BGP_NOTIFY_UPDATE_MAL_AS_PATH);
                                 NULL, 0);      return BGP_ATTR_PARSE_ERROR;
     }      }
   
   /* First AS check for EBGP. */    /* First AS check for EBGP. */
   if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))    if (bgp != NULL && bgp_flag_check (bgp, BGP_FLAG_ENFORCE_FIRST_AS))
     {      {
      if (peer_sort (peer) == BGP_PEER_EBGP       if (peer->sort == BGP_PEER_EBGP
           && ! aspath_firstas_check (attr->aspath, peer->as))            && ! aspath_firstas_check (attr->aspath, peer->as))
         {          {
           zlog (peer->log, LOG_ERR,            zlog (peer->log, LOG_ERR,
                 "%s incorrect first AS (must be %u)", peer->host, peer->as);                  "%s incorrect first AS (must be %u)", peer->host, peer->as);
          return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,          bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR,
                                     BGP_NOTIFY_UPDATE_MAL_AS_PATH,                           BGP_NOTIFY_UPDATE_MAL_AS_PATH);
                                     NULL, 0);          return BGP_ATTR_PARSE_ERROR;
         }          }
     }      }
   
Line 919  bgp_attr_aspath_check (struct peer *peer, struct attr  Line 1051  bgp_attr_aspath_check (struct peer *peer, struct attr 
 /* Parse AS4 path information.  This function is another wrapper of  /* Parse AS4 path information.  This function is another wrapper of
    aspath_parse. */     aspath_parse. */
 static int  static int
bgp_attr_as4_path (struct peer *peer, bgp_size_t length,bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)
                 struct attr *attr, u_char flag, u_char *startp, 
                 struct aspath **as4_path) 
 {  {
  bgp_size_t total;  struct peer *const peer = args->peer; 
  struct attr *const attr = args->attr;
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  const bgp_size_t length = args->length;
  
  /* Flag check. */ 
  if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) 
      || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) 
    { 
      zlog (peer->log, LOG_ERR,  
            "As4-Path attribute flag isn't optional/transitive %d", flag); 
      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
    } 
 
   *as4_path = aspath_parse (peer->ibuf, length, 1);    *as4_path = aspath_parse (peer->ibuf, length, 1);
   
   /* In case of IBGP, length will be zero. */    /* In case of IBGP, length will be zero. */
Line 946  bgp_attr_as4_path (struct peer *peer, bgp_size_t lengt Line 1065  bgp_attr_as4_path (struct peer *peer, bgp_size_t lengt
       zlog (peer->log, LOG_ERR,        zlog (peer->log, LOG_ERR,
             "Malformed AS4 path from %s, length is %d",              "Malformed AS4 path from %s, length is %d",
             peer->host, length);              peer->host, length);
      return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_MAL_AS_PATH,                                   BGP_NOTIFY_UPDATE_MAL_AS_PATH,
                                 NULL, 0);                                 0);
     }      }
   
   /* Set aspath attribute flag. */    /* Set aspath attribute flag. */
Line 960  bgp_attr_as4_path (struct peer *peer, bgp_size_t lengt Line 1079  bgp_attr_as4_path (struct peer *peer, bgp_size_t lengt
   
 /* Nexthop attribute. */  /* Nexthop attribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_nexthop (struct peer *peer, bgp_size_t length, bgp_attr_nexthop (struct bgp_attr_parser_args *args)
                  struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total;  struct peer *const peer = args->peer; 
   struct attr *const attr = args->attr;
   const bgp_size_t length = args->length;
   
   in_addr_t nexthop_h, nexthop_n;
   
   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  
   
   /* Flag check. */  
   if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)  
       || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))  
     {  
       zlog (peer->log, LOG_ERR,   
             "Origin attribute flag isn't transitive %d", flag);  
       return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,  
                                  BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,  
                                  startp, total);  
     }  
   
   /* Check nexthop attribute length. */    /* Check nexthop attribute length. */
   if (length != 4)    if (length != 4)
     {      {
       zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",        zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",
               length);                length);
   
      return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 startp, total);                                 args->total);
     }      }
   
  attr->nexthop.s_addr = stream_get_ipv4 (peer->ibuf);  /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
      attribute must result in a NOTIFICATION message (this is implemented below).
      At the same time, semantically incorrect NEXT_HOP is more likely to be just
      logged locally (this is implemented somewhere else). The UPDATE message
      gets ignored in any of these cases. */
   nexthop_n = stream_get_ipv4 (peer->ibuf);
   nexthop_h = ntohl (nexthop_n);
   if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
     {
       char buf[INET_ADDRSTRLEN];
       inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
       zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
       return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
                                  args->total);
     }
 
   attr->nexthop.s_addr = nexthop_n;
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
   
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
Line 997  bgp_attr_nexthop (struct peer *peer, bgp_size_t length Line 1123  bgp_attr_nexthop (struct peer *peer, bgp_size_t length
   
 /* MED atrribute. */  /* MED atrribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_med (struct peer *peer, bgp_size_t length, bgp_attr_med (struct bgp_attr_parser_args *args)
              struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total;  struct peer *const peer = args->peer; 
  struct attr *const attr = args->attr;
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  const bgp_size_t length = args->length;
  
  /* Flag checks. */ 
  if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) 
    { 
      zlog (peer->log, LOG_ERR, 
            "MULTI_EXIT_DISC attribute must be flagged as \"optional\" (%u)", flag); 
      bgp_notify_send_with_data (peer, 
                                 BGP_NOTIFY_UPDATE_ERR, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
      return -1; 
    } 
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) 
    { 
      zlog (peer->log, LOG_ERR, 
            "MULTI_EXIT_DISC attribute must not be flagged as \"transitive\" (%u)", flag); 
      bgp_notify_send_with_data (peer, 
                                 BGP_NOTIFY_UPDATE_ERR, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
      return -1; 
    } 
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) 
    { 
      zlog (peer->log, LOG_ERR, 
            "MULTI_EXIT_DISC attribute must not be flagged as \"partial\" (%u)", flag); 
      bgp_notify_send_with_data (peer, 
                                 BGP_NOTIFY_UPDATE_ERR, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
      return -1; 
    } 
 
   /* Length check. */    /* Length check. */
   if (length != 4)    if (length != 4)
     {      {
       zlog (peer->log, LOG_ERR,         zlog (peer->log, LOG_ERR, 
             "MED attribute length isn't four [%d]", length);              "MED attribute length isn't four [%d]", length);
   
      return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 startp, total);                                 args->total);
     }      }
   
   attr->med = stream_getl (peer->ibuf);    attr->med = stream_getl (peer->ibuf);
Line 1056  bgp_attr_med (struct peer *peer, bgp_size_t length,  Line 1149  bgp_attr_med (struct peer *peer, bgp_size_t length, 
   
 /* Local preference attribute. */  /* Local preference attribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_local_pref (struct peer *peer, bgp_size_t length, bgp_attr_local_pref (struct bgp_attr_parser_args *args)
                     struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total;  struct peer *const peer = args->peer; 
   struct attr *const attr = args->attr;
   const bgp_size_t length = args->length;
   
   /* Length check. */
   if (length != 4)
   {
     zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]",
           length);
     return bgp_attr_malformed (args,
                                BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                args->total);
   }
   
   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  
   /* Flag checks. */  
   if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))  
     {  
       zlog (peer->log, LOG_ERR,  
             "LOCAL_PREF attribute must be flagged as \"well-known\" (%u)", flag);  
       bgp_notify_send_with_data (peer,  
                                  BGP_NOTIFY_UPDATE_ERR,  
                                  BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,  
                                  startp, total);  
       return -1;  
     }  
   if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))  
     {  
       zlog (peer->log, LOG_ERR,  
             "LOCAL_PREF attribute must be flagged as \"transitive\" (%u)", flag);  
       bgp_notify_send_with_data (peer,  
                                  BGP_NOTIFY_UPDATE_ERR,  
                                  BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,  
                                  startp, total);  
       return -1;  
     }  
   
   /* If it is contained in an UPDATE message that is received from an    /* If it is contained in an UPDATE message that is received from an
      external peer, then this attribute MUST be ignored by the       external peer, then this attribute MUST be ignored by the
      receiving speaker. */       receiving speaker. */
  if (peer_sort (peer) == BGP_PEER_EBGP)  if (peer->sort == BGP_PEER_EBGP)
     {      {
       stream_forward_getp (peer->ibuf, length);        stream_forward_getp (peer->ibuf, length);
       return BGP_ATTR_PARSE_PROCEED;        return BGP_ATTR_PARSE_PROCEED;
     }      }
   
  if (length == 4)   attr->local_pref = stream_getl (peer->ibuf);
    attr->local_pref = stream_getl (peer->ibuf); 
  else  
    attr->local_pref = 0; 
   
   /* Set atomic aggregate flag. */    /* Set atomic aggregate flag. */
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
Line 1106  bgp_attr_local_pref (struct peer *peer, bgp_size_t len Line 1184  bgp_attr_local_pref (struct peer *peer, bgp_size_t len
   
 /* Atomic aggregate. */  /* Atomic aggregate. */
 static int  static int
bgp_attr_atomic (struct peer *peer, bgp_size_t length, bgp_attr_atomic (struct bgp_attr_parser_args *args)
                 struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total;  struct peer *const peer = args->peer; 
  struct attr *const attr = args->attr;
  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  const bgp_size_t length = args->length;
  /* Flag checks. */  
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) 
    { 
      zlog (peer->log, LOG_ERR, 
            "ATOMIC_AGGREGATE attribute must not be flagged as \"optional\" (%u)", flag); 
      bgp_notify_send_with_data (peer, 
                                 BGP_NOTIFY_UPDATE_ERR, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
      return -1; 
    } 
  if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) 
    { 
      zlog (peer->log, LOG_ERR, 
            "ATOMIC_AGGREGATE attribute must be flagged as \"transitive\" (%u)", flag); 
      bgp_notify_send_with_data (peer, 
                                 BGP_NOTIFY_UPDATE_ERR, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
      return -1; 
    } 
  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL)) 
    { 
      zlog (peer->log, LOG_ERR, 
            "ATOMIC_AGGREGATE attribute must not be flagged as \"partial\" (%u)", flag); 
      bgp_notify_send_with_data (peer, 
                                 BGP_NOTIFY_UPDATE_ERR, 
                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, 
                                 startp, total); 
      return -1; 
    } 
 
   /* Length check. */    /* Length check. */
   if (length != 0)    if (length != 0)
     {      {
      zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length);      zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
            length);
      return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 NULL, 0);                                 args->total);
     }      }
   
   /* Set atomic aggregate flag. */    /* Set atomic aggregate flag. */
Line 1162  bgp_attr_atomic (struct peer *peer, bgp_size_t length, Line 1208  bgp_attr_atomic (struct peer *peer, bgp_size_t length,
   
 /* Aggregator attribute */  /* Aggregator attribute */
 static int  static int
bgp_attr_aggregator (struct peer *peer, bgp_size_t length,bgp_attr_aggregator (struct bgp_attr_parser_args *args)
                     struct attr *attr, u_char flag) 
 {  {
     struct peer *const peer = args->peer; 
     struct attr *const attr = args->attr;
     const bgp_size_t length = args->length;
     
   int wantedlen = 6;    int wantedlen = 6;
   struct attr_extra *attre = bgp_attr_extra_get (attr);    struct attr_extra *attre = bgp_attr_extra_get (attr);
       
Line 1174  bgp_attr_aggregator (struct peer *peer, bgp_size_t len Line 1223  bgp_attr_aggregator (struct peer *peer, bgp_size_t len
       
   if (length != wantedlen)    if (length != wantedlen)
     {      {
      zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length);      zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]",
            wantedlen, length);
      return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 NULL, 0);                                 args->total);
     }      }
       
   if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )    if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
Line 1195  bgp_attr_aggregator (struct peer *peer, bgp_size_t len Line 1244  bgp_attr_aggregator (struct peer *peer, bgp_size_t len
   
 /* New Aggregator attribute */  /* New Aggregator attribute */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args,
                     struct attr *attr, u_char flag                         as_t *as4_aggregator_as,
                     as_t *as4_aggregator_as,                         struct in_addr *as4_aggregator_addr)
                     struct in_addr *as4_aggregator_addr) 
 {  {
     struct peer *const peer = args->peer; 
     struct attr *const attr = args->attr;
     const bgp_size_t length = args->length;
         
   if (length != 8)    if (length != 8)
     {      {
      zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length);      zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]",
      return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,            length);
       return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 NULL, 0);                                 0);
     }      }
     
   *as4_aggregator_as = stream_getl (peer->ibuf);    *as4_aggregator_as = stream_getl (peer->ibuf);
   as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);    as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);
   
Line 1218  bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t Line 1272  bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t
 /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.  /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.
  */   */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, u_char flag,bgp_attr_munge_as4_attrs (struct peer *const peer,
                           struct attr *const attr,
                           struct aspath *as4_path, as_t as4_aggregator,                            struct aspath *as4_path, as_t as4_aggregator,
                           struct in_addr *as4_aggregator_addr)                            struct in_addr *as4_aggregator_addr)
 {  {
Line 1247  bgp_attr_munge_as4_attrs (struct peer *peer, struct at Line 1302  bgp_attr_munge_as4_attrs (struct peer *peer, struct at
       return BGP_ATTR_PARSE_PROCEED;        return BGP_ATTR_PARSE_PROCEED;
     }      }
       
   if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH))  
       && !(attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))))  
     {  
       /* Hu? This is not supposed to happen at all!  
        * got as4_path and no aspath,  
        *   This should already  
        *   have been handled by 'well known attributes missing'  
        *   But... yeah, paranoia  
        * Take this as a "malformed attribute"  
        */  
       zlog (peer->log, LOG_ERR,   
             "%s BGP not AS4 capable peer sent AS4_PATH but"  
             " no AS_PATH, cant do anything here", peer->host);  
       return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,  
                                  BGP_NOTIFY_UPDATE_MAL_ATTR,  
                                  NULL, 0);  
     }  
   
   /* We have a asn16 peer.  First, look for AS4_AGGREGATOR    /* We have a asn16 peer.  First, look for AS4_AGGREGATOR
    * because that may override AS4_PATH     * because that may override AS4_PATH
    */     */
Line 1323  bgp_attr_munge_as4_attrs (struct peer *peer, struct at Line 1360  bgp_attr_munge_as4_attrs (struct peer *peer, struct at
   /* need to reconcile NEW_AS_PATH and AS_PATH */    /* need to reconcile NEW_AS_PATH and AS_PATH */
   if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))    if (!ignore_as4_path && (attr->flag & (ATTR_FLAG_BIT( BGP_ATTR_AS4_PATH))))
     {      {
          if (!attr->aspath)
            return BGP_ATTR_PARSE_PROCEED;
   
        newpath = aspath_reconcile_as4 (attr->aspath, as4_path);         newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
        aspath_unintern (&attr->aspath);         aspath_unintern (&attr->aspath);
        attr->aspath = aspath_intern (newpath);         attr->aspath = aspath_intern (newpath);
Line 1332  bgp_attr_munge_as4_attrs (struct peer *peer, struct at Line 1372  bgp_attr_munge_as4_attrs (struct peer *peer, struct at
   
 /* Community attribute. */  /* Community attribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_community (struct peer *peer, bgp_size_t length, bgp_attr_community (struct bgp_attr_parser_args *args)
                    struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total  struct peer *const peer = args->peer; 
    = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  struct attr *const attr = args->attr;  
   const bgp_size_t length = args->length;
       
   if (length == 0)    if (length == 0)
     {      {
Line 1351  bgp_attr_community (struct peer *peer, bgp_size_t leng Line 1391  bgp_attr_community (struct peer *peer, bgp_size_t leng
   stream_forward_getp (peer->ibuf, length);    stream_forward_getp (peer->ibuf, length);
   
   if (!attr->community)    if (!attr->community)
    return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,    return bgp_attr_malformed (args,
                                BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,                                 BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
                               startp, total);                               args->total);
       
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
   
Line 1362  bgp_attr_community (struct peer *peer, bgp_size_t leng Line 1402  bgp_attr_community (struct peer *peer, bgp_size_t leng
   
 /* Originator ID attribute. */  /* Originator ID attribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_originator_id (struct peer *peer, bgp_size_t length, bgp_attr_originator_id (struct bgp_attr_parser_args *args)
                        struct attr *attr, u_char flag) 
 {  {
     struct peer *const peer = args->peer; 
     struct attr *const attr = args->attr;
     const bgp_size_t length = args->length;
     
     /* Length check. */
   if (length != 4)    if (length != 4)
     {      {
       zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);        zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length);
   
      return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 NULL, 0);                                 args->total);
     }      }
   
   (bgp_attr_extra_get (attr))->originator_id.s_addr     (bgp_attr_extra_get (attr))->originator_id.s_addr 
Line 1384  bgp_attr_originator_id (struct peer *peer, bgp_size_t  Line 1428  bgp_attr_originator_id (struct peer *peer, bgp_size_t 
   
 /* Cluster list attribute. */  /* Cluster list attribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, bgp_attr_cluster_list (struct bgp_attr_parser_args *args)
                       struct attr *attr, u_char flag) 
 {  {
     struct peer *const peer = args->peer; 
     struct attr *const attr = args->attr;
     const bgp_size_t length = args->length;
     
   /* Check length. */    /* Check length. */
   if (length % 4)    if (length % 4)
     {      {
       zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);        zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length);
   
      return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,      return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,                                 args->total);
                                 NULL, 0); 
     }      }
   
   (bgp_attr_extra_get (attr))->cluster     (bgp_attr_extra_get (attr))->cluster 
Line 1410  bgp_attr_cluster_list (struct peer *peer, bgp_size_t l Line 1456  bgp_attr_cluster_list (struct peer *peer, bgp_size_t l
   
 /* Multiprotocol reachability information parse. */  /* Multiprotocol reachability information parse. */
 int  int
bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
                    struct bgp_nlri *mp_update)                    struct bgp_nlri *mp_update)
 {  {
   afi_t afi;    afi_t afi;
   safi_t safi;    safi_t safi;
Line 1419  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng Line 1465  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
   size_t start;    size_t start;
   int ret;    int ret;
   struct stream *s;    struct stream *s;
     struct peer *const peer = args->peer;  
     struct attr *const attr = args->attr;
     const bgp_size_t length = args->length;
   struct attr_extra *attre = bgp_attr_extra_get(attr);    struct attr_extra *attre = bgp_attr_extra_get(attr);
       
   /* Set end of packet. */    /* Set end of packet. */
Line 1459  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng Line 1508  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
         memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);          memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);
       break;        break;
     case 12:      case 12:
      {      stream_getl (s); /* RD high */
        u_int32_t rd_high;      stream_getl (s); /* RD low */
        u_int32_t rd_low;      stream_get (&attre->mp_nexthop_global_in, s, 4);
 
        rd_high = stream_getl (s); 
        rd_low = stream_getl (s); 
        stream_get (&attre->mp_nexthop_global_in, s, 4); 
      } 
       break;        break;
 #ifdef HAVE_IPV6  #ifdef HAVE_IPV6
     case 16:      case 16:
Line 1520  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng Line 1564  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
       return BGP_ATTR_PARSE_ERROR;        return BGP_ATTR_PARSE_ERROR;
     }      }
     
  if (safi != BGP_SAFI_VPNV4)  if (safi != SAFI_MPLS_LABELED_VPN)
     {      {
       ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);        ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len);
       if (ret < 0)         if (ret < 0) 
Line 1544  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng Line 1588  bgp_mp_reach_parse (struct peer *peer, bgp_size_t leng
   
 /* Multiprotocol unreachable parse */  /* Multiprotocol unreachable parse */
 int  int
bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length, bgp_mp_unreach_parse (struct bgp_attr_parser_args *args,
                       struct bgp_nlri *mp_withdraw)                        struct bgp_nlri *mp_withdraw)
 {  {
   struct stream *s;    struct stream *s;
Line 1552  bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le Line 1596  bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le
   safi_t safi;    safi_t safi;
   u_int16_t withdraw_len;    u_int16_t withdraw_len;
   int ret;    int ret;
     struct peer *const peer = args->peer;  
     const bgp_size_t length = args->length;
   
   s = peer->ibuf;    s = peer->ibuf;
       
Line 1564  bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le Line 1610  bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le
       
   withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;    withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
   
  if (safi != BGP_SAFI_VPNV4)  if (safi != SAFI_MPLS_LABELED_VPN)
     {      {
       ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);        ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);
       if (ret < 0)        if (ret < 0)
Line 1583  bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le Line 1629  bgp_mp_unreach_parse (struct peer *peer, bgp_size_t le
   
 /* Extended Community attribute. */  /* Extended Community attribute. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, bgp_attr_ext_communities (struct bgp_attr_parser_args *args)
                          struct attr *attr, u_char flag, u_char *startp) 
 {  {
  bgp_size_t total  struct peer *const peer = args->peer;  
    = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  struct attr *const attr = args->attr;  
   const bgp_size_t length = args->length;
       
   if (length == 0)    if (length == 0)
     {      {
Line 1603  bgp_attr_ext_communities (struct peer *peer, bgp_size_ Line 1649  bgp_attr_ext_communities (struct peer *peer, bgp_size_
   stream_forward_getp (peer->ibuf, length);    stream_forward_getp (peer->ibuf, length);
       
   if (!attr->extra->ecommunity)    if (!attr->extra->ecommunity)
    return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,    return bgp_attr_malformed (args,
                               flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,                               BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
                               startp, total);                               args->total);
       
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
   
Line 1614  bgp_attr_ext_communities (struct peer *peer, bgp_size_ Line 1660  bgp_attr_ext_communities (struct peer *peer, bgp_size_
   
 /* BGP unknown attribute treatment. */  /* BGP unknown attribute treatment. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,bgp_attr_unknown (struct bgp_attr_parser_args *args)
                  u_char type, bgp_size_t length, u_char *startp) 
 {  {
  bgp_size_t total;  bgp_size_t total = args->total;
   struct transit *transit;    struct transit *transit;
   struct attr_extra *attre;    struct attr_extra *attre;
     struct peer *const peer = args->peer; 
     struct attr *const attr = args->attr;
     u_char *const startp = args->startp;
     const u_char type = args->type;
     const u_char flag = args->flags;  
     const bgp_size_t length = args->length;
     
   
   if (BGP_DEBUG (normal, NORMAL))    if (BGP_DEBUG (normal, NORMAL))
   zlog_debug ("%s Unknown attribute is received (type %d, length %d)",    zlog_debug ("%s Unknown attribute is received (type %d, length %d)",
Line 1632  bgp_attr_unknown (struct peer *peer, struct attr *attr Line 1684  bgp_attr_unknown (struct peer *peer, struct attr *attr
   /* Forward read pointer of input stream. */    /* Forward read pointer of input stream. */
   stream_forward_getp (peer->ibuf, length);    stream_forward_getp (peer->ibuf, length);
   
   /* Adjest total length to include type and length. */  
   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);  
   
   /* If any of the mandatory well-known attributes are not recognized,    /* If any of the mandatory well-known attributes are not recognized,
      then the Error Subcode is set to Unrecognized Well-known       then the Error Subcode is set to Unrecognized Well-known
      Attribute.  The Data field contains the unrecognized attribute       Attribute.  The Data field contains the unrecognized attribute
      (type, length and value). */       (type, length and value). */
   if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))    if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
     {      {
      return bgp_attr_malformed (peer, type, flag,      return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_UNREC_ATTR,                                   BGP_NOTIFY_UPDATE_UNREC_ATTR,
                                 startp, total);                                 args->total);
     }      }
   
   /* Unrecognized non-transitive optional attributes must be quietly    /* Unrecognized non-transitive optional attributes must be quietly
Line 1676  bgp_attr_unknown (struct peer *peer, struct attr *attr Line 1725  bgp_attr_unknown (struct peer *peer, struct attr *attr
 }  }
   
 /* Read attribute of update packet.  This function is called from  /* Read attribute of update packet.  This function is called from
   bgp_update() in bgpd.c.  */   bgp_update_receive() in bgp_packet.c.  */
 bgp_attr_parse_ret_t  bgp_attr_parse_ret_t
 bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,  bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,
                 struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)                  struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)
Line 1720  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 1769  bgp_attr_parse (struct peer *peer, struct attr *attr, 
   
       /* Fetch attribute flag and type. */        /* Fetch attribute flag and type. */
       startp = BGP_INPUT_PNT (peer);        startp = BGP_INPUT_PNT (peer);
      flag = stream_getc (BGP_INPUT (peer));      /* "The lower-order four bits of the Attribute Flags octet are
          unused.  They MUST be zero when sent and MUST be ignored when
          received." */
       flag = 0xF0 & stream_getc (BGP_INPUT (peer));
       type = stream_getc (BGP_INPUT (peer));        type = stream_getc (BGP_INPUT (peer));
   
       /* Check whether Extended-Length applies and is in bounds */        /* Check whether Extended-Length applies and is in bounds */
Line 1737  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 1789  bgp_attr_parse (struct peer *peer, struct attr *attr, 
                            BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);                             BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
           return BGP_ATTR_PARSE_ERROR;            return BGP_ATTR_PARSE_ERROR;
         }          }
      
       /* Check extended attribue length bit. */        /* Check extended attribue length bit. */
       if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))        if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))
         length = stream_getw (BGP_INPUT (peer));          length = stream_getw (BGP_INPUT (peer));
Line 1777  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 1829  bgp_attr_parse (struct peer *peer, struct attr *attr, 
                            BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);                             BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
           return BGP_ATTR_PARSE_ERROR;            return BGP_ATTR_PARSE_ERROR;
         }          }
           
           struct bgp_attr_parser_args attr_args = {
             .peer = peer,
             .length = length,
             .attr = attr,
             .type = type,
             .flags = flag,
             .startp = startp,
             .total = attr_endp - startp,
           };
         
           
         /* If any recognized attribute has Attribute Flags that conflict
            with the Attribute Type Code, then the Error Subcode is set to
            Attribute Flags Error.  The Data field contains the erroneous
            attribute (type, length and value). */
         if (bgp_attr_flag_invalid (&attr_args))
           {
             bgp_attr_parse_ret_t ret;
             ret = bgp_attr_malformed (&attr_args,
                                       BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
                                       attr_args.total);
             if (ret == BGP_ATTR_PARSE_PROCEED)
               continue;
             return ret;
           }
   
       /* OK check attribute and store it's value. */        /* OK check attribute and store it's value. */
       switch (type)        switch (type)
         {          {
         case BGP_ATTR_ORIGIN:          case BGP_ATTR_ORIGIN:
          ret = bgp_attr_origin (peer, length, attr, flag, startp);          ret = bgp_attr_origin (&attr_args);
           break;            break;
         case BGP_ATTR_AS_PATH:          case BGP_ATTR_AS_PATH:
          ret = bgp_attr_aspath (peer, length, attr, flag, startp);          ret = bgp_attr_aspath (&attr_args);
           break;            break;
         case BGP_ATTR_AS4_PATH:          case BGP_ATTR_AS4_PATH:
          ret = bgp_attr_as4_path (peer, length, attr, flag, startp, &as4_path);          ret = bgp_attr_as4_path (&attr_args, &as4_path);
           break;            break;
         case BGP_ATTR_NEXT_HOP:           case BGP_ATTR_NEXT_HOP: 
          ret = bgp_attr_nexthop (peer, length, attr, flag, startp);          ret = bgp_attr_nexthop (&attr_args);
           break;            break;
         case BGP_ATTR_MULTI_EXIT_DISC:          case BGP_ATTR_MULTI_EXIT_DISC:
          ret = bgp_attr_med (peer, length, attr, flag, startp);          ret = bgp_attr_med (&attr_args);
           break;            break;
         case BGP_ATTR_LOCAL_PREF:          case BGP_ATTR_LOCAL_PREF:
          ret = bgp_attr_local_pref (peer, length, attr, flag, startp);          ret = bgp_attr_local_pref (&attr_args);
           break;            break;
         case BGP_ATTR_ATOMIC_AGGREGATE:          case BGP_ATTR_ATOMIC_AGGREGATE:
          ret = bgp_attr_atomic (peer, length, attr, flag, startp);          ret = bgp_attr_atomic (&attr_args);
           break;            break;
         case BGP_ATTR_AGGREGATOR:          case BGP_ATTR_AGGREGATOR:
          ret = bgp_attr_aggregator (peer, length, attr, flag);          ret = bgp_attr_aggregator (&attr_args);
           break;            break;
         case BGP_ATTR_AS4_AGGREGATOR:          case BGP_ATTR_AS4_AGGREGATOR:
          ret = bgp_attr_as4_aggregator (peer, length, attr, flag,          ret = bgp_attr_as4_aggregator (&attr_args,
                                         &as4_aggregator,                                          &as4_aggregator,
                                          &as4_aggregator_addr);                                           &as4_aggregator_addr);
           break;            break;
         case BGP_ATTR_COMMUNITIES:          case BGP_ATTR_COMMUNITIES:
          ret = bgp_attr_community (peer, length, attr, flag, startp);          ret = bgp_attr_community (&attr_args);
           break;            break;
         case BGP_ATTR_ORIGINATOR_ID:          case BGP_ATTR_ORIGINATOR_ID:
          ret = bgp_attr_originator_id (peer, length, attr, flag);          ret = bgp_attr_originator_id (&attr_args);
           break;            break;
         case BGP_ATTR_CLUSTER_LIST:          case BGP_ATTR_CLUSTER_LIST:
          ret = bgp_attr_cluster_list (peer, length, attr, flag);          ret = bgp_attr_cluster_list (&attr_args);
           break;            break;
         case BGP_ATTR_MP_REACH_NLRI:          case BGP_ATTR_MP_REACH_NLRI:
          ret = bgp_mp_reach_parse (peer, length, attr, mp_update);          ret = bgp_mp_reach_parse (&attr_args, mp_update);
           break;            break;
         case BGP_ATTR_MP_UNREACH_NLRI:          case BGP_ATTR_MP_UNREACH_NLRI:
          ret = bgp_mp_unreach_parse (peer, length, mp_withdraw);          ret = bgp_mp_unreach_parse (&attr_args, mp_withdraw);
           break;            break;
         case BGP_ATTR_EXT_COMMUNITIES:          case BGP_ATTR_EXT_COMMUNITIES:
          ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);          ret = bgp_attr_ext_communities (&attr_args);
           break;            break;
         default:          default:
          ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);          ret = bgp_attr_unknown (&attr_args);
           break;            break;
         }          }
               
Line 1899  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 1977  bgp_attr_parse (struct peer *peer, struct attr *attr, 
    * all attributes first, including these 32bit ones, and now,     * all attributes first, including these 32bit ones, and now,
    * afterwards, we look what and if something is to be done for as4.     * afterwards, we look what and if something is to be done for as4.
    */     */
  if (bgp_attr_munge_as4_attrs (peer, attr, flag, as4_path,  if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
                                 as4_aggregator, &as4_aggregator_addr))                                  as4_aggregator, &as4_aggregator_addr))
     {      {
       if (as4_path)        if (as4_path)
Line 1931  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2009  bgp_attr_parse (struct peer *peer, struct attr *attr, 
    */     */
   if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))    if (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS_PATH)))
     {      {
      ret = bgp_attr_aspath_check (peer, attr, flag);      ret = bgp_attr_aspath_check (peer, attr);
       if (ret != BGP_ATTR_PARSE_PROCEED)        if (ret != BGP_ATTR_PARSE_PROCEED)
         return ret;          return ret;
     }      }
Line 1958  bgp_attr_check (struct peer *peer, struct attr *attr) Line 2036  bgp_attr_check (struct peer *peer, struct attr *attr)
   if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))    if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))
     type = BGP_ATTR_NEXT_HOP;      type = BGP_ATTR_NEXT_HOP;
   
  if (peer_sort (peer) == BGP_PEER_IBGP  if (peer->sort == BGP_PEER_IBGP
       && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))        && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
     type = BGP_ATTR_LOCAL_PREF;      type = BGP_ATTR_LOCAL_PREF;
   
Line 2007  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2085  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
   /* AS path attribute. */    /* AS path attribute. */
   
   /* If remote-peer is EBGP */    /* If remote-peer is EBGP */
  if (peer_sort (peer) == BGP_PEER_EBGP  if (peer->sort == BGP_PEER_EBGP
       && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)        && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_AS_PATH_UNCHANGED)
           || attr->aspath->segments == NULL)            || attr->aspath->segments == NULL)
       && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))        && (! CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_RSERVER_CLIENT)))
Line 2023  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2101  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
         }          }
       else        else
         {          {
          aspath = aspath_add_seq (aspath, peer->local_as);          if (peer->change_local_as) {
          if (peer->change_local_as)            /* If replace-as is specified, we only use the change_local_as when
                advertising routes. */
             if( ! CHECK_FLAG (peer->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS) ) {
               aspath = aspath_add_seq (aspath, peer->local_as);
             }
             aspath = aspath_add_seq (aspath, peer->change_local_as);              aspath = aspath_add_seq (aspath, peer->change_local_as);
             } else {
               aspath = aspath_add_seq (aspath, peer->local_as);
             }
         }          }
     }      }
  else if (peer_sort (peer) == BGP_PEER_CONFED)  else if (peer->sort == BGP_PEER_CONFED)
     {      {
       /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */        /* A confed member, so we need to do the AS_CONFED_SEQUENCE thing */
       aspath = aspath_dup (attr->aspath);        aspath = aspath_dup (attr->aspath);
Line 2085  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2170  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
     }      }
   
   /* Local preference. */    /* Local preference. */
  if (peer_sort (peer) == BGP_PEER_IBGP ||  if (peer->sort == BGP_PEER_IBGP ||
      peer_sort (peer) == BGP_PEER_CONFED)      peer->sort == BGP_PEER_CONFED)
     {      {
       stream_putc (s, BGP_ATTR_FLAG_TRANS);        stream_putc (s, BGP_ATTR_FLAG_TRANS);
       stream_putc (s, BGP_ATTR_LOCAL_PREF);        stream_putc (s, BGP_ATTR_LOCAL_PREF);
Line 2159  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2244  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
     }      }
   
   /* Route Reflector. */    /* Route Reflector. */
  if (peer_sort (peer) == BGP_PEER_IBGP  if (peer->sort == BGP_PEER_IBGP
       && from        && from
      && peer_sort (from) == BGP_PEER_IBGP)      && from->sort == BGP_PEER_IBGP)
     {      {
       /* Originator ID. */        /* Originator ID. */
       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);        stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);
Line 2269  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2354  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
       sizep = stream_get_endp (s);        sizep = stream_get_endp (s);
       stream_putc (s, 0);       /* Length of this attribute. */        stream_putc (s, 0);       /* Length of this attribute. */
       stream_putw (s, AFI_IP);  /* AFI */        stream_putw (s, AFI_IP);  /* AFI */
      stream_putc (s, BGP_SAFI_VPNV4);      /* SAFI */      stream_putc (s, SAFI_MPLS_LABELED_VPN);      /* SAFI */
   
       stream_putc (s, 12);        stream_putc (s, 12);
       stream_putl (s, 0);        stream_putl (s, 0);
Line 2297  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2382  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
               
       assert (attre);        assert (attre);
               
      if (peer_sort (peer) == BGP_PEER_IBGP       if (peer->sort == BGP_PEER_IBGP
          || peer_sort (peer) == BGP_PEER_CONFED)          || peer->sort == BGP_PEER_CONFED)
         {          {
           if (attre->ecommunity->size * 8 > 255)            if (attre->ecommunity->size * 8 > 255)
             {              {
Line 2432  bgp_packet_withdraw (struct peer *peer, struct stream  Line 2517  bgp_packet_withdraw (struct peer *peer, struct stream 
   if (safi == SAFI_MPLS_VPN)    if (safi == SAFI_MPLS_VPN)
     {      {
       /* SAFI */        /* SAFI */
      stream_putc (s, BGP_SAFI_VPNV4);      stream_putc (s, SAFI_MPLS_LABELED_VPN);
   
       /* prefix. */        /* prefix. */
       stream_putc (s, p->prefixlen + 88);        stream_putc (s, p->prefixlen + 88);

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.3


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