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

version 1.1.1.3, 2013/07/21 23:54:37 version 1.1.1.4, 2016/11/02 10:09:10
Line 29  Software Foundation, Inc., 59 Temple Place - Suite 330 Line 29  Software Foundation, Inc., 59 Temple Place - Suite 330
 #include "log.h"  #include "log.h"
 #include "hash.h"  #include "hash.h"
 #include "jhash.h"  #include "jhash.h"
   #include "filter.h"
   
 #include "bgpd/bgpd.h"  #include "bgpd/bgpd.h"
 #include "bgpd/bgp_attr.h"  #include "bgpd/bgp_attr.h"
Line 38  Software Foundation, Inc., 59 Temple Place - Suite 330 Line 39  Software Foundation, Inc., 59 Temple Place - Suite 330
 #include "bgpd/bgp_debug.h"  #include "bgpd/bgp_debug.h"
 #include "bgpd/bgp_packet.h"  #include "bgpd/bgp_packet.h"
 #include "bgpd/bgp_ecommunity.h"  #include "bgpd/bgp_ecommunity.h"
#include "table.h"
 #include "bgp_encap_types.h"
 
 /* Attribute strings for logging. */  /* Attribute strings for logging. */
 static const struct message attr_str [] =   static const struct message attr_str [] = 
 {  {
Line 61  static const struct message attr_str [] =  Line 64  static const struct message attr_str [] = 
   { BGP_ATTR_AS4_PATH,         "AS4_PATH" },     { BGP_ATTR_AS4_PATH,         "AS4_PATH" }, 
   { BGP_ATTR_AS4_AGGREGATOR,   "AS4_AGGREGATOR" },     { BGP_ATTR_AS4_AGGREGATOR,   "AS4_AGGREGATOR" }, 
   { BGP_ATTR_AS_PATHLIMIT,     "AS_PATHLIMIT" },    { BGP_ATTR_AS_PATHLIMIT,     "AS_PATHLIMIT" },
     { BGP_ATTR_ENCAP,            "ENCAP" },
 };  };
 static const int attr_str_max = array_size(attr_str);  static const int attr_str_max = array_size(attr_str);
   
Line 72  static const struct message attr_flag_str[] = Line 76  static const struct message attr_flag_str[] =
   /* bgp_attr_flags_diagnose() relies on this bit being last in this list */    /* bgp_attr_flags_diagnose() relies on this bit being last in this list */
   { BGP_ATTR_FLAG_EXTLEN,   "Extended Length" },    { 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;
   
 static void *  static void *
Line 204  cluster_init (void) Line 207  cluster_init (void)
 static void  static void
 cluster_finish (void)  cluster_finish (void)
 {  {
     hash_clean (cluster_hash, (void (*)(void *))cluster_free);
   hash_free (cluster_hash);    hash_free (cluster_hash);
   cluster_hash = NULL;    cluster_hash = NULL;
 }  }
 struct bgp_attr_encap_subtlv *
 encap_tlv_dup(struct bgp_attr_encap_subtlv *orig)
 {
     struct bgp_attr_encap_subtlv *new;
     struct bgp_attr_encap_subtlv *tail;
     struct bgp_attr_encap_subtlv *p;
 
     for (p = orig, tail = new = NULL; p; p = p->next) {
         int size = sizeof(struct bgp_attr_encap_subtlv) - 1 + p->length;
         if (tail) {
             tail->next = XCALLOC(MTYPE_ENCAP_TLV, size);
             tail = tail->next;
         } else {
             tail = new = XCALLOC(MTYPE_ENCAP_TLV, size);
         }
         assert(tail);
         memcpy(tail, p, size);
         tail->next = NULL;
     }
 
     return new;
 }
 
 static void
 encap_free(struct bgp_attr_encap_subtlv *p)
 {
     struct bgp_attr_encap_subtlv *next;
     while (p) {
         next    = p->next;
         p->next = NULL;
         XFREE(MTYPE_ENCAP_TLV, p);
         p       = next;
     }
 }
 
 void
 bgp_attr_flush_encap(struct attr *attr)
 {
     if (!attr || !attr->extra)
         return;
 
     if (attr->extra->encap_subtlvs) {
         encap_free(attr->extra->encap_subtlvs);
         attr->extra->encap_subtlvs = NULL;
     }
 }
 
 /*
  * Compare encap sub-tlv chains
  *
  *      1 = equivalent
  *      0 = not equivalent
  *
  * This algorithm could be made faster if needed
  */
 static int
 encap_same(struct bgp_attr_encap_subtlv *h1, struct bgp_attr_encap_subtlv *h2)
 {
     struct bgp_attr_encap_subtlv *p;
     struct bgp_attr_encap_subtlv *q;
 
     if (!h1 && !h2)
         return 1;
     if (h1 && !h2)
         return 0;
     if (!h1 && h2)
         return 0;
     if (h1 == h2)
         return 1;
 
     for (p = h1; p; p = p->next) {
         for (q = h2; q; q = q->next) {
             if ((p->type == q->type) &&
                 (p->length == q->length) &&
                 !memcmp(p->value, q->value, p->length)) {
 
                 break;
             }
         }
         if (!q)
             return 0;
     }
 
     for (p = h2; p; p = p->next) {
         for (q = h1; q; q = q->next) {
             if ((p->type == q->type) &&
                 (p->length == q->length) &&
                 !memcmp(p->value, q->value, p->length)) {
 
                 break;
             }
         }
         if (!q)
             return 0;
     }
 
     return 1;
 }
 
 /* Unknown transit attribute. */  /* Unknown transit attribute. */
 static struct hash *transit_hash;  static struct hash *transit_hash;
   
Line 280  transit_init (void) Line 383  transit_init (void)
 static void  static void
 transit_finish (void)  transit_finish (void)
 {  {
     hash_clean (transit_hash, (void (*)(void *))transit_free);
   hash_free (transit_hash);    hash_free (transit_hash);
   transit_hash = NULL;    transit_hash = NULL;
 }  }
 /* Attribute hash routines. */  /* Attribute hash routines. */
 static struct hash *attrhash;  static struct hash *attrhash;
   
Line 298  bgp_attr_extra_free (struct attr *attr) Line 402  bgp_attr_extra_free (struct attr *attr)
 {  {
   if (attr->extra)    if (attr->extra)
     {      {
         if (attr->extra->encap_subtlvs) {
           encap_free(attr->extra->encap_subtlvs);
           attr->extra->encap_subtlvs = NULL;
         }
       XFREE (MTYPE_ATTR_EXTRA, attr->extra);        XFREE (MTYPE_ATTR_EXTRA, attr->extra);
       attr->extra = NULL;        attr->extra = NULL;
     }      }
Line 333  bgp_attr_dup (struct attr *new, struct attr *orig) Line 441  bgp_attr_dup (struct attr *new, struct attr *orig)
     {      {
       new->extra = extra;        new->extra = extra;
       memset(new->extra, 0, sizeof(struct attr_extra));        memset(new->extra, 0, sizeof(struct attr_extra));
      if (orig->extra)      if (orig->extra) {
         *new->extra = *orig->extra;          *new->extra = *orig->extra;
           if (orig->extra->encap_subtlvs) {
             new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs);
           }
         }
     }      }
   else if (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;
         if (orig->extra->encap_subtlvs) {
           new->extra->encap_subtlvs = encap_tlv_dup(orig->extra->encap_subtlvs);
         }
     }      }
 }  }
   
