diff options
| author | Avneesh Sachdev <avneesh@opensourcerouting.org> | 2012-04-11 23:51:08 -0700 | 
|---|---|---|
| committer | Avneesh Sachdev <avneesh@opensourcerouting.org> | 2012-04-11 23:51:08 -0700 | 
| commit | 14d2bbaa3f4aa53152472694c29f336808e47313 (patch) | |
| tree | e39bdddef4ea53207dd8fb61e1fd6b54d8c7721d /bgpd | |
| parent | 51d4ef832c1e58150325630e25c442866e5a6cf5 (diff) | |
| parent | e96b312150d8e376c1ef463793d1929eca3618d5 (diff) | |
Merge quagga mainline into the google ISIS code.
The steps were:
  $ git checkout google-is-is
  $ git merge quagga
  $ git checkout google-is-is -- isisd
  # Resolve conflicts in the following:
  lib/md5.h
  zebra/rt_netlink.c
  zebra/zebra_rib.c
  zebra/zserv.c
Note that the content in the isisd directory is left unchanged in the
merge. As a result, changes made to isisd as part of the following
commits on the quagga mainline are dropped.
  # 8ced4e82 is the merge base, e96b3121 is the current quagga master
  $ git log --oneline --reverse 8ced4e82..e96b3121 -- isisd
  5574999 isisd: fix crash on "no router isis" (BZ#536)
  8998075 isisd: raise hello rate for DIS (BZ#539)
  306ca83 isisd: include hash.h, not hash.c
  b82cdeb delete CVS keywords
  2f65867 isisd: indent longopts array
  b511468 quagga: option "-z" ("--socket <path>") added
  05e54ee build: delete .cvsignore files
  b4e45f6 fix zebra protocol after MP-BGP changes
  7fd6cd8 isisd: fix circuit state machine
  907fd95 isisd: send proper LSP after DIS election
  d034aa0 isisd: fix wrong next-hops from SPF
  c25eaff isisd: unexpected kernel routing table (BZ#544)
  e6b03b7 isisd: implement MD5 circuit authentication
Diffstat (limited to 'bgpd')
| -rw-r--r-- | bgpd/.cvsignore | 15 | ||||
| -rw-r--r-- | bgpd/bgp_advertise.c | 10 | ||||
| -rw-r--r-- | bgpd/bgp_aspath.c | 160 | ||||
| -rw-r--r-- | bgpd/bgp_aspath.h | 4 | ||||
| -rw-r--r-- | bgpd/bgp_attr.c | 1010 | ||||
| -rw-r--r-- | bgpd/bgp_attr.h | 30 | ||||
| -rw-r--r-- | bgpd/bgp_clist.c | 4 | ||||
| -rw-r--r-- | bgpd/bgp_community.c | 13 | ||||
| -rw-r--r-- | bgpd/bgp_community.h | 2 | ||||
| -rw-r--r-- | bgpd/bgp_debug.c | 4 | ||||
| -rw-r--r-- | bgpd/bgp_ecommunity.c | 47 | ||||
| -rw-r--r-- | bgpd/bgp_ecommunity.h | 4 | ||||
| -rw-r--r-- | bgpd/bgp_fsm.c | 8 | ||||
| -rw-r--r-- | bgpd/bgp_main.c | 9 | ||||
| -rw-r--r-- | bgpd/bgp_mplsvpn.c | 8 | ||||
| -rw-r--r-- | bgpd/bgp_network.c | 94 | ||||
| -rw-r--r-- | bgpd/bgp_nexthop.c | 146 | ||||
| -rw-r--r-- | bgpd/bgp_nexthop.h | 2 | ||||
| -rw-r--r-- | bgpd/bgp_open.c | 40 | ||||
| -rw-r--r-- | bgpd/bgp_packet.c | 127 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 122 | ||||
| -rw-r--r-- | bgpd/bgp_route.h | 4 | ||||
| -rw-r--r-- | bgpd/bgp_routemap.c | 153 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 281 | ||||
| -rw-r--r-- | bgpd/bgp_zebra.c | 43 | ||||
| -rw-r--r-- | bgpd/bgp_zebra.h | 4 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 18 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 9 | 
28 files changed, 1357 insertions, 1014 deletions
| diff --git a/bgpd/.cvsignore b/bgpd/.cvsignore deleted file mode 100644 index f4504f62..00000000 --- a/bgpd/.cvsignore +++ /dev/null @@ -1,15 +0,0 @@ -Makefile -Makefile.in -*.o -bgpd -bgp_btoa -bgpd.conf -tags -TAGS -.deps -.nfs* -*.lo -*.la -*.libs -.arch-inventory -.arch-ids diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c index 87eb7ac7..666218fa 100644 --- a/bgpd/bgp_advertise.c +++ b/bgpd/bgp_advertise.c @@ -140,13 +140,13 @@ bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa)      baa->refcnt--;    if (baa->refcnt && baa->attr) -    bgp_attr_unintern (baa->attr); +    bgp_attr_unintern (&baa->attr);    else      {        if (baa->attr)  	{  	  hash_release (hash, baa); -	  bgp_attr_unintern (baa->attr); +	  bgp_attr_unintern (&baa->attr);  	}        baa_free (baa);      } @@ -319,7 +319,7 @@ bgp_adj_out_remove (struct bgp_node *rn, struct bgp_adj_out *adj,  		    struct peer *peer, afi_t afi, safi_t safi)  {    if (adj->attr) -    bgp_attr_unintern (adj->attr); +    bgp_attr_unintern (&adj->attr);    if (adj->adv)      bgp_advertise_clean (peer, adj, afi, safi); @@ -339,7 +339,7 @@ bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr)  	{  	  if (adj->attr != attr)  	    { -	      bgp_attr_unintern (adj->attr); +	      bgp_attr_unintern (&adj->attr);  	      adj->attr = bgp_attr_intern (attr);  	    }  	  return; @@ -355,7 +355,7 @@ bgp_adj_in_set (struct bgp_node *rn, struct peer *peer, struct attr *attr)  void  bgp_adj_in_remove (struct bgp_node *rn, struct bgp_adj_in *bai)  { -  bgp_attr_unintern (bai->attr); +  bgp_attr_unintern (&bai->attr);    BGP_ADJ_IN_DEL (rn, bai);    peer_unlock (bai->peer); /* adj_in peer reference */    XFREE (MTYPE_BGP_ADJ_IN, bai); diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index cf930427..776c7127 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -91,13 +91,13 @@ static struct hash *ashash;  /* Stream for SNMP. See aspath_snmp_pathseg */  static struct stream *snmp_stream; -static inline as_t * +static as_t *  assegment_data_new (int num)  {    return (XCALLOC (MTYPE_AS_SEG_DATA, ASSEGMENT_DATA_SIZE (num, 1)));  } -static inline void +static void  assegment_data_free (as_t *asdata)  {    XFREE (MTYPE_AS_SEG_DATA,asdata); @@ -340,19 +340,21 @@ aspath_free (struct aspath *aspath)  /* Unintern aspath from AS path bucket. */  void -aspath_unintern (struct aspath *aspath) +aspath_unintern (struct aspath **aspath)  {    struct aspath *ret; +  struct aspath *asp = *aspath; +   +  if (asp->refcnt) +    asp->refcnt--; -  if (aspath->refcnt) -    aspath->refcnt--; - -  if (aspath->refcnt == 0) +  if (asp->refcnt == 0)      {        /* This aspath must exist in aspath hash table. */ -      ret = hash_release (ashash, aspath); +      ret = hash_release (ashash, asp);        assert (ret != NULL); -      aspath_free (aspath); +      aspath_free (asp); +      *aspath = NULL;      }  } @@ -671,80 +673,79 @@ aspath_hash_alloc (void *arg)    return aspath;  } -/* parse as-segment byte stream in struct assegment - * - * Returns NULL if the AS_PATH or AS4_PATH is not valid. - */ -static struct assegment * -assegments_parse (struct stream *s, size_t length, int use32bit, int as4_path) +/* parse as-segment byte stream in struct assegment */ +static int +assegments_parse (struct stream *s, size_t length,  +                  struct assegment **result, int use32bit)  {    struct assegment_header segh;    struct assegment *seg, *prev = NULL, *head = NULL; +  size_t bytes = 0; -  assert (length > 0);  /* does not expect empty AS_PATH or AS4_PATH    */ +  /* empty aspath (ie iBGP or somesuch) */ +  if (length == 0) +    return 0;    if (BGP_DEBUG (as4, AS4_SEGMENT))      zlog_debug ("[AS4SEG] Parse aspath segment: got total byte length %lu",  		(unsigned long) length); - -  /* double check that length does not exceed stream    */ -  if (STREAM_READABLE(s) < length) -    return NULL; +  /* basic checks */ +  if ((STREAM_READABLE(s) < length) +      || (STREAM_READABLE(s) < AS_HEADER_SIZE)  +      || (length % AS16_VALUE_SIZE )) +    return -1; -  /* deal with each segment in turn                             */ -  while (length > 0) +  while (bytes < length)      {        int i;        size_t seg_size; -      /* softly softly, get the header first on its own */ -      if (length < AS_HEADER_SIZE) +      if ((length - bytes) <= AS_HEADER_SIZE)          { -          assegment_free_all (head); -          return NULL; +          if (head) +            assegment_free_all (head); +          return -1;          } +      /* softly softly, get the header first on its own */        segh.type = stream_getc (s);        segh.length = stream_getc (s);        seg_size = ASSEGMENT_SIZE(segh.length, use32bit); -                                      /* includes the header bytes */        if (BGP_DEBUG (as4, AS4_SEGMENT))  	zlog_debug ("[AS4SEG] Parse aspath segment: got type %d, length %d",                      segh.type, segh.length); +      /* check it.. */ +      if ( ((bytes + seg_size) > length) +          /* 1771bis 4.3b: seg length contains one or more */ +          || (segh.length == 0)  +          /* Paranoia in case someone changes type of segment length. +           * Shift both values by 0x10 to make the comparison operate +           * on more, than 8 bits (otherwise it's a warning, bug #564). +           */ +          || ((sizeof segh.length > 1)  +              && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX))) +        { +          if (head) +            assegment_free_all (head); +          return -1; +        } +              switch (segh.type)          {            case AS_SEQUENCE:            case AS_SET: -            break ; -            case AS_CONFED_SEQUENCE:            case AS_CONFED_SET: -            if (!as4_path) -              break ; -              /* RFC4893 3: "invalid for the AS4_PATH attribute"            */ -              /* fall through */ - -          default:    /* reject unknown or invalid AS_PATH segment types  */ -            seg_size = 0 ; -        } -      -     /* Stop now if segment is not valid (discarding anything collected to date) -      * -      * RFC4271 4.3, Path Attributes, b) AS_PATH: -      * -      *   "path segment value field contains one or more AS numbers" -           */ -      if ((seg_size == 0) || (seg_size > length) || (segh.length == 0)) -        { -          assegment_free_all (head); -          return NULL; +            break; +          default: +            if (head) +              assegment_free_all (head); +            return -1;          } -      length -= seg_size ; -              /* now its safe to trust lengths */        seg = assegment_new (segh.type, segh.length); @@ -756,52 +757,47 @@ assegments_parse (struct stream *s, size_t length, int use32bit, int as4_path)        for (i = 0; i < segh.length; i++)  	seg->as[i] = (use32bit) ? stream_getl (s) : stream_getw (s); +      bytes += seg_size; +              if (BGP_DEBUG (as4, AS4_SEGMENT)) -	zlog_debug ("[AS4SEG] Parse aspath segment: length left: %lu", -	            (unsigned long) length); +	zlog_debug ("[AS4SEG] Parse aspath segment: Bytes now: %lu", +	            (unsigned long) bytes);        prev = seg;      } -  return assegment_normalise (head); +  *result = assegment_normalise (head); +  return 0;  } -/* AS path parse function -- parses AS_PATH and AS4_PATH attributes - * - * Requires: s        -- stream, currently positioned before first segment - *                       of AS_PATH or AS4_PATH (ie after attribute header) - *           length   -- length of the value of the AS_PATH or AS4_PATH - *           use32bit -- true <=> 4Byte ASN, otherwise 2Byte ASN - *           as4_path -- true <=> AS4_PATH, otherwise AS_PATH - * - * Returns: if valid: address of struct aspath in the hash of known aspaths, - *                    with reference count incremented. - *              else: NULL - * - * NB: empty AS path (length == 0) is valid.  The returned struct aspath will - *     have segments == NULL and str == zero length string (unique). +/* AS path parse function.  pnt is a pointer to byte stream and length +   is length of byte stream.  If there is same AS path in the the AS +   path hash then return it else make new AS path structure.  +    +   On error NULL is returned.   */  struct aspath * -aspath_parse (struct stream *s, size_t length, int use32bit, int as4_path) +aspath_parse (struct stream *s, size_t length, int use32bit)  {    struct aspath as;    struct aspath *find; -  /* Parse each segment and construct normalised list of struct assegment */ -  memset (&as, 0, sizeof (struct aspath)); -  if (length != 0) -    { -      as.segments = assegments_parse (s, length, use32bit, as4_path); +  /* If length is odd it's malformed AS path. */ +  /* Nit-picking: if (use32bit == 0) it is malformed if odd, +   * otherwise its malformed when length is larger than 2 and (length-2)  +   * is not dividable by 4. +   * But... this time we're lazy +   */ +  if (length % AS16_VALUE_SIZE ) +    return NULL; -      if (as.segments == NULL) -        return NULL ;   /* Invalid AS_PATH or AS4_PATH  */ -    } ; +  memset (&as, 0, sizeof (struct aspath)); +  if (assegments_parse (s, length, &as.segments, use32bit) < 0) +    return NULL;    /* If already same aspath exist then return it. */    find = hash_get (ashash, &as, aspath_hash_alloc); -  assert(find) ;        /* valid aspath, so must find or create */ -      /* aspath_hash_alloc dupes segments too. that probably could be     * optimised out.     */ @@ -809,12 +805,14 @@ aspath_parse (struct stream *s, size_t length, int use32bit, int as4_path)    if (as.str)      XFREE (MTYPE_AS_STR, as.str); +  if (! find) +    return NULL;    find->refcnt++;    return find;  } -static inline void +static void  assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)  {    int i; @@ -832,7 +830,7 @@ assegment_data_put (struct stream *s, as_t *as, int num, int use32bit)        }  } -static inline size_t +static size_t  assegment_header_put (struct stream *s, u_char type, int length)  {    size_t lenp; @@ -1632,7 +1630,7 @@ aspath_segment_add (struct aspath *as, int type)  struct aspath *  aspath_empty (void)  { -  return aspath_parse (NULL, 0, 1, 0); /* 32Bit ;-) not AS4_PATH */ +  return aspath_parse (NULL, 0, 1); /* 32Bit ;-) */  }  struct aspath * diff --git a/bgpd/bgp_aspath.h b/bgpd/bgp_aspath.h index d63b914c..d55f9ce6 100644 --- a/bgpd/bgp_aspath.h +++ b/bgpd/bgp_aspath.h @@ -65,7 +65,7 @@ struct aspath  /* Prototypes. */  extern void aspath_init (void);  extern void aspath_finish (void); -extern struct aspath *aspath_parse (struct stream *, size_t, int, int); +extern struct aspath *aspath_parse (struct stream *, size_t, int);  extern struct aspath *aspath_dup (struct aspath *);  extern struct aspath *aspath_aggregate (struct aspath *, struct aspath *);  extern struct aspath *aspath_prepend (struct aspath *, struct aspath *); @@ -80,7 +80,7 @@ extern struct aspath *aspath_empty_get (void);  extern struct aspath *aspath_str2aspath (const char *);  extern void aspath_free (struct aspath *);  extern struct aspath *aspath_intern (struct aspath *); -extern void aspath_unintern (struct aspath *); +extern void aspath_unintern (struct aspath **);  extern const char *aspath_print (struct aspath *);  extern void aspath_print_vty (struct vty *, const char *, struct aspath *, const char *);  extern void aspath_print_all_vty (struct vty *); diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 01598c87..0d82aba0 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -51,7 +51,7 @@ static const struct message attr_str [] =    { BGP_ATTR_AGGREGATOR,       "AGGREGATOR" },     { BGP_ATTR_COMMUNITIES,      "COMMUNITY" },     { BGP_ATTR_ORIGINATOR_ID,    "ORIGINATOR_ID" }, -  { BGP_ATTR_CLUSTER_LIST,     "CLUSTERLIST" },  +  { BGP_ATTR_CLUSTER_LIST,     "CLUSTER_LIST" },     { BGP_ATTR_DPA,              "DPA" },    { BGP_ATTR_ADVERTISER,       "ADVERTISER"} ,    { BGP_ATTR_RCID_PATH,        "RCID_PATH" }, @@ -63,6 +63,17 @@ static const struct message attr_str [] =    { BGP_ATTR_AS_PATHLIMIT,     "AS_PATHLIMIT" },  };  static const int attr_str_max = sizeof(attr_str)/sizeof(attr_str[0]); + +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 = +  sizeof (attr_flag_str) / sizeof (attr_flag_str[0]);  static struct hash *cluster_hash; @@ -175,14 +186,12 @@ cluster_intern (struct cluster_list *cluster)  void  cluster_unintern (struct cluster_list *cluster)  { -  struct cluster_list *ret; -    if (cluster->refcnt)      cluster->refcnt--;    if (cluster->refcnt == 0)      { -      ret = hash_release (cluster_hash, cluster); +      hash_release (cluster_hash, cluster);        cluster_free (cluster);      }  } @@ -235,14 +244,12 @@ transit_intern (struct transit *transit)  void  transit_unintern (struct transit *transit)  { -  struct transit *ret; -    if (transit->refcnt)      transit->refcnt--;    if (transit->refcnt == 0)      { -      ret = hash_release (transit_hash, transit); +      hash_release (transit_hash, transit);        transit_free (transit);      }  } @@ -500,6 +507,7 @@ bgp_attr_intern (struct attr *attr)              attre->ecommunity = ecommunity_intern (attre->ecommunity);            else              attre->ecommunity->refcnt++; +                    }        if (attre->cluster)          { @@ -516,10 +524,10 @@ bgp_attr_intern (struct attr *attr)              attre->transit->refcnt++;          }      } - +      find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);    find->refcnt++; - +      return find;  } @@ -551,17 +559,16 @@ bgp_attr_default_intern (u_char origin)  {    struct attr attr;    struct attr *new; -  struct attr_extra *attre;    memset (&attr, 0, sizeof (struct attr)); -  attre = bgp_attr_extra_get (&attr); +  bgp_attr_extra_get (&attr);    bgp_attr_default_set(&attr, origin);    new = bgp_attr_intern (&attr);    bgp_attr_extra_free (&attr); -  aspath_unintern (new->aspath); +  aspath_unintern (&new->aspath);    return new;  } @@ -613,52 +620,68 @@ bgp_attr_aggregate_intern (struct bgp *bgp, u_char origin,    new = bgp_attr_intern (&attr);    bgp_attr_extra_free (&attr); -  aspath_unintern (new->aspath); +  aspath_unintern (&new->aspath);    return new;  } +/* Unintern just the sub-components of the attr, but not the attr */ +void +bgp_attr_unintern_sub (struct attr *attr) +{ +  /* aspath refcount shoud be decrement. */ +  if (attr->aspath) +    aspath_unintern (&attr->aspath); +  UNSET_FLAG(attr->flag, BGP_ATTR_AS_PATH); +   +  if (attr->community) +    community_unintern (&attr->community); +  UNSET_FLAG(attr->flag, BGP_ATTR_COMMUNITIES); +   +  if (attr->extra) +    { +      if (attr->extra->ecommunity) +        ecommunity_unintern (&attr->extra->ecommunity); +      UNSET_FLAG(attr->flag, BGP_ATTR_EXT_COMMUNITIES); +       +      if (attr->extra->cluster) +        cluster_unintern (attr->extra->cluster); +      UNSET_FLAG(attr->flag, BGP_ATTR_CLUSTER_LIST); +       +      if (attr->extra->transit) +        transit_unintern (attr->extra->transit); +    } +} +  /* Free bgp attribute and aspath. */  void -bgp_attr_unintern (struct attr *attr) +bgp_attr_unintern (struct attr **attr)  {    struct attr *ret; -  struct aspath *aspath; -  struct community *community; -  struct ecommunity *ecommunity = NULL; -  struct cluster_list *cluster = NULL; -  struct transit *transit = NULL; - +  struct attr tmp; +      /* Decrement attribute reference. */ -  attr->refcnt--; -  aspath = attr->aspath; -  community = attr->community; -  if (attr->extra) +  (*attr)->refcnt--; +   +  tmp = *(*attr); +   +  if ((*attr)->extra)      { -      ecommunity = attr->extra->ecommunity; -      cluster = attr->extra->cluster; -      transit = attr->extra->transit; +      tmp.extra = bgp_attr_extra_new (); +      memcpy (tmp.extra, (*attr)->extra, sizeof (struct attr_extra));      } - +      /* 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); -      bgp_attr_extra_free (attr); -      XFREE (MTYPE_ATTR, attr); +      bgp_attr_extra_free (*attr); +      XFREE (MTYPE_ATTR, *attr); +      *attr = NULL;      } -  /* aspath refcount shoud be decrement. */ -  if (aspath) -    aspath_unintern (aspath); -  if (community) -    community_unintern (community); -  if (ecommunity) -    ecommunity_unintern (ecommunity); -  if (cluster) -    cluster_unintern (cluster); -  if (transit) -    transit_unintern (transit); +  bgp_attr_unintern_sub (&tmp); +  bgp_attr_extra_free (&tmp);  }  void @@ -671,8 +694,9 @@ bgp_attr_flush (struct attr *attr)    if (attr->extra)      {        struct attr_extra *attre = attr->extra; +        if (attre->ecommunity && ! attre->ecommunity->refcnt) -        ecommunity_free (attre->ecommunity); +        ecommunity_free (&attre->ecommunity);        if (attre->cluster && ! attre->cluster->refcnt)          cluster_free (attre->cluster);        if (attre->transit && ! attre->transit->refcnt) @@ -680,32 +704,217 @@ bgp_attr_flush (struct attr *attr)      }  } -/* Get origin attribute of the update message. */ -static int -bgp_attr_origin (struct peer *peer, bgp_size_t length,  -		 struct attr *attr, u_char flag, u_char *startp) +/* Implement draft-scudder-idr-optional-transitive behaviour and + * avoid resetting sessions for malformed attributes which are + * are partial/optional and hence where the error likely was not + * introduced by the sending neighbour. + */ +static bgp_attr_parse_ret_t +bgp_attr_malformed (struct bgp_attr_parser_args *args, u_char subcode, +                    bgp_size_t length)  { -  bgp_size_t total; +  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 */ +  if (peer_sort (peer) != BGP_PEER_EBGP) +    { +      bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, +                                 notify_datap, length); +      return BGP_ATTR_PARSE_ERROR; + +    } +   +  /* Adjust the stream getp to the end of the attribute, in case we can +   * still proceed but the caller hasn't read all the attribute. +   */ +  stream_set_getp (BGP_INPUT (peer), +                   (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_AGGREGATOR: +    case BGP_ATTR_ATOMIC_AGGREGATE: +      return BGP_ATTR_PARSE_PROCEED; +     +    /* Core attributes, particularly ones which may influence route +     * selection, should always cause session resets +     */ +    case BGP_ATTR_ORIGIN: +    case BGP_ATTR_AS_PATH: +    case BGP_ATTR_NEXT_HOP: +    case BGP_ATTR_MULTI_EXIT_DISC: +    case BGP_ATTR_LOCAL_PREF: +    case BGP_ATTR_COMMUNITIES: +    case BGP_ATTR_ORIGINATOR_ID: +    case BGP_ATTR_CLUSTER_LIST: +    case BGP_ATTR_MP_REACH_NLRI: +    case BGP_ATTR_MP_UNREACH_NLRI: +    case BGP_ATTR_EXT_COMMUNITIES: +      bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, subcode, +                                 notify_datap, length); +      return BGP_ATTR_PARSE_ERROR; +  } +   +  /* Partial optional attributes that are malformed should not cause +   * the whole session to be reset. Instead treat it as a withdrawal +   * of the routes, if possible. +   */ +  if (CHECK_FLAG (flags, BGP_ATTR_FLAG_TRANS) +      && CHECK_FLAG (flags, BGP_ATTR_FLAG_OPTIONAL) +      && CHECK_FLAG (flags, BGP_ATTR_FLAG_PARTIAL)) +    return BGP_ATTR_PARSE_WITHDRAW; +   +  /* default to reset */ +  return BGP_ATTR_PARSE_ERROR; +} + +/* Find out what is wrong with the path attribute flag bits and log the error. +   "Flag bits" here stand for Optional, Transitive and Partial, but not for +   Extended Length. Checking O/T/P bits at once implies, that the attribute +   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 */ +) +{ +  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), -     Attribute Type code (1) and Attribute length (1 or 2).  */ -  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); +/* Required flags for attributes. EXTLEN will be masked off when testing, + * as will PARTIAL for optional+transitive attributes. + */ +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 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 (flag != BGP_ATTR_FLAG_TRANS) +static int +bgp_attr_flag_invalid (struct bgp_attr_parser_args *args) +{ +  u_int8_t mask = BGP_ATTR_FLAG_EXTLEN; +  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,  -	    "Origin attribute flag isn't transitive %d", flag); -      bgp_notify_send_with_data (peer,  -				 BGP_NOTIFY_UPDATE_ERR,  -				 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, -				 startp, total); -      return -1; +      zlog (peer->log, LOG_ERR, +            "%s well-known attributes must have transitive flag set (%x)", +            LOOKUP (attr_str, attr_code), flags); +      return 1;      } +   +  /* "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       with the expected length (based on the attribute type code), then       the Error Subcode is set to Attribute Length Error.  The Data @@ -715,10 +924,9 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length,      {        zlog (peer->log, LOG_ERR, "Origin attribute length is not one %d",  	    length); -      bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR,  -				 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, -				 startp, total); -      return -1; +      return bgp_attr_malformed (args, +                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +                                 args->total);      }    /* Fetch origin attribute. */ @@ -733,12 +941,9 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length,      {        zlog (peer->log, LOG_ERR, "Origin attribute value is invalid %d",  	      attr->origin); - -      bgp_notify_send_with_data (peer,  -				 BGP_NOTIFY_UPDATE_ERR,  -				 BGP_NOTIFY_UPDATE_INVAL_ORIGIN, -				 startp, total); -      return -1; +      return bgp_attr_malformed (args, +                                 BGP_NOTIFY_UPDATE_INVAL_ORIGIN, +                                 args->total);      }    /* Set oring attribute flag. */ @@ -746,82 +951,40 @@ bgp_attr_origin (struct peer *peer, bgp_size_t length,    return 0;  } -/* Parse AS path information.  This function is wrapper of aspath_parse. - * - * Parses AS_PATH or AS4_PATH. - * - * Returns: if valid: address of struct aspath in the hash of known aspaths, - *                    with reference count incremented. - *              else: NULL - * - * NB: empty AS path (length == 0) is valid.  The returned struct aspath will - *     have segments == NULL and str == zero length string (unique). - */ -static struct aspath * -bgp_attr_aspath (struct peer *peer, bgp_size_t length,  -		 struct attr *attr, u_char flag, u_char *startp, int as4_path) -{ -  u_char require ; -  struct aspath *asp ; - -  /* Check the attribute flags                                          */ -  require = as4_path ? BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS -                     :                          BGP_ATTR_FLAG_TRANS ; - -  if ((flag & (BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS)) != require) -    { -      const char* path_type ; -      bgp_size_t total; - -      path_type = as4_path ? "AS4_PATH" : "AS_PATH" ; - -      if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS)) -      zlog (peer->log, LOG_ERR,  -            "%s attribute flag isn't transitive %d", path_type, flag) ; -      if ((flag & BGP_ATTR_FLAG_OPTIONAL) != (require & BGP_ATTR_FLAG_OPTIONAL)) -        zlog (peer->log, LOG_ERR, -            "%s attribute flag must %sbe optional %d", path_type, -            (flag & BGP_ATTR_FLAG_OPTIONAL) ? "not " : "", flag) ; - -      total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - -      bgp_notify_send_with_data (peer,  -				 BGP_NOTIFY_UPDATE_ERR,  -				 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, -				 startp, total); - -      return NULL ; -    } ; - -  /* Parse the AS_PATH/AS4_PATH body. -   * -   * For AS_PATH  peer with AS4 => 4Byte ASN otherwise 2Byte ASN -   *     AS4_PATH 4Byte ASN +/* Parse AS path information.  This function is wrapper of +   aspath_parse. */ +static int +bgp_attr_aspath (struct bgp_attr_parser_args *args) +{ +  struct attr *const attr = args->attr; +  struct peer *const peer = args->peer;  +  const bgp_size_t length = args->length; +   +  /* +   * peer with AS4 => will get 4Byte ASnums +   * otherwise, will get 16 Bit     */ -  asp = aspath_parse (peer->ibuf, length, -               as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ; +  attr->aspath = aspath_parse (peer->ibuf, length,  +                               CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV)); -  if (asp != NULL) +  /* In case of IBGP, length will be zero. */ +  if (! attr->aspath)      { -      attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH -                                            : BGP_ATTR_AS_PATH) ; +      zlog (peer->log, LOG_ERR, +            "Malformed AS path from %s, length is %d", +            peer->host, length); +      return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, 0);      } -  else -    { -      zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length); -      /* TODO: should BGP_NOTIFY_UPDATE_MAL_AS_PATH be sent for AS4_PATH ??  */ -      bgp_notify_send (peer,  -		       BGP_NOTIFY_UPDATE_ERR,  -		       BGP_NOTIFY_UPDATE_MAL_AS_PATH); -    } ; +  /* Set aspath attribute flag. */ +  attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS_PATH); -  return asp ; +  return BGP_ATTR_PARSE_PROCEED;  } -static int bgp_attr_aspath_check( struct peer *peer,  -		struct attr *attr) +static bgp_attr_parse_ret_t +bgp_attr_aspath_check (struct peer *const peer, struct attr *const attr)  {    /* These checks were part of bgp_attr_aspath, but with     * as4 we should to check aspath things when @@ -840,10 +1003,9 @@ static int bgp_attr_aspath_check( struct peer *peer,       (peer_sort (peer) == BGP_PEER_EBGP && aspath_confed_check (attr->aspath)))      {        zlog (peer->log, LOG_ERR, "Malformed AS path from %s", peer->host); -      bgp_notify_send (peer,  -		       BGP_NOTIFY_UPDATE_ERR,  -		       BGP_NOTIFY_UPDATE_MAL_AS_PATH); -      return -1; +      bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, +                       BGP_NOTIFY_UPDATE_MAL_AS_PATH); +      return BGP_ATTR_PARSE_ERROR;      }    /* First AS check for EBGP. */ @@ -854,10 +1016,9 @@ static int bgp_attr_aspath_check( struct peer *peer,   	{   	  zlog (peer->log, LOG_ERR,   		"%s incorrect first AS (must be %u)", peer->host, peer->as); - 	  bgp_notify_send (peer, - 			   BGP_NOTIFY_UPDATE_ERR, - 			   BGP_NOTIFY_UPDATE_MAL_AS_PATH); -	  return -1; +          bgp_notify_send (peer, BGP_NOTIFY_UPDATE_ERR, +                           BGP_NOTIFY_UPDATE_MAL_AS_PATH); +          return BGP_ATTR_PARSE_ERROR;   	}      } @@ -867,150 +1028,193 @@ static int bgp_attr_aspath_check( struct peer *peer,      {        aspath = aspath_dup (attr->aspath);        aspath = aspath_add_seq (aspath, peer->change_local_as); -      aspath_unintern (attr->aspath); +      aspath_unintern (&attr->aspath);        attr->aspath = aspath_intern (aspath);      } -  return 0; - +  return BGP_ATTR_PARSE_PROCEED;  } -/* Nexthop attribute. */ +/* Parse AS4 path information.  This function is another wrapper of +   aspath_parse. */  static int -bgp_attr_nexthop (struct peer *peer, bgp_size_t length,  -		  struct attr *attr, u_char flag, u_char *startp) +bgp_attr_as4_path (struct bgp_attr_parser_args *args, struct aspath **as4_path)  { -  bgp_size_t total; - -  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); +  struct peer *const peer = args->peer;  +  struct attr *const attr = args->attr; +  const bgp_size_t length = args->length; +   +  *as4_path = aspath_parse (peer->ibuf, length, 1); -  /* Flag check. */ -  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL) -      || ! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) +  /* In case of IBGP, length will be zero. */ +  if (!*as4_path)      { -      zlog (peer->log, LOG_ERR,  -	    "Origin attribute flag isn't transitive %d", flag); -      bgp_notify_send_with_data (peer,  -				 BGP_NOTIFY_UPDATE_ERR,  -				 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, -				 startp, total); -      return -1; +      zlog (peer->log, LOG_ERR, +            "Malformed AS4 path from %s, length is %d", +            peer->host, length); +      return bgp_attr_malformed (args, +                                 BGP_NOTIFY_UPDATE_MAL_AS_PATH, +                                 0);      } +  /* Set aspath attribute flag. */ +  if (as4_path) +    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_PATH); + +  return BGP_ATTR_PARSE_PROCEED; +} + +/* Nexthop attribute. */ +static bgp_attr_parse_ret_t +bgp_attr_nexthop (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; +   +  in_addr_t nexthop_h, nexthop_n; +    /* Check nexthop attribute length. */    if (length != 4)      {        zlog (peer->log, LOG_ERR, "Nexthop attribute length isn't four [%d]",  	      length); -      bgp_notify_send_with_data (peer,  -				 BGP_NOTIFY_UPDATE_ERR,  -				 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, -				 startp, total); -      return -1; +      return bgp_attr_malformed (args, +                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +                                 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); -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* MED atrribute. */ -static int -bgp_attr_med (struct peer *peer, bgp_size_t length,  -	      struct attr *attr, u_char flag, u_char *startp) +static bgp_attr_parse_ret_t +bgp_attr_med (struct bgp_attr_parser_args *args)  { -  bgp_size_t total; - -  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3); - +  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,   	    "MED attribute length isn't four [%d]", length); -       -      bgp_notify_send_with_data (peer,  -				 BGP_NOTIFY_UPDATE_ERR,  -				 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, -				 startp, total); -      return -1; + +      return bgp_attr_malformed (args, +                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +                                 args->total);      }    attr->med = stream_getl (peer->ibuf);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* Local preference attribute. */ -static int -bgp_attr_local_pref (struct peer *peer, bgp_size_t length,  -		     struct attr *attr, u_char flag) +static bgp_attr_parse_ret_t +bgp_attr_local_pref (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; +   +  /* 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); +  } +    /* If it is contained in an UPDATE message that is received from an       external peer, then this attribute MUST be ignored by the       receiving speaker. */    if (peer_sort (peer) == BGP_PEER_EBGP)      {        stream_forward_getp (peer->ibuf, length); -      return 0; +      return BGP_ATTR_PARSE_PROCEED;      } -  if (length == 4)  -    attr->local_pref = stream_getl (peer->ibuf); -  else  -    attr->local_pref = 0; +  attr->local_pref = stream_getl (peer->ibuf);    /* Set atomic aggregate flag. */    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF); -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* Atomic aggregate. */  static int -bgp_attr_atomic (struct peer *peer, bgp_size_t length,  -		 struct attr *attr, u_char flag) +bgp_attr_atomic (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; +   +  /* Length check. */    if (length != 0)      { -      zlog (peer->log, LOG_ERR, "Bad atomic aggregate length %d", length); - -      bgp_notify_send (peer,  -		       BGP_NOTIFY_UPDATE_ERR,  -		       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); -      return -1; +      zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", +            length); +      return bgp_attr_malformed (args, +                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +                                 args->total);      }    /* Set atomic aggregate flag. */    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE); -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* Aggregator attribute */  static int -bgp_attr_aggregator (struct peer *peer, bgp_size_t length, -		     struct attr *attr, u_char flag) +bgp_attr_aggregator (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; +      int wantedlen = 6;    struct attr_extra *attre = bgp_attr_extra_get (attr);    /* peer with AS4 will send 4 Byte AS, peer without will send 2 Byte */ -  if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) +  if (CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV))      wantedlen = 8;    if (length != wantedlen)      { -      zlog (peer->log, LOG_ERR, "Aggregator length is not %d [%d]", wantedlen, length); - -      bgp_notify_send (peer, -		       BGP_NOTIFY_UPDATE_ERR, -		       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); -      return -1; +      zlog (peer->log, LOG_ERR, "AGGREGATOR attribute length isn't %u [%u]", +            wantedlen, length); +      return bgp_attr_malformed (args, +                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +                                 args->total);      }    if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) ) @@ -1022,36 +1226,41 @@ bgp_attr_aggregator (struct peer *peer, bgp_size_t length,    /* Set atomic aggregate flag. */    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR); -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* New Aggregator attribute */ -static int -bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length, -		     struct attr *attr, as_t *as4_aggregator_as, -		     struct in_addr *as4_aggregator_addr) +static bgp_attr_parse_ret_t +bgp_attr_as4_aggregator (struct bgp_attr_parser_args *args, +		         as_t *as4_aggregator_as, +		         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)      { -      zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", length); - -      bgp_notify_send (peer, -		       BGP_NOTIFY_UPDATE_ERR, -		       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); -      return -1; +      zlog (peer->log, LOG_ERR, "New Aggregator length is not 8 [%d]", +            length); +      return bgp_attr_malformed (args, +                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +                                 0);      } +      *as4_aggregator_as = stream_getl (peer->ibuf);    as4_aggregator_addr->s_addr = stream_get_ipv4 (peer->ibuf);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR); -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* Munge Aggregator and New-Aggregator, AS_PATH and NEW_AS_PATH.   */ -static int -bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr, +static bgp_attr_parse_ret_t +bgp_attr_munge_as4_attrs (struct peer *const peer, +                          struct attr *const attr,                            struct aspath *as4_path, as_t as4_aggregator,                            struct in_addr *as4_aggregator_addr)  { @@ -1059,7 +1268,7 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,    struct aspath *newpath;    struct attr_extra *attre = attr->extra; -  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         * if given. @@ -1077,34 +1286,15 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,                          peer->host, "AS4 capable peer, yet it sent");          } -      return 0; +      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); -      bgp_notify_send (peer,  -                       BGP_NOTIFY_UPDATE_ERR,  -                       BGP_NOTIFY_UPDATE_MAL_ATTR); -      return -1; -    } -    /* We have a asn16 peer.  First, look for AS4_AGGREGATOR     * because that may override AS4_PATH     */    if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AS4_AGGREGATOR) ) )      { -      if ( attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) ) +      if (attr->flag & (ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR) ) )          {            assert (attre); @@ -1120,7 +1310,7 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,             *        Aggregating node and the AS_PATH is to be             *        constructed "as in all other cases"             */ -          if ( attre->aggregator_as != BGP_AS_TRANS ) +          if (attre->aggregator_as != BGP_AS_TRANS)              {                /* ignore */                if ( BGP_DEBUG(as4, AS4)) @@ -1155,24 +1345,27 @@ bgp_attr_munge_as4_attrs (struct peer *peer, struct attr *attr,      }    /* 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))))      {         newpath = aspath_reconcile_as4 (attr->aspath, as4_path); -       aspath_unintern (attr->aspath); +       aspath_unintern (&attr->aspath);         attr->aspath = aspath_intern (newpath);      } -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* Community attribute. */ -static int -bgp_attr_community (struct peer *peer, bgp_size_t length,  -		    struct attr *attr, u_char flag) +static bgp_attr_parse_ret_t +bgp_attr_community (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 (length == 0)      {        attr->community = NULL; -      return 0; +      return BGP_ATTR_PARSE_PROCEED;      }    attr->community = @@ -1182,26 +1375,31 @@ bgp_attr_community (struct peer *peer, bgp_size_t length,    stream_forward_getp (peer->ibuf, length);    if (!attr->community) -    return -1; +    return bgp_attr_malformed (args, +                               BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, +                               args->total);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES); -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* Originator ID attribute. */ -static int -bgp_attr_originator_id (struct peer *peer, bgp_size_t length,  -			struct attr *attr, u_char flag) +static bgp_attr_parse_ret_t +bgp_attr_originator_id (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; +   +  /* Length check. */    if (length != 4)      {        zlog (peer->log, LOG_ERR, "Bad originator ID length %d", length); -      bgp_notify_send (peer,  -		       BGP_NOTIFY_UPDATE_ERR,  -		       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); -      return -1; +      return bgp_attr_malformed (args, +                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +                                 args->total);      }    (bgp_attr_extra_get (attr))->originator_id.s_addr  @@ -1209,39 +1407,41 @@ bgp_attr_originator_id (struct peer *peer, bgp_size_t length,    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID); -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* Cluster list attribute. */ -static int -bgp_attr_cluster_list (struct peer *peer, bgp_size_t length,  -		       struct attr *attr, u_char flag) +static bgp_attr_parse_ret_t +bgp_attr_cluster_list (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; +      /* Check length. */    if (length % 4)      {        zlog (peer->log, LOG_ERR, "Bad cluster list length %d", length); -      bgp_notify_send (peer,  -		       BGP_NOTIFY_UPDATE_ERR,  -		       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); -      return -1; +      return bgp_attr_malformed (args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, +                                 args->total);      }    (bgp_attr_extra_get (attr))->cluster       = cluster_parse ((struct in_addr *)stream_pnt (peer->ibuf), length); - -  stream_forward_getp (peer->ibuf, length);; +   +  /* XXX: Fix cluster_parse to use stream API and then remove this */ +  stream_forward_getp (peer->ibuf, length);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_CLUSTER_LIST); -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* Multiprotocol reachability information parse. */  int -bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr, -		    struct bgp_nlri *mp_update) +bgp_mp_reach_parse (struct bgp_attr_parser_args *args, +                    struct bgp_nlri *mp_update)  {    afi_t afi;    safi_t safi; @@ -1249,6 +1449,9 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,    size_t start;    int ret;    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);    /* Set end of packet. */ @@ -1262,7 +1465,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,      {        zlog_info ("%s: %s sent invalid length, %lu",   		 __func__, peer->host, (unsigned long)length); -      return -1; +      return BGP_ATTR_PARSE_ERROR;      }    /* Load AFI, SAFI. */ @@ -1276,7 +1479,7 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,      {        zlog_info ("%s: %s, MP nexthop length, %u, goes past end of attribute",   		 __func__, peer->host, attre->mp_nexthop_len); -      return -1; +      return BGP_ATTR_PARSE_ERROR;      }    /* Nexthop length check. */ @@ -1289,14 +1492,9 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,          memcpy(&attr->nexthop.s_addr, &attre->mp_nexthop_global_in, 4);        break;      case 12: -      { -	u_int32_t rd_high; -	u_int32_t rd_low; - -	rd_high = stream_getl (s); -	rd_low = stream_getl (s); -	stream_get (&attre->mp_nexthop_global_in, s, 4); -      } +      stream_getl (s); /* RD high */ +      stream_getl (s); /* RD low */ +      stream_get (&attre->mp_nexthop_global_in, s, 4);        break;  #ifdef HAVE_IPV6      case 16: @@ -1324,14 +1522,14 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,      default:        zlog_info ("%s: (%s) Wrong multiprotocol next hop length: %d",   		 __func__, peer->host, attre->mp_nexthop_len); -      return -1; +      return BGP_ATTR_PARSE_ERROR;      }    if (!LEN_LEFT)      {        zlog_info ("%s: (%s) Failed to read SNPA and NLRI(s)",                   __func__, peer->host); -      return -1; +      return BGP_ATTR_PARSE_ERROR;      }    { @@ -1347,17 +1545,17 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,      {        zlog_info ("%s: (%s) Failed to read NLRI",                   __func__, peer->host); -      return -1; +      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);        if (ret < 0)           {            zlog_info ("%s: (%s) NLRI doesn't pass sanity check",                       __func__, peer->host); -	  return -1; +	  return BGP_ATTR_PARSE_ERROR;  	}      } @@ -1368,13 +1566,13 @@ bgp_mp_reach_parse (struct peer *peer, bgp_size_t length, struct attr *attr,    stream_forward_getp (s, nlri_len); -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  #undef LEN_LEFT  }  /* Multiprotocol unreachable parse */  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 stream *s; @@ -1382,23 +1580,25 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,    safi_t safi;    u_int16_t withdraw_len;    int ret; +  struct peer *const peer = args->peer;   +  const bgp_size_t length = args->length;    s = peer->ibuf;  #define BGP_MP_UNREACH_MIN_SIZE 3    if ((length > STREAM_READABLE(s)) || (length <  BGP_MP_UNREACH_MIN_SIZE)) -    return -1; +    return BGP_ATTR_PARSE_ERROR;    afi = stream_getw (s);    safi = stream_getc (s);    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);        if (ret < 0) -	return -1; +	return BGP_ATTR_PARSE_ERROR;      }    mp_withdraw->afi = afi; @@ -1408,20 +1608,23 @@ bgp_mp_unreach_parse (struct peer *peer, bgp_size_t length,    stream_forward_getp (s, withdraw_len); -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* Extended Community attribute. */ -static int -bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,  -			  struct attr *attr, u_char flag) +static bgp_attr_parse_ret_t +bgp_attr_ext_communities (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 (length == 0)      {        if (attr->extra)          attr->extra->ecommunity = NULL;        /* Empty extcomm doesn't seem to be invalid per se */ -      return 0; +      return BGP_ATTR_PARSE_PROCEED;      }    (bgp_attr_extra_get (attr))->ecommunity = @@ -1430,21 +1633,29 @@ bgp_attr_ext_communities (struct peer *peer, bgp_size_t length,    stream_forward_getp (peer->ibuf, length);    if (!attr->extra->ecommunity) -    return -1; +    return bgp_attr_malformed (args, +                               BGP_NOTIFY_UPDATE_OPT_ATTR_ERR, +                               args->total);    attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* BGP unknown attribute treatment. */ -static int -bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag, -		  u_char type, bgp_size_t length, u_char *startp) +static bgp_attr_parse_ret_t +bgp_attr_unknown (struct bgp_attr_parser_args *args)  {    bgp_size_t total;    struct transit *transit;    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))    zlog_debug ("%s Unknown attribute is received (type %d, length %d)", @@ -1457,27 +1668,21 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,    /* Forward read pointer of input stream. */    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,       then the Error Subcode is set to Unrecognized Well-known       Attribute.  The Data field contains the unrecognized attribute       (type, length and value). */ -  if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)) +  if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))      { -      /* Adjust startp to do not include flag value. */ -      bgp_notify_send_with_data (peer,  -				 BGP_NOTIFY_UPDATE_ERR,  -				 BGP_NOTIFY_UPDATE_UNREC_ATTR, -				 startp, total); -      return -1; +      return bgp_attr_malformed (args, +                                 BGP_NOTIFY_UPDATE_UNREC_ATTR, +                                 args->total);      }    /* Unrecognized non-transitive optional attributes must be quietly       ignored and not passed along to other BGP peers. */    if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS)) -    return 0; +    return BGP_ATTR_PARSE_PROCEED;    /* If a path with recognized transitive optional attribute is       accepted and passed along to other BGP peers and the Partial bit @@ -1500,17 +1705,17 @@ bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,    memcpy (transit->val + transit->length, startp, total);    transit->length += total; -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* Read attribute of update packet.  This function is called from     bgp_update() in bgpd.c.  */ -int +bgp_attr_parse_ret_t  bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,  		struct bgp_nlri *mp_update, struct bgp_nlri *mp_withdraw)  {    int ret; -  u_char flag; +  u_char flag = 0;    u_char type = 0;    bgp_size_t length;    u_char *startp, *endp; @@ -1527,7 +1732,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,    /* End pointer of BGP attribute. */    endp = BGP_INPUT_PNT (peer) + size; - +      /* Get attributes to the end of attribute length. */    while (BGP_INPUT_PNT (peer) < endp)      { @@ -1536,19 +1741,22 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,  	{  	  /* XXX warning: long int format, int arg (arg 5) */  	  zlog (peer->log, LOG_WARNING,  -		"%s error BGP attribute length %lu is smaller than min len", +		"%s: error BGP attribute length %lu is smaller than min len",  		peer->host,  		(unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));  	  bgp_notify_send (peer,   			   BGP_NOTIFY_UPDATE_ERR,   			   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); -	  return -1; +	  return BGP_ATTR_PARSE_ERROR;  	}        /* Fetch attribute flag and type. */        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));        /* Check whether Extended-Length applies and is in bounds */ @@ -1556,16 +1764,16 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,            && ((endp - startp) < (BGP_ATTR_MIN_LEN + 1)))  	{  	  zlog (peer->log, LOG_WARNING,  -		"%s Extended length set, but just %lu bytes of attr header", +		"%s: Extended length set, but just %lu bytes of attr header",  		peer->host,  		(unsigned long) (endp - STREAM_PNT (BGP_INPUT (peer))));  	  bgp_notify_send (peer,   			   BGP_NOTIFY_UPDATE_ERR,   			   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); -	  return -1; +	  return BGP_ATTR_PARSE_ERROR;  	} - +              /* Check extended attribue length bit. */        if (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN))  	length = stream_getw (BGP_INPUT (peer)); @@ -1579,13 +1787,13 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,        if (CHECK_BITMAP (seen, type))  	{  	  zlog (peer->log, LOG_WARNING, -		"%s error BGP attribute type %d appears twice in a message", +		"%s: error BGP attribute type %d appears twice in a message",  		peer->host, type);  	  bgp_notify_send (peer,   			   BGP_NOTIFY_UPDATE_ERR,   			   BGP_NOTIFY_UPDATE_MAL_ATTR); -	  return -1; +	  return BGP_ATTR_PARSE_ERROR;  	}        /* Set type to bitmap to check duplicate attribute.  `type' is @@ -1599,81 +1807,120 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,        if (attr_endp > endp)  	{  	  zlog (peer->log, LOG_WARNING,  -		"%s BGP type %d length %d is too large, attribute total length is %d.  attr_endp is %p.  endp is %p", peer->host, type, length, size, attr_endp, endp); +		"%s: BGP type %d length %d is too large, attribute total length is %d.  attr_endp is %p.  endp is %p", peer->host, type, length, size, attr_endp, endp);  	  bgp_notify_send (peer,   			   BGP_NOTIFY_UPDATE_ERR,   			   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); -	  return -1; +	  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. */        switch (type)  	{  	case BGP_ATTR_ORIGIN: -	  ret = bgp_attr_origin (peer, length, attr, flag, startp); +	  ret = bgp_attr_origin (&attr_args);  	  break;  	case BGP_ATTR_AS_PATH: -          attr->aspath = bgp_attr_aspath (peer, length, attr, flag, startp, 0); -          ret = attr->aspath ? 0 : -1 ; +	  ret = bgp_attr_aspath (&attr_args);  	  break;  	case BGP_ATTR_AS4_PATH: -          as4_path = bgp_attr_aspath (peer, length, attr, flag, startp, 1); -          ret = as4_path  ? 0 : -1 ; +	  ret = bgp_attr_as4_path (&attr_args, &as4_path);  	  break;  	case BGP_ATTR_NEXT_HOP:	 -	  ret = bgp_attr_nexthop (peer, length, attr, flag, startp); +	  ret = bgp_attr_nexthop (&attr_args);  	  break;  	case BGP_ATTR_MULTI_EXIT_DISC: -	  ret = bgp_attr_med (peer, length, attr, flag, startp); +	  ret = bgp_attr_med (&attr_args);  	  break;  	case BGP_ATTR_LOCAL_PREF: -	  ret = bgp_attr_local_pref (peer, length, attr, flag); +	  ret = bgp_attr_local_pref (&attr_args);  	  break;  	case BGP_ATTR_ATOMIC_AGGREGATE: -	  ret = bgp_attr_atomic (peer, length, attr, flag); +	  ret = bgp_attr_atomic (&attr_args);  	  break;  	case BGP_ATTR_AGGREGATOR: -	  ret = bgp_attr_aggregator (peer, length, attr, flag); +	  ret = bgp_attr_aggregator (&attr_args);  	  break;  	case BGP_ATTR_AS4_AGGREGATOR: -	  ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr); +	  ret = bgp_attr_as4_aggregator (&attr_args, +	                                 &as4_aggregator, +	                                 &as4_aggregator_addr);  	  break;  	case BGP_ATTR_COMMUNITIES: -	  ret = bgp_attr_community (peer, length, attr, flag); +	  ret = bgp_attr_community (&attr_args);  	  break;  	case BGP_ATTR_ORIGINATOR_ID: -	  ret = bgp_attr_originator_id (peer, length, attr, flag); +	  ret = bgp_attr_originator_id (&attr_args);  	  break;  	case BGP_ATTR_CLUSTER_LIST: -	  ret = bgp_attr_cluster_list (peer, length, attr, flag); +	  ret = bgp_attr_cluster_list (&attr_args);  	  break;  	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;  	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;  	case BGP_ATTR_EXT_COMMUNITIES: -	  ret = bgp_attr_ext_communities (peer, length, attr, flag); +	  ret = bgp_attr_ext_communities (&attr_args);  	  break;  	default: -	  ret = bgp_attr_unknown (peer, attr, flag, type, length, startp); +	  ret = bgp_attr_unknown (&attr_args);  	  break;  	} - -      /* If error occured immediately return to the caller. */ -      if (ret < 0) +       +      /* If hard error occured immediately return to the caller. */ +      if (ret == BGP_ATTR_PARSE_ERROR)          {            zlog (peer->log, LOG_WARNING,                  "%s: Attribute %s, parse error",                   peer->host,                   LOOKUP (attr_str, type)); -           bgp_notify_send (peer,  -                            BGP_NOTIFY_UPDATE_ERR, -                            BGP_NOTIFY_UPDATE_MAL_ATTR); -           return ret; +          bgp_notify_send (peer,  +                           BGP_NOTIFY_UPDATE_ERR, +                           BGP_NOTIFY_UPDATE_MAL_ATTR); +          if (as4_path) +            aspath_unintern (&as4_path); +          return ret;          } - +      if (ret == BGP_ATTR_PARSE_WITHDRAW) +        { +           +          zlog (peer->log, LOG_WARNING, +                "%s: Attribute %s, parse error - treating as withdrawal", +                peer->host, +                LOOKUP (attr_str, type)); +          if (as4_path) +            aspath_unintern (&as4_path); +          return ret; +        } +              /* Check the fetched length. */        if (BGP_INPUT_PNT (peer) != attr_endp)  	{ @@ -1683,7 +1930,9 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,  	  bgp_notify_send (peer,   			   BGP_NOTIFY_UPDATE_ERR,   			   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); -	  return -1; +          if (as4_path) +            aspath_unintern (&as4_path); +	  return BGP_ATTR_PARSE_ERROR;  	}      } @@ -1691,12 +1940,14 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,    if (BGP_INPUT_PNT (peer) != endp)      {        zlog (peer->log, LOG_WARNING,  -	    "%s BGP attribute %s, length mismatch", +	    "%s: BGP attribute %s, length mismatch",  	    peer->host, LOOKUP (attr_str, type));        bgp_notify_send (peer,   		       BGP_NOTIFY_UPDATE_ERR,   		       BGP_NOTIFY_UPDATE_ATTR_LENG_ERR); -      return -1; +      if (as4_path) +        aspath_unintern (&as4_path); +      return BGP_ATTR_PARSE_ERROR;      }    /*  @@ -1712,17 +1963,20 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,     */    if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,                                  as4_aggregator, &as4_aggregator_addr)) -    return -1; +    { +      if (as4_path) +        aspath_unintern (&as4_path); +      return BGP_ATTR_PARSE_ERROR; +    }    /* At this stage, we have done all fiddling with as4, and the     * resulting info is in attr->aggregator resp. attr->aspath     * so we can chuck as4_aggregator and as4_path alltogether in     * order to save memory     */ -  if ( as4_path ) +  if (as4_path)      { -      aspath_unintern( as4_path ); /* unintern - it is in the hash */ -      as4_path = NULL; +      aspath_unintern (&as4_path); /* unintern - it is in the hash */        /* The flag that we got this is still there, but that does not         * do any trouble         */ @@ -1737,10 +1991,10 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,     * Finally do the checks on the aspath we did not do yet     * because we waited for a potentially synthesized aspath.     */ -  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 ); -      if ( ret < 0 ) +      ret = bgp_attr_aspath_check (peer, attr); +      if (ret != BGP_ATTR_PARSE_PROCEED)  	return ret;      } @@ -1748,7 +2002,7 @@ bgp_attr_parse (struct peer *peer, struct attr *attr, bgp_size_t size,    if (attr->extra && attr->extra->transit)      attr->extra->transit = transit_intern (attr->extra->transit); -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  /* Well-known attribute check. */ @@ -1779,9 +2033,9 @@ bgp_attr_check (struct peer *peer, struct attr *attr)  				 BGP_NOTIFY_UPDATE_ERR,   				 BGP_NOTIFY_UPDATE_MISS_ATTR,  				 &type, 1); -      return -1; +      return BGP_ATTR_PARSE_ERROR;      } -  return 0; +  return BGP_ATTR_PARSE_PROCEED;  }  int stream_put_prefix (struct stream *, struct prefix *); @@ -2077,7 +2331,7 @@ bgp_packet_attribute (struct bgp *bgp, struct peer *peer,        sizep = stream_get_endp (s);        stream_putc (s, 0);	/* Length of this attribute. */        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_putl (s, 0); @@ -2240,7 +2494,7 @@ bgp_packet_withdraw (struct peer *peer, struct stream *s, struct prefix *p,    if (safi == SAFI_MPLS_VPN)      {        /* SAFI */ -      stream_putc (s, BGP_SAFI_VPNV4); +      stream_putc (s, SAFI_MPLS_LABELED_VPN);        /* prefix. */        stream_putc (s, p->prefixlen + 88); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index af9dcf5e..df87c863 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -132,17 +132,25 @@ struct transit  #define ATTR_FLAG_BIT(X)  (1 << ((X) - 1)) +typedef enum { + BGP_ATTR_PARSE_PROCEED = 0, + BGP_ATTR_PARSE_ERROR = -1, + BGP_ATTR_PARSE_WITHDRAW = -2, +} bgp_attr_parse_ret_t; +  /* Prototypes. */  extern void bgp_attr_init (void);  extern void bgp_attr_finish (void); -extern int bgp_attr_parse (struct peer *, struct attr *, bgp_size_t, -		    struct bgp_nlri *, struct bgp_nlri *); +extern bgp_attr_parse_ret_t bgp_attr_parse (struct peer *, struct attr *, +                                           bgp_size_t, struct bgp_nlri *, +                                           struct bgp_nlri *);  extern int bgp_attr_check (struct peer *, struct attr *);  extern struct attr_extra *bgp_attr_extra_get (struct attr *);  extern void bgp_attr_extra_free (struct attr *);  extern void bgp_attr_dup (struct attr *, struct attr *);  extern struct attr *bgp_attr_intern (struct attr *attr); -extern void bgp_attr_unintern (struct attr *); +extern void bgp_attr_unintern_sub (struct attr *); +extern void bgp_attr_unintern (struct attr **);  extern void bgp_attr_flush (struct attr *);  extern struct attr *bgp_attr_default_set (struct attr *attr, u_char);  extern struct attr *bgp_attr_default_intern (u_char); @@ -171,9 +179,19 @@ extern void cluster_unintern (struct cluster_list *);  /* Transit attribute prototypes. */  void transit_unintern (struct transit *); -/* Exported for unit-test purposes only */ -extern int bgp_mp_reach_parse (struct peer *, bgp_size_t, struct attr *, +/* Below exported for unit-test purposes only */ +struct bgp_attr_parser_args { +  struct peer *peer; +  bgp_size_t length; /* attribute data length; */ +  bgp_size_t total; /* total length, inc header */ +  struct attr *attr; +  u_int8_t type; +  u_int8_t flags; +  u_char *startp;    +}; +extern int bgp_mp_reach_parse (struct bgp_attr_parser_args *args,   			       struct bgp_nlri *); -extern int bgp_mp_unreach_parse (struct peer *, bgp_size_t, struct bgp_nlri *); +extern int bgp_mp_unreach_parse (struct bgp_attr_parser_args *args, +                                 struct bgp_nlri *);  #endif /* _QUAGGA_BGP_ATTR_H */ diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index d6601674..6c9976e3 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -70,7 +70,7 @@ community_entry_free (struct community_entry *entry)        if (entry->config)          XFREE (MTYPE_ECOMMUNITY_STR, entry->config);        if (entry->u.ecom) -        ecommunity_free (entry->u.ecom); +        ecommunity_free (&entry->u.ecom);        break;      case COMMUNITY_LIST_EXPANDED:      case EXTCOMMUNITY_LIST_EXPANDED: @@ -806,7 +806,7 @@ extcommunity_list_unset (struct community_list_handler *ch,      entry = community_list_entry_lookup (list, str, direct);    if (ecom) -    ecommunity_free (ecom); +    ecommunity_free (&ecom);    if (regex)      bgp_regex_free (regex); diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index ae1d7a15..2ba45f6e 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -321,21 +321,22 @@ community_intern (struct community *com)  /* Free community attribute. */  void -community_unintern (struct community *com) +community_unintern (struct community **com)  {    struct community *ret; -  if (com->refcnt) -    com->refcnt--; +  if ((*com)->refcnt) +    (*com)->refcnt--;    /* Pull off from hash.  */ -  if (com->refcnt == 0) +  if ((*com)->refcnt == 0)      {        /* Community value com must exist in hash. */ -      ret = (struct community *) hash_release (comhash, com); +      ret = (struct community *) hash_release (comhash, *com);        assert (ret != NULL); -      community_free (com); +      community_free (*com); +      *com = NULL;      }  } diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h index bc1e56ef..9e483770 100644 --- a/bgpd/bgp_community.h +++ b/bgpd/bgp_community.h @@ -57,7 +57,7 @@ extern void community_free (struct community *);  extern struct community *community_uniq_sort (struct community *);  extern struct community *community_parse (u_int32_t *, u_short);  extern struct community *community_intern (struct community *); -extern void community_unintern (struct community *); +extern void community_unintern (struct community **);  extern char *community_str (struct community *);  extern unsigned int community_hash_make (struct community *);  extern struct community *community_str2com (const char *); diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 26b35dfc..8e161864 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -105,6 +105,7 @@ static const int bgp_notify_head_msg_max = BGP_NOTIFY_HEADER_MAX;  static const struct message bgp_notify_open_msg[] =   { +  { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},    { BGP_NOTIFY_OPEN_UNSUP_VERSION, "/Unsupported Version Number" },    { BGP_NOTIFY_OPEN_BAD_PEER_AS, "/Bad Peer AS"},    { BGP_NOTIFY_OPEN_BAD_BGP_IDENT, "/Bad BGP Identifier"}, @@ -117,6 +118,7 @@ static const int bgp_notify_open_msg_max = BGP_NOTIFY_OPEN_MAX;  static const struct message bgp_notify_update_msg[] =   { +  { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},    { BGP_NOTIFY_UPDATE_MAL_ATTR, "/Malformed Attribute List"},    { BGP_NOTIFY_UPDATE_UNREC_ATTR, "/Unrecognized Well-known Attribute"},    { BGP_NOTIFY_UPDATE_MISS_ATTR, "/Missing Well-known Attribute"}, @@ -133,6 +135,7 @@ static const int bgp_notify_update_msg_max = BGP_NOTIFY_UPDATE_MAX;  static const struct message bgp_notify_cease_msg[] =  { +  { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},    { BGP_NOTIFY_CEASE_MAX_PREFIX, "/Maximum Number of Prefixes Reached"},    { BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, "/Administratively Shutdown"},    { BGP_NOTIFY_CEASE_PEER_UNCONFIG, "/Peer Unconfigured"}, @@ -146,6 +149,7 @@ static const int bgp_notify_cease_msg_max = BGP_NOTIFY_CEASE_MAX;  static const struct message bgp_notify_capability_msg[] =   { +  { BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"},    { BGP_NOTIFY_CAPABILITY_INVALID_ACTION, "/Invalid Action Value" },    { BGP_NOTIFY_CAPABILITY_INVALID_LENGTH, "/Invalid Capability Length"},    { BGP_NOTIFY_CAPABILITY_MALFORMED_CODE, "/Malformed Capability Value"}, diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 8d5fa741..440c15a4 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -42,13 +42,14 @@ ecommunity_new (void)  /* Allocate ecommunities.  */  void -ecommunity_free (struct ecommunity *ecom) +ecommunity_free (struct ecommunity **ecom)  { -  if (ecom->val) -    XFREE (MTYPE_ECOMMUNITY_VAL, ecom->val); -  if (ecom->str) -    XFREE (MTYPE_ECOMMUNITY_STR, ecom->str); -  XFREE (MTYPE_ECOMMUNITY, ecom); +  if ((*ecom)->val) +    XFREE (MTYPE_ECOMMUNITY_VAL, (*ecom)->val); +  if ((*ecom)->str) +    XFREE (MTYPE_ECOMMUNITY_STR, (*ecom)->str); +  XFREE (MTYPE_ECOMMUNITY, *ecom); +  ecom = NULL;  }  /* Add a new Extended Communities value to Extended Communities @@ -197,7 +198,7 @@ ecommunity_intern (struct ecommunity *ecom)    find = (struct ecommunity *) hash_get (ecomhash, ecom, hash_alloc_intern);    if (find != ecom) -    ecommunity_free (ecom); +    ecommunity_free (&ecom);    find->refcnt++; @@ -209,18 +210,18 @@ ecommunity_intern (struct ecommunity *ecom)  /* Unintern Extended Communities Attribute.  */  void -ecommunity_unintern (struct ecommunity *ecom) +ecommunity_unintern (struct ecommunity **ecom)  {    struct ecommunity *ret; -  if (ecom->refcnt) -    ecom->refcnt--; - +  if ((*ecom)->refcnt) +    (*ecom)->refcnt--; +        /* Pull off from hash.  */ -  if (ecom->refcnt == 0) +  if ((*ecom)->refcnt == 0)      {        /* Extended community must be in the hash.  */ -      ret = (struct ecommunity *) hash_release (ecomhash, ecom); +      ret = (struct ecommunity *) hash_release (ecomhash, *ecom);        assert (ret != NULL);        ecommunity_free (ecom); @@ -516,7 +517,7 @@ ecommunity_str2com (const char *str, int type, int keyword_included)  	  if (! keyword_included || keyword)  	    {  	      if (ecom) -		ecommunity_free (ecom); +		ecommunity_free (&ecom);  	      return NULL;  	    }  	  keyword = 1; @@ -536,7 +537,7 @@ ecommunity_str2com (const char *str, int type, int keyword_included)  	      if (! keyword)  		{  		  if (ecom) -		    ecommunity_free (ecom); +		    ecommunity_free (&ecom);  		  return NULL;  		}  	      keyword = 0; @@ -549,7 +550,7 @@ ecommunity_str2com (const char *str, int type, int keyword_included)  	case ecommunity_token_unknown:  	default:  	  if (ecom) -	    ecommunity_free (ecom); +	    ecommunity_free (&ecom);  	  return NULL;  	}      } @@ -619,6 +620,13 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)    for (i = 0; i < ecom->size; i++)      { +      /* Make it sure size is enough.  */ +      while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size) +	{ +	  str_size *= 2; +	  str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size); +	} +        /* Space between each value.  */        if (! first)  	str_buf[str_pnt++] = ' '; @@ -662,13 +670,6 @@ ecommunity_ecom2str (struct ecommunity *ecom, int format)  	  break;  	} -      /* Make it sure size is enough.  */ -      while (str_pnt + ECOMMUNITY_STR_DEFAULT_LEN >= str_size) -	{ -	  str_size *= 2; -	  str_buf = XREALLOC (MTYPE_ECOMMUNITY_STR, str_buf, str_size); -	} -        /* Put string into buffer.  */        if (encode == ECOMMUNITY_ENCODE_AS4)  	{ diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 942fdc73..2f59dc40 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -67,13 +67,13 @@ struct ecommunity_val  extern void ecommunity_init (void);  extern void ecommunity_finish (void); -extern void ecommunity_free (struct ecommunity *); +extern void ecommunity_free (struct ecommunity **);  extern struct ecommunity *ecommunity_parse (u_int8_t *, u_short);  extern struct ecommunity *ecommunity_dup (struct ecommunity *);  extern struct ecommunity *ecommunity_merge (struct ecommunity *, struct ecommunity *);  extern struct ecommunity *ecommunity_intern (struct ecommunity *);  extern int ecommunity_cmp (const void *, const void *); -extern void ecommunity_unintern (struct ecommunity *); +extern void ecommunity_unintern (struct ecommunity **);  extern unsigned int ecommunity_hash_make (void *);  extern struct ecommunity *ecommunity_str2com (const char *, int, int);  extern char *ecommunity_ecom2str (struct ecommunity *, int); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 487ebddb..813e59ef 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -355,7 +355,7 @@ bgp_graceful_restart_timer_expire (struct thread *thread)    /* NSF delete stale route */    for (afi = AFI_IP ; afi < AFI_MAX ; afi++) -    for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) +    for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)        if (peer->nsf[afi][safi])  	bgp_clear_stale_route (peer, afi, safi); @@ -388,7 +388,7 @@ bgp_graceful_stale_timer_expire (struct thread *thread)    /* NSF delete stale route */    for (afi = AFI_IP ; afi < AFI_MAX ; afi++) -    for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) +    for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)        if (peer->nsf[afi][safi])  	bgp_clear_stale_route (peer, afi, safi); @@ -481,7 +481,7 @@ bgp_stop (struct peer *peer)  	  UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);  	  for (afi = AFI_IP ; afi < AFI_MAX ; afi++) -	    for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) +	    for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)  	      peer->nsf[afi][safi] = 0;  	} @@ -799,7 +799,7 @@ bgp_establish (struct peer *peer)    /* graceful restart */    UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_WAIT);    for (afi = AFI_IP ; afi < AFI_MAX ; afi++) -    for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) +    for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)        {  	if (peer->afc_nego[afi][safi]  	    && CHECK_FLAG (peer->cap, PEER_CAP_RESTART_ADV) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 1a460c6b..8dede587 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -54,6 +54,7 @@ static const struct option longopts[] =    { "daemon",      no_argument,       NULL, 'd'},    { "config_file", required_argument, NULL, 'f'},    { "pid_file",    required_argument, NULL, 'i'}, +  { "socket",      required_argument, NULL, 'z'},    { "bgp_port",    required_argument, NULL, 'p'},    { "listenon",    required_argument, NULL, 'l'},    { "vty_addr",    required_argument, NULL, 'A'}, @@ -119,6 +120,7 @@ static zebra_capabilities_t _caps_p [] =  {      ZCAP_BIND,       ZCAP_NET_RAW, +    ZCAP_NET_ADMIN,  };  struct zebra_privs_t bgpd_privs = @@ -149,6 +151,7 @@ redistribution between different routing protocols.\n\n\  -d, --daemon       Runs in daemon mode\n\  -f, --config_file  Set configuration file name\n\  -i, --pid_file     Set process identifier file name\n\ +-z, --socket       Set path of zebra socket\n\  -p, --bgp_port     Set bgp protocol's port number\n\  -l, --listenon     Listen on specified address (implies -n)\n\  -A, --vty_addr     Set vty's bind address\n\ @@ -196,6 +199,7 @@ sigint (void)    if (! retain_mode)      bgp_terminate (); +  zprivs_terminate (&bgpd_privs);    bgp_exit (0);  } @@ -335,7 +339,7 @@ main (int argc, char **argv)    /* Command line argument treatment. */    while (1)       { -      opt = getopt_long (argc, argv, "df:i:hp:l:A:P:rnu:g:vC", longopts, 0); +      opt = getopt_long (argc, argv, "df:i:z:hp:l:A:P:rnu:g:vC", longopts, 0);        if (opt == EOF)  	break; @@ -353,6 +357,9 @@ main (int argc, char **argv)          case 'i':            pid_file = optarg;            break; +	case 'z': +	  zclient_serv_path_set (optarg); +	  break;  	case 'p':  	  tmp_port = atoi (optarg);  	  if (tmp_port <= 0 || tmp_port > 0xffff) diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 72ad089e..c1f1fbb3 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -233,9 +233,13 @@ str2tag (const char *str, u_char *tag)    char *endptr;    u_int32_t t; -  l = strtoul (str, &endptr, 10); +  if (*str == '-') +    return 0; -  if (*endptr == '\0' || l == ULONG_MAX || l > UINT32_MAX) +  errno = 0; +  l = strtoul (str, &endptr, 10); + +  if (*endptr != '\0' || errno || l > UINT32_MAX)      return 0;    t = (u_int32_t) l; diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 570cc3b7..a7dca531 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -238,46 +238,36 @@ bgp_bind (struct peer *peer)  }  static int -bgp_bind_address (int sock, struct in_addr *addr) +bgp_update_address (struct interface *ifp, const union sockunion *dst, +		    union sockunion *addr)  { -  int ret; -  struct sockaddr_in local; - -  memset (&local, 0, sizeof (struct sockaddr_in)); -  local.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN -  local.sin_len = sizeof(struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ -  memcpy (&local.sin_addr, addr, sizeof (struct in_addr)); - -  if ( bgpd_privs.change (ZPRIVS_RAISE) ) -    zlog_err ("bgp_bind_address: could not raise privs"); -     -  ret = bind (sock, (struct sockaddr *)&local, sizeof (struct sockaddr_in)); -  if (ret < 0) -    ; -     -  if (bgpd_privs.change (ZPRIVS_LOWER) ) -    zlog_err ("bgp_bind_address: could not lower privs"); -     -  return 0; -} - -static struct in_addr * -bgp_update_address (struct interface *ifp) -{ -  struct prefix_ipv4 *p; +  struct prefix *p, *sel, *d;    struct connected *connected;    struct listnode *node; +  int common; + +  d = sockunion2hostprefix (dst); +  sel = NULL; +  common = -1;    for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, connected))      { -      p = (struct prefix_ipv4 *) connected->address; - -      if (p->family == AF_INET) -	return &p->prefix; +      p = connected->address; +      if (p->family != d->family) +	continue; +      if (prefix_common_bits (p, d) > common) +	{ +	  sel = p; +	  common = prefix_common_bits (sel, d); +	}      } -  return NULL; + +  prefix_free (d); +  if (!sel) +    return 1; + +  prefix2sockunion (sel, addr); +  return 0;  }  /* Update source selection.  */ @@ -285,7 +275,7 @@ static void  bgp_update_source (struct peer *peer)  {    struct interface *ifp; -  struct in_addr *addr; +  union sockunion addr;    /* Source is specified with interface name.  */    if (peer->update_if) @@ -294,11 +284,10 @@ bgp_update_source (struct peer *peer)        if (! ifp)  	return; -      addr = bgp_update_address (ifp); -      if (! addr) +      if (bgp_update_address (ifp, &peer->su, &addr))  	return; -      bgp_bind_address (peer->fd, addr); +      sockunion_bind (peer->fd, &addr, 0, &addr);      }    /* Source is specified with IP address.  */ @@ -328,8 +317,16 @@ bgp_connect (struct peer *peer)    sockopt_reuseport (peer->fd);  #ifdef IPTOS_PREC_INTERNETCONTROL +  if (bgpd_privs.change (ZPRIVS_RAISE)) +    zlog_err ("%s: could not raise privs", __func__);    if (sockunion_family (&peer->su) == AF_INET)      setsockopt_ipv4_tos (peer->fd, IPTOS_PREC_INTERNETCONTROL); +# ifdef HAVE_IPV6 +  else if (sockunion_family (&peer->su) == AF_INET6) +    setsockopt_ipv6_tclass (peer->fd, IPTOS_PREC_INTERNETCONTROL); +# endif +  if (bgpd_privs.change (ZPRIVS_LOWER)) +    zlog_err ("%s: could not lower privs", __func__);  #endif    if (peer->password) @@ -386,27 +383,24 @@ bgp_listener (int sock, struct sockaddr *sa, socklen_t salen)    sockopt_reuseaddr (sock);    sockopt_reuseport (sock); +  if (bgpd_privs.change (ZPRIVS_RAISE)) +    zlog_err ("%s: could not raise privs", __func__); +  #ifdef IPTOS_PREC_INTERNETCONTROL    if (sa->sa_family == AF_INET)      setsockopt_ipv4_tos (sock, IPTOS_PREC_INTERNETCONTROL); +#  ifdef HAVE_IPV6 +  else if (sa->sa_family == AF_INET6) +    setsockopt_ipv6_tclass (sock, IPTOS_PREC_INTERNETCONTROL); +#  endif  #endif -#ifdef IPV6_V6ONLY -  /* Want only IPV6 on ipv6 socket (not mapped addresses) */ -  if (sa->sa_family == AF_INET6) { -    int on = 1; -    setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, -		(void *) &on, sizeof (on)); -  } -#endif - -  if (bgpd_privs.change (ZPRIVS_RAISE) ) -    zlog_err ("bgp_socket: could not raise privs"); +  sockopt_v6only (sa->sa_family, sock);    ret = bind (sock, sa, salen);    en = errno; -  if (bgpd_privs.change (ZPRIVS_LOWER) ) -    zlog_err ("bgp_bind_address: could not lower privs"); +  if (bgpd_privs.change (ZPRIVS_LOWER)) +    zlog_err ("%s: could not lower privs", __func__);    if (ret < 0)      { diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 719cb966..fdf251b2 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -146,7 +146,7 @@ bgp_nexthop_same (struct nexthop *next1, struct nexthop *next2)  }  static int -bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1, +bgp_nexthop_cache_different (struct bgp_nexthop_cache *bnc1,  			   struct bgp_nexthop_cache *bnc2)  {    int i; @@ -171,14 +171,14 @@ bgp_nexthop_cache_changed (struct bgp_nexthop_cache *bnc1,  /* If nexthop exists on connected network return 1. */  int -bgp_nexthop_check_ebgp (afi_t afi, struct attr *attr) +bgp_nexthop_onlink (afi_t afi, struct attr *attr)  {    struct bgp_node *rn; - +      /* If zebra is not enabled return */    if (zlookup->sock < 0)      return 1; - +      /* Lookup the address is onlink or not. */    if (afi == AFI_IP)      { @@ -222,7 +222,7 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,    struct prefix p;    struct bgp_nexthop_cache *bnc;    struct attr *attr; - +      /* If lookup is not enabled, return valid. */    if (zlookup->sock < 0)      { @@ -230,7 +230,7 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,          ri->extra->igpmetric = 0;        return 1;      } - +      /* Only check IPv6 global address only nexthop. */    attr = ri->attr; @@ -253,15 +253,15 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,      }    else      { -      bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global); -      if (bnc) +      if (NULL == (bnc = zlookup_query_ipv6 (&attr->extra->mp_nexthop_global))) +	bnc = bnc_new (); +      else  	{ -	  struct bgp_table *old; -	  struct bgp_node *oldrn; -	  struct bgp_nexthop_cache *oldbnc; -  	  if (changed)  	    { +	      struct bgp_table *old; +	      struct bgp_node *oldrn; +  	      if (bgp_nexthop_cache_table[AFI_IP6] == cache1_table[AFI_IP6])  		old = cache2_table[AFI_IP6];  	      else @@ -270,9 +270,9 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,  	      oldrn = bgp_node_lookup (old, &p);  	      if (oldrn)  		{ -		  oldbnc = oldrn->info; +		  struct bgp_nexthop_cache *oldbnc = oldrn->info; -		  bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); +		  bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc);  		  if (bnc->metric != oldbnc->metric)  		    bnc->metricchanged = 1; @@ -281,11 +281,6 @@ bgp_nexthop_lookup_ipv6 (struct peer *peer, struct bgp_info *ri, int *changed,  		}  	    }  	} -      else -	{ -	  bnc = bnc_new (); -	  bnc->valid = 0; -	}        rn->info = bnc;      } @@ -313,7 +308,7 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,    struct prefix p;    struct bgp_nexthop_cache *bnc;    struct in_addr addr; - +      /* If lookup is not enabled, return valid. */    if (zlookup->sock < 0)      { @@ -321,7 +316,7 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,          ri->extra->igpmetric = 0;        return 1;      } - +    #ifdef HAVE_IPV6    if (afi == AFI_IP6)      return bgp_nexthop_lookup_ipv6 (peer, ri, changed, metricchanged); @@ -344,15 +339,15 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,      }    else      { -      bnc = zlookup_query (addr); -      if (bnc) +      if (NULL == (bnc = zlookup_query (addr))) +	bnc = bnc_new (); +      else  	{ -	  struct bgp_table *old; -	  struct bgp_node *oldrn; -	  struct bgp_nexthop_cache *oldbnc; -  	  if (changed)  	    { +	      struct bgp_table *old; +	      struct bgp_node *oldrn; +  	      if (bgp_nexthop_cache_table[AFI_IP] == cache1_table[AFI_IP])  		old = cache2_table[AFI_IP];  	      else @@ -361,9 +356,9 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,  	      oldrn = bgp_node_lookup (old, &p);  	      if (oldrn)  		{ -		  oldbnc = oldrn->info; +		  struct bgp_nexthop_cache *oldbnc = oldrn->info; -		  bnc->changed = bgp_nexthop_cache_changed (bnc, oldbnc); +		  bnc->changed = bgp_nexthop_cache_different (bnc, oldbnc);  		  if (bnc->metric != oldbnc->metric)  		    bnc->metricchanged = 1; @@ -372,11 +367,6 @@ bgp_nexthop_lookup (afi_t afi, struct peer *peer, struct bgp_info *ri,  		}  	    }  	} -      else -	{ -	  bnc = bnc_new (); -	  bnc->valid = 0; -	}        rn->info = bnc;      } @@ -462,7 +452,7 @@ bgp_scan (afi_t afi, safi_t safi)  	      metricchanged = 0;  	      if (peer_sort (bi->peer) == BGP_PEER_EBGP && bi->peer->ttl == 1) -		valid = bgp_nexthop_check_ebgp (afi, bi->attr); +		valid = bgp_nexthop_onlink (afi, bi->attr);  	      else  		valid = bgp_nexthop_lookup (afi, bi->peer, bi,  					    &changed, &metricchanged); @@ -1098,12 +1088,7 @@ zlookup_connect (struct thread *t)    if (zlookup->sock != -1)      return 0; -#ifdef HAVE_TCP_ZEBRA -  zlookup->sock = zclient_socket (); -#else -  zlookup->sock = zclient_socket_un (ZEBRA_SERV_PATH); -#endif /* HAVE_TCP_ZEBRA */ -  if (zlookup->sock < 0) +  if (zclient_socket_connect (zlookup) < 0)      return -1;    return 0; @@ -1201,16 +1186,13 @@ ALIAS (no_bgp_scan_time,         "Configure background scanner interval\n"         "Scanner interval (seconds)\n") -DEFUN (show_ip_bgp_scan, -       show_ip_bgp_scan_cmd, -       "show ip bgp scan", -       SHOW_STR -       IP_STR -       BGP_STR -       "BGP scan status\n") +static int +show_ip_bgp_scan_tables (struct vty *vty, const char detail)  {    struct bgp_node *rn;    struct bgp_nexthop_cache *bnc; +  char buf[INET6_ADDRSTRLEN]; +  u_char i;    if (bgp_scan_thread)      vty_out (vty, "BGP scan is running%s", VTY_NEWLINE); @@ -1223,28 +1205,57 @@ DEFUN (show_ip_bgp_scan,      if ((bnc = rn->info) != NULL)        {  	if (bnc->valid) +	{  	  vty_out (vty, " %s valid [IGP metric %d]%s", -		   inet_ntoa (rn->p.u.prefix4), bnc->metric, VTY_NEWLINE); +		   inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), bnc->metric, VTY_NEWLINE); +	  if (detail) +	    for (i = 0; i < bnc->nexthop_num; i++) +	      switch (bnc->nexthop[i].type) +	      { +	      case NEXTHOP_TYPE_IPV4: +		vty_out (vty, "  gate %s%s", inet_ntop (AF_INET, &bnc->nexthop[i].gate.ipv4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); +		break; +	      case NEXTHOP_TYPE_IFINDEX: +		vty_out (vty, "  ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); +		break; +	      default: +		vty_out (vty, "  invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE); +	      } +	}  	else  	  vty_out (vty, " %s invalid%s", -		   inet_ntoa (rn->p.u.prefix4), VTY_NEWLINE); +		   inet_ntop (AF_INET, &rn->p.u.prefix4, buf, INET6_ADDRSTRLEN), VTY_NEWLINE);        }  #ifdef HAVE_IPV6    { -    char buf[BUFSIZ];      for (rn = bgp_table_top (bgp_nexthop_cache_table[AFI_IP6]);            rn;            rn = bgp_route_next (rn))        if ((bnc = rn->info) != NULL)  	{  	  if (bnc->valid) +	  {  	    vty_out (vty, " %s valid [IGP metric %d]%s", -		     inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), +		     inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),  		     bnc->metric, VTY_NEWLINE); +	    if (detail) +	      for (i = 0; i < bnc->nexthop_num; i++) +		switch (bnc->nexthop[i].type) +		{ +		case NEXTHOP_TYPE_IPV6: +		  vty_out (vty, "  gate %s%s", inet_ntop (AF_INET6, &bnc->nexthop[i].gate.ipv6, buf, INET6_ADDRSTRLEN), VTY_NEWLINE); +		  break; +		case NEXTHOP_TYPE_IFINDEX: +		  vty_out (vty, "  ifidx %u%s", bnc->nexthop[i].ifindex, VTY_NEWLINE); +		  break; +		default: +		  vty_out (vty, "  invalid nexthop type %u%s", bnc->nexthop[i].type, VTY_NEWLINE); +		} +	  }  	  else  	    vty_out (vty, " %s invalid%s", -		     inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), +		     inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),  		     VTY_NEWLINE);  	}    } @@ -1260,14 +1271,12 @@ DEFUN (show_ip_bgp_scan,  #ifdef HAVE_IPV6    { -    char buf[BUFSIZ]; -      for (rn = bgp_table_top (bgp_connected_table[AFI_IP6]);            rn;            rn = bgp_route_next (rn))        if (rn->info != NULL)  	vty_out (vty, " %s/%d%s", -		 inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, BUFSIZ), +		 inet_ntop (AF_INET6, &rn->p.u.prefix6, buf, INET6_ADDRSTRLEN),  		 rn->p.prefixlen,  		 VTY_NEWLINE);    } @@ -1276,6 +1285,29 @@ DEFUN (show_ip_bgp_scan,    return CMD_SUCCESS;  } +DEFUN (show_ip_bgp_scan, +       show_ip_bgp_scan_cmd, +       "show ip bgp scan", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP scan status\n") +{ +  return show_ip_bgp_scan_tables (vty, 0); +} + +DEFUN (show_ip_bgp_scan_detail, +       show_ip_bgp_scan_detail_cmd, +       "show ip bgp scan detail", +       SHOW_STR +       IP_STR +       BGP_STR +       "BGP scan status\n" +       "More detailed output\n") +{ +  return show_ip_bgp_scan_tables (vty, 1); +} +  int  bgp_config_write_scan_time (struct vty *vty)  { @@ -1317,8 +1349,10 @@ bgp_scan_init (void)    install_element (BGP_NODE, &no_bgp_scan_time_cmd);    install_element (BGP_NODE, &no_bgp_scan_time_val_cmd);    install_element (VIEW_NODE, &show_ip_bgp_scan_cmd); +  install_element (VIEW_NODE, &show_ip_bgp_scan_detail_cmd);    install_element (RESTRICTED_NODE, &show_ip_bgp_scan_cmd);    install_element (ENABLE_NODE, &show_ip_bgp_scan_cmd); +  install_element (ENABLE_NODE, &show_ip_bgp_scan_detail_cmd);  }  void diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 2dad742f..874f3bba 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -54,7 +54,7 @@ extern void bgp_connected_add (struct connected *c);  extern void bgp_connected_delete (struct connected *c);  extern int bgp_multiaccess_check_v4 (struct in_addr, char *);  extern int bgp_config_write_scan_time (struct vty *); -extern int bgp_nexthop_check_ebgp (afi_t, struct attr *); +extern int bgp_nexthop_onlink (afi_t, struct attr *);  extern int bgp_nexthop_self (afi_t, struct attr *);  #endif /* _QUAGGA_BGP_NEXTHOP_H */ diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 37595817..b5b50bb5 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -93,11 +93,8 @@ bgp_capability_vty_out (struct vty *vty, struct peer *peer)  	    case SAFI_MULTICAST:  	      vty_out (vty, "SAFI Multicast");  	      break; -	    case SAFI_UNICAST_MULTICAST: -	      vty_out (vty, "SAFI Unicast Multicast"); -	      break; -	    case BGP_SAFI_VPNV4: -	      vty_out (vty, "SAFI MPLS-VPN"); +	    case SAFI_MPLS_LABELED_VPN: +	      vty_out (vty, "SAFI MPLS-labeled VPN");  	      break;  	    default:  	      vty_out (vty, "SAFI Unknown %d ", mpc.safi); @@ -127,14 +124,6 @@ bgp_capability_mp_data (struct stream *s, struct capability_mp_data *mpc)  int  bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)  { -  /* VPNvX are AFI specific */ -  if ((afi == AFI_IP6 && *safi == BGP_SAFI_VPNV4) -      || (afi == AFI_IP && *safi == BGP_SAFI_VPNV6)) -    { -      zlog_warn ("Invalid afi/safi combination (%u/%u)", afi, *safi); -      return 0; -    } -      switch (afi)      {        case AFI_IP: @@ -143,9 +132,8 @@ bgp_afi_safi_valid_indices (afi_t afi, safi_t *safi)  #endif          switch (*safi)            { -            /* BGP VPNvX SAFI isn't contigious with others, remap */ -            case BGP_SAFI_VPNV4: -            case BGP_SAFI_VPNV6: +            /* BGP MPLS-labeled VPN SAFI isn't contigious with others, remap */ +            case SAFI_MPLS_LABELED_VPN:                *safi = SAFI_MPLS_VPN;              case SAFI_UNICAST:              case SAFI_MULTICAST: @@ -392,7 +380,7 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)                    peer->v_gr_restart);      } -  while (stream_get_getp (s) + 4 < end) +  while (stream_get_getp (s) + 4 <= end)      {        afi_t afi = stream_getw (s);        safi_t safi = stream_getc (s); @@ -433,13 +421,20 @@ bgp_capability_restart (struct peer *peer, struct capability_header *caphdr)  static as_t  bgp_capability_as4 (struct peer *peer, struct capability_header *hdr)  { +  SET_FLAG (peer->cap, PEER_CAP_AS4_RCV); +   +  if (hdr->length != CAPABILITY_CODE_AS4_LEN) +    { +      zlog_err ("%s AS4 capability has incorrect data length %d", +                peer->host, hdr->length); +      return 0; +    } +      as_t as4 = stream_getl (BGP_INPUT(peer));    if (BGP_DEBUG (as4, AS4))      zlog_debug ("%s [AS4] about to set cap PEER_CAP_AS4_RCV, got as4 %u",                  peer->host, as4); -  SET_FLAG (peer->cap, PEER_CAP_AS4_RCV); -      return as4;  } @@ -701,9 +696,6 @@ peek_for_as4_capability (struct peer *peer, u_char length)  	      if (hdr.code == CAPABILITY_CODE_AS4)  	        { -	          if (hdr.length != CAPABILITY_CODE_AS4_LEN) -	            goto end; -                    	          if (BGP_DEBUG (as4, AS4))  	            zlog_info ("[AS4] found AS4 capability, about to parse");  	          as4 = bgp_capability_as4 (peer, &hdr); @@ -859,7 +851,7 @@ bgp_open_capability_orf (struct stream *s, struct peer *peer,    int number_of_orfs = 0;    if (safi == SAFI_MPLS_VPN) -    safi = BGP_SAFI_VPNV4; +    safi = SAFI_MPLS_LABELED_VPN;    stream_putc (s, BGP_OPEN_OPT_CAP);    capp = stream_get_endp (s);           /* Set Capability Len Pointer */ @@ -967,7 +959,7 @@ bgp_open_capability (struct stream *s, struct peer *peer)        stream_putc (s, CAPABILITY_CODE_MP_LEN);        stream_putw (s, AFI_IP);        stream_putc (s, 0); -      stream_putc (s, BGP_SAFI_VPNV4); +      stream_putc (s, SAFI_MPLS_LABELED_VPN);      }  #ifdef HAVE_IPV6    /* IPv6 unicast. */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index ed2cb73e..5d8087a8 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -206,7 +206,7 @@ bgp_update_packet (struct peer *peer, afi_t afi, safi_t safi)        /* Synchnorize attribute.  */        if (adj->attr) -	bgp_attr_unintern (adj->attr); +	bgp_attr_unintern (&adj->attr);        else  	peer->scount[afi][safi]++; @@ -895,14 +895,27 @@ bgp_notify_send_with_data (struct peer *peer, u_char code, u_char sub_code,    if (sub_code != BGP_NOTIFY_CEASE_CONFIG_CHANGE)      {        if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET) -      peer->last_reset = PEER_DOWN_USER_RESET; +      { +        peer->last_reset = PEER_DOWN_USER_RESET; +        zlog_info ("Notification sent to neighbor %s: User reset", peer->host); +      }        else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) -      peer->last_reset = PEER_DOWN_USER_SHUTDOWN; +      { +        peer->last_reset = PEER_DOWN_USER_SHUTDOWN; +        zlog_info ("Notification sent to neighbor %s: shutdown", peer->host); +      }        else -      peer->last_reset = PEER_DOWN_NOTIFY_SEND; +      { +        peer->last_reset = PEER_DOWN_NOTIFY_SEND; +        zlog_info ("Notification sent to neighbor %s: type %u/%u", +                   peer->host, code, sub_code); +      }      } +  else +     zlog_info ("Notification sent to neighbor %s: configuration change", +                peer->host); -  /* Call imidiately. */ +  /* Call immediately. */    BGP_WRITE_OFF (peer->t_write);    bgp_write_notify (peer); @@ -933,7 +946,7 @@ bgp_route_refresh_send (struct peer *peer, afi_t afi, safi_t safi,    /* Adjust safi code. */    if (safi == SAFI_MPLS_VPN) -    safi = BGP_SAFI_VPNV4; +    safi = SAFI_MPLS_LABELED_VPN;    s = stream_new (BGP_MAX_PACKET_SIZE); @@ -1023,7 +1036,7 @@ bgp_capability_send (struct peer *peer, afi_t afi, safi_t safi,    /* Adjust safi code. */    if (safi == SAFI_MPLS_VPN) -    safi = BGP_SAFI_VPNV4; +    safi = SAFI_MPLS_LABELED_VPN;    s = stream_new (BGP_MAX_PACKET_SIZE); @@ -1368,7 +1381,7 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)    /* remote router-id check. */    if (remote_id.s_addr == 0 -      || ntohl (remote_id.s_addr) >= 0xe0000000 +      || IPV4_CLASS_DE (ntohl (remote_id.s_addr))        || ntohl (peer->local_id.s_addr) == ntohl (remote_id.s_addr))      {        if (BGP_DEBUG (normal, NORMAL)) @@ -1446,9 +1459,13 @@ bgp_open_receive (struct peer *peer, bgp_size_t size)    /* Open option part parse. */    if (optlen != 0)       { -      ret = bgp_open_option_parse (peer, optlen, &capability); -      if (ret < 0) -	return ret; +      if ((ret = bgp_open_option_parse (peer, optlen, &capability)) < 0) +        { +          bgp_notify_send (peer, +                 BGP_NOTIFY_OPEN_ERR, +                 BGP_NOTIFY_OPEN_UNACEP_HOLDTIME); +	  return ret; +        }      }    else      { @@ -1583,26 +1600,47 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)  		       BGP_NOTIFY_UPDATE_MAL_ATTR);        return -1;      } +   +  /* Certain attribute parsing errors should not be considered bad enough +   * to reset the session for, most particularly any partial/optional +   * attributes that have 'tunneled' over speakers that don't understand +   * them. Instead we withdraw only the prefix concerned. +   *  +   * Complicates the flow a little though.. +   */ +  bgp_attr_parse_ret_t attr_parse_ret = BGP_ATTR_PARSE_PROCEED; +  /* This define morphs the update case into a withdraw when lower levels +   * have signalled an error condition where this is best. +   */ +#define NLRI_ATTR_ARG (attr_parse_ret != BGP_ATTR_PARSE_WITHDRAW ? &attr : NULL)    /* Parse attribute when it exists. */    if (attribute_len)      { -      ret = bgp_attr_parse (peer, &attr, attribute_len,  +      attr_parse_ret = bgp_attr_parse (peer, &attr, attribute_len,   			    &mp_update, &mp_withdraw); -      if (ret < 0) +      if (attr_parse_ret == BGP_ATTR_PARSE_ERROR)  	return -1;      } - +      /* Logging the attribute. */ -  if (BGP_DEBUG (update, UPDATE_IN)) +  if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW +      || BGP_DEBUG (update, UPDATE_IN))      {        ret= bgp_dump_attr (peer, &attr, attrstr, BUFSIZ); +      int lvl = (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) +                 ? LOG_ERR : LOG_DEBUG; +       +      if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) +        zlog (peer->log, LOG_ERR, +              "%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.", +              peer->host);        if (ret) -	zlog (peer->log, LOG_DEBUG, "%s rcvd UPDATE w/ attr: %s", +	zlog (peer->log, lvl, "%s rcvd UPDATE w/ attr: %s",  	      peer->host, attrstr);      } - +      /* Network Layer Reachability Information. */    update_len = end - stream_pnt (s); @@ -1611,7 +1649,12 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)        /* Check NLRI packet format and prefix length. */        ret = bgp_nlri_sanity_check (peer, AFI_IP, stream_pnt (s), update_len);        if (ret < 0) -	return -1; +        { +          bgp_attr_unintern_sub (&attr); +          if (attr.extra) +            bgp_attr_extra_free (&attr); +	  return -1; +	}        /* Set NLRI portion to structure. */        update.afi = AFI_IP; @@ -1634,15 +1677,20 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)  	     update. */  	  ret = bgp_attr_check (peer, &attr);  	  if (ret < 0) -	    return -1; +	    { +	      bgp_attr_unintern_sub (&attr); +              if (attr.extra) +                bgp_attr_extra_free (&attr); +	      return -1; +            } -	  bgp_nlri_parse (peer, &attr, &update); +	  bgp_nlri_parse (peer, NLRI_ATTR_ARG, &update);  	}        if (mp_update.length  	  && mp_update.afi == AFI_IP   	  && mp_update.safi == SAFI_UNICAST) -	bgp_nlri_parse (peer, &attr, &mp_update); +	bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update);        if (mp_withdraw.length  	  && mp_withdraw.afi == AFI_IP  @@ -1669,7 +1717,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)        if (mp_update.length  	  && mp_update.afi == AFI_IP   	  && mp_update.safi == SAFI_MULTICAST) -	bgp_nlri_parse (peer, &attr, &mp_update); +	bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update);        if (mp_withdraw.length  	  && mp_withdraw.afi == AFI_IP  @@ -1699,7 +1747,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)        if (mp_update.length   	  && mp_update.afi == AFI_IP6   	  && mp_update.safi == SAFI_UNICAST) -	bgp_nlri_parse (peer, &attr, &mp_update); +	bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update);        if (mp_withdraw.length   	  && mp_withdraw.afi == AFI_IP6  @@ -1728,7 +1776,7 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)        if (mp_update.length   	  && mp_update.afi == AFI_IP6   	  && mp_update.safi == SAFI_MULTICAST) -	bgp_nlri_parse (peer, &attr, &mp_update); +	bgp_nlri_parse (peer, NLRI_ATTR_ARG, &mp_update);        if (mp_withdraw.length   	  && mp_withdraw.afi == AFI_IP6  @@ -1755,17 +1803,17 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)      {        if (mp_update.length   	  && mp_update.afi == AFI_IP  -	  && mp_update.safi == BGP_SAFI_VPNV4) -	bgp_nlri_parse_vpnv4 (peer, &attr, &mp_update); +	  && mp_update.safi == SAFI_MPLS_LABELED_VPN) +	bgp_nlri_parse_vpnv4 (peer, NLRI_ATTR_ARG, &mp_update);        if (mp_withdraw.length   	  && mp_withdraw.afi == AFI_IP  -	  && mp_withdraw.safi == BGP_SAFI_VPNV4) +	  && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN)  	bgp_nlri_parse_vpnv4 (peer, NULL, &mp_withdraw);        if (! withdraw_len  	  && mp_withdraw.afi == AFI_IP -	  && mp_withdraw.safi == BGP_SAFI_VPNV4 +	  && mp_withdraw.safi == SAFI_MPLS_LABELED_VPN  	  && mp_withdraw.length == 0)  	{  	  /* End-of-RIB received */ @@ -1778,21 +1826,10 @@ bgp_update_receive (struct peer *peer, bgp_size_t size)    /* Everything is done.  We unintern temporary structures which       interned in bgp_attr_parse(). */ -  if (attr.aspath) -    aspath_unintern (attr.aspath); -  if (attr.community) -    community_unintern (attr.community); +  bgp_attr_unintern_sub (&attr);    if (attr.extra) -    { -      if (attr.extra->ecommunity) -        ecommunity_unintern (attr.extra->ecommunity); -      if (attr.extra->cluster) -        cluster_unintern (attr.extra->cluster); -      if (attr.extra->transit) -        transit_unintern (attr.extra->transit); -      bgp_attr_extra_free (&attr); -    } - +    bgp_attr_extra_free (&attr); +      /* If peering is stopped due to some reason, do not generate BGP       event.  */    if (peer->status != Established) @@ -1936,7 +1973,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)    /* Check AFI and SAFI. */    if ((afi != AFI_IP && afi != AFI_IP6)        || (safi != SAFI_UNICAST && safi != SAFI_MULTICAST -	  && safi != BGP_SAFI_VPNV4)) +	  && safi != SAFI_MPLS_LABELED_VPN))      {        if (BGP_DEBUG (normal, NORMAL))  	{ @@ -1947,7 +1984,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)      }    /* Adjust safi code. */ -  if (safi == BGP_SAFI_VPNV4) +  if (safi == SAFI_MPLS_LABELED_VPN)      safi = SAFI_MPLS_VPN;    if (size != BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE) @@ -2021,7 +2058,7 @@ bgp_route_refresh_receive (struct peer *peer, bgp_size_t size)  		      break;  		    }  		  ok = ((p_end - p_pnt) >= sizeof(u_int32_t)) ; -		  if (!ok) +		  if (ok)  		    {  		      memcpy (&seq, p_pnt, sizeof (u_int32_t));                        p_pnt += sizeof (u_int32_t); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 5c516f02..ba530321 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -137,7 +137,7 @@ static void  bgp_info_free (struct bgp_info *binfo)  {    if (binfo->attr) -    bgp_attr_unintern (binfo->attr); +    bgp_attr_unintern (&binfo->attr);    bgp_info_extra_free (&binfo->extra); @@ -1069,11 +1069,9 @@ bgp_announce_check_rsclient (struct bgp_info *ri, struct peer *rsclient,    struct bgp_filter *filter;    struct bgp_info info;    struct peer *from; -  struct bgp *bgp;    from = ri->peer;    filter = &rsclient->filter[afi][safi]; -  bgp = rsclient->bgp;    if (DISABLE_BGP_ANNOUNCE)      return 0; @@ -1493,7 +1491,7 @@ bgp_process_main (struct work_queue *wq, void *data)        if (! CHECK_FLAG (old_select->flags, BGP_INFO_ATTR_CHANGED))          {            if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED)) -            bgp_zebra_announce (p, old_select, bgp); +            bgp_zebra_announce (p, old_select, bgp, safi);            UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED);            return WQ_SUCCESS; @@ -1516,20 +1514,20 @@ bgp_process_main (struct work_queue *wq, void *data)      }    /* FIB update. */ -  if (safi == SAFI_UNICAST && ! bgp->name && -      ! bgp_option_check (BGP_OPT_NO_FIB)) +  if ((safi == SAFI_UNICAST || safi == SAFI_MULTICAST) && (! bgp->name && +      ! bgp_option_check (BGP_OPT_NO_FIB)))      {        if (new_select   	  && new_select->type == ZEBRA_ROUTE_BGP   	  && new_select->sub_type == BGP_ROUTE_NORMAL) -	bgp_zebra_announce (p, new_select, bgp); +	bgp_zebra_announce (p, new_select, bgp, safi);        else  	{  	  /* Withdraw the route from the kernel. */  	  if (old_select   	      && old_select->type == ZEBRA_ROUTE_BGP  	      && old_select->sub_type == BGP_ROUTE_NORMAL) -	    bgp_zebra_withdraw (p, old_select); +	    bgp_zebra_withdraw (p, old_select, safi);  	}      } @@ -1659,7 +1657,7 @@ bgp_maximum_prefix_overflow (struct peer *peer, afi_t afi,         u_int8_t ndata[7];         if (safi == SAFI_MPLS_VPN) -         safi = BGP_SAFI_VPNV4; +         safi = SAFI_MPLS_LABELED_VPN;         ndata[0] = (afi >>  8);         ndata[1] = afi; @@ -1802,23 +1800,23 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,    /* Apply import policy. */    if (bgp_import_modifier (rsclient, peer, p, &new_attr, afi, safi) == RMAP_DENY)      { -      bgp_attr_unintern (attr_new2); +      bgp_attr_unintern (&attr_new2);        reason = "import-policy;";        goto filtered;      }    attr_new = bgp_attr_intern (&new_attr); -  bgp_attr_unintern (attr_new2); +  bgp_attr_unintern (&attr_new2);    /* IPv4 unicast next hop check.  */ -  if (afi == AFI_IP && safi == SAFI_UNICAST) +  if ((afi == AFI_IP) && ((safi == SAFI_UNICAST) || safi == SAFI_MULTICAST))      { -     /* Next hop must not be 0.0.0.0 nor Class E address. */ +     /* Next hop must not be 0.0.0.0 nor Class D/E address. */        if (new_attr.nexthop.s_addr == 0 -         || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000) +         || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr)))         { -         bgp_attr_unintern (attr_new); +         bgp_attr_unintern (&attr_new);           reason = "martian next-hop;";           goto filtered; @@ -1848,7 +1846,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,                      p->prefixlen, rsclient->host);            bgp_unlock_node (rn); -          bgp_attr_unintern (attr_new); +          bgp_attr_unintern (&attr_new);            return;          } @@ -1868,7 +1866,7 @@ bgp_update_rsclient (struct peer *rsclient, afi_t afi, safi_t safi,        bgp_info_set_flag (rn, ri, BGP_INFO_ATTR_CHANGED);        /* Update to new attribute.  */ -      bgp_attr_unintern (ri->attr); +      bgp_attr_unintern (&ri->attr);        ri->attr = attr_new;        /* Update MPLS tag.  */ @@ -2063,18 +2061,18 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,        /* If the peer is EBGP and nexthop is not on connected route,  	 discard it.  */        if (peer_sort (peer) == BGP_PEER_EBGP && peer->ttl == 1 -	  && ! bgp_nexthop_check_ebgp (afi, &new_attr) +	  && ! bgp_nexthop_onlink (afi, &new_attr)  	  && ! CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))  	{  	  reason = "non-connected next-hop;";  	  goto filtered;  	} -      /* Next hop must not be 0.0.0.0 nor Class E address.  Next hop +      /* Next hop must not be 0.0.0.0 nor Class D/E address. Next hop  	 must not be my own address.  */        if (bgp_nexthop_self (afi, &new_attr)  	  || new_attr.nexthop.s_addr == 0 -	  || ntohl (new_attr.nexthop.s_addr) >= 0xe0000000) +	  || IPV4_CLASS_DE (ntohl (new_attr.nexthop.s_addr)))  	{  	  reason = "martian next-hop;";  	  goto filtered; @@ -2128,7 +2126,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,  	    }  	  bgp_unlock_node (rn); -	  bgp_attr_unintern (attr_new); +	  bgp_attr_unintern (&attr_new);  	  bgp_attr_extra_free (&new_attr);  	  return 0; @@ -2175,7 +2173,7 @@ bgp_update_main (struct peer *peer, struct prefix *p, struct attr *attr,  	}        /* Update to new attribute.  */ -      bgp_attr_unintern (ri->attr); +      bgp_attr_unintern (&ri->attr);        ri->attr = attr_new;        /* Update MPLS tag.  */ @@ -2467,7 +2465,7 @@ bgp_default_originate (struct peer *peer, afi_t afi, safi_t safi, int withdraw)      }    bgp_attr_extra_free (&attr); -  aspath_unintern (aspath); +  aspath_unintern (&aspath);  }  static void @@ -2936,7 +2934,7 @@ bgp_cleanup_routes (void)  	  if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)  	      && ri->type == ZEBRA_ROUTE_BGP   	      && ri->sub_type == BGP_ROUTE_NORMAL) -	    bgp_zebra_withdraw (&rn->p, ri); +	    bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST);        table = bgp->rib[AFI_IP6][SAFI_UNICAST]; @@ -2945,7 +2943,7 @@ bgp_cleanup_routes (void)  	  if (CHECK_FLAG (ri->flags, BGP_INFO_SELECTED)  	      && ri->type == ZEBRA_ROUTE_BGP   	      && ri->sub_type == BGP_ROUTE_NORMAL) -	    bgp_zebra_withdraw (&rn->p, ri); +	    bgp_zebra_withdraw (&rn->p, ri,SAFI_UNICAST);      }  } @@ -3215,7 +3213,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,            bgp_attr_flush (&attr_tmp);            /* Unintern original. */ -          aspath_unintern (attr.aspath); +          aspath_unintern (&attr.aspath);            bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi);            bgp_attr_extra_free (&attr); @@ -3242,8 +3240,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,        bgp->peer_self->rmap_type = 0; -      bgp_attr_unintern (attr_new); -      aspath_unintern (attr.aspath); +      bgp_attr_unintern (&attr_new); +      aspath_unintern (&attr.aspath);        bgp_attr_extra_free (&attr);        bgp_static_withdraw_rsclient (bgp, rsclient, p, afi, safi); @@ -3253,7 +3251,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,    bgp->peer_self->rmap_type = 0; -  bgp_attr_unintern (attr_new); +  bgp_attr_unintern (&attr_new);    attr_new = bgp_attr_intern (&new_attr);    bgp_attr_extra_free (&new_attr); @@ -3268,8 +3266,8 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,  	  !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))          {            bgp_unlock_node (rn); -          bgp_attr_unintern (attr_new); -          aspath_unintern (attr.aspath); +          bgp_attr_unintern (&attr_new); +          aspath_unintern (&attr.aspath);            bgp_attr_extra_free (&attr);            return;         } @@ -3281,14 +3279,14 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,            /* Rewrite BGP route information. */  	  if (CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))  	    bgp_info_restore(rn, ri); -          bgp_attr_unintern (ri->attr); +          bgp_attr_unintern (&ri->attr);            ri->attr = attr_new;            ri->uptime = bgp_clock ();            /* Process change. */            bgp_process (bgp, rn, afi, safi);            bgp_unlock_node (rn); -          aspath_unintern (attr.aspath); +          aspath_unintern (&attr.aspath);            bgp_attr_extra_free (&attr);            return;          } @@ -3313,7 +3311,7 @@ bgp_static_update_rsclient (struct peer *rsclient, struct prefix *p,    bgp_process (bgp, rn, afi, safi);    /* Unintern original. */ -  aspath_unintern (attr.aspath); +  aspath_unintern (&attr.aspath);    bgp_attr_extra_free (&attr);  } @@ -3363,7 +3361,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,  	  bgp_attr_flush (&attr_tmp);  	  /* Unintern original. */ -	  aspath_unintern (attr.aspath); +	  aspath_unintern (&attr.aspath);  	  bgp_attr_extra_free (&attr);  	  bgp_static_withdraw (bgp, p, afi, safi);  	  return; @@ -3384,8 +3382,8 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,  	  !CHECK_FLAG(ri->flags, BGP_INFO_REMOVED))  	{  	  bgp_unlock_node (rn); -	  bgp_attr_unintern (attr_new); -	  aspath_unintern (attr.aspath); +	  bgp_attr_unintern (&attr_new); +	  aspath_unintern (&attr.aspath);  	  bgp_attr_extra_free (&attr);  	  return;  	} @@ -3399,7 +3397,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,  	    bgp_info_restore(rn, ri);  	  else  	    bgp_aggregate_decrement (bgp, p, ri, afi, safi); -	  bgp_attr_unintern (ri->attr); +	  bgp_attr_unintern (&ri->attr);  	  ri->attr = attr_new;  	  ri->uptime = bgp_clock (); @@ -3407,7 +3405,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,  	  bgp_aggregate_increment (bgp, p, ri, afi, safi);  	  bgp_process (bgp, rn, afi, safi);  	  bgp_unlock_node (rn); -	  aspath_unintern (attr.aspath); +	  aspath_unintern (&attr.aspath);  	  bgp_attr_extra_free (&attr);  	  return;  	} @@ -3435,7 +3433,7 @@ bgp_static_update_main (struct bgp *bgp, struct prefix *p,    bgp_process (bgp, rn, afi, safi);    /* Unintern original. */ -  aspath_unintern (attr.aspath); +  aspath_unintern (&attr.aspath);    bgp_attr_extra_free (&attr);  } @@ -4169,7 +4167,7 @@ DEFUN (ipv6_bgp_network,         "Specify a network to announce via BGP\n"         "IPv6 prefix <network>/<length>\n")  { -  return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST, +  return bgp_static_set (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty),                           NULL, 0);  } @@ -4192,7 +4190,7 @@ DEFUN (no_ipv6_bgp_network,         "Specify a network to announce via BGP\n"         "IPv6 prefix <network>/<length>\n")  { -  return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, SAFI_UNICAST); +  return bgp_static_unset (vty, vty->index, argv[0], AFI_IP6, bgp_node_safi(vty));  }  ALIAS (no_ipv6_bgp_network, @@ -5244,7 +5242,8 @@ ALIAS (no_ipv6_aggregate_address_summary_only,  /* Redistribute route treatment. */  void -bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop, +bgp_redistribute_add (struct prefix *p, const struct in_addr *nexthop, +		      const struct in6_addr *nexthop6,  		      u_int32_t metric, u_char type)  {    struct bgp *bgp; @@ -5264,6 +5263,15 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,    if (nexthop)      attr.nexthop = *nexthop; +#ifdef HAVE_IPV6 +  if (nexthop6) +    { +      struct attr_extra *extra = bgp_attr_extra_get(&attr); +      extra->mp_nexthop_global = *nexthop6; +      extra->mp_nexthop_len = 16; +    } +#endif +    attr.med = metric;    attr.flag |= ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC); @@ -5299,7 +5307,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,  		  bgp_attr_extra_free (&attr_new);  		  /* Unintern original. */ -		  aspath_unintern (attr.aspath); +		  aspath_unintern (&attr.aspath);  		  bgp_attr_extra_free (&attr);  		  bgp_redistribute_delete (p, type);  		  return; @@ -5322,8 +5330,8 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,   	      if (attrhash_cmp (bi->attr, new_attr) &&  		  !CHECK_FLAG(bi->flags, BGP_INFO_REMOVED))   		{ - 		  bgp_attr_unintern (new_attr); - 		  aspath_unintern (attr.aspath); + 		  bgp_attr_unintern (&new_attr); + 		  aspath_unintern (&attr.aspath);   		  bgp_attr_extra_free (&attr);   		  bgp_unlock_node (bn);   		  return; @@ -5338,7 +5346,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,  		    bgp_info_restore(bn, bi);  		  else  		    bgp_aggregate_decrement (bgp, p, bi, afi, SAFI_UNICAST); - 		  bgp_attr_unintern (bi->attr); + 		  bgp_attr_unintern (&bi->attr);   		  bi->attr = new_attr;   		  bi->uptime = bgp_clock (); @@ -5346,7 +5354,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,   		  bgp_aggregate_increment (bgp, p, bi, afi, SAFI_UNICAST);   		  bgp_process (bgp, bn, afi, SAFI_UNICAST);   		  bgp_unlock_node (bn); - 		  aspath_unintern (attr.aspath); + 		  aspath_unintern (&attr.aspath);   		  bgp_attr_extra_free (&attr);   		  return;   		}  @@ -5368,7 +5376,7 @@ bgp_redistribute_add (struct prefix *p, struct in_addr *nexthop,      }    /* Unintern original. */ -  aspath_unintern (attr.aspath); +  aspath_unintern (&attr.aspath);    bgp_attr_extra_free (&attr);  } @@ -9379,10 +9387,8 @@ bgp_table_stats_vty (struct vty *vty, const char *name,          safi = SAFI_MULTICAST;        else if (strncmp (safi_str, "u", 1) == 0)          safi = SAFI_UNICAST; -      else if (strncmp (safi_str, "vpnv4", 5) == 0) -        safi = BGP_SAFI_VPNV4; -      else if (strncmp (safi_str, "vpnv6", 6) == 0) -        safi = BGP_SAFI_VPNV6; +      else if (strncmp (safi_str, "vpnv4", 5) == 0 || strncmp (safi_str, "vpnv6", 5) == 0) +        safi = SAFI_MPLS_LABELED_VPN;        else          {            vty_out (vty, "%% Invalid subsequent address family %s%s", @@ -9397,13 +9403,6 @@ bgp_table_stats_vty (struct vty *vty, const char *name,        return CMD_WARNING;      } -  if ((afi == AFI_IP && safi ==  BGP_SAFI_VPNV6) -      || (afi == AFI_IP6 && safi == BGP_SAFI_VPNV4)) -    { -      vty_out (vty, "%% Invalid subsequent address family %s for %s%s", -               afi_str, safi_str, VTY_NEWLINE); -      return CMD_WARNING; -    }    return bgp_table_stats (vty, bgp, afi, safi);  } @@ -12581,6 +12580,9 @@ bgp_route_init (void)    install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_cmd);    install_element (BGP_IPV6_NODE, &no_ipv6_aggregate_address_summary_only_cmd); +  install_element (BGP_IPV6M_NODE, &ipv6_bgp_network_cmd); +  install_element (BGP_IPV6M_NODE, &no_ipv6_bgp_network_cmd); +    /* Old config IPv6 BGP commands.  */    install_element (BGP_NODE, &old_ipv6_bgp_network_cmd);    install_element (BGP_NODE, &old_no_ipv6_bgp_network_cmd); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 3e528596..7adc573b 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -192,7 +192,9 @@ extern int bgp_nlri_parse (struct peer *, struct attr *, struct bgp_nlri *);  extern int bgp_maximum_prefix_overflow (struct peer *, afi_t, safi_t, int); -extern void bgp_redistribute_add (struct prefix *, struct in_addr *, u_int32_t, u_char); +extern void bgp_redistribute_add (struct prefix *, const struct in_addr *, +				  const struct in6_addr *, +				  u_int32_t, u_char);  extern void bgp_redistribute_delete (struct prefix *, u_char);  extern void bgp_redistribute_withdraw (struct bgp *, afi_t, int); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 255b25ae..abb85fd2 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -525,8 +525,13 @@ route_match_metric_compile (const char *arg)    char *endptr = NULL;    unsigned long tmpval; +  /* Metric value shoud be integer. */ +  if (! all_digit (arg)) +    return NULL; + +  errno = 0;    tmpval = strtoul (arg, &endptr, 10); -  if (*endptr != '\0' || tmpval == ULONG_MAX || tmpval > UINT32_MAX) +  if (*endptr != '\0' || errno || tmpval > UINT32_MAX)      return NULL;    med = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); @@ -790,6 +795,75 @@ struct route_map_rule_cmd route_match_origin_cmd =    route_match_origin_compile,    route_match_origin_free  }; + +/* match probability  { */ + +static route_map_result_t +route_match_probability (void *rule, struct prefix *prefix, +		    route_map_object_t type, void *object) +{ +  long r; +#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 +  r = random(); +#else +  r = (long) rand(); +#endif + +  switch (*(unsigned *) rule) +  { +    case 0: break; +    case RAND_MAX: return RMAP_MATCH; +    default: +      if (r < *(unsigned *) rule) +        { +          return RMAP_MATCH; +        } +  } + +  return RMAP_NOMATCH; +} + +static void * +route_match_probability_compile (const char *arg) +{ +  unsigned *lobule; +  unsigned  perc; + +#if _SVID_SOURCE || _BSD_SOURCE || _XOPEN_SOURCE >= 500 +  srandom (time (NULL)); +#else +  srand (time (NULL)); +#endif + +  perc    = atoi (arg); +  lobule  = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (unsigned)); + +  switch (perc) +    { +      case 0:   *lobule = 0; break; +      case 100: *lobule = RAND_MAX; break; +      default:  *lobule = RAND_MAX / 100 * perc; +    } + +  return lobule; +} + +static void +route_match_probability_free (void *rule) +{ +  XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +struct route_map_rule_cmd route_match_probability_cmd = +{ +  "probability", +  route_match_probability, +  route_match_probability_compile, +  route_match_probability_free +}; + +/* } */ +  /* `set ip next-hop IP_ADDRESS' */  /* Set nexthop to object.  ojbect must be pointer to struct attr. */ @@ -933,8 +1007,9 @@ route_set_local_pref_compile (const char *arg)    if (! all_digit (arg))      return NULL; +  errno = 0;    tmp = strtoul (arg, &endptr, 10); -  if (*endptr != '\0' || tmp == ULONG_MAX || tmp > UINT32_MAX) +  if (*endptr != '\0' || errno || tmp > UINT32_MAX)      return NULL;    local_pref = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t));  @@ -1001,9 +1076,9 @@ route_set_weight_compile (const char *arg)    if (! all_digit (arg))      return NULL; - +  errno = 0;    tmp = strtoul (arg, &endptr, 10); -  if (*endptr != '\0' || tmp == ULONG_MAX || tmp > UINT32_MAX) +  if (*endptr != '\0' || errno || tmp > UINT32_MAX)      return NULL;    weight = XMALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (u_int32_t)); @@ -1092,8 +1167,9 @@ route_set_metric_compile (const char *arg)    if (all_digit (arg))      {        /* set metric value check*/ +      errno = 0;        larg = strtoul (arg, &endptr, 10); -      if (*endptr != '\0' || larg == ULONG_MAX || larg > UINT32_MAX) +      if (*endptr != '\0' || errno || larg > UINT32_MAX)          return NULL;        metric = larg;      } @@ -1105,8 +1181,9 @@ route_set_metric_compile (const char *arg)  	   || (! all_digit (arg+1)))  	return NULL; +      errno = 0;        larg = strtoul (arg+1, &endptr, 10); -      if (*endptr != '\0' || larg == ULONG_MAX || larg > UINT32_MAX) +      if (*endptr != '\0' || errno || larg > UINT32_MAX)  	return NULL;        metric = larg;      } @@ -1482,10 +1559,10 @@ route_set_ecommunity_rt (void *rule, struct prefix *prefix,        else  	new_ecom = ecommunity_dup (ecom); -      bgp_info->attr->extra->ecommunity = new_ecom; +      bgp_info->attr->extra->ecommunity = ecommunity_intern (new_ecom);        if (old_ecom) -	ecommunity_free (old_ecom); +	ecommunity_unintern (&old_ecom);        bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);      } @@ -1501,7 +1578,7 @@ route_set_ecommunity_rt_compile (const char *arg)    ecom = ecommunity_str2com (arg, ECOMMUNITY_ROUTE_TARGET, 0);    if (! ecom)      return NULL; -  return ecom; +  return ecommunity_intern (ecom);  }  /* Free function for set community. */ @@ -1509,7 +1586,7 @@ static void  route_set_ecommunity_rt_free (void *rule)  {    struct ecommunity *ecom = rule; -  ecommunity_free (ecom); +  ecommunity_unintern (&ecom);  }  /* Set community rule structure. */ @@ -1528,7 +1605,7 @@ static route_map_result_t  route_set_ecommunity_soo (void *rule, struct prefix *prefix,   			 route_map_object_t type, void *object)  { -  struct ecommunity *ecom; +  struct ecommunity *ecom, *old_ecom, *new_ecom;    struct bgp_info *bgp_info;    if (type == RMAP_BGP) @@ -1539,8 +1616,19 @@ route_set_ecommunity_soo (void *rule, struct prefix *prefix,        if (! ecom)  	return RMAP_OKAY; +      old_ecom = (bgp_attr_extra_get (bgp_info->attr))->ecommunity; +       +      if (old_ecom) +	new_ecom = ecommunity_merge (ecommunity_dup (old_ecom), ecom); +      else +	new_ecom = ecommunity_dup (ecom); + +      bgp_info->attr->extra->ecommunity = ecommunity_intern (new_ecom); + +      if (old_ecom) +	ecommunity_unintern (&old_ecom); +        bgp_info->attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES); -      (bgp_attr_extra_get (bgp_info->attr))->ecommunity = ecommunity_dup (ecom);      }    return RMAP_OKAY;  } @@ -1555,7 +1643,7 @@ route_set_ecommunity_soo_compile (const char *arg)    if (! ecom)      return NULL; -  return ecom; +  return ecommunity_intern (ecom);  }  /* Free function for set community. */ @@ -1563,7 +1651,7 @@ static void  route_set_ecommunity_soo_free (void *rule)  {    struct ecommunity *ecom = rule; -  ecommunity_free (ecom); +  ecommunity_unintern (&ecom);  }  /* Set community rule structure. */ @@ -2451,6 +2539,38 @@ ALIAS (no_match_ip_next_hop,         "IP access-list number (expanded range)\n"         "IP Access-list name\n") +/* match probability { */ + +DEFUN (match_probability, +       match_probability_cmd, +       "match probability <0-100>", +       MATCH_STR +       "Match portion of routes defined by percentage value\n" +       "Percentage of routes\n") +{ +  return bgp_route_match_add (vty, vty->index, "probability", argv[0]); +} + +DEFUN (no_match_probability, +       no_match_probability_cmd, +       "no match probability", +       NO_STR +       MATCH_STR +       "Match portion of routes defined by percentage value\n") +{ +  return bgp_route_match_delete (vty, vty->index, "probability", argc ? argv[0] : NULL); +} + +ALIAS (no_match_probability, +       no_match_probability_val_cmd, +       "no match probability <1-99>", +       NO_STR +       MATCH_STR +       "Match portion of routes defined by percentage value\n" +       "Percentage of routes\n") + +/* } */ +  DEFUN (match_ip_route_source,          match_ip_route_source_cmd,         "match ip route-source (<1-199>|<1300-2699>|WORD)", @@ -3738,6 +3858,7 @@ bgp_route_map_init (void)    route_map_install_match (&route_match_ecommunity_cmd);    route_map_install_match (&route_match_metric_cmd);    route_map_install_match (&route_match_origin_cmd); +  route_map_install_match (&route_match_probability_cmd);    route_map_install_set (&route_set_ip_nexthop_cmd);    route_map_install_set (&route_set_local_pref_cmd); @@ -3769,7 +3890,6 @@ bgp_route_map_init (void)    install_element (RMAP_NODE, &match_ip_route_source_cmd);    install_element (RMAP_NODE, &no_match_ip_route_source_cmd);    install_element (RMAP_NODE, &no_match_ip_route_source_val_cmd); -    install_element (RMAP_NODE, &match_ip_address_prefix_list_cmd);    install_element (RMAP_NODE, &no_match_ip_address_prefix_list_cmd);    install_element (RMAP_NODE, &no_match_ip_address_prefix_list_val_cmd); @@ -3797,6 +3917,9 @@ bgp_route_map_init (void)    install_element (RMAP_NODE, &match_origin_cmd);    install_element (RMAP_NODE, &no_match_origin_cmd);    install_element (RMAP_NODE, &no_match_origin_val_cmd); +  install_element (RMAP_NODE, &match_probability_cmd); +  install_element (RMAP_NODE, &no_match_probability_cmd); +  install_element (RMAP_NODE, &no_match_probability_val_cmd);    install_element (RMAP_NODE, &set_ip_nexthop_cmd);    install_element (RMAP_NODE, &set_ip_nexthop_peer_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index e7e7dba1..f65bb157 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3707,7 +3707,7 @@ peer_maximum_prefix_set_vty (struct vty *vty, const char *ip_str, afi_t afi,    if (! peer)      return CMD_WARNING; -  VTY_GET_INTEGER ("maxmum number", max, num_str); +  VTY_GET_INTEGER ("maximum number", max, num_str);    if (threshold_str)      threshold = atoi (threshold_str);    else @@ -4215,18 +4215,10 @@ bgp_clear (struct vty *vty, struct bgp *bgp,  afi_t afi, safi_t safi,    if (sort == clear_as)      {        as_t as; -      unsigned long as_ul;        int find = 0; -      VTY_GET_LONG ("AS", as_ul, arg); +      VTY_GET_INTEGER_RANGE ("AS", as, arg, 1, BGP_AS4_MAX); -      if (!as_ul) -	{ -	  vty_out (vty, "Invalid AS number%s", VTY_NEWLINE);  -	  return CMD_WARNING; -	} -      as = (as_t) as_ul; -        for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer))  	{  	  if (peer->as != as)  @@ -8381,57 +8373,16 @@ ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary,  /* Redistribute VTY commands.  */ -/* Utility function to convert user input route type string to route -   type.  */ -static int -bgp_str2route_type (int afi, const char *str) -{ -  if (! str) -    return 0; - -  if (afi == AFI_IP) -    { -      if (strncmp (str, "k", 1) == 0) -	return ZEBRA_ROUTE_KERNEL; -      else if (strncmp (str, "c", 1) == 0) -	return ZEBRA_ROUTE_CONNECT; -      else if (strncmp (str, "s", 1) == 0) -	return ZEBRA_ROUTE_STATIC; -      else if (strncmp (str, "r", 1) == 0) -	return ZEBRA_ROUTE_RIP; -      else if (strncmp (str, "o", 1) == 0) -	return ZEBRA_ROUTE_OSPF; -    } -  if (afi == AFI_IP6) -    { -      if (strncmp (str, "k", 1) == 0) -	return ZEBRA_ROUTE_KERNEL; -      else if (strncmp (str, "c", 1) == 0) -	return ZEBRA_ROUTE_CONNECT; -      else if (strncmp (str, "s", 1) == 0) -	return ZEBRA_ROUTE_STATIC; -      else if (strncmp (str, "r", 1) == 0) -	return ZEBRA_ROUTE_RIPNG; -      else if (strncmp (str, "o", 1) == 0) -	return ZEBRA_ROUTE_OSPF6; -    } -  return 0; -} -  DEFUN (bgp_redistribute_ipv4,         bgp_redistribute_ipv4_cmd, -       "redistribute (connected|kernel|ospf|rip|static)", +       "redistribute " QUAGGA_IP_REDIST_STR_BGPD,         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPF)\n" -       "Routing Information Protocol (RIP)\n" -       "Static routes\n") +       QUAGGA_IP_REDIST_HELP_STR_BGPD)  {    int type; -  type = bgp_str2route_type (AFI_IP, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8441,20 +8392,16 @@ DEFUN (bgp_redistribute_ipv4,  DEFUN (bgp_redistribute_ipv4_rmap,         bgp_redistribute_ipv4_rmap_cmd, -       "redistribute (connected|kernel|ospf|rip|static) route-map WORD", +       "redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD",         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPF)\n" -       "Routing Information Protocol (RIP)\n" -       "Static routes\n" +       QUAGGA_IP_REDIST_HELP_STR_BGPD         "Route map reference\n"         "Pointer to route-map entries\n")  {    int type; -  type = bgp_str2route_type (AFI_IP, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8466,21 +8413,17 @@ DEFUN (bgp_redistribute_ipv4_rmap,  DEFUN (bgp_redistribute_ipv4_metric,         bgp_redistribute_ipv4_metric_cmd, -       "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", +       "redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>",         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPF)\n" -       "Routing Information Protocol (RIP)\n" -       "Static routes\n" +       QUAGGA_IP_REDIST_HELP_STR_BGPD         "Metric for redistributed routes\n"         "Default metric\n")  {    int type;    u_int32_t metric; -  type = bgp_str2route_type (AFI_IP, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8493,13 +8436,9 @@ DEFUN (bgp_redistribute_ipv4_metric,  DEFUN (bgp_redistribute_ipv4_rmap_metric,         bgp_redistribute_ipv4_rmap_metric_cmd, -       "redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", +       "redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPF)\n" -       "Routing Information Protocol (RIP)\n" -       "Static routes\n" +       QUAGGA_IP_REDIST_HELP_STR_BGPD         "Route map reference\n"         "Pointer to route-map entries\n"         "Metric for redistributed routes\n" @@ -8508,8 +8447,8 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric,    int type;    u_int32_t metric; -  type = bgp_str2route_type (AFI_IP, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8523,13 +8462,9 @@ DEFUN (bgp_redistribute_ipv4_rmap_metric,  DEFUN (bgp_redistribute_ipv4_metric_rmap,         bgp_redistribute_ipv4_metric_rmap_cmd, -       "redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", +       "redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPF)\n" -       "Routing Information Protocol (RIP)\n" -       "Static routes\n" +       QUAGGA_IP_REDIST_HELP_STR_BGPD         "Metric for redistributed routes\n"         "Default metric\n"         "Route map reference\n" @@ -8538,8 +8473,8 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap,    int type;    u_int32_t metric; -  type = bgp_str2route_type (AFI_IP, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8553,19 +8488,15 @@ DEFUN (bgp_redistribute_ipv4_metric_rmap,  DEFUN (no_bgp_redistribute_ipv4,         no_bgp_redistribute_ipv4_cmd, -       "no redistribute (connected|kernel|ospf|rip|static)", +       "no redistribute " QUAGGA_IP_REDIST_STR_BGPD,         NO_STR         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPF)\n" -       "Routing Information Protocol (RIP)\n" -       "Static routes\n") +       QUAGGA_IP_REDIST_HELP_STR_BGPD)  {    int type; -  type = bgp_str2route_type (AFI_IP, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8576,21 +8507,17 @@ DEFUN (no_bgp_redistribute_ipv4,  DEFUN (no_bgp_redistribute_ipv4_rmap,         no_bgp_redistribute_ipv4_rmap_cmd, -       "no redistribute (connected|kernel|ospf|rip|static) route-map WORD", +       "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD",         NO_STR         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPF)\n" -       "Routing Information Protocol (RIP)\n" -       "Static routes\n" +       QUAGGA_IP_REDIST_HELP_STR_BGPD         "Route map reference\n"         "Pointer to route-map entries\n")  {    int type; -  type = bgp_str2route_type (AFI_IP, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8602,21 +8529,17 @@ DEFUN (no_bgp_redistribute_ipv4_rmap,  DEFUN (no_bgp_redistribute_ipv4_metric,         no_bgp_redistribute_ipv4_metric_cmd, -       "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295>", +       "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295>",         NO_STR         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPF)\n" -       "Routing Information Protocol (RIP)\n" -       "Static routes\n" +       QUAGGA_IP_REDIST_HELP_STR_BGPD         "Metric for redistributed routes\n"         "Default metric\n")  {    int type; -  type = bgp_str2route_type (AFI_IP, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8628,14 +8551,10 @@ DEFUN (no_bgp_redistribute_ipv4_metric,  DEFUN (no_bgp_redistribute_ipv4_rmap_metric,         no_bgp_redistribute_ipv4_rmap_metric_cmd, -       "no redistribute (connected|kernel|ospf|rip|static) route-map WORD metric <0-4294967295>", +       "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",         NO_STR         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPF)\n" -       "Routing Information Protocol (RIP)\n" -       "Static routes\n" +       QUAGGA_IP_REDIST_HELP_STR_BGPD         "Route map reference\n"         "Pointer to route-map entries\n"         "Metric for redistributed routes\n" @@ -8643,8 +8562,8 @@ DEFUN (no_bgp_redistribute_ipv4_rmap_metric,  {    int type; -  type = bgp_str2route_type (AFI_IP, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8657,14 +8576,10 @@ DEFUN (no_bgp_redistribute_ipv4_rmap_metric,  ALIAS (no_bgp_redistribute_ipv4_rmap_metric,         no_bgp_redistribute_ipv4_metric_rmap_cmd, -       "no redistribute (connected|kernel|ospf|rip|static) metric <0-4294967295> route-map WORD", +       "no redistribute " QUAGGA_IP_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",         NO_STR         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPF)\n" -       "Routing Information Protocol (RIP)\n" -       "Static routes\n" +       QUAGGA_IP_REDIST_HELP_STR_BGPD         "Metric for redistributed routes\n"         "Default metric\n"         "Route map reference\n" @@ -8673,18 +8588,14 @@ ALIAS (no_bgp_redistribute_ipv4_rmap_metric,  #ifdef HAVE_IPV6  DEFUN (bgp_redistribute_ipv6,         bgp_redistribute_ipv6_cmd, -       "redistribute (connected|kernel|ospf6|ripng|static)", +       "redistribute " QUAGGA_IP6_REDIST_STR_BGPD,         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPFv3)\n" -       "Routing Information Protocol (RIPng)\n" -       "Static routes\n") +       QUAGGA_IP6_REDIST_HELP_STR_BGPD)  {    int type; -  type = bgp_str2route_type (AFI_IP6, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP6, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8695,20 +8606,16 @@ DEFUN (bgp_redistribute_ipv6,  DEFUN (bgp_redistribute_ipv6_rmap,         bgp_redistribute_ipv6_rmap_cmd, -       "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", +       "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD",         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPFv3)\n" -       "Routing Information Protocol (RIPng)\n" -       "Static routes\n" +       QUAGGA_IP6_REDIST_HELP_STR_BGPD         "Route map reference\n"         "Pointer to route-map entries\n")  {    int type; -  type = bgp_str2route_type (AFI_IP6, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP6, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8720,21 +8627,17 @@ DEFUN (bgp_redistribute_ipv6_rmap,  DEFUN (bgp_redistribute_ipv6_metric,         bgp_redistribute_ipv6_metric_cmd, -       "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", +       "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>",         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPFv3)\n" -       "Routing Information Protocol (RIPng)\n" -       "Static routes\n" +       QUAGGA_IP6_REDIST_HELP_STR_BGPD         "Metric for redistributed routes\n"         "Default metric\n")  {    int type;    u_int32_t metric; -  type = bgp_str2route_type (AFI_IP6, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP6, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8747,13 +8650,9 @@ DEFUN (bgp_redistribute_ipv6_metric,  DEFUN (bgp_redistribute_ipv6_rmap_metric,         bgp_redistribute_ipv6_rmap_metric_cmd, -       "redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", +       "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPFv3)\n" -       "Routing Information Protocol (RIPng)\n" -       "Static routes\n" +       QUAGGA_IP6_REDIST_HELP_STR_BGPD         "Route map reference\n"         "Pointer to route-map entries\n"         "Metric for redistributed routes\n" @@ -8762,8 +8661,8 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric,    int type;    u_int32_t metric; -  type = bgp_str2route_type (AFI_IP6, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP6, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8777,13 +8676,9 @@ DEFUN (bgp_redistribute_ipv6_rmap_metric,  DEFUN (bgp_redistribute_ipv6_metric_rmap,         bgp_redistribute_ipv6_metric_rmap_cmd, -       "redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", +       "redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPFv3)\n" -       "Routing Information Protocol (RIPng)\n" -       "Static routes\n" +       QUAGGA_IP6_REDIST_HELP_STR_BGPD         "Metric for redistributed routes\n"         "Default metric\n"         "Route map reference\n" @@ -8792,8 +8687,8 @@ DEFUN (bgp_redistribute_ipv6_metric_rmap,    int type;    u_int32_t metric; -  type = bgp_str2route_type (AFI_IP6, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP6, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8807,19 +8702,15 @@ DEFUN (bgp_redistribute_ipv6_metric_rmap,  DEFUN (no_bgp_redistribute_ipv6,         no_bgp_redistribute_ipv6_cmd, -       "no redistribute (connected|kernel|ospf6|ripng|static)", +       "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD,         NO_STR         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPFv3)\n" -       "Routing Information Protocol (RIPng)\n" -       "Static routes\n") +       QUAGGA_IP6_REDIST_HELP_STR_BGPD)  {    int type; -  type = bgp_str2route_type (AFI_IP6, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP6, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8830,21 +8721,17 @@ DEFUN (no_bgp_redistribute_ipv6,  DEFUN (no_bgp_redistribute_ipv6_rmap,         no_bgp_redistribute_ipv6_rmap_cmd, -       "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD", +       "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD",         NO_STR         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPFv3)\n" -       "Routing Information Protocol (RIPng)\n" -       "Static routes\n" +       QUAGGA_IP6_REDIST_HELP_STR_BGPD         "Route map reference\n"         "Pointer to route-map entries\n")  {    int type; -  type = bgp_str2route_type (AFI_IP6, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP6, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8856,21 +8743,17 @@ DEFUN (no_bgp_redistribute_ipv6_rmap,  DEFUN (no_bgp_redistribute_ipv6_metric,         no_bgp_redistribute_ipv6_metric_cmd, -       "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295>", +       "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295>",         NO_STR         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPFv3)\n" -       "Routing Information Protocol (RIPng)\n" -       "Static routes\n" +       QUAGGA_IP6_REDIST_HELP_STR_BGPD         "Metric for redistributed routes\n"         "Default metric\n")  {    int type; -  type = bgp_str2route_type (AFI_IP6, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP6, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8882,14 +8765,10 @@ DEFUN (no_bgp_redistribute_ipv6_metric,  DEFUN (no_bgp_redistribute_ipv6_rmap_metric,         no_bgp_redistribute_ipv6_rmap_metric_cmd, -       "no redistribute (connected|kernel|ospf6|ripng|static) route-map WORD metric <0-4294967295>", +       "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " route-map WORD metric <0-4294967295>",         NO_STR         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPFv3)\n" -       "Routing Information Protocol (RIPng)\n" -       "Static routes\n" +       QUAGGA_IP6_REDIST_HELP_STR_BGPD         "Route map reference\n"         "Pointer to route-map entries\n"         "Metric for redistributed routes\n" @@ -8897,8 +8776,8 @@ DEFUN (no_bgp_redistribute_ipv6_rmap_metric,  {    int type; -  type = bgp_str2route_type (AFI_IP6, argv[0]); -  if (! type) +  type = proto_redistnum (AFI_IP6, argv[0]); +  if (type < 0 || type == ZEBRA_ROUTE_BGP)      {        vty_out (vty, "%% Invalid route type%s", VTY_NEWLINE);        return CMD_WARNING; @@ -8911,14 +8790,10 @@ DEFUN (no_bgp_redistribute_ipv6_rmap_metric,  ALIAS (no_bgp_redistribute_ipv6_rmap_metric,         no_bgp_redistribute_ipv6_metric_rmap_cmd, -       "no redistribute (connected|kernel|ospf6|ripng|static) metric <0-4294967295> route-map WORD", +       "no redistribute " QUAGGA_IP6_REDIST_STR_BGPD " metric <0-4294967295> route-map WORD",         NO_STR         "Redistribute information from another routing protocol\n" -       "Connected\n" -       "Kernel routes\n" -       "Open Shurtest Path First (OSPFv3)\n" -       "Routing Information Protocol (RIPng)\n" -       "Static routes\n" +       QUAGGA_IP6_REDIST_HELP_STR_BGPD         "Metric for redistributed routes\n"         "Default metric\n"         "Route map reference\n" diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index f3baeee0..20feba0f 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -232,12 +232,10 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)  {    struct stream *s;    struct zapi_ipv4 api; -  unsigned long ifindex;    struct in_addr nexthop;    struct prefix_ipv4 p;    s = zclient->ibuf; -  ifindex = 0;    nexthop.s_addr = 0;    /* Type, flags, message. */ @@ -260,7 +258,7 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))      {        api.ifindex_num = stream_getc (s); -      ifindex = stream_getl (s); +      stream_getl (s); /* ifindex, unused */      }    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))      api.distance = stream_getc (s); @@ -281,7 +279,8 @@ zebra_read_ipv4 (int command, struct zclient *zclient, zebra_size_t length)  		     inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])),  		     api.metric);  	} -      bgp_redistribute_add((struct prefix *)&p, &nexthop, api.metric, api.type); +      bgp_redistribute_add((struct prefix *)&p, &nexthop, NULL, +			   api.metric, api.type);      }    else      { @@ -309,12 +308,10 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)  {    struct stream *s;    struct zapi_ipv6 api; -  unsigned long ifindex;    struct in6_addr nexthop;    struct prefix_ipv6 p;    s = zclient->ibuf; -  ifindex = 0;    memset (&nexthop, 0, sizeof (struct in6_addr));    /* Type, flags, message. */ @@ -337,7 +334,7 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX))      {        api.ifindex_num = stream_getc (s); -      ifindex = stream_getl (s); +      stream_getl (s); /* ifindex, unused */      }    if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE))      api.distance = stream_getc (s); @@ -356,23 +353,29 @@ zebra_read_ipv6 (int command, struct zclient *zclient, zebra_size_t length)      {        if (BGP_DEBUG(zebra, ZEBRA))  	{ -	  char buf[INET6_ADDRSTRLEN]; -	  zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d metric %u", +	  char buf[2][INET6_ADDRSTRLEN]; +	  zlog_debug("Zebra rcvd: IPv6 route add %s %s/%d nexthop %s metric %u",  		     zebra_route_string(api.type), -		     inet_ntop(AF_INET6, &p.prefix, buf, sizeof(buf)), -		     p.prefixlen, api.metric); +		     inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), +		     p.prefixlen, +		     inet_ntop(AF_INET, &nexthop, buf[1], sizeof(buf[1])), +		     api.metric);  	} -      bgp_redistribute_add ((struct prefix *)&p, NULL, api.metric, api.type); +      bgp_redistribute_add ((struct prefix *)&p, NULL, &nexthop, +			    api.metric, api.type);      }    else      {        if (BGP_DEBUG(zebra, ZEBRA))  	{ -	  char buf[INET6_ADDRSTRLEN]; -	  zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d metric %u", +	  char buf[2][INET6_ADDRSTRLEN]; +	  zlog_debug("Zebra rcvd: IPv6 route delete %s %s/%d " +		     "nexthop %s metric %u",  		     zebra_route_string(api.type), -		     inet_ntop(AF_INET6, &p.prefix, buf, sizeof(buf)), -		     p.prefixlen, api.metric); +		     inet_ntop(AF_INET6, &p.prefix, buf[0], sizeof(buf[0])), +		     p.prefixlen, +		     inet_ntop(AF_INET6, &nexthop, buf[1], sizeof(buf[1])), +		     api.metric);  	}        bgp_redistribute_delete ((struct prefix *) &p, api.type);      } @@ -640,7 +643,7 @@ bgp_nexthop_set (union sockunion *local, union sockunion *remote,  }  void -bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp) +bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp, safi_t safi)  {    int flags;    u_char distance; @@ -675,6 +678,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)        api.type = ZEBRA_ROUTE_BGP;        api.message = 0; +      api.safi = safi;        SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);        api.nexthop_num = 1;        api.nexthop = &nexthop; @@ -749,6 +753,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)        api.flags = flags;        api.type = ZEBRA_ROUTE_BGP;        api.message = 0; +      api.safi = safi;        SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);        api.nexthop_num = 1;        api.nexthop = &nexthop; @@ -775,7 +780,7 @@ bgp_zebra_announce (struct prefix *p, struct bgp_info *info, struct bgp *bgp)  }  void -bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info) +bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info, safi_t safi)  {    int flags;    struct peer *peer; @@ -809,6 +814,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info)        api.type = ZEBRA_ROUTE_BGP;        api.message = 0; +      api.safi = safi;        SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);        api.nexthop_num = 1;        api.nexthop = &nexthop; @@ -864,6 +870,7 @@ bgp_zebra_withdraw (struct prefix *p, struct bgp_info *info)        api.flags = flags;        api.type = ZEBRA_ROUTE_BGP;        api.message = 0; +      api.safi = safi;        SET_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP);        api.nexthop_num = 1;        api.nexthop = &nexthop; diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index bd953864..1351333f 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -25,8 +25,8 @@ extern void bgp_zebra_init (void);  extern int bgp_if_update_all (void);  extern int bgp_config_write_redistribute (struct vty *, struct bgp *, afi_t, safi_t,  				   int *); -extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *); -extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *); +extern void bgp_zebra_announce (struct prefix *, struct bgp_info *, struct bgp *, safi_t); +extern void bgp_zebra_withdraw (struct prefix *, struct bgp_info *, safi_t);  extern int bgp_redistribute_set (struct bgp *, afi_t, int);  extern int bgp_redistribute_rmap_set (struct bgp *, afi_t, int, const char *); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index ee0cc5da..5dc014be 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -695,7 +695,7 @@ peer_sort (struct peer *peer)      }  } -static inline void +static void  peer_free (struct peer *peer)  {    assert (peer->status == Deleted); @@ -1147,7 +1147,7 @@ peer_nsf_stop (struct peer *peer)    UNSET_FLAG (peer->sflags, PEER_STATUS_NSF_MODE);    for (afi = AFI_IP ; afi < AFI_MAX ; afi++) -    for (safi = SAFI_UNICAST ; safi < SAFI_UNICAST_MULTICAST ; safi++) +    for (safi = SAFI_UNICAST ; safi < SAFI_RESERVED_3 ; safi++)        peer->nsf[afi][safi] = 0;    if (peer->t_gr_restart) @@ -2048,6 +2048,10 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name)  	}      } +  bgp = bgp_create (as, name); +  bgp_router_id_set(bgp, &router_id_zebra); +  *bgp_val = bgp; +    /* Create BGP server socket, if first instance.  */    if (list_isempty(bm->bgp))      { @@ -2055,10 +2059,7 @@ bgp_get (struct bgp **bgp_val, as_t *as, const char *name)  	return BGP_ERR_INVALID_VALUE;      } -  bgp = bgp_create (as, name);    listnode_add (bm->bgp, bgp); -  bgp_router_id_set(bgp, &router_id_zebra); -  *bgp_val = bgp;    return 0;  } @@ -4720,12 +4721,10 @@ static void  bgp_config_write_peer (struct vty *vty, struct bgp *bgp,  		       struct peer *peer, afi_t afi, safi_t safi)  { -  struct bgp_filter *filter;    struct peer *g_peer = NULL;    char buf[SU_ADDRSTRLEN];    char *addr; -  filter = &peer->filter[afi][safi];    addr = peer->host;    if (peer_group_active (peer))      g_peer = peer->group->conf; @@ -5014,6 +5013,11 @@ bgp_config_write_peer (struct vty *vty, struct bgp *bgp,        && ! peer->af_group[afi][safi])      vty_out (vty, " neighbor %s route-server-client%s", addr, VTY_NEWLINE); +  /* Nexthop-local unchanged. */ +  if (CHECK_FLAG (peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) +      && ! peer->af_group[afi][safi]) +    vty_out (vty, " neighbor %s nexthop-local unchanged%s", addr, VTY_NEWLINE); +    /* Allow AS in.  */    if (peer_af_flag_check (peer, afi, safi, PEER_FLAG_ALLOWAS_IN))      if (! peer_group_active (peer) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 4da19e71..892e7dec 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -632,6 +632,8 @@ struct bgp_nlri  #define BGP_NOTIFY_CAPABILITY_ERR                7  #define BGP_NOTIFY_MAX	                         8 +#define BGP_NOTIFY_SUBCODE_UNSPECIFIC            0 +  /* BGP_NOTIFY_HEADER_ERR sub codes.  */  #define BGP_NOTIFY_HEADER_NOT_SYNC               1  #define BGP_NOTIFY_HEADER_BAD_MESLEN             2 @@ -662,7 +664,7 @@ struct bgp_nlri  #define BGP_NOTIFY_UPDATE_MAL_AS_PATH           11  #define BGP_NOTIFY_UPDATE_MAX                   12 -/* BGP_NOTIFY_CEASE sub codes (draft-ietf-idr-cease-subcode-05).  */ +/* BGP_NOTIFY_CEASE sub codes (RFC 4486).  */  #define BGP_NOTIFY_CEASE_MAX_PREFIX              1  #define BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN          2  #define BGP_NOTIFY_CEASE_PEER_UNCONFIG           3 @@ -725,9 +727,8 @@ struct bgp_nlri  #define BGP_DEFAULT_RESTART_TIME               120  #define BGP_DEFAULT_STALEPATH_TIME             360 -/* SAFI which used in open capability negotiation.  */ -#define BGP_SAFI_VPNV4                         128 -#define BGP_SAFI_VPNV6                         129 +/* RFC4364 */ +#define SAFI_MPLS_LABELED_VPN                  128  /* Max TTL value.  */  #define TTL_MAX                                255 | 