Line 379  attrhash_key_make (void *p) Line 494  attrhash_key_make (void *p)
       MIX(extra->aggregator_addr.s_addr);        MIX(extra->aggregator_addr.s_addr);
       MIX(extra->weight);        MIX(extra->weight);
       MIX(extra->mp_nexthop_global_in.s_addr);        MIX(extra->mp_nexthop_global_in.s_addr);
         MIX(extra->originator_id.s_addr);
     }      }
       
   if (attr->aspath)    if (attr->aspath)
Line 395  attrhash_key_make (void *p) Line 511  attrhash_key_make (void *p)
       if (extra->transit)        if (extra->transit)
         MIX(transit_hash_key_make (extra->transit));          MIX(transit_hash_key_make (extra->transit));
   
 #ifdef HAVE_IPV6  
       MIX(extra->mp_nexthop_len);        MIX(extra->mp_nexthop_len);
       key = jhash(extra->mp_nexthop_global.s6_addr, 16, key);        key = jhash(extra->mp_nexthop_global.s6_addr, 16, key);
       key = jhash(extra->mp_nexthop_local.s6_addr, 16, key);        key = jhash(extra->mp_nexthop_local.s6_addr, 16, key);
 #endif /* HAVE_IPV6 */  
     }      }
   
   return key;    return key;
Line 426  attrhash_cmp (const void *p1, const void *p2) Line 540  attrhash_cmp (const void *p1, const void *p2)
           && ae1->aggregator_as == ae2->aggregator_as            && ae1->aggregator_as == ae2->aggregator_as
           && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr            && ae1->aggregator_addr.s_addr == ae2->aggregator_addr.s_addr
           && ae1->weight == ae2->weight            && ae1->weight == ae2->weight
 #ifdef HAVE_IPV6  
           && ae1->mp_nexthop_len == ae2->mp_nexthop_len            && ae1->mp_nexthop_len == ae2->mp_nexthop_len
           && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)            && IPV6_ADDR_SAME (&ae1->mp_nexthop_global, &ae2->mp_nexthop_global)
           && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)            && IPV6_ADDR_SAME (&ae1->mp_nexthop_local, &ae2->mp_nexthop_local)
 #endif /* HAVE_IPV6 */  
           && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)            && IPV4_ADDR_SAME (&ae1->mp_nexthop_global_in, &ae2->mp_nexthop_global_in)
           && ae1->ecommunity == ae2->ecommunity            && ae1->ecommunity == ae2->ecommunity
           && ae1->cluster == ae2->cluster            && ae1->cluster == ae2->cluster
          && ae1->transit == ae2->transit)          && ae1->transit == ae2->transit
           && (ae1->encap_tunneltype == ae2->encap_tunneltype)
           && encap_same(ae1->encap_subtlvs, ae2->encap_subtlvs)
           && IPV4_ADDR_SAME (&ae1->originator_id, &ae2->originator_id))
         return 1;          return 1;
       else if (ae1 || ae2)        else if (ae1 || ae2)
         return 0;          return 0;
Line 451  attrhash_init (void) Line 566  attrhash_init (void)
   attrhash = hash_create (attrhash_key_make, attrhash_cmp);    attrhash = hash_create (attrhash_key_make, attrhash_cmp);
 }  }
   
   /*
    * special for hash_clean below
    */
 static void  static void
   attr_vfree (void *attr)
   {
     bgp_attr_extra_free ((struct attr *)attr);
     XFREE (MTYPE_ATTR, attr);
   }
   
   static void
 attrhash_finish (void)  attrhash_finish (void)
 {  {
     hash_clean(attrhash, attr_vfree);
   hash_free (attrhash);    hash_free (attrhash);
   attrhash = NULL;    attrhash = NULL;
 }  }
Line 488  bgp_attr_hash_alloc (void *p) Line 614  bgp_attr_hash_alloc (void *p)
     {      {
       attr->extra = bgp_attr_extra_new ();        attr->extra = bgp_attr_extra_new ();
       *attr->extra = *val->extra;        *attr->extra = *val->extra;
   
         if (attr->extra->encap_subtlvs) {
           attr->extra->encap_subtlvs = encap_tlv_dup(attr->extra->encap_subtlvs);
         }
     }      }
   attr->refcnt = 0;    attr->refcnt = 0;
   return attr;    return attr;
Line 562  bgp_attr_default_set (struct attr *attr, u_char origin Line 692  bgp_attr_default_set (struct attr *attr, u_char origin
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH);
   attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;    attr->extra->weight = BGP_ATTR_DEFAULT_WEIGHT;
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP);
 #ifdef HAVE_IPV6  
   attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;    attr->extra->mp_nexthop_len = IPV6_MAX_BYTELEN;
 #endif  
   
   return attr;    return attr;
 }  }
Line 577  bgp_attr_default_intern (u_char origin) Line 705  bgp_attr_default_intern (u_char origin)
   struct attr attr;    struct attr attr;
   struct attr *new;    struct attr *new;
   
     memset (&attr, 0, sizeof (struct attr));
     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 620  bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori Line 751  bgp_attr_aggregate_intern (struct bgp *bgp, u_char ori
     }      }
   
   attre.weight = BGP_ATTR_DEFAULT_WEIGHT;    attre.weight = BGP_ATTR_DEFAULT_WEIGHT;
 #ifdef HAVE_IPV6  
   attre.mp_nexthop_len = IPV6_MAX_BYTELEN;    attre.mp_nexthop_len = IPV6_MAX_BYTELEN;
#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);
Line 645  bgp_attr_unintern_sub (struct attr *attr) Line 775  bgp_attr_unintern_sub (struct attr *attr)
   /* aspath refcount shoud be decrement. */    /* aspath refcount shoud be decrement. */
   if (attr->aspath)    if (attr->aspath)
     aspath_unintern (&attr->aspath);      aspath_unintern (&attr->aspath);
  UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH);  UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH));
       
   if (attr->community)    if (attr->community)
     community_unintern (&attr->community);      community_unintern (&attr->community);
  UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES);  UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES));
       
   if (attr->extra)    if (attr->extra)
     {      {
       if (attr->extra->ecommunity)        if (attr->extra->ecommunity)
         ecommunity_unintern (&attr->extra->ecommunity);          ecommunity_unintern (&attr->extra->ecommunity);
      UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES);      UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES));
               
       if (attr->extra->cluster)        if (attr->extra->cluster)
         cluster_unintern (attr->extra->cluster);          cluster_unintern (attr->extra->cluster);
      UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST);      UNSET_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST));
               
       if (attr->extra->transit)        if (attr->extra->transit)
         transit_unintern (attr->extra->transit);          transit_unintern (attr->extra->transit);
Line 703  void Line 833  void
 bgp_attr_flush (struct attr *attr)  bgp_attr_flush (struct attr *attr)
 {  {
   if (attr->aspath && ! attr->aspath->refcnt)    if (attr->aspath && ! attr->aspath->refcnt)
    aspath_free (attr->aspath);    {
       aspath_free (attr->aspath);
       attr->aspath = NULL;
     }
   if (attr->community && ! attr->community->refcnt)    if (attr->community && ! attr->community->refcnt)
    community_free (attr->community);    {
       community_free (attr->community);
       attr->community = NULL;
     }
   if (attr->extra)    if (attr->extra)
     {      {
       struct attr_extra *attre = attr->extra;        struct attr_extra *attre = attr->extra;
Line 713  bgp_attr_flush (struct attr *attr) Line 849  bgp_attr_flush (struct attr *attr)
       if (attre->ecommunity && ! attre->ecommunity->refcnt)        if (attre->ecommunity && ! attre->ecommunity->refcnt)
         ecommunity_free (&attre->ecommunity);          ecommunity_free (&attre->ecommunity);
       if (attre->cluster && ! attre->cluster->refcnt)        if (attre->cluster && ! attre->cluster->refcnt)
        cluster_free (attre->cluster);        {
           cluster_free (attre->cluster);
           attre->cluster = NULL;
         }
       if (attre->transit && ! attre->transit->refcnt)        if (attre->transit && ! attre->transit->refcnt)
        transit_free (attre->transit);        {
           transit_free (attre->transit);
           attre->transit = NULL;
         }
       encap_free(attre->encap_subtlvs);
       attre->encap_subtlvs = NULL;
     }      }
 }  }
   
Line 792  bgp_attr_malformed (struct bgp_attr_parser_args *args, Line 936  bgp_attr_malformed (struct bgp_attr_parser_args *args,
     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_NOTIFYPLS;
 }  }
   
 /* Find out what is wrong with the path attribute flag bits and log the error.  /* Find out what is wrong with the path attribute flag bits and log the error.
Line 1108  bgp_attr_nexthop (struct bgp_attr_parser_args *args) Line 1252  bgp_attr_nexthop (struct bgp_attr_parser_args *args)
   if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))    if (IPV4_NET0 (nexthop_h) || IPV4_NET127 (nexthop_h) || IPV4_CLASS_DE (nexthop_h))
     {      {
       char buf[INET_ADDRSTRLEN];        char buf[INET_ADDRSTRLEN];
      inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);      inet_ntop (AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN);
       zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);        zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
       return bgp_attr_malformed (args,        return bgp_attr_malformed (args,
                                  BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,                                   BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
Line 1280  bgp_attr_munge_as4_attrs (struct peer *const peer, Line 1424  bgp_attr_munge_as4_attrs (struct peer *const peer,
   int ignore_as4_path = 0;    int ignore_as4_path = 0;
   struct aspath *newpath;    struct aspath *newpath;
   struct attr_extra *attre = attr->extra;    struct attr_extra *attre = attr->extra;
      
   if (!attr->aspath)
     {
       /* NULL aspath shouldn't be possible as bgp_attr_parse should have
        * checked that all well-known, mandatory attributes were present.
        * 
        * Can only be a problem with peer itself - hard error
        */
       return BGP_ATTR_PARSE_ERROR;
     }
   
   if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))    if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))
     {      {
       /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR        /* peer can do AS4, so we ignore AS4_PATH and AS4_AGGREGATOR
Line 1360  bgp_attr_munge_as4_attrs (struct peer *const peer, Line 1514  bgp_attr_munge_as4_attrs (struct peer *const peer,
   /* 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)      newpath = aspath_reconcile_as4 (attr->aspath, as4_path);
         return BGP_ATTR_PARSE_PROCEED;      aspath_unintern (&attr->aspath);
      attr->aspath = aspath_intern (newpath);
       newpath = aspath_reconcile_as4 (attr->aspath, as4_path); 
       aspath_unintern (&attr->aspath); 
       attr->aspath = aspath_intern (newpath); 
     }      }
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
 }  }
Line 1463  bgp_mp_reach_parse (struct bgp_attr_parser_args *args, Line 1614  bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
   safi_t safi;    safi_t safi;
   bgp_size_t nlri_len;    bgp_size_t nlri_len;
   size_t start;    size_t start;
   int ret;  
   struct stream *s;    struct stream *s;
   struct peer *const peer = args->peer;      struct peer *const peer = args->peer;  
   struct attr *const attr = args->attr;    struct attr *const attr = args->attr;
Line 1481  bgp_mp_reach_parse (struct bgp_attr_parser_args *args, Line 1631  bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
     {      {
       zlog_info ("%s: %s sent invalid length, %lu",         zlog_info ("%s: %s sent invalid length, %lu", 
                  __func__, peer->host, (unsigned long)length);                   __func__, peer->host, (unsigned long)length);
      return BGP_ATTR_PARSE_ERROR;      return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
     }      }
       
   /* Load AFI, SAFI. */    /* Load AFI, SAFI. */
Line 1495  bgp_mp_reach_parse (struct bgp_attr_parser_args *args, Line 1645  bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
     {      {
       zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",         zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute", 
                  __func__, peer->host, attre->mp_nexthop_len);                   __func__, peer->host, attre->mp_nexthop_len);
      return BGP_ATTR_PARSE_ERROR;      return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
     }      }
       
   /* Nexthop length check. */    /* Nexthop length check. */
Line 1512  bgp_mp_reach_parse (struct bgp_attr_parser_args *args, Line 1662  bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
       stream_getl (s); /* RD low */        stream_getl (s); /* RD low */
       stream_get (&attre->mp_nexthop_global_in, s, 4);        stream_get (&attre->mp_nexthop_global_in, s, 4);
       break;        break;
#ifdef HAVE_IPV6    case 24:
       {
         u_int32_t rd_high __attribute__((unused));
         u_int32_t rd_low __attribute__((unused));
 
         rd_high = stream_getl (s);
         rd_low = stream_getl (s);
       }
       /* fall through */
     case 16:      case 16:
       stream_get (&attre->mp_nexthop_global, s, 16);        stream_get (&attre->mp_nexthop_global, s, 16);
       break;        break;
     case 32:      case 32:
       case 48:
         if (attre->mp_nexthop_len == 48) {
           u_int32_t rd_high __attribute__((unused));
           u_int32_t rd_low __attribute__((unused));
   
           rd_high = stream_getl (s);
           rd_low = stream_getl (s);
         }
       stream_get (&attre->mp_nexthop_global, s, 16);        stream_get (&attre->mp_nexthop_global, s, 16);
   
         if (attre->mp_nexthop_len == 48) {
           u_int32_t rd_high __attribute__((unused));
           u_int32_t rd_low __attribute__((unused));
   
           rd_high = stream_getl (s);
           rd_low = stream_getl (s);
         }
       stream_get (&attre->mp_nexthop_local, s, 16);        stream_get (&attre->mp_nexthop_local, s, 16);
       if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))        if (! IN6_IS_ADDR_LINKLOCAL (&attre->mp_nexthop_local))
         {          {
Line 1534  bgp_mp_reach_parse (struct bgp_attr_parser_args *args, Line 1708  bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
           attre->mp_nexthop_len = 16;            attre->mp_nexthop_len = 16;
         }          }
       break;        break;
 #endif /* HAVE_IPV6 */  
     default:      default:
       zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",         zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d", 
                  __func__, peer->host, attre->mp_nexthop_len);                   __func__, peer->host, attre->mp_nexthop_len);
      return BGP_ATTR_PARSE_ERROR;      return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
     }      }
   
   if (!LEN_LEFT)    if (!LEN_LEFT)
     {      {
       zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",        zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",
                  __func__, peer->host);                   __func__, peer->host);
      return BGP_ATTR_PARSE_ERROR;      return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
     }      }
       
   {    {
Line 1561  bgp_mp_reach_parse (struct bgp_attr_parser_args *args, Line 1734  bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
     {      {
       zlog_info ("%s: (%s) Failed to read NLRI",        zlog_info ("%s: (%s) Failed to read NLRI",
                  __func__, peer->host);                   __func__, peer->host);
      return BGP_ATTR_PARSE_ERROR;      return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
     }      }
   
  if (safi != SAFI_MPLS_LABELED_VPN) 
    { 
      ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), nlri_len); 
      if (ret < 0)  
        { 
          zlog_info ("%s: (%s) NLRI doesn't pass sanity check", 
                     __func__, peer->host); 
          return BGP_ATTR_PARSE_ERROR; 
        } 
    } 
 
   mp_update->afi = afi;    mp_update->afi = afi;
   mp_update->safi = safi;    mp_update->safi = safi;
   mp_update->nlri = stream_pnt (s);    mp_update->nlri = stream_pnt (s);
Line 1582  bgp_mp_reach_parse (struct bgp_attr_parser_args *args, Line 1744  bgp_mp_reach_parse (struct bgp_attr_parser_args *args,
   
   stream_forward_getp (s, nlri_len);    stream_forward_getp (s, nlri_len);
   
     attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI);
   
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
 #undef LEN_LEFT  #undef LEN_LEFT
 }  }
Line 1595  bgp_mp_unreach_parse (struct bgp_attr_parser_args *arg Line 1759  bgp_mp_unreach_parse (struct bgp_attr_parser_args *arg
   afi_t afi;    afi_t afi;
   safi_t safi;    safi_t safi;
   u_int16_t withdraw_len;    u_int16_t withdraw_len;
   int ret;  
   struct peer *const peer = args->peer;      struct peer *const peer = args->peer;  
     struct attr *const attr = args->attr;
   const bgp_size_t length = args->length;    const bgp_size_t length = args->length;
   
   s = peer->ibuf;    s = peer->ibuf;
       
 #define BGP_MP_UNREACH_MIN_SIZE 3  #define BGP_MP_UNREACH_MIN_SIZE 3
   if ((length > STREAM_READABLE(s)) || (length <  BGP_MP_UNREACH_MIN_SIZE))    if ((length > STREAM_READABLE(s)) || (length <  BGP_MP_UNREACH_MIN_SIZE))
    return BGP_ATTR_PARSE_ERROR;    return BGP_ATTR_PARSE_ERROR_NOTIFYPLS;
       
   afi = stream_getw (s);    afi = stream_getw (s);
   safi = stream_getc (s);    safi = stream_getc (s);
       
   withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;    withdraw_len = length - BGP_MP_UNREACH_MIN_SIZE;
   
   if (safi != SAFI_MPLS_LABELED_VPN)  
     {  
       ret = bgp_nlri_sanity_check (peer, afi, stream_pnt (s), withdraw_len);  
       if (ret < 0)  
         return BGP_ATTR_PARSE_ERROR;  
     }  
   
   mp_withdraw->afi = afi;    mp_withdraw->afi = afi;
   mp_withdraw->safi = safi;    mp_withdraw->safi = safi;
   mp_withdraw->nlri = stream_pnt (s);    mp_withdraw->nlri = stream_pnt (s);
Line 1624  bgp_mp_unreach_parse (struct bgp_attr_parser_args *arg Line 1781  bgp_mp_unreach_parse (struct bgp_attr_parser_args *arg
   
   stream_forward_getp (s, withdraw_len);    stream_forward_getp (s, withdraw_len);
   
     attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI);
   
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
 }  }
   
Line 1658  bgp_attr_ext_communities (struct bgp_attr_parser_args  Line 1817  bgp_attr_ext_communities (struct bgp_attr_parser_args 
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
 }  }
   
   /* Parse Tunnel Encap attribute in an UPDATE */
   static int
   bgp_attr_encap(
     uint8_t       type,
     struct peer   *peer,  /* IN */
     bgp_size_t    length, /* IN: attr's length field */
     struct attr   *attr,  /* IN: caller already allocated */
     u_char        flag,   /* IN: attr's flags field */
     u_char        *startp)
   {
     bgp_size_t                    total;
     struct attr_extra             *attre = NULL;
     struct bgp_attr_encap_subtlv  *stlv_last = NULL;
     uint16_t                      tunneltype;
   
     total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
   
     if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)
          || !CHECK_FLAG(flag, BGP_ATTR_FLAG_OPTIONAL))
       {
         zlog (peer->log, LOG_ERR,
               "Tunnel Encap attribute flag isn't optional and transitive %d", flag);
         bgp_notify_send_with_data (peer,
                                    BGP_NOTIFY_UPDATE_ERR,
                                    BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
                                    startp, total);
         return -1;
       }
   
     if (BGP_ATTR_ENCAP == type) {
       /* read outer TLV type and length */
       uint16_t    tlv_length;
   
       if (length < 4) {
           zlog (peer->log, LOG_ERR,
               "Tunnel Encap attribute not long enough to contain outer T,L");
           bgp_notify_send_with_data(peer,
                                    BGP_NOTIFY_UPDATE_ERR,
                                    BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
                                    startp, total);
           return -1;
       }
       tunneltype = stream_getw (BGP_INPUT (peer));
       tlv_length = stream_getw (BGP_INPUT (peer));
       length -= 4;
   
       if (tlv_length != length) {
           zlog (peer->log, LOG_ERR, "%s: tlv_length(%d) != length(%d)",
               __func__, tlv_length, length);
       }
     }
   
     while (length >= 4) {
       uint16_t    subtype;
       uint16_t    sublength;
       struct bgp_attr_encap_subtlv *tlv;
   
       if (BGP_ATTR_ENCAP == type) {
           subtype   = stream_getc (BGP_INPUT (peer));
           sublength = stream_getc (BGP_INPUT (peer));
           length   -= 2;
       }
   
       if (sublength > length) {
         zlog (peer->log, LOG_ERR,
               "Tunnel Encap attribute sub-tlv length %d exceeds remaining length %d",
               sublength, length);
         bgp_notify_send_with_data (peer,
                                    BGP_NOTIFY_UPDATE_ERR,
                                    BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
                                    startp, total);
         return -1;
       }
   
       /* alloc and copy sub-tlv */
       /* TBD make sure these are freed when attributes are released */
       tlv = XCALLOC (MTYPE_ENCAP_TLV, sizeof(struct bgp_attr_encap_subtlv)-1+sublength);
       tlv->type = subtype;
       tlv->length = sublength;
       stream_get(tlv->value, peer->ibuf, sublength);
       length -= sublength;
   
       /* attach tlv to encap chain */
       if (!attre) {
           attre = bgp_attr_extra_get(attr);
           if (BGP_ATTR_ENCAP == type) {
               for (stlv_last = attre->encap_subtlvs; stlv_last && stlv_last->next;
                   stlv_last = stlv_last->next);
               if (stlv_last) {
                   stlv_last->next = tlv;
               } else {
                   attre->encap_subtlvs = tlv;
               }
           }
       } else {
           stlv_last->next = tlv;
       }
       stlv_last = tlv;
     }
   
     if (attre && (BGP_ATTR_ENCAP == type)) {
         attre->encap_tunneltype = tunneltype;
     }
   
     if (length) {
       /* spurious leftover data */
         zlog (peer->log, LOG_ERR,
               "Tunnel Encap attribute length is bad: %d leftover octets", length);
         bgp_notify_send_with_data (peer,
                                    BGP_NOTIFY_UPDATE_ERR,
                                    BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
                                    startp, total);
         return -1;
     }
   
     return 0;
   }
   
 /* BGP unknown attribute treatment. */  /* BGP unknown attribute treatment. */
 static bgp_attr_parse_ret_t  static bgp_attr_parse_ret_t
 bgp_attr_unknown (struct bgp_attr_parser_args *args)  bgp_attr_unknown (struct bgp_attr_parser_args *args)
Line 1724  bgp_attr_unknown (struct bgp_attr_parser_args *args) Line 2001  bgp_attr_unknown (struct bgp_attr_parser_args *args)
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
 }  }
   
   /* Well-known attribute check. */
   static int
   bgp_attr_check (struct peer *peer, struct attr *attr)
   {
     u_char type = 0;
     
     /* BGP Graceful-Restart End-of-RIB for IPv4 unicast is signaled as an
      * empty UPDATE.  */
     if (CHECK_FLAG (peer->cap, PEER_CAP_RESTART_RCV) && !attr->flag)
       return BGP_ATTR_PARSE_PROCEED;
     
     /* "An UPDATE message that contains the MP_UNREACH_NLRI is not required
        to carry any other path attributes.", though if MP_REACH_NLRI or NLRI
        are present, it should.  Check for any other attribute being present
        instead.
      */
     if (attr->flag == ATTR_FLAG_BIT (BGP_ATTR_MP_UNREACH_NLRI))
       return BGP_ATTR_PARSE_PROCEED;
     
     if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN)))
       type = BGP_ATTR_ORIGIN;
   
     if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))
       type = BGP_ATTR_AS_PATH;
     
     /* RFC 2858 makes Next-Hop optional/ignored, if MP_REACH_NLRI is present and
      * NLRI is empty. We can't easily check NLRI empty here though.
      */
     if (!CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP))
         && !CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_MP_REACH_NLRI)))
       type = BGP_ATTR_NEXT_HOP;
     
     if (peer->sort == BGP_PEER_IBGP
         && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))
       type = BGP_ATTR_LOCAL_PREF;
   
     if (type)
       {
         zlog (peer->log, LOG_WARNING, 
               "%s Missing well-known attribute %d / %s",
               peer->host, type, LOOKUP (attr_str, type));
         bgp_notify_send_with_data (peer, 
                                    BGP_NOTIFY_UPDATE_ERR, 
                                    BGP_NOTIFY_UPDATE_MISS_ATTR,
                                    &type, 1);
         return BGP_ATTR_PARSE_ERROR;
       }
     return BGP_ATTR_PARSE_PROCEED;
   }
   
 /* Read attribute of update packet.  This function is called from  /* Read attribute of update packet.  This function is called from
    bgp_update_receive() in bgp_packet.c.  */     bgp_update_receive() in bgp_packet.c.  */
 bgp_attr_parse_ret_t  bgp_attr_parse_ret_t
Line 1741  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2068  bgp_attr_parse (struct peer *peer, struct attr *attr, 
   /* same goes for as4_aggregator */    /* same goes for as4_aggregator */
   struct aspath *as4_path = NULL;    struct aspath *as4_path = NULL;
   as_t as4_aggregator = 0;    as_t as4_aggregator = 0;
  struct in_addr as4_aggregator_addr = { 0 };  struct in_addr as4_aggregator_addr = { .s_addr = 0 };
   
   /* Initialize bitmap. */    /* Initialize bitmap. */
   memset (seen, 0, BGP_ATTR_BITMAP_SIZE);    memset (seen, 0, BGP_ATTR_BITMAP_SIZE);
Line 1906  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2233  bgp_attr_parse (struct peer *peer, struct attr *attr, 
         case BGP_ATTR_EXT_COMMUNITIES:          case BGP_ATTR_EXT_COMMUNITIES:
           ret = bgp_attr_ext_communities (&attr_args);            ret = bgp_attr_ext_communities (&attr_args);
           break;            break;
           case BGP_ATTR_ENCAP:
             ret = bgp_attr_encap (type, peer, length, attr, flag, startp);
             break;
         default:          default:
           ret = bgp_attr_unknown (&attr_args);            ret = bgp_attr_unknown (&attr_args);
           break;            break;
         }          }
               
         if (ret == BGP_ATTR_PARSE_ERROR_NOTIFYPLS)
           {
             bgp_notify_send (peer, 
                              BGP_NOTIFY_UPDATE_ERR,
                              BGP_NOTIFY_UPDATE_MAL_ATTR);
             ret = BGP_ATTR_PARSE_ERROR;
           }
   
       /* If hard error occured immediately return to the caller. */        /* If hard error occured immediately return to the caller. */
       if (ret == BGP_ATTR_PARSE_ERROR)        if (ret == BGP_ATTR_PARSE_ERROR)
         {          {
Line 1918  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2256  bgp_attr_parse (struct peer *peer, struct attr *attr, 
                 "%s: Attribute %s, parse error",                   "%s: Attribute %s, parse error", 
                 peer->host,                   peer->host, 
                 LOOKUP (attr_str, type));                  LOOKUP (attr_str, type));
           bgp_notify_send (peer,   
                            BGP_NOTIFY_UPDATE_ERR,  
                            BGP_NOTIFY_UPDATE_MAL_ATTR);  
           if (as4_path)            if (as4_path)
             aspath_unintern (&as4_path);              aspath_unintern (&as4_path);
           return ret;            return ret;
Line 1951  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2286  bgp_attr_parse (struct peer *peer, struct attr *attr, 
           return BGP_ATTR_PARSE_ERROR;            return BGP_ATTR_PARSE_ERROR;
         }          }
     }      }
   
   /* Check final read pointer is same as end pointer. */    /* Check final read pointer is same as end pointer. */
   if (BGP_INPUT_PNT (peer) != endp)    if (BGP_INPUT_PNT (peer) != endp)
     {      {
Line 1965  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2299  bgp_attr_parse (struct peer *peer, struct attr *attr, 
         aspath_unintern (&as4_path);          aspath_unintern (&as4_path);
       return BGP_ATTR_PARSE_ERROR;        return BGP_ATTR_PARSE_ERROR;
     }      }
  
   /* Check all mandatory well-known attributes are present */
   {
     bgp_attr_parse_ret_t ret;
     if ((ret = bgp_attr_check (peer, attr)) < 0)
       {
         if (as4_path)
           aspath_unintern (&as4_path);
         return ret;
       }
   }
   
   /*     /* 
    * At this place we can see whether we got AS4_PATH and/or     * At this place we can see whether we got AS4_PATH and/or
    * AS4_AGGREGATOR from a 16Bit peer and act accordingly.     * AS4_AGGREGATOR from a 16Bit peer and act accordingly.
Line 1976  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2321  bgp_attr_parse (struct peer *peer, struct attr *attr, 
    * So, to be defensive, we are not relying on any order and read     * So, to be defensive, we are not relying on any order and read
    * 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.
      *
      * It is possible to not have AS_PATH, e.g. GR EoR and sole
      * MP_UNREACH_NLRI.
    */     */
  if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,  /* actually... this doesn't ever return failure currently, but
    * better safe than sorry */
   if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH))
       && bgp_attr_munge_as4_attrs (peer, attr, as4_path,
                                 as4_aggregator, &as4_aggregator_addr))                                  as4_aggregator, &as4_aggregator_addr))
     {      {
         bgp_notify_send (peer, 
                          BGP_NOTIFY_UPDATE_ERR,
                          BGP_NOTIFY_UPDATE_MAL_ATTR);
       if (as4_path)        if (as4_path)
         aspath_unintern (&as4_path);          aspath_unintern (&as4_path);
       return BGP_ATTR_PARSE_ERROR;        return BGP_ATTR_PARSE_ERROR;
Line 2021  bgp_attr_parse (struct peer *peer, struct attr *attr,  Line 2375  bgp_attr_parse (struct peer *peer, struct attr *attr, 
   return BGP_ATTR_PARSE_PROCEED;    return BGP_ATTR_PARSE_PROCEED;
 }  }
   
/* Well-known attribute check. */int stream_put_prefix (struct stream *, struct prefix *);
int
bgp_attr_check (struct peer *peer, struct attr *attr)size_t
 bgp_packet_mpattr_start (struct stream *s, afi_t afi, safi_t safi,
                          struct attr *attr)
 {  {
  u_char type = 0;  size_t sizep;
   
  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_ORIGIN))) 
    type = BGP_ATTR_ORIGIN; 
   
  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_AS_PATH)))  /* Set extended bit always to encode the attribute length as 2 bytes */
    type = BGP_ATTR_AS_PATH;  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
   stream_putc (s, BGP_ATTR_MP_REACH_NLRI);
   sizep = stream_get_endp (s);
   stream_putw (s, 0);   /* Marker: Attribute length. */
   
  if (! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP)))  stream_putw (s, afi);
    type = BGP_ATTR_NEXT_HOP;  stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi);
   
  if (peer->sort == BGP_PEER_IBGP  /* Nexthop */
      && ! CHECK_FLAG (attr->flag, ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF)))  switch (afi)
    type = BGP_ATTR_LOCAL_PREF;    {
     case AFI_IP:
       switch (safi)
         {
         case SAFI_MULTICAST:
           stream_putc (s, 4);
           stream_put_ipv4 (s, attr->nexthop.s_addr);
           break;
         case SAFI_MPLS_VPN:
           stream_putc (s, 12);
           stream_putl (s, 0);   /* RD = 0, per RFC */
           stream_putl (s, 0);
           stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
           break;
         case SAFI_ENCAP:
           stream_putc (s, 4);
           stream_put (s, &attr->extra->mp_nexthop_global_in, 4);
           break;
         case SAFI_UNICAST:      /* invalid for IPv4 */
         default:
           break;
         }
       break;
     case AFI_IP6:
       switch (safi)
       {
       case SAFI_UNICAST:
       case SAFI_MULTICAST:
         {
           struct attr_extra *attre = attr->extra;
   
  if (type)          assert (attr->extra);
           stream_putc (s, attre->mp_nexthop_len);
           stream_put (s, &attre->mp_nexthop_global, 16);
           if (attre->mp_nexthop_len == 32)
             stream_put (s, &attre->mp_nexthop_local, 16);
         }
         break;
       case SAFI_MPLS_VPN:
         {
           struct attr_extra *attre = attr->extra;
 
           assert (attr->extra);
           if (attre->mp_nexthop_len == 16) {
             stream_putc (s, 24);
             stream_putl (s, 0);   /* RD = 0, per RFC */
             stream_putl (s, 0);
             stream_put (s, &attre->mp_nexthop_global, 16);
           } else if (attre->mp_nexthop_len == 32) {
             stream_putc (s, 48);
             stream_putl (s, 0);   /* RD = 0, per RFC */
             stream_putl (s, 0);
             stream_put (s, &attre->mp_nexthop_global, 16);
             stream_putl (s, 0);   /* RD = 0, per RFC */
             stream_putl (s, 0);
             stream_put (s, &attre->mp_nexthop_local, 16);
           }
         }
         break;
         case SAFI_ENCAP:
           assert (attr->extra);
           stream_putc (s, 16);
           stream_put (s, &attr->extra->mp_nexthop_global, 16);
           break;
       default:
         break;
       }
       break;
     default:
       break;
     }
 
   /* SNPA */
   stream_putc (s, 0);
   return sizep;
 }
 
 void
 bgp_packet_mpattr_prefix (struct stream *s, afi_t afi, safi_t safi,
                           struct prefix *p, struct prefix_rd *prd,
                           u_char *tag)
 {
   if (safi == SAFI_MPLS_VPN)
     {      {
      zlog (peer->log, LOG_WARNING,       /* Tag, RD, Prefix write. */
            "%s Missing well-known attribute %d.",      stream_putc (s, p->prefixlen + 88);
            peer->host, type);      stream_put (s, tag, 3);
      bgp_notify_send_with_data (peer,       stream_put (s, prd->val, 8);
                                 BGP_NOTIFY_UPDATE_ERR,       stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));
                                 BGP_NOTIFY_UPDATE_MISS_ATTR, 
                                 &type, 1); 
      return BGP_ATTR_PARSE_ERROR; 
     }      }
  return BGP_ATTR_PARSE_PROCEED;  else
     stream_put_prefix (s, p);
 }  }
   
 int stream_put_prefix (struct stream *, struct prefix *);  
   
   size_t
   bgp_packet_mpattr_prefix_size (afi_t afi, safi_t safi, struct prefix *p)
   {
     int size = PSIZE (p->prefixlen);
     if (safi == SAFI_MPLS_VPN)
         size += 88;
     return size;
   }
   
   /*
    * Encodes the tunnel encapsulation attribute
    */
   static void
   bgp_packet_mpattr_tea(
       struct bgp          *bgp,
       struct peer         *peer,
       struct stream       *s,
       struct attr         *attr,
       uint8_t             attrtype)
   {
       unsigned int                        attrlenfield = 0;
       unsigned int                        attrhdrlen   = 0;
       struct bgp_attr_encap_subtlv        *subtlvs;
       struct bgp_attr_encap_subtlv        *st;
       const char                          *attrname;
   
       if (!attr || !attr->extra)
           return;
   
       switch (attrtype) {
           case BGP_ATTR_ENCAP:
               attrname = "Tunnel Encap";
               subtlvs = attr->extra->encap_subtlvs;
   
               /*
                * The tunnel encap attr has an "outer" tlv.
                * T = tunneltype,
                * L = total length of subtlvs,
                * V = concatenated subtlvs.
                */
               attrlenfield = 2 + 2;       /* T + L */
               attrhdrlen   = 1 + 1;       /* subTLV T + L */
               break;
   
           default:
               assert(0);
       }
   
   
       /* if no tlvs, don't make attr */
       if (subtlvs == NULL)
           return;
   
       /* compute attr length */
       for (st = subtlvs; st; st = st->next) {
           attrlenfield += (attrhdrlen + st->length);
       }
   
       if (attrlenfield > 0xffff) {
           zlog (peer->log, LOG_ERR,
               "%s attribute is too long (length=%d), can't send it",
               attrname,
               attrlenfield);
           return;
       }
   
       if (attrlenfield > 0xff) {
           /* 2-octet length field */
           stream_putc (s,
               BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
           stream_putc (s, attrtype);
           stream_putw (s, attrlenfield & 0xffff);
       } else {
           /* 1-octet length field */
           stream_putc (s, BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL);
           stream_putc (s, attrtype);
           stream_putc (s, attrlenfield & 0xff);
       }
   
       if (attrtype == BGP_ATTR_ENCAP) {
           /* write outer T+L */
           stream_putw(s, attr->extra->encap_tunneltype);
           stream_putw(s, attrlenfield - 4);
       }
   
       /* write each sub-tlv */
       for (st = subtlvs; st; st = st->next) {
           if (attrtype == BGP_ATTR_ENCAP) {
               stream_putc (s, st->type);
               stream_putc (s, st->length);
           }
           stream_put (s, st->value, st->length);
       }
   }
   
   void
   bgp_packet_mpattr_end (struct stream *s, size_t sizep)
   {
     /* Set MP attribute length. Don't count the (2) bytes used to encode
        the attr length */
     stream_putw_at (s, sizep, (stream_get_endp (s) - sizep) - 2);
   }
   
 /* Make attribute packet. */  /* Make attribute packet. */
 bgp_size_t  bgp_size_t
 bgp_packet_attribute (struct bgp *bgp, struct peer *peer,  bgp_packet_attribute (struct bgp *bgp, struct peer *peer,
                      struct stream *s, struct attr *attr, struct prefix *p,                      struct stream *s, struct attr *attr,
                      afi_t afi, safi_t safi, struct peer *from,                      struct prefix *p, afi_t afi, safi_t safi,
                      struct prefix_rd *prd, u_char *tag)                      struct peer *from, struct prefix_rd *prd, u_char *tag)
 {  {
   size_t cp;    size_t cp;
   size_t aspath_sizep;    size_t aspath_sizep;
Line 2076  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2611  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
   /* Remember current pointer. */    /* Remember current pointer. */
   cp = stream_get_endp (s);    cp = stream_get_endp (s);
   
     if (p && !(afi == AFI_IP && safi == SAFI_UNICAST))
       {
         size_t mpattrlen_pos = 0;
         mpattrlen_pos = bgp_packet_mpattr_start(s, afi, safi, attr);
         bgp_packet_mpattr_prefix(s, afi, safi, p, prd, tag);
         bgp_packet_mpattr_end(s, mpattrlen_pos);
       }
   
   /* Origin attribute. */    /* Origin attribute. */
   stream_putc (s, BGP_ATTR_FLAG_TRANS);    stream_putc (s, BGP_ATTR_FLAG_TRANS);
   stream_putc (s, BGP_ATTR_ORIGIN);    stream_putc (s, BGP_ATTR_ORIGIN);
Line 2144  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2687  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
       send_as4_path = 1; /* we'll do this later, at the correct place */        send_as4_path = 1; /* we'll do this later, at the correct place */
       
   /* Nexthop attribute. */    /* Nexthop attribute. */
  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP)  if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_NEXT_HOP) && afi == AFI_IP &&
     safi ==  SAFI_UNICAST)   /* only write NH attr for unicast safi */
     {      {
       stream_putc (s, BGP_ATTR_FLAG_TRANS);        stream_putc (s, BGP_ATTR_FLAG_TRANS);
       stream_putc (s, BGP_ATTR_NEXT_HOP);        stream_putc (s, BGP_ATTR_NEXT_HOP);
Line 2284  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2828  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
         }          }
     }      }
   
 #ifdef HAVE_IPV6  
   /* If p is IPv6 address put it into attribute. */  
   if (p->family == AF_INET6)  
     {  
       unsigned long sizep;  
       struct attr_extra *attre = attr->extra;  
         
       assert (attr->extra);  
         
       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);  
       stream_putc (s, BGP_ATTR_MP_REACH_NLRI);  
       sizep = stream_get_endp (s);  
       stream_putc (s, 0);       /* Marker: Attribute length. */  
       stream_putw (s, AFI_IP6); /* AFI */  
       stream_putc (s, safi);    /* SAFI */  
   
       stream_putc (s, attre->mp_nexthop_len);  
   
       if (attre->mp_nexthop_len == 16)  
         stream_put (s, &attre->mp_nexthop_global, 16);  
       else if (attre->mp_nexthop_len == 32)  
         {  
           stream_put (s, &attre->mp_nexthop_global, 16);  
           stream_put (s, &attre->mp_nexthop_local, 16);  
         }  
         
       /* SNPA */  
       stream_putc (s, 0);  
   
       /* Prefix write. */  
       stream_put_prefix (s, p);  
   
       /* Set MP attribute length. */  
       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);  
     }  
 #endif /* HAVE_IPV6 */  
   
   if (p->family == AF_INET && safi == SAFI_MULTICAST)  
     {  
       unsigned long sizep;  
   
       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);  
       stream_putc (s, BGP_ATTR_MP_REACH_NLRI);  
       sizep = stream_get_endp (s);  
       stream_putc (s, 0);       /* Marker: Attribute Length. */  
       stream_putw (s, AFI_IP);  /* AFI */  
       stream_putc (s, SAFI_MULTICAST);  /* SAFI */  
   
       stream_putc (s, 4);  
       stream_put_ipv4 (s, attr->nexthop.s_addr);  
   
       /* SNPA */  
       stream_putc (s, 0);  
   
       /* Prefix write. */  
       stream_put_prefix (s, p);  
   
       /* Set MP attribute length. */  
       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);  
     }  
   
   if (p->family == AF_INET && safi == SAFI_MPLS_VPN)  
     {  
       unsigned long sizep;  
   
       stream_putc (s, BGP_ATTR_FLAG_OPTIONAL);  
       stream_putc (s, BGP_ATTR_MP_REACH_NLRI);  
       sizep = stream_get_endp (s);  
       stream_putc (s, 0);       /* Length of this attribute. */  
       stream_putw (s, AFI_IP);  /* AFI */  
       stream_putc (s, SAFI_MPLS_LABELED_VPN);   /* SAFI */  
   
       stream_putc (s, 12);  
       stream_putl (s, 0);  
       stream_putl (s, 0);  
       stream_put (s, &attr->extra->mp_nexthop_global_in, 4);  
   
       /* SNPA */  
       stream_putc (s, 0);  
   
       /* Tag, RD, Prefix write. */  
       stream_putc (s, p->prefixlen + 88);  
       stream_put (s, tag, 3);  
       stream_put (s, prd->val, 8);  
       stream_put (s, &p->u.prefix, PSIZE (p->prefixlen));  
   
       /* Set MP attribute length. */  
       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);  
     }  
   
   /* Extended Communities attribute. */    /* Extended Communities attribute. */
   if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY)     if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_SEND_EXT_COMMUNITY) 
       && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))        && (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES)))
Line 2486  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2940  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
       stream_putl (s, attr->extra->aggregator_as);        stream_putl (s, attr->extra->aggregator_as);
       stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);        stream_put_ipv4 (s, attr->extra->aggregator_addr.s_addr);
     }      }
  
   if ((afi == AFI_IP || afi == AFI_IP6) &&
       (safi == SAFI_ENCAP || safi == SAFI_MPLS_VPN))
     {
         /* Tunnel Encap attribute */
         bgp_packet_mpattr_tea(bgp, peer, s, attr, BGP_ATTR_ENCAP);
     }
 
   /* Unknown transit attribute. */    /* Unknown transit attribute. */
   if (attr->extra && attr->extra->transit)    if (attr->extra && attr->extra->transit)
     stream_put (s, attr->extra->transit->val, attr->extra->transit->length);      stream_put (s, attr->extra->transit->val, attr->extra->transit->length);
Line 2495  bgp_packet_attribute (struct bgp *bgp, struct peer *pe Line 2956  bgp_packet_attribute (struct bgp *bgp, struct peer *pe
   return stream_get_endp (s) - cp;    return stream_get_endp (s) - cp;
 }  }
   
bgp_size_tsize_t
bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,bgp_packet_mpunreach_start (struct stream *s, afi_t afi, safi_t safi)
                     afi_t afi, safi_t safi, struct prefix_rd *prd, 
                     u_char *tag) 
 {  {
   unsigned long cp;  
   unsigned long attrlen_pnt;    unsigned long attrlen_pnt;
   bgp_size_t size;  
   
  cp = stream_get_endp (s);  /* Set extended bit always to encode the attribute length as 2 bytes */
  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL|BGP_ATTR_FLAG_EXTLEN);
  stream_putc (s, BGP_ATTR_FLAG_OPTIONAL); 
   stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);    stream_putc (s, BGP_ATTR_MP_UNREACH_NLRI);
   
   attrlen_pnt = stream_get_endp (s);    attrlen_pnt = stream_get_endp (s);
  stream_putc (s, 0);                /* Length of this attribute. */  stream_putw (s, 0);                /* Length of this attribute. */
   
  stream_putw (s, family2afi (p->family));  stream_putw (s, afi);
   stream_putc (s, (safi == SAFI_MPLS_VPN) ? SAFI_MPLS_LABELED_VPN : safi);
   return attrlen_pnt;
 }
   
  if (safi == SAFI_MPLS_VPN)void
    {bgp_packet_mpunreach_prefix (struct stream *s, struct prefix *p,
      /* SAFI */                             afi_t afi, safi_t safi, struct prefix_rd *prd,
      stream_putc (s, SAFI_MPLS_LABELED_VPN);                             u_char *tag)
 {
   bgp_packet_mpattr_prefix (s, afi, safi, p, prd, tag);
 }
   
      /* prefix. */void
      stream_putc (s, p->prefixlen + 88);bgp_packet_mpunreach_end (struct stream *s, size_t attrlen_pnt)
      stream_put (s, tag, 3);{
      stream_put (s, prd->val, 8);  bgp_packet_mpattr_end (s, attrlen_pnt);
      stream_put (s, &p->u.prefix, PSIZE (p->prefixlen)); 
    } 
  else 
    { 
      /* SAFI */ 
      stream_putc (s, safi); 
 
      /* prefix */ 
      stream_put_prefix (s, p); 
    } 
 
  /* Set MP attribute length. */ 
  size = stream_get_endp (s) - attrlen_pnt - 1; 
  stream_putc_at (s, attrlen_pnt, size); 
 
  return stream_get_endp (s) - cp; 
 }  }
   
 /* Initialization of attribute. */  /* Initialization of attribute. */
Line 2598  bgp_dump_routes_attr (struct stream *s, struct attr *a Line 3044  bgp_dump_routes_attr (struct stream *s, struct attr *a
   /* Nexthop attribute. */    /* Nexthop attribute. */
   /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */    /* If it's an IPv6 prefix, don't dump the IPv4 nexthop to save space */
   if(prefix != NULL    if(prefix != NULL
 #ifdef HAVE_IPV6  
      && prefix->family != AF_INET6       && prefix->family != AF_INET6
 #endif /* HAVE_IPV6 */  
      )       )
     {      {
       stream_putc (s, BGP_ATTR_FLAG_TRANS);        stream_putc (s, BGP_ATTR_FLAG_TRANS);
Line 2664  bgp_dump_routes_attr (struct stream *s, struct attr *a Line 3108  bgp_dump_routes_attr (struct stream *s, struct attr *a
       stream_put (s, attr->community->val, attr->community->size * 4);        stream_put (s, attr->community->val, attr->community->size * 4);
     }      }
   
 #ifdef HAVE_IPV6  
   /* Add a MP_NLRI attribute to dump the IPv6 next hop */    /* Add a MP_NLRI attribute to dump the IPv6 next hop */
   if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&    if (prefix != NULL && prefix->family == AF_INET6 && attr->extra &&
      (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )       (attr->extra->mp_nexthop_len == 16 || attr->extra->mp_nexthop_len == 32) )
Line 2696  bgp_dump_routes_attr (struct stream *s, struct attr *a Line 3139  bgp_dump_routes_attr (struct stream *s, struct attr *a
       /* Set MP attribute length. */        /* Set MP attribute length. */
       stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);        stream_putc_at (s, sizep, (stream_get_endp (s) - sizep) - 1);
     }      }
 #endif /* HAVE_IPV6 */  
   
   /* Return total size of attribute. */    /* Return total size of attribute. */
   len = stream_get_endp (s) - cp - 2;    len = stream_get_endp (s) - cp - 2;

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


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