Marker merge for 'RE-0.99.17.6'

This marker merge (i.e. an 'ours' strategy merge) is a placeholder to show
that all commits in Quagga-RE stable, to its release RE-0.99.17.6 tag, have
been reviewed and merged into 'master'.
diff --git a/README.NetBSD b/README.NetBSD
index 9aac4c3..6bbc680 100755
--- a/README.NetBSD
+++ b/README.NetBSD
@@ -20,13 +20,15 @@
 case $1 in
 
     build)
+	# Omitted because it is now default:
+	#   --enable-opaque-lsa
 	./bootstrap.sh
 	LDFLAGS="-L/usr/pkg/lib -R/usr/pkg/lib" CPPFLAGS="-I/usr/pkg/include" \
     	./configure --prefix=${PREFIX} \
 	    --sysconfdir=/etc/zebra --localstatedir=/var/run/zebra \
 	    --enable-exampledir=${PREFIX}/share/examples/zebra \
 	    --enable-pkgsrcrcdir=${PREFIX}/etc/rc.d \
-	    --enable-opaque-lsa --enable-vtysh
+	    --enable-vtysh
 	${MAKE}
 	;;
 
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index 87eb7ac..666218f 100644
--- a/bgpd/bgp_advertise.c
+++ b/bgpd/bgp_advertise.c
@@ -140,13 +140,13 @@
     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 @@
 		    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 @@
 	{
 	  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 @@
 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 5a73eef..776c712 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -91,13 +91,13 @@
 /* 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 @@
 
 /* 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,78 +673,78 @@
   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)
         {
+          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);
       
-          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 ;
-          } ;
-        }
-      else
-        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"
+      /* 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).
            */
-      if ((seg_size == 0) || (seg_size > length) || (segh.length == 0))
+          || ((sizeof segh.length > 1) 
+              && (0x10 + segh.length > 0x10 + AS_SEGMENT_MAX)))
         {
+          if (head)
             assegment_free_all (head);
-          return NULL;
+          return -1;
         }
       
-      length -= seg_size ;
+      switch (segh.type)
+        {
+          case AS_SEQUENCE:
+          case AS_SET:
+          case AS_CONFED_SEQUENCE:
+          case AS_CONFED_SET:
+            break;
+          default:
+            if (head)
+              assegment_free_all (head);
+            return -1;
+        }
       
       /* now its safe to trust lengths */
       seg = assegment_new (segh.type, segh.length);
@@ -755,52 +757,47 @@
       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.
    */
@@ -808,12 +805,14 @@
   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;
@@ -831,7 +830,7 @@
       }
 }
 
-static inline size_t
+static size_t
 assegment_header_put (struct stream *s, u_char type, int length)
 {
   size_t lenp;
@@ -1631,7 +1630,7 @@
 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 d63b914..d55f9ce 100644
--- a/bgpd/bgp_aspath.h
+++ b/bgpd/bgp_aspath.h
@@ -65,7 +65,7 @@
 /* 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_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 2205e26..92c1a09 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -28,6 +28,7 @@
 #include "stream.h"
 #include "log.h"
 #include "hash.h"
+#include "jhash.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_attr.h"
@@ -127,18 +128,9 @@
 static unsigned int
 cluster_hash_key_make (void *p)
 {
-  struct cluster_list * cluster = (struct cluster_list *) p;
-  unsigned int key = 0;
-  int length;
-  caddr_t pnt;
+  const struct cluster_list *cluster = p;
 
-  length = cluster->length;
-  pnt = (caddr_t) cluster->list;
-  
-  while (length)
-    key += pnt[--length];
-
-  return key;
+  return jhash(cluster->list, cluster->length, 0);
 }
 
 static int
@@ -194,14 +186,12 @@
 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);
     }
 }
@@ -254,14 +244,12 @@
 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);
     }
 }
@@ -269,18 +257,9 @@
 static unsigned int
 transit_hash_key_make (void *p)
 {
-  struct transit * transit = (struct transit *) p;
-  unsigned int key = 0;
-  int length;
-  caddr_t pnt;
+  const struct transit * transit = p;
 
-  length = transit->length;
-  pnt = (caddr_t) transit->val;
-  
-  while (length)
-    key += pnt[--length];
-
-  return key;
+  return jhash(transit->val, transit->length, 0);
 }
 
 static int
@@ -363,8 +342,14 @@
 unsigned int
 attrhash_key_make (void *p)
 {
-  struct attr * attr = (struct attr *) p;
-  unsigned int key = 0;
+  const struct attr * attr = (struct attr *) p;
+  uint32_t key = 0;
+#define MIX(val)	key = jhash_1word(val, key)
+
+  MIX(attr->origin);
+  MIX(attr->nexthop.s_addr);
+  MIX(attr->med);
+  MIX(attr->local_pref);
 
   key += attr->origin;
   key += attr->nexthop.s_addr;
@@ -373,36 +358,30 @@
   
   if (attr->extra)
     {
-      key += attr->extra->aggregator_as;
-      key += attr->extra->aggregator_addr.s_addr;
-      key += attr->extra->weight;
-      key += attr->extra->mp_nexthop_global_in.s_addr;
+      MIX(attr->extra->aggregator_as);
+      MIX(attr->extra->aggregator_addr.s_addr);
+      MIX(attr->extra->weight);
+      MIX(attr->extra->mp_nexthop_global_in.s_addr);
     }
   
   if (attr->aspath)
-    key += aspath_key_make (attr->aspath);
+    MIX(aspath_key_make (attr->aspath));
   if (attr->community)
-    key += community_hash_make (attr->community);
+    MIX(community_hash_make (attr->community));
   
   if (attr->extra)
     {
       if (attr->extra->ecommunity)
-        key += ecommunity_hash_make (attr->extra->ecommunity);
+        MIX(ecommunity_hash_make (attr->extra->ecommunity));
       if (attr->extra->cluster)
-        key += cluster_hash_key_make (attr->extra->cluster);
+        MIX(cluster_hash_key_make (attr->extra->cluster));
       if (attr->extra->transit)
-        key += transit_hash_key_make (attr->extra->transit);
+        MIX(transit_hash_key_make (attr->extra->transit));
 
 #ifdef HAVE_IPV6
-      {
-        int i;
-        
-        key += attr->extra->mp_nexthop_len;
-        for (i = 0; i < 16; i++)
-          key += attr->extra->mp_nexthop_global.s6_addr[i];
-        for (i = 0; i < 16; i++)
-          key += attr->extra->mp_nexthop_local.s6_addr[i];
-      }
+      MIX(attr->extra->mp_nexthop_len);
+      key = jhash(attr->extra->mp_nexthop_global.s6_addr, 16, key);
+      key = jhash(attr->extra->mp_nexthop_local.s6_addr, 16, key);
 #endif /* HAVE_IPV6 */
     }
 
@@ -528,6 +507,7 @@
             attre->ecommunity = ecommunity_intern (attre->ecommunity);
           else
             attre->ecommunity->refcnt++;
+          
         }
       if (attre->cluster)
         {
@@ -544,10 +524,10 @@
             attre->transit->refcnt++;
         }
     }
-
+  
   find = (struct attr *) hash_get (attrhash, attr, bgp_attr_hash_alloc);
   find->refcnt++;
-
+  
   return find;
 }
 
@@ -579,17 +559,16 @@
 {
   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;
 }
 
@@ -641,52 +620,68 @@
   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
@@ -699,8 +694,9 @@
   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)
@@ -708,6 +704,67 @@
     }
 }
 
+/* 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 peer *peer, u_char type, u_char flag,
+                    u_char subcode, u_char *startp, bgp_size_t length)
+{
+  /* 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,
+                                 startp, length);
+      return BGP_ATTR_PARSE_ERROR;
+
+    }
+  
+  switch (type) {
+    /* where an optional attribute is 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,
+                                 startp, 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 (flag, BGP_ATTR_FLAG_TRANS)
+      && CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
+      && CHECK_FLAG (flag, 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
@@ -743,7 +800,7 @@
 }
 
 /* Get origin attribute of the update message. */
-static int
+static bgp_attr_parse_ret_t
 bgp_attr_origin (struct peer *peer, bgp_size_t length, 
 		 struct attr *attr, u_char flag, u_char *startp)
 {
@@ -760,8 +817,7 @@
   if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
   {
     bgp_attr_flags_diagnose (peer, BGP_ATTR_ORIGIN, BGP_ATTR_FLAG_TRANS, flag);
-    bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
-    return -1;
+    return bgp_attr_malformed (peer, BGP_ATTR_ORIGIN, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
   }
 
   /* If any recognized attribute has Attribute Length that conflicts
@@ -773,10 +829,9 @@
     {
       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 (peer, BGP_ATTR_ORIGIN, flag,
+                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                 startp, total);
     }
 
   /* Fetch origin attribute. */
@@ -791,12 +846,9 @@
     {
       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 (peer, BGP_ATTR_ORIGIN, flag,
+                                 BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
+                                 startp, total);
     }
 
   /* Set oring attribute flag. */
@@ -804,93 +856,72 @@
 
   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 *
+
+/* Parse AS path information.  This function is wrapper of
+   aspath_parse. */
+static int
 bgp_attr_aspath (struct peer *peer, bgp_size_t length, 
-		 struct attr *attr, u_char flag, u_char *startp, int as4_path)
+		 struct attr *attr, u_char flag, u_char *startp)
 {
-  u_char require ;
-  struct aspath *asp ;
   bgp_size_t total;
 
   total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
 
-  /* Check the attribute flags                                          */
-  if (!as4_path && CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
+  /* Flags check. */
+  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_PARTIAL))
     {
       zlog (peer->log, LOG_ERR,
 	    "AS_PATH attribute must not be flagged as \"partial\" (%u)", flag);
-      bgp_notify_send_with_data (peer,
-				 BGP_NOTIFY_UPDATE_ERR,
+      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
 				 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
 				 startp, total);
-      return NULL;
     }
 
-  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)
+  if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
     {
-      const char* path_type ;
-
-      path_type = as4_path ? "AS4_PATH" : "AS_PATH" ;
-
-      if (!CHECK_FLAG(flag, BGP_ATTR_FLAG_TRANS))
+      zlog (peer->log, LOG_ERR,
+            "AS_PATH attribute must be flagged as \"transitive\" (%u)", flag);
+      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
+				 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+				 startp, total);
+    }
+  
+  if (CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL))
+    {
       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,
-            CHECK_FLAG (require, BGP_ATTR_FLAG_OPTIONAL) ? "" : "not ", flag);
-
-      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
-   */
-  asp = aspath_parse (peer->ibuf, length,
-               as4_path || CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV), as4_path) ;
-
-  if (asp != NULL)
-    {
-      attr->flag |= ATTR_FLAG_BIT (as4_path ? BGP_ATTR_AS4_PATH
-                                            : BGP_ATTR_AS_PATH) ;
+            "AS_PATH attribute must not be flagged as \"optional\" (%u)", flag);
+      
+      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
+                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+                                 startp, total);
     }
-  else
+
+  /*
+   * peer with AS4 => will get 4Byte ASnums
+   * otherwise, will get 16 Bit
+   */
+  attr->aspath = aspath_parse (peer->ibuf, length, 
+                               CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV));
+
+  /* In case of IBGP, length will be zero. */
+  if (! attr->aspath)
     {
-      zlog (peer->log, LOG_ERR, "Malformed AS path length is %d", length);
+      zlog (peer->log, LOG_ERR,
+            "Malformed AS path from %s, length is %d",
+            peer->host, length);
+      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
+                                 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
+                                 NULL, 0);
+    }
 
-      /* 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 *peer, struct attr *attr, u_char flag)
 {
   /* These checks were part of bgp_attr_aspath, but with
    * as4 we should to check aspath things when
@@ -909,10 +940,9 @@
      (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;
+      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
+                                 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
+                                 NULL, 0);
     }
 
   /* First AS check for EBGP. */
@@ -923,10 +953,9 @@
  	{
  	  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;
+          return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
+                                     BGP_NOTIFY_UPDATE_MAL_AS_PATH,
+                                     NULL, 0);
  	}
     }
 
@@ -936,16 +965,57 @@
     {
       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;
+}
 
+/* Parse AS4 path information.  This function is another wrapper of
+   aspath_parse. */
+static int
+bgp_attr_as4_path (struct peer *peer, bgp_size_t length,
+		 struct attr *attr, u_char flag, u_char *startp,
+		 struct aspath **as4_path)
+{
+  bgp_size_t total;
+
+  total = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+
+  /* Flag check. */
+  if (!CHECK_FLAG (flag, BGP_ATTR_FLAG_OPTIONAL)
+      || !CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
+    {
+      zlog (peer->log, LOG_ERR, 
+	    "As4-Path attribute flag isn't optional/transitive %d", flag);
+      return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
+                                 BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+                                 startp, total);
+    }
+
+  *as4_path = aspath_parse (peer->ibuf, length, 1);
+
+  /* In case of IBGP, length will be zero. */
+  if (!*as4_path)
+    {
+      zlog (peer->log, LOG_ERR,
+            "Malformed AS4 path from %s, length is %d",
+            peer->host, length);
+      return bgp_attr_malformed (peer, BGP_ATTR_AS4_PATH, flag,
+                                 BGP_NOTIFY_UPDATE_MAL_AS_PATH,
+                                 NULL, 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 int
+static bgp_attr_parse_ret_t
 bgp_attr_nexthop (struct peer *peer, bgp_size_t length, 
 		  struct attr *attr, u_char flag, u_char *startp)
 {
@@ -958,8 +1028,7 @@
   if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
   {
     bgp_attr_flags_diagnose (peer, BGP_ATTR_NEXT_HOP, BGP_ATTR_FLAG_TRANS, flag);
-    bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
-    return -1;
+    return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
   }
 
   /* Check nexthop attribute length. */
@@ -968,11 +1037,9 @@
       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 (peer, BGP_ATTR_NEXT_HOP, flag,
+                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                 startp, total);
     }
 
   /* According to section 6.3 of RFC4271, syntactically incorrect NEXT_HOP
@@ -987,21 +1054,19 @@
       char buf[INET_ADDRSTRLEN];
       inet_ntop (AF_INET, &nexthop_h, buf, INET_ADDRSTRLEN);
       zlog (peer->log, LOG_ERR, "Martian nexthop %s", buf);
-      bgp_notify_send_with_data (peer,
-				 BGP_NOTIFY_UPDATE_ERR,
-				 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
-				 startp, total);
-      return -1;
+      return bgp_attr_malformed (peer, BGP_ATTR_NEXT_HOP, flag,
+                                 BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP,
+                                 startp, 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
+static bgp_attr_parse_ret_t
 bgp_attr_med (struct peer *peer, bgp_size_t length, 
 	      struct attr *attr, u_char flag, u_char *startp)
 {
@@ -1013,8 +1078,9 @@
   if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
   {
     bgp_attr_flags_diagnose (peer, BGP_ATTR_MULTI_EXIT_DISC, BGP_ATTR_FLAG_OPTIONAL, flag);
-    bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
-    return -1;
+    return bgp_attr_malformed (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
+                               BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+                               startp, total);
   }
 
   /* Length check. */
@@ -1022,23 +1088,21 @@
     {
       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 (peer, BGP_ATTR_MULTI_EXIT_DISC, flag,
+                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                 startp, 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
+static bgp_attr_parse_ret_t
 bgp_attr_local_pref (struct peer *peer, bgp_size_t length, 
 		     struct attr *attr, u_char flag, u_char *startp)
 {
@@ -1049,18 +1113,17 @@
   if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
   {
     bgp_attr_flags_diagnose (peer, BGP_ATTR_LOCAL_PREF, BGP_ATTR_FLAG_TRANS, flag);
-    bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
-    return -1;
+    return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag,
+                               BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+                               startp, total);
   }
   /* Length check. */
   if (length != 4)
   {
     zlog (peer->log, LOG_ERR, "LOCAL_PREF attribute length isn't 4 [%u]", length);
-    bgp_notify_send_with_data (peer,
-                               BGP_NOTIFY_UPDATE_ERR,
+    return bgp_attr_malformed (peer, BGP_ATTR_LOCAL_PREF, flag,
                                BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
                                startp, total);
-    return -1;
   }
 
   /* If it is contained in an UPDATE message that is received from an
@@ -1069,7 +1132,7 @@
   if (peer_sort (peer) == BGP_PEER_EBGP)
     {
       stream_forward_getp (peer->ibuf, length);
-      return 0;
+      return BGP_ATTR_PARSE_PROCEED;
     }
 
   attr->local_pref = stream_getl (peer->ibuf);
@@ -1077,7 +1140,7 @@
   /* Set atomic aggregate flag. */
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_LOCAL_PREF);
 
-  return 0;
+  return BGP_ATTR_PARSE_PROCEED;
 }
 
 /* Atomic aggregate. */
@@ -1092,25 +1155,24 @@
   if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_TRANS)
   {
     bgp_attr_flags_diagnose (peer, BGP_ATTR_ATOMIC_AGGREGATE, BGP_ATTR_FLAG_TRANS, flag);
-    bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
-    return -1;
+    return bgp_attr_malformed (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
+                               BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+                               startp, total);
   }
 
   /* Length check. */
   if (length != 0)
     {
       zlog (peer->log, LOG_ERR, "ATOMIC_AGGREGATE attribute length isn't 0 [%u]", 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 (peer, BGP_ATTR_ATOMIC_AGGREGATE, flag,
+                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                 startp, total);
     }
 
   /* Set atomic aggregate flag. */
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ATOMIC_AGGREGATE);
 
-  return 0;
+  return BGP_ATTR_PARSE_PROCEED;
 }
 
 /* Aggregator attribute */
@@ -1128,34 +1190,28 @@
   {
     zlog (peer->log, LOG_ERR,
           "AGGREGATOR attribute must be flagged as \"optional\" (%u)", flag);
-    bgp_notify_send_with_data (peer,
-                               BGP_NOTIFY_UPDATE_ERR,
+    return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
                                BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
                                startp, total);
-    return -1;
   }
   if (! CHECK_FLAG (flag, BGP_ATTR_FLAG_TRANS))
   {
     zlog (peer->log, LOG_ERR,
           "AGGREGATOR attribute must be flagged as \"transitive\" (%u)", flag);
-    bgp_notify_send_with_data (peer,
-                               BGP_NOTIFY_UPDATE_ERR,
+    return bgp_attr_malformed (peer, BGP_ATTR_AGGREGATOR, flag,
                                BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
                                startp, total);
-    return -1;
   }
   /* 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 attribute length isn't %u [%u]", wantedlen, 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 (peer, BGP_ATTR_AGGREGATOR, flag,
+                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                 startp, total);
     }
   
   if ( CHECK_FLAG (peer->cap, PEER_CAP_AS4_RCV ) )
@@ -1167,36 +1223,35 @@
   /* Set atomic aggregate flag. */
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_AGGREGATOR);
 
-  return 0;
+  return BGP_ATTR_PARSE_PROCEED;
 }
 
 /* New Aggregator attribute */
-static int
+static bgp_attr_parse_ret_t
 bgp_attr_as4_aggregator (struct peer *peer, bgp_size_t length,
-		     struct attr *attr, as_t *as4_aggregator_as,
+		     struct attr *attr, u_char flag, 
+		     as_t *as4_aggregator_as,
 		     struct in_addr *as4_aggregator_addr)
 {
   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;
+      return bgp_attr_malformed (peer, BGP_ATTR_AS4_AGGREGATOR, flag,
+                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                 NULL, 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 *peer, struct attr *attr, u_char flag,
                           struct aspath *as4_path, as_t as4_aggregator,
                           struct in_addr *as4_aggregator_addr)
 {
@@ -1204,7 +1259,7 @@
   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.
@@ -1222,11 +1277,11 @@
                         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))))
+  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,
@@ -1238,10 +1293,9 @@
       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;
+      return bgp_attr_malformed (peer, BGP_ATTR_AS_PATH, flag,
+                                 BGP_NOTIFY_UPDATE_MAL_ATTR,
+                                 NULL, 0);
     }
 
   /* We have a asn16 peer.  First, look for AS4_AGGREGATOR
@@ -1249,7 +1303,7 @@
    */
   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);
           
@@ -1265,7 +1319,7 @@
            *        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))
@@ -1300,24 +1354,27 @@
     }
 
   /* 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
+static bgp_attr_parse_ret_t
 bgp_attr_community (struct peer *peer, bgp_size_t length, 
-		    struct attr *attr, u_char flag)
+		    struct attr *attr, u_char flag, u_char *startp)
 {
+  bgp_size_t total
+    = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+  
   if (length == 0)
     {
       attr->community = NULL;
-      return 0;
+      return BGP_ATTR_PARSE_PROCEED;
     }
   
   attr->community =
@@ -1327,15 +1384,17 @@
   stream_forward_getp (peer->ibuf, length);
 
   if (!attr->community)
-    return -1;
+    return bgp_attr_malformed (peer, BGP_ATTR_COMMUNITIES, flag,
+                               BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+                               startp, total);
   
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_COMMUNITIES);
 
-  return 0;
+  return BGP_ATTR_PARSE_PROCEED;
 }
 
 /* Originator ID attribute. */
-static int
+static bgp_attr_parse_ret_t
 bgp_attr_originator_id (struct peer *peer, bgp_size_t length, 
 			struct attr *attr, u_char flag, u_char *startp)
 {
@@ -1346,19 +1405,18 @@
   if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
   {
     bgp_attr_flags_diagnose (peer, BGP_ATTR_ORIGINATOR_ID, BGP_ATTR_FLAG_OPTIONAL, flag);
-    bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
-    return -1;
+    return bgp_attr_malformed (peer, BGP_ATTR_ORIGINATOR_ID, flag,
+                               BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+                               startp, total);
   }
   /* Length check. */
   if (length != 4)
     {
       zlog (peer->log, LOG_ERR, "Bad originator ID length %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 (peer, BGP_ATTR_ORIGINATOR_ID, flag,
+                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                 startp, total);
     }
 
   (bgp_attr_extra_get (attr))->originator_id.s_addr 
@@ -1366,11 +1424,11 @@
 
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_ORIGINATOR_ID);
 
-  return 0;
+  return BGP_ATTR_PARSE_PROCEED;
 }
 
 /* Cluster list attribute. */
-static int
+static bgp_attr_parse_ret_t
 bgp_attr_cluster_list (struct peer *peer, bgp_size_t length, 
 		       struct attr *attr, u_char flag, u_char *startp)
 {
@@ -1381,29 +1439,29 @@
   if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
   {
     bgp_attr_flags_diagnose (peer, BGP_ATTR_CLUSTER_LIST, BGP_ATTR_FLAG_OPTIONAL, flag);
-    bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
-    return -1;
+    return bgp_attr_malformed (peer, BGP_ATTR_CLUSTER_LIST, flag,
+                               BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+                               startp, total);
   }
   /* Check length. */
   if (length % 4)
     {
       zlog (peer->log, LOG_ERR, "Bad cluster list length %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 (peer, BGP_ATTR_CLUSTER_LIST, flag,
+                                 BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+                                 startp, 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. */
@@ -1425,8 +1483,9 @@
   if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
   {
     bgp_attr_flags_diagnose (peer, BGP_ATTR_MP_REACH_NLRI, BGP_ATTR_FLAG_OPTIONAL, flag);
-    bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
-    return -1;
+    return bgp_attr_malformed (peer, BGP_ATTR_MP_REACH_NLRI, flag,
+                               BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+                               startp, total);
   }
   /* Set end of packet. */
   s = BGP_INPUT(peer);
@@ -1439,7 +1498,7 @@
     {
       zlog_info ("%s: %s sent invalid length, %lu", 
 		 __func__, peer->host, (unsigned long)length);
-      return -1;
+      return BGP_ATTR_PARSE_ERROR;
     }
   
   /* Load AFI, SAFI. */
@@ -1453,7 +1512,7 @@
     {
       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. */
@@ -1466,14 +1525,9 @@
         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:
@@ -1501,14 +1555,14 @@
     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;
     }
   
   {
@@ -1524,7 +1578,7 @@
     {
       zlog_info ("%s: (%s) Failed to read NLRI",
                  __func__, peer->host);
-      return -1;
+      return BGP_ATTR_PARSE_ERROR;
     }
  
   if (safi != SAFI_MPLS_LABELED_VPN)
@@ -1534,7 +1588,7 @@
         {
           zlog_info ("%s: (%s) NLRI doesn't pass sanity check",
                      __func__, peer->host);
-	  return -1;
+	  return BGP_ATTR_PARSE_ERROR;
 	}
     }
 
@@ -1545,7 +1599,7 @@
 
   stream_forward_getp (s, nlri_len);
 
-  return 0;
+  return BGP_ATTR_PARSE_PROCEED;
 #undef LEN_LEFT
 }
 
@@ -1567,15 +1621,16 @@
   if ((flag & ~BGP_ATTR_FLAG_EXTLEN) != BGP_ATTR_FLAG_OPTIONAL)
   {
     bgp_attr_flags_diagnose (peer, BGP_ATTR_MP_UNREACH_NLRI, BGP_ATTR_FLAG_OPTIONAL, flag);
-    bgp_notify_send_with_data (peer, BGP_NOTIFY_UPDATE_ERR, BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR, startp, total);
-    return -1;
+    return bgp_attr_malformed (peer, BGP_ATTR_MP_UNREACH_NLRI, flag,
+                               BGP_NOTIFY_UPDATE_ATTR_FLAG_ERR,
+                               startp, total);
   }
 
   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);
@@ -1586,7 +1641,7 @@
     {
       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;
@@ -1596,20 +1651,23 @@
 
   stream_forward_getp (s, withdraw_len);
 
-  return 0;
+  return BGP_ATTR_PARSE_PROCEED;
 }
 
 /* Extended Community attribute. */
-static int
+static bgp_attr_parse_ret_t
 bgp_attr_ext_communities (struct peer *peer, bgp_size_t length, 
-			  struct attr *attr, u_char flag)
+			  struct attr *attr, u_char flag, u_char *startp)
 {
+  bgp_size_t total
+    = length + (CHECK_FLAG (flag, BGP_ATTR_FLAG_EXTLEN) ? 4 : 3);
+  
   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 =
@@ -1618,15 +1676,17 @@
   stream_forward_getp (peer->ibuf, length);
   
   if (!attr->extra->ecommunity)
-    return -1;
+    return bgp_attr_malformed (peer, BGP_ATTR_EXT_COMMUNITIES,
+                               flag, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
+                               startp, total);
   
   attr->flag |= ATTR_FLAG_BIT (BGP_ATTR_EXT_COMMUNITIES);
 
-  return 0;
+  return BGP_ATTR_PARSE_PROCEED;
 }
 
 /* BGP unknown attribute treatment. */
-static int
+static bgp_attr_parse_ret_t
 bgp_attr_unknown (struct peer *peer, struct attr *attr, u_char flag,
 		  u_char type, bgp_size_t length, u_char *startp)
 {
@@ -1652,20 +1712,17 @@
      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 (peer, type, flag,
+                                 BGP_NOTIFY_UPDATE_UNREC_ATTR,
+                                 startp, 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
@@ -1688,17 +1745,17 @@
   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;
@@ -1715,7 +1772,7 @@
 
   /* 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)
     {
@@ -1731,7 +1788,7 @@
 	  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. */
@@ -1754,7 +1811,7 @@
 	  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. */
@@ -1776,7 +1833,7 @@
 	  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
@@ -1794,7 +1851,7 @@
 	  bgp_notify_send (peer, 
 			   BGP_NOTIFY_UPDATE_ERR, 
 			   BGP_NOTIFY_UPDATE_ATTR_LENG_ERR);
-	  return -1;
+	  return BGP_ATTR_PARSE_ERROR;
 	}
 
       /* OK check attribute and store it's value. */
@@ -1804,12 +1861,10 @@
 	  ret = bgp_attr_origin (peer, length, attr, flag, startp);
 	  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 (peer, length, attr, flag, startp);
 	  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 (peer, length, attr, flag, startp, &as4_path);
 	  break;
 	case BGP_ATTR_NEXT_HOP:	
 	  ret = bgp_attr_nexthop (peer, length, attr, flag, startp);
@@ -1827,10 +1882,12 @@
 	  ret = bgp_attr_aggregator (peer, length, attr, flag, startp);
 	  break;
 	case BGP_ATTR_AS4_AGGREGATOR:
-	  ret = bgp_attr_as4_aggregator (peer, length, attr, &as4_aggregator, &as4_aggregator_addr);
+	  ret = bgp_attr_as4_aggregator (peer, length, attr, flag,
+	                                 &as4_aggregator, 
+	                                 &as4_aggregator_addr);
 	  break;
 	case BGP_ATTR_COMMUNITIES:
-	  ret = bgp_attr_community (peer, length, attr, flag);
+	  ret = bgp_attr_community (peer, length, attr, flag, startp);
 	  break;
 	case BGP_ATTR_ORIGINATOR_ID:
 	  ret = bgp_attr_originator_id (peer, length, attr, flag, startp);
@@ -1845,26 +1902,39 @@
 	  ret = bgp_mp_unreach_parse (peer, length, flag, startp, mp_withdraw);
 	  break;
 	case BGP_ATTR_EXT_COMMUNITIES:
-	  ret = bgp_attr_ext_communities (peer, length, attr, flag);
+	  ret = bgp_attr_ext_communities (peer, length, attr, flag, startp);
 	  break;
 	default:
 	  ret = bgp_attr_unknown (peer, attr, flag, type, length, startp);
 	  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)
 	{
@@ -1874,7 +1944,9 @@
 	  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;
 	}
     }
 
@@ -1887,7 +1959,9 @@
       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;
     }
 
   /* 
@@ -1901,19 +1975,22 @@
    * all attributes first, including these 32bit ones, and now,
    * afterwards, we look what and if something is to be done for as4.
    */
-  if (bgp_attr_munge_as4_attrs (peer, attr, as4_path,
+  if (bgp_attr_munge_as4_attrs (peer, attr, flag, 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
        */
@@ -1928,10 +2005,10 @@
    * 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, flag);
+      if (ret != BGP_ATTR_PARSE_PROCEED)
 	return ret;
     }
 
@@ -1939,7 +2016,7 @@
   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. */
@@ -1970,9 +2047,9 @@
 				 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 *);
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 4cb7067..e630074 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -132,17 +132,25 @@
 
 #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);
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index d660167..6c9976e 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -70,7 +70,7 @@
       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 @@
     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 ae1d7a1..2ba45f6 100644
--- a/bgpd/bgp_community.c
+++ b/bgpd/bgp_community.c
@@ -321,21 +321,22 @@
 
 /* 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 bc1e56e..9e48377 100644
--- a/bgpd/bgp_community.h
+++ b/bgpd/bgp_community.h
@@ -57,7 +57,7 @@
 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_ecommunity.c b/bgpd/bgp_ecommunity.c
index e7eb0a0..440c15a 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -42,13 +42,14 @@
 
 /* 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 @@
   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 @@
 
 /* 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 @@
 	  if (! keyword_included || keyword)
 	    {
 	      if (ecom)
-		ecommunity_free (ecom);
+		ecommunity_free (&ecom);
 	      return NULL;
 	    }
 	  keyword = 1;
@@ -536,7 +537,7 @@
 	      if (! keyword)
 		{
 		  if (ecom)
-		    ecommunity_free (ecom);
+		    ecommunity_free (&ecom);
 		  return NULL;
 		}
 	      keyword = 0;
@@ -549,7 +550,7 @@
 	case ecommunity_token_unknown:
 	default:
 	  if (ecom)
-	    ecommunity_free (ecom);
+	    ecommunity_free (&ecom);
 	  return NULL;
 	}
     }
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index 942fdc7..2f59dc4 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -67,13 +67,13 @@
 
 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_main.c b/bgpd/bgp_main.c
index f835fe7..8dede58 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -247,7 +247,15 @@
   if (retain_mode)
     if_add_hook (IF_DELETE_HOOK, NULL);
   for (ALL_LIST_ELEMENTS (iflist, node, nnode, ifp))
-    if_delete (ifp);
+    {
+      struct listnode *c_node, *c_nnode;
+      struct connected *c;
+
+      for (ALL_LIST_ELEMENTS (ifp->connected, c_node, c_nnode, c))
+        bgp_connected_delete (c);
+
+      if_delete (ifp);
+    }
   list_free (iflist);
 
   /* reverse bgp_attr_init */
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index b5c4c60..a7dca53 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -30,6 +30,7 @@
 #include "command.h"
 #include "privs.h"
 #include "linklist.h"
+#include "network.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_fsm.h"
@@ -150,6 +151,7 @@
       zlog_err ("[Error] BGP socket accept failed (%s)", safe_strerror (errno));
       return -1;
     }
+  set_nonblocking (bgp_sock);
 
   if (BGP_DEBUG (events, EVENTS))
     zlog_debug ("[Event] BGP connection from host %s", inet_sutop (&su, buf));
@@ -172,8 +174,11 @@
     }
 
   /* In case of peer is EBGP, we should set TTL for this connection.  */
-  if (peer_sort (peer1) == BGP_PEER_EBGP)
+  if (peer_sort (peer1) == BGP_PEER_EBGP) {
     sockopt_ttl (peer1->su.sa.sa_family, bgp_sock, peer1->ttl);
+    if (peer1->gtsm_hops)
+      sockopt_minttl (peer1->su.sa.sa_family, bgp_sock, MAXTTL + 1 - peer1->gtsm_hops);
+  }
 
   /* Make dummy peer until read Open packet. */
   if (BGP_DEBUG (events, EVENTS))
@@ -302,8 +307,11 @@
     return -1;
 
   /* If we can get socket for the peer, adjest TTL and make connection. */
-  if (peer_sort (peer) == BGP_PEER_EBGP)
+  if (peer_sort (peer) == BGP_PEER_EBGP) {
     sockopt_ttl (peer->su.sa.sa_family, peer->fd, peer->ttl);
+    if (peer->gtsm_hops)
+      sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - peer->gtsm_hops);
+  }
 
   sockopt_reuseaddr (peer->fd);
   sockopt_reuseport (peer->fd);
@@ -455,7 +463,10 @@
 	  zlog_err ("socket: %s", safe_strerror (errno));
 	  continue;
 	}
-
+	
+      /* if we intend to implement ttl-security, this socket needs ttl=255 */
+      sockopt_ttl (ainfo->ai_family, sock, MAXTTL);
+      
       ret = bgp_listener (sock, ainfo->ai_addr, ainfo->ai_addrlen);
       if (ret == 0)
 	++count;
@@ -488,6 +499,9 @@
       return sock;
     }
 
+  /* if we intend to implement ttl-security, this socket needs ttl=255 */
+  sockopt_ttl (AF_INET, sock, MAXTTL);
+
   memset (&sin, 0, sizeof (struct sockaddr_in));
   sin.sin_family = AF_INET;
   sin.sin_port = htons (port);
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index f8d1ade..e9c78b3 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -264,6 +264,8 @@
 
 		  if (bnc->metric != oldbnc->metric)
 		    bnc->metricchanged = 1;
+
+                  bgp_unlock_node (oldrn);
 		}
 	    }
 	}
@@ -340,6 +342,8 @@
 
 		  if (bnc->metric != oldbnc->metric)
 		    bnc->metricchanged = 1;
+
+                  bgp_unlock_node (oldrn);
 		}
 	    }
 	}
@@ -541,7 +545,7 @@
 	}
       else
 	{
-	  bc = XCALLOC (0, sizeof (struct bgp_connected_ref));
+	  bc = XCALLOC (MTYPE_BGP_CONN, sizeof (struct bgp_connected_ref));
 	  bc->refcnt = 1;
 	  rn->info = bc;
 	}
@@ -566,7 +570,7 @@
 	}
       else
 	{
-	  bc = XCALLOC (0, sizeof (struct bgp_connected_ref));
+	  bc = XCALLOC (MTYPE_BGP_CONN, sizeof (struct bgp_connected_ref));
 	  bc->refcnt = 1;
 	  rn->info = bc;
 	}
@@ -606,7 +610,7 @@
       bc->refcnt--;
       if (bc->refcnt == 0)
 	{
-	  XFREE (0, bc);
+	  XFREE (MTYPE_BGP_CONN, bc);
 	  rn->info = NULL;
 	}
       bgp_unlock_node (rn);
@@ -632,7 +636,7 @@
       bc->refcnt--;
       if (bc->refcnt == 0)
 	{
-	  XFREE (0, bc);
+	  XFREE (MTYPE_BGP_CONN, bc);
 	  rn->info = NULL;
 	}
       bgp_unlock_node (rn);
@@ -1101,11 +1105,15 @@
   rn1 = bgp_node_match (bgp_connected_table[AFI_IP], &p1);
   if (! rn1)
     return 0;
+  bgp_unlock_node (rn1);
   
   rn2 = bgp_node_match (bgp_connected_table[AFI_IP], &p2);
   if (! rn2)
     return 0;
+  bgp_unlock_node (rn2);
 
+  /* This is safe, even with above unlocks, since we are just
+     comparing pointers to the objects, not the objects themselves. */
   if (rn1 == rn2)
     return 1;
 
@@ -1330,6 +1338,9 @@
 void
 bgp_scan_finish (void)
 {
+  /* Only the current one needs to be reset. */
+  bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP]);
+
   bgp_table_unlock (cache1_table[AFI_IP]);
   cache1_table[AFI_IP] = NULL;
 
@@ -1340,6 +1351,9 @@
   bgp_connected_table[AFI_IP] = NULL;
 
 #ifdef HAVE_IPV6
+  /* Only the current one needs to be reset. */
+  bgp_nexthop_cache_reset (bgp_nexthop_cache_table[AFI_IP6]);
+
   bgp_table_unlock (cache1_table[AFI_IP6]);
   cache1_table[AFI_IP6] = NULL;
 
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index fc653e2..f5a74d1 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -206,7 +206,7 @@
 
       /* Synchnorize attribute.  */
       if (adj->attr)
-	bgp_attr_unintern (adj->attr);
+	bgp_attr_unintern (&adj->attr);
       else
 	peer->scount[afi][safi]++;
 
@@ -598,7 +598,6 @@
   struct stream *s; 
   int num;
   unsigned int count = 0;
-  int write_errno;
 
   /* Yes first of all get peer pointer. */
   peer = THREAD_ARG (thread);
@@ -611,46 +610,37 @@
       return 0;
     }
 
-    /* Nonblocking write until TCP output buffer is full.  */
-  while (1)
+  s = bgp_write_packet (peer);
+  if (!s)
+    return 0;	/* nothing to send */
+
+  sockopt_cork (peer->fd, 1);
+
+  /* Nonblocking write until TCP output buffer is full.  */
+  do
     {
       int writenum;
-      int val;
-
-      s = bgp_write_packet (peer);
-      if (! s)
-	return 0;
-      
-      /* XXX: FIXME, the socket should be NONBLOCK from the start
-       * status shouldnt need to be toggled on each write
-       */
-      val = fcntl (peer->fd, F_GETFL, 0);
-      fcntl (peer->fd, F_SETFL, val|O_NONBLOCK);
 
       /* Number of bytes to be sent.  */
       writenum = stream_get_endp (s) - stream_get_getp (s);
 
       /* Call write() system call.  */
       num = write (peer->fd, STREAM_PNT (s), writenum);
-      write_errno = errno;
-      fcntl (peer->fd, F_SETFL, val);
-      if (num <= 0)
+      if (num < 0)
 	{
-	  /* Partial write. */
-	  if (write_errno == EWOULDBLOCK || write_errno == EAGAIN)
-	      break;
+	  /* write failed either retry needed or error */
+	  if (ERRNO_IO_RETRY(errno))
+		break;
 
-	  BGP_EVENT_ADD (peer, TCP_fatal_error);
+          BGP_EVENT_ADD (peer, TCP_fatal_error);
 	  return 0;
 	}
+
       if (num != writenum)
 	{
+	  /* Partial write */
 	  stream_forward_getp (s, num);
-
-	  if (write_errno == EAGAIN)
-	    break;
-
-	  continue;
+	  break;
 	}
 
       /* Retrieve BGP packet type. */
@@ -691,13 +681,14 @@
 
       /* OK we send packet so delete it. */
       bgp_packet_delete (peer);
-
-      if (++count >= BGP_WRITE_PACKET_MAX)
-	break;
     }
+  while (++count < BGP_WRITE_PACKET_MAX &&
+	 (s = bgp_write_packet (peer)) != NULL);
   
   if (bgp_write_proceed (peer))
     BGP_WRITE_ON (peer->t_write, bgp_write, peer->fd);
+  else
+    sockopt_cork (peer->fd, 0);
   
   return 0;
 }
@@ -706,7 +697,7 @@
 static int
 bgp_write_notify (struct peer *peer)
 {
-  int ret;
+  int ret, val;
   u_char type;
   struct stream *s; 
 
@@ -716,7 +707,10 @@
     return 0;
   assert (stream_get_endp (s) >= BGP_HEADER_SIZE);
 
-  /* I'm not sure fd is writable. */
+  /* Put socket in blocking mode. */
+  val = fcntl (peer->fd, F_GETFL, 0);
+  fcntl (peer->fd, F_SETFL, val & ~O_NONBLOCK);
+
   ret = writen (peer->fd, STREAM_DATA (s), stream_get_endp (s));
   if (ret <= 0)
     {
@@ -1602,26 +1596,47 @@
 		       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);
 
@@ -1630,7 +1645,12 @@
       /* 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;
@@ -1653,15 +1673,20 @@
 	     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 
@@ -1688,7 +1713,7 @@
       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 
@@ -1718,7 +1743,7 @@
       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 
@@ -1747,7 +1772,7 @@
       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 
@@ -1775,7 +1800,7 @@
       if (mp_update.length 
 	  && mp_update.afi == AFI_IP 
 	  && mp_update.safi == SAFI_MPLS_LABELED_VPN)
-	bgp_nlri_parse_vpnv4 (peer, &attr, &mp_update);
+	bgp_nlri_parse_vpnv4 (peer, NLRI_ATTR_ARG, &mp_update);
 
       if (mp_withdraw.length 
 	  && mp_withdraw.afi == AFI_IP 
@@ -1797,21 +1822,10 @@
 
   /* 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)
@@ -2028,7 +2042,7 @@
                    * as possible without going beyond the bounds of the entry,
                    * to maximise debug information.
                    */
-		  int ok ;
+		  int ok;
 		  memset (&orfp, 0, sizeof (struct orf_prefix));
 		  common = *p_pnt++;
 		  /* after ++: p_pnt <= p_end */
@@ -2042,9 +2056,9 @@
 		  ok = ((p_end - p_pnt) >= sizeof(u_int32_t)) ;
 		  if (ok)
 		    {
-		  memcpy (&seq, p_pnt, sizeof (u_int32_t));
-		  p_pnt += sizeof (u_int32_t);
-		  orfp.seq = ntohl (seq);
+		      memcpy (&seq, p_pnt, sizeof (u_int32_t));
+                      p_pnt += sizeof (u_int32_t);
+                      orfp.seq = ntohl (seq);
 		    }
 		  else
 		    p_pnt = p_end ;
@@ -2082,16 +2096,17 @@
 			       inet_ntop (orfp.p.family, &orfp.p.u.prefix, buf, BUFSIZ),
 			       orfp.p.prefixlen, orfp.ge, orfp.le,
 			       ok ? "" : " MALFORMED");
-
+                  
 		  if (ok)
-		  ret = prefix_bgp_orf_set (name, afi, &orfp,
-				 (common & ORF_COMMON_PART_DENY ? 0 : 1 ),
-				 (common & ORF_COMMON_PART_REMOVE ? 0 : 1));
+		    ret = prefix_bgp_orf_set (name, afi, &orfp,
+				   (common & ORF_COMMON_PART_DENY ? 0 : 1 ),
+				   (common & ORF_COMMON_PART_REMOVE ? 0 : 1));
 
 		  if (!ok || (ret != CMD_SUCCESS))
 		    {
 		      if (BGP_DEBUG (normal, NORMAL))
-			zlog_debug ("%s Received misformatted prefixlist ORF. Remove All pfxlist", peer->host);
+			zlog_debug ("%s Received misformatted prefixlist ORF."
+			            " Remove All pfxlist", peer->host);
 		      prefix_bgp_orf_remove_all (name);
 		      break;
 		    }
@@ -2276,12 +2291,13 @@
     return 0;
 
   /* Read packet from fd. */
-  nbytes = stream_read_unblock (peer->ibuf, peer->fd, readsize);
+  nbytes = stream_read_try (peer->ibuf, peer->fd, readsize);
 
   /* If read byte is smaller than zero then error occured. */
   if (nbytes < 0) 
     {
-      if (errno == EAGAIN)
+      /* Transient error should retry */
+      if (nbytes == -2)
 	return -1;
 
       plog_err (peer->log, "%s [Error] bgp_read_packet error: %s",
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 189929a..68d0548 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -137,7 +137,7 @@
 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 @@
   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;
@@ -1568,14 +1566,13 @@
     }
   
   bm->process_main_queue->spec.workfunc = &bgp_process_main;
-  bm->process_rsclient_queue->spec.workfunc = &bgp_process_rsclient;
   bm->process_main_queue->spec.del_item_data = &bgp_processq_del;
-  bm->process_rsclient_queue->spec.del_item_data
-    =  bm->process_main_queue->spec.del_item_data;
-  bm->process_main_queue->spec.max_retries
-    = bm->process_main_queue->spec.max_retries = 0;
-  bm->process_rsclient_queue->spec.hold
-    = bm->process_main_queue->spec.hold = 50;
+  bm->process_main_queue->spec.max_retries = 0;
+  bm->process_main_queue->spec.hold = 50;
+  
+  memcpy (bm->process_rsclient_queue, bm->process_main_queue,
+          sizeof (struct work_queue *));
+  bm->process_rsclient_queue->spec.workfunc = &bgp_process_rsclient;
 }
 
 void
@@ -1803,14 +1800,14 @@
   /* 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)
@@ -1819,7 +1816,7 @@
       if (new_attr.nexthop.s_addr == 0
          || 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;
@@ -1849,7 +1846,7 @@
                     p->prefixlen, rsclient->host);
 
           bgp_unlock_node (rn);
-          bgp_attr_unintern (attr_new);
+          bgp_attr_unintern (&attr_new);
 
           return;
         }
@@ -1869,7 +1866,7 @@
       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.  */
@@ -2129,7 +2126,7 @@
 	    }
 
 	  bgp_unlock_node (rn);
-	  bgp_attr_unintern (attr_new);
+	  bgp_attr_unintern (&attr_new);
 	  bgp_attr_extra_free (&new_attr);
 	  
 	  return 0;
@@ -2176,7 +2173,7 @@
 	}
 	
       /* Update to new attribute.  */
-      bgp_attr_unintern (ri->attr);
+      bgp_attr_unintern (&ri->attr);
       ri->attr = attr_new;
 
       /* Update MPLS tag.  */
@@ -2468,7 +2465,7 @@
     }
   
   bgp_attr_extra_free (&attr);
-  aspath_unintern (aspath);
+  aspath_unintern (&aspath);
 }
 
 static void
@@ -3216,7 +3213,7 @@
           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);
           
@@ -3227,7 +3224,7 @@
   else
     attr_new = bgp_attr_intern (&attr);
   
-  new_attr = *attr_new;
+  bgp_attr_dup(&new_attr, attr_new);
   
   SET_FLAG (bgp->peer_self->rmap_type, PEER_RMAP_TYPE_NETWORK);
 
@@ -3243,8 +3240,8 @@
 
       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);
@@ -3254,8 +3251,9 @@
 
   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);
 
   for (ri = rn->info; ri; ri = ri->next)
     if (ri->peer == bgp->peer_self && ri->type == ZEBRA_ROUTE_BGP
@@ -3268,8 +3266,8 @@
 	  !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 @@
           /* 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_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_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 @@
 	  !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_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_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_process (bgp, rn, afi, safi);
 
   /* Unintern original. */
-  aspath_unintern (attr.aspath);
+  aspath_unintern (&attr.aspath);
   bgp_attr_extra_free (&attr);
 }
 
@@ -4806,7 +4804,53 @@
 #define AGGREGATE_AS_SET       1
 
 static int
-bgp_aggregate_set (struct vty *vty, const char *prefix_str, 
+bgp_aggregate_unset (struct vty *vty, const char *prefix_str,
+                     afi_t afi, safi_t safi)
+{
+  int ret;
+  struct prefix p;
+  struct bgp_node *rn;
+  struct bgp *bgp;
+  struct bgp_aggregate *aggregate;
+
+  /* Convert string to prefix structure. */
+  ret = str2prefix (prefix_str, &p);
+  if (!ret)
+    {
+      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  apply_mask (&p);
+
+  /* Get BGP structure. */
+  bgp = vty->index;
+
+  /* Old configuration check. */
+  rn = bgp_node_lookup (bgp->aggregate[afi][safi], &p);
+  if (! rn)
+    {
+      vty_out (vty, "%% There is no aggregate-address configuration.%s",
+               VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  aggregate = rn->info;
+  if (aggregate->safi & SAFI_UNICAST)
+    bgp_aggregate_delete (bgp, &p, afi, SAFI_UNICAST, aggregate);
+  if (aggregate->safi & SAFI_MULTICAST)
+    bgp_aggregate_delete (bgp, &p, afi, SAFI_MULTICAST, aggregate);
+
+  /* Unlock aggregate address configuration. */
+  rn->info = NULL;
+  bgp_aggregate_free (aggregate);
+  bgp_unlock_node (rn);
+  bgp_unlock_node (rn);
+
+  return CMD_SUCCESS;
+}
+
+static int
+bgp_aggregate_set (struct vty *vty, const char *prefix_str,
                    afi_t afi, safi_t safi,
 		   u_char summary_only, u_char as_set)
 {
@@ -4834,8 +4878,14 @@
   if (rn->info)
     {
       vty_out (vty, "There is already same aggregate network.%s", VTY_NEWLINE);
-      bgp_unlock_node (rn);
-      return CMD_WARNING;
+      /* try to remove the old entry */
+      ret = bgp_aggregate_unset (vty, prefix_str, afi, safi);
+      if (ret)
+        {
+          vty_out (vty, "Error deleting aggregate.%s", VTY_NEWLINE);
+	  bgp_unlock_node (rn);
+	  return CMD_WARNING;
+        }
     }
 
   /* Make aggregate address structure. */
@@ -4854,52 +4904,6 @@
   return CMD_SUCCESS;
 }
 
-static int
-bgp_aggregate_unset (struct vty *vty, const char *prefix_str, 
-                     afi_t afi, safi_t safi)
-{
-  int ret;
-  struct prefix p;
-  struct bgp_node *rn;
-  struct bgp *bgp;
-  struct bgp_aggregate *aggregate;
-
-  /* Convert string to prefix structure. */
-  ret = str2prefix (prefix_str, &p);
-  if (!ret)
-    {
-      vty_out (vty, "Malformed prefix%s", VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-  apply_mask (&p);
-
-  /* Get BGP structure. */
-  bgp = vty->index;
-
-  /* Old configuration check. */
-  rn = bgp_node_lookup (bgp->aggregate[afi][safi], &p);
-  if (! rn)
-    {
-      vty_out (vty, "%% There is no aggregate-address configuration.%s",
-	       VTY_NEWLINE);
-      return CMD_WARNING;
-    }
-
-  aggregate = rn->info;
-  if (aggregate->safi & SAFI_UNICAST)
-    bgp_aggregate_delete (bgp, &p, afi, SAFI_UNICAST, aggregate);
-  if (aggregate->safi & SAFI_MULTICAST)
-    bgp_aggregate_delete (bgp, &p, afi, SAFI_MULTICAST, aggregate);
-
-  /* Unlock aggregate address configuration. */
-  rn->info = NULL;
-  bgp_aggregate_free (aggregate);
-  bgp_unlock_node (rn);
-  bgp_unlock_node (rn);
-
-  return CMD_SUCCESS;
-}
-
 DEFUN (aggregate_address,
        aggregate_address_cmd,
        "aggregate-address A.B.C.D/M",
@@ -5303,7 +5307,7 @@
 		  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;
@@ -5326,8 +5330,8 @@
  	      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;
@@ -5342,7 +5346,7 @@
 		    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 ();
  
@@ -5350,7 +5354,7 @@
  		  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;
  		} 
@@ -5372,7 +5376,7 @@
     }
 
   /* Unintern original. */
-  aspath_unintern (attr.aspath);
+  aspath_unintern (&attr.aspath);
   bgp_attr_extra_free (&attr);
 }
 
@@ -6381,7 +6385,10 @@
               if ((rm = bgp_node_match (table, &match)) != NULL)
                 {
                   if (prefix_check && rm->p.prefixlen != match.prefixlen)
-                    continue;
+                    {
+                      bgp_unlock_node (rm);
+                      continue;
+                    }
 
                   for (ri = rm->info; ri; ri = ri->next)
                     {
@@ -6395,6 +6402,8 @@
                       display++;
                       route_vty_out_detail (vty, bgp, &rm->p, ri, AFI_IP, SAFI_MPLS_VPN);
                     }
+
+                  bgp_unlock_node (rm);
                 }
             }
         }
@@ -6418,6 +6427,8 @@
                   route_vty_out_detail (vty, bgp, &rn->p, ri, afi, safi);
                 }
             }
+
+          bgp_unlock_node (rn);
         }
     }
 
@@ -6490,6 +6501,15 @@
   return bgp_show (vty, NULL, AFI_IP, SAFI_UNICAST, bgp_show_type_normal, NULL);
 }
 
+ALIAS (show_ip_bgp_ipv4,
+       show_bgp_ipv4_safi_cmd,
+       "show bgp ipv4 (unicast|multicast)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n")
+
 DEFUN (show_ip_bgp_route,
        show_ip_bgp_route_cmd,
        "show ip bgp A.B.C.D",
@@ -6518,6 +6538,16 @@
   return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 0);
 }
 
+ALIAS (show_ip_bgp_ipv4_route,
+       show_bgp_ipv4_safi_route_cmd,
+       "show bgp ipv4 (unicast|multicast) A.B.C.D",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Network in the BGP routing table to display\n")
+
 DEFUN (show_ip_bgp_vpnv4_all_route,
        show_ip_bgp_vpnv4_all_route_cmd,
        "show ip bgp vpnv4 all A.B.C.D",
@@ -6582,6 +6612,16 @@
   return bgp_show_route (vty, NULL, argv[1], AFI_IP, SAFI_UNICAST, NULL, 1);
 }
 
+ALIAS (show_ip_bgp_ipv4_prefix,
+       show_bgp_ipv4_safi_prefix_cmd,
+       "show bgp ipv4 (unicast|multicast) A.B.C.D/M",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+
 DEFUN (show_ip_bgp_vpnv4_all_prefix,
        show_ip_bgp_vpnv4_all_prefix_cmd,
        "show ip bgp vpnv4 all A.B.C.D/M",
@@ -6684,6 +6724,22 @@
        BGP_STR
        "Address family\n")
 
+DEFUN (show_bgp_ipv6_safi,
+       show_bgp_ipv6_safi_cmd,
+       "show bgp ipv6 (unicast|multicast)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show (vty, NULL, AFI_IP6, SAFI_MULTICAST, bgp_show_type_normal,
+                     NULL);
+
+  return bgp_show (vty, NULL, AFI_IP6, SAFI_UNICAST, bgp_show_type_normal, NULL);
+}
+
 /* old command */
 DEFUN (show_ipv6_bgp,
        show_ipv6_bgp_cmd,
@@ -6714,6 +6770,22 @@
        "Address family\n"
        "Network in the BGP routing table to display\n")
 
+DEFUN (show_bgp_ipv6_safi_route,
+       show_bgp_ipv6_safi_route_cmd,
+       "show bgp ipv6 (unicast|multicast) X:X::X:X",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Network in the BGP routing table to display\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 0);
+
+  return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 0);
+}
+
 /* old command */
 DEFUN (show_ipv6_bgp_route,
        show_ipv6_bgp_route_cmd,
@@ -6744,6 +6816,22 @@
        "Address family\n"
        "IPv6 prefix <network>/<length>\n")
 
+DEFUN (show_bgp_ipv6_safi_prefix,
+       show_bgp_ipv6_safi_prefix_cmd,
+       "show bgp ipv6 (unicast|multicast) X:X::X:X/M",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_MULTICAST, NULL, 1);
+
+  return bgp_show_route (vty, NULL, argv[1], AFI_IP6, SAFI_UNICAST, NULL, 1);
+}
+
 /* old command */
 DEFUN (show_ipv6_bgp_prefix,
        show_ipv6_bgp_prefix_cmd,
@@ -7448,15 +7536,36 @@
 #endif /* HAVE_IPV6 */
 
 static int
-bgp_show_community (struct vty *vty, int argc, const char **argv, int exact,
-                    afi_t afi, safi_t safi)
+bgp_show_community (struct vty *vty, const char *view_name, int argc,
+		    const char **argv, int exact, afi_t afi, safi_t safi)
 {
   struct community *com;
   struct buffer *b;
+  struct bgp *bgp;
   int i;
   char *str;
   int first = 0;
 
+  /* BGP structure lookup */
+  if (view_name)
+    {
+      bgp = bgp_lookup_by_name (view_name);
+      if (bgp == NULL)
+	{
+	  vty_out (vty, "Can't find BGP view %s%s", view_name, VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+  else
+    {
+      bgp = bgp_get_default ();
+      if (bgp == NULL)
+	{
+	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+
   b = buffer_new (1024);
   for (i = 0; i < argc; i++)
     {
@@ -7484,7 +7593,7 @@
       return CMD_WARNING;
     }
 
-  return bgp_show (vty, NULL, afi, safi,
+  return bgp_show (vty, bgp, afi, safi,
                    (exact ? bgp_show_type_community_exact :
 		            bgp_show_type_community), com);
 }
@@ -7501,7 +7610,7 @@
        "Do not advertise to any peer (well-known community)\n"
        "Do not export to next AS (well-known community)\n")
 {
-  return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_UNICAST);
+  return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST);
 }
 
 ALIAS (show_ip_bgp_community,
@@ -7580,9 +7689,9 @@
        "Do not export to next AS (well-known community)\n")
 {
   if (strncmp (argv[0], "m", 1) == 0)
-    return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_MULTICAST);
+    return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_MULTICAST);
  
-  return bgp_show_community (vty, argc, argv, 0, AFI_IP, SAFI_UNICAST);
+  return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP, SAFI_UNICAST);
 }
 
 ALIAS (show_ip_bgp_ipv4_community,
@@ -7654,6 +7763,177 @@
        "Do not advertise to any peer (well-known community)\n"
        "Do not export to next AS (well-known community)\n")
 
+DEFUN (show_bgp_view_afi_safi_community_all,
+       show_bgp_view_afi_safi_community_all_cmd,
+#ifdef HAVE_IPV6
+       "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community",
+#else
+       "show bgp view WORD ipv4 (unicast|multicast) community",
+#endif
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "Address family\n"
+#ifdef HAVE_IPV6
+       "Address family\n"
+#endif
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Display routes containing communities\n")
+{
+  int afi;
+  int safi;
+  struct bgp *bgp;
+
+  /* BGP structure lookup. */
+  bgp = bgp_lookup_by_name (argv[0]);
+  if (bgp == NULL)
+    {
+      vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+#ifdef HAVE_IPV6
+  afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
+  safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+#else
+  afi = AFI_IP;
+  safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+#endif
+  return bgp_show (vty, bgp, afi, safi, bgp_show_type_community_all, NULL);
+}
+
+DEFUN (show_bgp_view_afi_safi_community,
+       show_bgp_view_afi_safi_community_cmd,
+#ifdef HAVE_IPV6
+       "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)",
+#else
+       "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export)",
+#endif
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "Address family\n"
+#ifdef HAVE_IPV6
+       "Address family\n"
+#endif
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+{
+  int afi;
+  int safi;
+
+#ifdef HAVE_IPV6
+  afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
+  safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  return bgp_show_community (vty, argv[0], argc-3, &argv[3], 0, afi, safi);
+#else
+  afi = AFI_IP;
+  safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  return bgp_show_community (vty, argv[0], argc-2, &argv[2], 0, afi, safi);
+#endif
+}
+
+ALIAS (show_bgp_view_afi_safi_community,
+       show_bgp_view_afi_safi_community2_cmd,
+#ifdef HAVE_IPV6
+       "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+#else
+       "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+#endif
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "Address family\n"
+#ifdef HAVE_IPV6
+       "Address family\n"
+#endif
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+ALIAS (show_bgp_view_afi_safi_community,
+       show_bgp_view_afi_safi_community3_cmd,
+#ifdef HAVE_IPV6
+       "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+#else
+       "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+#endif
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "Address family\n"
+#ifdef HAVE_IPV6
+       "Address family\n"
+#endif
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
+ALIAS (show_bgp_view_afi_safi_community,
+       show_bgp_view_afi_safi_community4_cmd,
+#ifdef HAVE_IPV6
+       "show bgp view WORD (ipv4|ipv6) (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+#else
+       "show bgp view WORD ipv4 (unicast|multicast) community (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export) (AA:NN|local-AS|no-advertise|no-export)",
+#endif
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "Address family\n"
+#ifdef HAVE_IPV6
+       "Address family\n"
+#endif
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Display routes matching the communities\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n"
+       "community number\n"
+       "Do not send outside local AS (well-known community)\n"
+       "Do not advertise to any peer (well-known community)\n"
+       "Do not export to next AS (well-known community)\n")
+
 DEFUN (show_ip_bgp_community_exact,
        show_ip_bgp_community_exact_cmd,
        "show ip bgp community (AA:NN|local-AS|no-advertise|no-export) exact-match",
@@ -7667,7 +7947,7 @@
        "Do not export to next AS (well-known community)\n"
        "Exact match of the communities")
 {
-  return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_UNICAST);
+  return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST);
 }
 
 ALIAS (show_ip_bgp_community_exact,
@@ -7750,9 +8030,9 @@
        "Exact match of the communities")
 {
   if (strncmp (argv[0], "m", 1) == 0)
-    return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_MULTICAST);
+    return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_MULTICAST);
  
-  return bgp_show_community (vty, argc, argv, 1, AFI_IP, SAFI_UNICAST);
+  return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP, SAFI_UNICAST);
 }
 
 ALIAS (show_ip_bgp_ipv4_community_exact,
@@ -7839,7 +8119,7 @@
        "Do not advertise to any peer (well-known community)\n"
        "Do not export to next AS (well-known community)\n")
 {
-  return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_UNICAST);
+  return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_UNICAST);
 }
 
 ALIAS (show_bgp_community,
@@ -7984,7 +8264,7 @@
        "Do not advertise to any peer (well-known community)\n"
        "Do not export to next AS (well-known community)\n")
 {
-  return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_UNICAST);
+  return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_UNICAST);
 }
 
 /* old command */
@@ -8062,7 +8342,7 @@
        "Do not export to next AS (well-known community)\n"
        "Exact match of the communities")
 {
-  return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_UNICAST);
+  return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_UNICAST);
 }
 
 ALIAS (show_bgp_community_exact,
@@ -8215,7 +8495,7 @@
        "Do not export to next AS (well-known community)\n"
        "Exact match of the communities")
 {
-  return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_UNICAST);
+  return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_UNICAST);
 }
 
 /* old command */
@@ -8297,7 +8577,7 @@
        "Do not advertise to any peer (well-known community)\n"
        "Do not export to next AS (well-known community)\n")
 {
-  return bgp_show_community (vty, argc, argv, 0, AFI_IP6, SAFI_MULTICAST);
+  return bgp_show_community (vty, NULL, argc, argv, 0, AFI_IP6, SAFI_MULTICAST);
 }
 
 /* old command */
@@ -8377,7 +8657,7 @@
        "Do not export to next AS (well-known community)\n"
        "Exact match of the communities")
 {
-  return bgp_show_community (vty, argc, argv, 1, AFI_IP6, SAFI_MULTICAST);
+  return bgp_show_community (vty, NULL, argc, argv, 1, AFI_IP6, SAFI_MULTICAST);
 }
 
 /* old command */
@@ -9777,6 +10057,56 @@
   return peer_adj_routes (vty, peer, AFI_IP, SAFI_UNICAST, 1);
 }
 
+DEFUN (show_bgp_view_afi_safi_neighbor_adv_recd_routes,
+       show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd,
+#ifdef HAVE_IPV6
+       "show bgp view WORD (ipv4|ipv6) (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)",
+#else
+       "show bgp view WORD ipv4 (unicast|multicast) neighbors (A.B.C.D|X:X::X:X) (advertised-routes|received-routes)",
+#endif
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "Address family\n"
+#ifdef HAVE_IPV6
+       "Address family\n"
+#endif
+       "Address family modifier\n"
+       "Address family modifier\n"
+       "Detailed information on TCP and BGP neighbor connections\n"
+       "Neighbor to display information about\n"
+       "Neighbor to display information about\n"
+       "Display the advertised routes to neighbor\n"
+       "Display the received routes from neighbor\n")
+{
+  int afi;
+  int safi;
+  int in;
+  struct peer *peer;
+
+#ifdef HAVE_IPV6
+    peer = peer_lookup_in_view (vty, argv[0], argv[3]);
+#else
+    peer = peer_lookup_in_view (vty, argv[0], argv[2]);
+#endif
+
+  if (! peer)
+    return CMD_WARNING;
+
+#ifdef HAVE_IPV6
+  afi = (strncmp (argv[1], "ipv6", 4) == 0) ? AFI_IP6 : AFI_IP;
+  safi = (strncmp (argv[2], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  in = (strncmp (argv[4], "r", 1) == 0) ? 1 : 0;
+#else
+  afi = AFI_IP;
+  safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  in = (strncmp (argv[3], "r", 1) == 0) ? 1 : 0;
+#endif
+
+  return peer_adj_routes (vty, peer, afi, safi, in);
+}
+
 DEFUN (show_ip_bgp_neighbor_received_prefix_filter,
        show_ip_bgp_neighbor_received_prefix_filter_cmd,
        "show ip bgp neighbors (A.B.C.D|X:X::X:X) received prefix-filter",
@@ -10184,6 +10514,65 @@
        "Information about Route Server Client\n"
        NEIGHBOR_ADDR_STR)
 
+DEFUN (show_bgp_view_ipv4_safi_rsclient,
+       show_bgp_view_ipv4_safi_rsclient_cmd,
+       "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Client\n"
+       NEIGHBOR_ADDR_STR)
+{
+  struct bgp_table *table;
+  struct peer *peer;
+  safi_t safi;
+
+  if (argc == 3) {
+    peer = peer_lookup_in_view (vty, argv[0], argv[2]);
+    safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  } else {
+    peer = peer_lookup_in_view (vty, NULL, argv[1]);
+    safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  }
+
+  if (! peer)
+    return CMD_WARNING;
+
+  if (! peer->afc[AFI_IP][safi])
+    {
+      vty_out (vty, "%% Activate the neighbor for the address family first%s",
+            VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi],
+              PEER_FLAG_RSERVER_CLIENT))
+    {
+      vty_out (vty, "%% Neighbor is not a Route-Server client%s",
+            VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  table = peer->rib[AFI_IP][safi];
+
+  return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL);
+}
+
+ALIAS (show_bgp_view_ipv4_safi_rsclient,
+       show_bgp_ipv4_safi_rsclient_cmd,
+       "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Client\n"
+       NEIGHBOR_ADDR_STR)
+
 DEFUN (show_ip_bgp_view_rsclient_route,
        show_ip_bgp_view_rsclient_route_cmd,
        "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D",
@@ -10257,6 +10646,87 @@
        NEIGHBOR_ADDR_STR
        "Network in the BGP routing table to display\n")
 
+DEFUN (show_bgp_view_ipv4_safi_rsclient_route,
+       show_bgp_view_ipv4_safi_rsclient_route_cmd,
+       "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Client\n"
+       NEIGHBOR_ADDR_STR
+       "Network in the BGP routing table to display\n")
+{
+  struct bgp *bgp;
+  struct peer *peer;
+  safi_t safi;
+
+  /* BGP structure lookup. */
+  if (argc == 4)
+    {
+      bgp = bgp_lookup_by_name (argv[0]);
+      if (bgp == NULL)
+	{
+	  vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+  else
+    {
+      bgp = bgp_get_default ();
+      if (bgp == NULL)
+	{
+	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+
+  if (argc == 4) {
+    peer = peer_lookup_in_view (vty, argv[0], argv[2]);
+    safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  } else {
+    peer = peer_lookup_in_view (vty, NULL, argv[1]);
+    safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  }
+
+  if (! peer)
+    return CMD_WARNING;
+
+  if (! peer->afc[AFI_IP][safi])
+    {
+      vty_out (vty, "%% Activate the neighbor for the address family first%s",
+            VTY_NEWLINE);
+      return CMD_WARNING;
+}
+
+  if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi],
+              PEER_FLAG_RSERVER_CLIENT))
+    {
+      vty_out (vty, "%% Neighbor is not a Route-Server client%s",
+            VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][safi],
+                                  (argc == 4) ? argv[3] : argv[2],
+                                  AFI_IP, safi, NULL, 0);
+}
+
+ALIAS (show_bgp_view_ipv4_safi_rsclient_route,
+       show_bgp_ipv4_safi_rsclient_route_cmd,
+       "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Client\n"
+       NEIGHBOR_ADDR_STR
+       "Network in the BGP routing table to display\n")
+
 DEFUN (show_ip_bgp_view_rsclient_prefix,
        show_ip_bgp_view_rsclient_prefix_cmd,
        "show ip bgp view WORD rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M",
@@ -10330,6 +10800,86 @@
        NEIGHBOR_ADDR_STR
        "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
 
+DEFUN (show_bgp_view_ipv4_safi_rsclient_prefix,
+       show_bgp_view_ipv4_safi_rsclient_prefix_cmd,
+       "show bgp view WORD ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Client\n"
+       NEIGHBOR_ADDR_STR
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
+{
+  struct bgp *bgp;
+  struct peer *peer;
+  safi_t safi;
+
+  /* BGP structure lookup. */
+  if (argc == 4)
+    {
+      bgp = bgp_lookup_by_name (argv[0]);
+      if (bgp == NULL)
+	{
+	  vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+  else
+    {
+      bgp = bgp_get_default ();
+      if (bgp == NULL)
+	{
+	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+
+  if (argc == 4) {
+    peer = peer_lookup_in_view (vty, argv[0], argv[2]);
+    safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  } else {
+    peer = peer_lookup_in_view (vty, NULL, argv[1]);
+    safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  }
+
+  if (! peer)
+    return CMD_WARNING;
+
+  if (! peer->afc[AFI_IP][safi])
+    {
+      vty_out (vty, "%% Activate the neighbor for the address family first%s",
+            VTY_NEWLINE);
+      return CMD_WARNING;
+}
+
+  if ( ! CHECK_FLAG (peer->af_flags[AFI_IP][safi],
+              PEER_FLAG_RSERVER_CLIENT))
+{
+      vty_out (vty, "%% Neighbor is not a Route-Server client%s",
+            VTY_NEWLINE);
+    return CMD_WARNING;
+    }
+
+  return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP][safi],
+                                  (argc == 4) ? argv[3] : argv[2],
+                                  AFI_IP, safi, NULL, 1);
+}
+
+ALIAS (show_bgp_view_ipv4_safi_rsclient_prefix,
+       show_bgp_ipv4_safi_rsclient_prefix_cmd,
+       "show bgp ipv4 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) A.B.C.D/M",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Client\n"
+       NEIGHBOR_ADDR_STR
+       "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
 
 #ifdef HAVE_IPV6
 DEFUN (show_bgp_view_neighbor_routes,
@@ -10596,6 +11146,65 @@
        "Information about Route Server Client\n"
        NEIGHBOR_ADDR_STR)
 
+DEFUN (show_bgp_view_ipv6_safi_rsclient,
+       show_bgp_view_ipv6_safi_rsclient_cmd,
+       "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Client\n"
+       NEIGHBOR_ADDR_STR)
+{
+  struct bgp_table *table;
+  struct peer *peer;
+  safi_t safi;
+
+  if (argc == 3) {
+    peer = peer_lookup_in_view (vty, argv[0], argv[2]);
+    safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  } else {
+    peer = peer_lookup_in_view (vty, NULL, argv[1]);
+    safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  }
+
+  if (! peer)
+    return CMD_WARNING;
+
+  if (! peer->afc[AFI_IP6][safi])
+    {
+      vty_out (vty, "%% Activate the neighbor for the address family first%s",
+            VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][safi],
+              PEER_FLAG_RSERVER_CLIENT))
+    {
+      vty_out (vty, "%% Neighbor is not a Route-Server client%s",
+            VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  table = peer->rib[AFI_IP6][safi];
+
+  return bgp_show_table (vty, table, &peer->remote_id, bgp_show_type_normal, NULL);
+}
+
+ALIAS (show_bgp_view_ipv6_safi_rsclient,
+       show_bgp_ipv6_safi_rsclient_cmd,
+       "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X)",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Client\n"
+       NEIGHBOR_ADDR_STR)
+
 DEFUN (show_bgp_view_rsclient_route,
        show_bgp_view_rsclient_route_cmd,
        "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X",
@@ -10667,6 +11276,87 @@
        NEIGHBOR_ADDR_STR
        "Network in the BGP routing table to display\n")
 
+DEFUN (show_bgp_view_ipv6_safi_rsclient_route,
+       show_bgp_view_ipv6_safi_rsclient_route_cmd,
+       "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Client\n"
+       NEIGHBOR_ADDR_STR
+       "Network in the BGP routing table to display\n")
+{
+  struct bgp *bgp;
+  struct peer *peer;
+  safi_t safi;
+
+  /* BGP structure lookup. */
+  if (argc == 4)
+    {
+      bgp = bgp_lookup_by_name (argv[0]);
+      if (bgp == NULL)
+	{
+	  vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+  else
+    {
+      bgp = bgp_get_default ();
+      if (bgp == NULL)
+	{
+	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+
+  if (argc == 4) {
+    peer = peer_lookup_in_view (vty, argv[0], argv[2]);
+    safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  } else {
+    peer = peer_lookup_in_view (vty, NULL, argv[1]);
+    safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  }
+
+  if (! peer)
+    return CMD_WARNING;
+
+  if (! peer->afc[AFI_IP6][safi])
+    {
+      vty_out (vty, "%% Activate the neighbor for the address family first%s",
+            VTY_NEWLINE);
+      return CMD_WARNING;
+}
+
+  if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][safi],
+              PEER_FLAG_RSERVER_CLIENT))
+    {
+      vty_out (vty, "%% Neighbor is not a Route-Server client%s",
+            VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+
+  return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][safi],
+                                  (argc == 4) ? argv[3] : argv[2],
+                                  AFI_IP6, safi, NULL, 0);
+}
+
+ALIAS (show_bgp_view_ipv6_safi_rsclient_route,
+       show_bgp_ipv6_safi_rsclient_route_cmd,
+       "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Client\n"
+       NEIGHBOR_ADDR_STR
+       "Network in the BGP routing table to display\n")
+
 DEFUN (show_bgp_view_rsclient_prefix,
        show_bgp_view_rsclient_prefix_cmd,
        "show bgp view WORD rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M",
@@ -10738,6 +11428,87 @@
        NEIGHBOR_ADDR_STR
        "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
 
+DEFUN (show_bgp_view_ipv6_safi_rsclient_prefix,
+       show_bgp_view_ipv6_safi_rsclient_prefix_cmd,
+       "show bgp view WORD ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "BGP view name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Client\n"
+       NEIGHBOR_ADDR_STR
+       "IP prefix <network>/<length>, e.g., 3ffe::/16\n")
+{
+  struct bgp *bgp;
+  struct peer *peer;
+  safi_t safi;
+
+  /* BGP structure lookup. */
+  if (argc == 4)
+    {
+      bgp = bgp_lookup_by_name (argv[0]);
+      if (bgp == NULL)
+	{
+	  vty_out (vty, "Can't find BGP view %s%s", argv[0], VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+  else
+    {
+      bgp = bgp_get_default ();
+      if (bgp == NULL)
+	{
+	  vty_out (vty, "No BGP process is configured%s", VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+
+  if (argc == 4) {
+    peer = peer_lookup_in_view (vty, argv[0], argv[2]);
+    safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  } else {
+    peer = peer_lookup_in_view (vty, NULL, argv[1]);
+    safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+  }
+
+  if (! peer)
+    return CMD_WARNING;
+
+  if (! peer->afc[AFI_IP6][safi])
+    {
+      vty_out (vty, "%% Activate the neighbor for the address family first%s",
+            VTY_NEWLINE);
+      return CMD_WARNING;
+}
+
+  if ( ! CHECK_FLAG (peer->af_flags[AFI_IP6][safi],
+              PEER_FLAG_RSERVER_CLIENT))
+{
+      vty_out (vty, "%% Neighbor is not a Route-Server client%s",
+            VTY_NEWLINE);
+    return CMD_WARNING;
+    }
+
+  return bgp_show_route_in_table (vty, bgp, peer->rib[AFI_IP6][safi],
+                                  (argc == 4) ? argv[3] : argv[2],
+                                  AFI_IP6, safi, NULL, 1);
+}
+
+ALIAS (show_bgp_view_ipv6_safi_rsclient_prefix,
+       show_bgp_ipv6_safi_rsclient_prefix_cmd,
+       "show bgp ipv6 (unicast|multicast) rsclient (A.B.C.D|X:X::X:X) X:X::X:X/M",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Client\n"
+       NEIGHBOR_ADDR_STR
+       "IP prefix <network>/<length>, e.g., 3ffe::/16\n")
+
 #endif /* HAVE_IPV6 */
 
 struct bgp_table *bgp_distance_table;
@@ -11166,41 +11937,49 @@
 
 	  if ((table = rn->info) != NULL)
 	    if ((rm = bgp_node_match (table, &match)) != NULL)
-	      if (! prefix_check || rm->p.prefixlen == match.prefixlen)
-		{
-		  ri = rm->info;
-		  while (ri)
-		    {
-		      if (ri->extra && ri->extra->damp_info)
-			{
-			  ri_temp = ri->next;
-			  bgp_damp_info_free (ri->extra->damp_info, 1);
-			  ri = ri_temp;
-			}
-		      else
-			ri = ri->next;
-		    }
-		}
+              {
+                if (! prefix_check || rm->p.prefixlen == match.prefixlen)
+                  {
+                    ri = rm->info;
+                    while (ri)
+                      {
+                        if (ri->extra && ri->extra->damp_info)
+                          {
+                            ri_temp = ri->next;
+                            bgp_damp_info_free (ri->extra->damp_info, 1);
+                            ri = ri_temp;
+                          }
+                        else
+                          ri = ri->next;
+                      }
+                  }
+
+                bgp_unlock_node (rm);
+              }
         }
     }
   else
     {
       if ((rn = bgp_node_match (bgp->rib[afi][safi], &match)) != NULL)
-	if (! prefix_check || rn->p.prefixlen == match.prefixlen)
-	  {
-	    ri = rn->info;
-	    while (ri)
-	      {
-		if (ri->extra && ri->extra->damp_info)
-		  {
-		    ri_temp = ri->next;
-		    bgp_damp_info_free (ri->extra->damp_info, 1);
-		    ri = ri_temp;
-		  }
-		else
-		  ri = ri->next;
-	      }
-	  }
+        {
+          if (! prefix_check || rn->p.prefixlen == match.prefixlen)
+            {
+              ri = rn->info;
+              while (ri)
+                {
+                  if (ri->extra && ri->extra->damp_info)
+                    {
+                      ri_temp = ri->next;
+                      bgp_damp_info_free (ri->extra->damp_info, 1);
+                      ri = ri_temp;
+                    }
+                  else
+                    ri = ri->next;
+                }
+            }
+
+          bgp_unlock_node (rn);
+        }
     }
 
   return CMD_SUCCESS;
@@ -11555,12 +12334,15 @@
 
   install_element (VIEW_NODE, &show_ip_bgp_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_safi_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_route_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_route_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_safi_route_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_route_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_prefix_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_prefix_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_safi_prefix_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_view_cmd);
@@ -11586,6 +12368,11 @@
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_community2_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_community3_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_community4_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_all_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_afi_safi_community_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_afi_safi_community2_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_afi_safi_community3_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_afi_safi_community4_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_community_exact_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_community2_exact_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_community3_exact_cmd);
@@ -11604,6 +12391,7 @@
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_routes_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_neighbor_routes_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
@@ -11621,20 +12409,28 @@
   install_element (VIEW_NODE, &show_ip_bgp_neighbor_flap_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_neighbor_damp_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_rsclient_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_rsclient_route_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_rsclient_prefix_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_route_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_view_rsclient_prefix_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd);
   
   /* Restricted node: VIEW_NODE - (set of dangerous commands) */
   install_element (RESTRICTED_NODE, &show_ip_bgp_route_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_route_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_route_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_prefix_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_prefix_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_prefix_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_view_route_cmd);
@@ -11647,6 +12443,11 @@
   install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community2_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_all_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community2_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community3_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_afi_safi_community4_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_community_exact_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_community2_exact_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_community3_exact_cmd);
@@ -11656,18 +12457,25 @@
   install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community3_exact_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_community4_exact_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_route_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_prefix_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_route_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_view_rsclient_prefix_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd);
 
   install_element (ENABLE_NODE, &show_ip_bgp_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_ipv4_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv4_safi_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_route_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_ipv4_route_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv4_safi_route_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_route_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_route_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_prefix_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_ipv4_prefix_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv4_safi_prefix_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_prefix_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_prefix_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_view_cmd);
@@ -11693,6 +12501,11 @@
   install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community2_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community3_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_ipv4_community4_cmd);
+  install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_all_cmd);
+  install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community_cmd);
+  install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community2_cmd);
+  install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community3_cmd);
+  install_element (ENABLE_NODE, &show_bgp_view_afi_safi_community4_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_community_exact_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_community2_exact_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_community3_exact_cmd);
@@ -11711,6 +12524,7 @@
   install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_advertised_route_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_routes_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_received_routes_cmd);
+  install_element (ENABLE_NODE, &show_bgp_view_afi_safi_neighbor_adv_recd_routes_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_neighbor_routes_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_ipv4_neighbor_routes_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_neighbor_received_prefix_filter_cmd);
@@ -11728,13 +12542,19 @@
   install_element (ENABLE_NODE, &show_ip_bgp_neighbor_flap_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_neighbor_damp_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_rsclient_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_rsclient_route_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_route_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_rsclient_prefix_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_prefix_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_advertised_route_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_view_neighbor_received_routes_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_cmd);
+  install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_route_cmd);
+  install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_route_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_view_rsclient_prefix_cmd);
+  install_element (ENABLE_NODE, &show_bgp_view_ipv4_safi_rsclient_prefix_cmd);
 
  /* BGP dampening clear commands */
   install_element (ENABLE_NODE, &clear_ip_bgp_dampening_cmd);
@@ -11771,10 +12591,13 @@
 
   install_element (VIEW_NODE, &show_bgp_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv6_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_safi_cmd);
   install_element (VIEW_NODE, &show_bgp_route_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv6_route_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_safi_route_cmd);
   install_element (VIEW_NODE, &show_bgp_prefix_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv6_prefix_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_safi_prefix_cmd);
   install_element (VIEW_NODE, &show_bgp_regexp_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv6_regexp_cmd);
   install_element (VIEW_NODE, &show_bgp_prefix_list_cmd);
@@ -11820,8 +12643,11 @@
   install_element (VIEW_NODE, &show_bgp_neighbor_damp_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv6_neighbor_damp_cmd);
   install_element (VIEW_NODE, &show_bgp_rsclient_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_cmd);
   install_element (VIEW_NODE, &show_bgp_rsclient_route_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd);
   install_element (VIEW_NODE, &show_bgp_rsclient_prefix_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd);
   install_element (VIEW_NODE, &show_bgp_view_cmd);
   install_element (VIEW_NODE, &show_bgp_view_ipv6_cmd);
   install_element (VIEW_NODE, &show_bgp_view_route_cmd);
@@ -11841,16 +12667,21 @@
   install_element (VIEW_NODE, &show_bgp_view_neighbor_damp_cmd);
   install_element (VIEW_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd); 
   install_element (VIEW_NODE, &show_bgp_view_rsclient_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd);
   install_element (VIEW_NODE, &show_bgp_view_rsclient_route_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd);
   install_element (VIEW_NODE, &show_bgp_view_rsclient_prefix_cmd);
+  install_element (VIEW_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd);
   
   /* Restricted:
    * VIEW_NODE - (set of dangerous commands) - (commands dependent on prev) 
    */
   install_element (RESTRICTED_NODE, &show_bgp_route_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv6_route_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_route_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_prefix_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv6_prefix_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_prefix_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_community_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv6_community_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_community2_cmd);
@@ -11868,7 +12699,9 @@
   install_element (RESTRICTED_NODE, &show_bgp_community4_exact_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv6_community4_exact_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_rsclient_route_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_rsclient_prefix_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_view_route_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_route_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_view_prefix_cmd);
@@ -11876,14 +12709,19 @@
   install_element (RESTRICTED_NODE, &show_bgp_view_neighbor_received_prefix_filter_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_neighbor_received_prefix_filter_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_route_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_view_rsclient_prefix_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd);
 
   install_element (ENABLE_NODE, &show_bgp_cmd);
   install_element (ENABLE_NODE, &show_bgp_ipv6_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_safi_cmd);
   install_element (ENABLE_NODE, &show_bgp_route_cmd);
   install_element (ENABLE_NODE, &show_bgp_ipv6_route_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_safi_route_cmd);
   install_element (ENABLE_NODE, &show_bgp_prefix_cmd);
   install_element (ENABLE_NODE, &show_bgp_ipv6_prefix_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_safi_prefix_cmd);
   install_element (ENABLE_NODE, &show_bgp_regexp_cmd);
   install_element (ENABLE_NODE, &show_bgp_ipv6_regexp_cmd);
   install_element (ENABLE_NODE, &show_bgp_prefix_list_cmd);
@@ -11929,8 +12767,11 @@
   install_element (ENABLE_NODE, &show_bgp_neighbor_damp_cmd);
   install_element (ENABLE_NODE, &show_bgp_ipv6_neighbor_damp_cmd);
   install_element (ENABLE_NODE, &show_bgp_rsclient_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_cmd);
   install_element (ENABLE_NODE, &show_bgp_rsclient_route_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_route_cmd);
   install_element (ENABLE_NODE, &show_bgp_rsclient_prefix_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_prefix_cmd);
   install_element (ENABLE_NODE, &show_bgp_view_cmd);
   install_element (ENABLE_NODE, &show_bgp_view_ipv6_cmd);
   install_element (ENABLE_NODE, &show_bgp_view_route_cmd);
@@ -11950,8 +12791,11 @@
   install_element (ENABLE_NODE, &show_bgp_view_neighbor_damp_cmd);
   install_element (ENABLE_NODE, &show_bgp_view_ipv6_neighbor_damp_cmd);
   install_element (ENABLE_NODE, &show_bgp_view_rsclient_cmd);
+  install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_cmd);
   install_element (ENABLE_NODE, &show_bgp_view_rsclient_route_cmd);
+  install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_route_cmd);
   install_element (ENABLE_NODE, &show_bgp_view_rsclient_prefix_cmd);
+  install_element (ENABLE_NODE, &show_bgp_view_ipv6_safi_rsclient_prefix_cmd);
   
   /* Statistics */
   install_element (ENABLE_NODE, &show_bgp_statistics_cmd);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 42c3e05..abb85fd 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -1470,6 +1470,13 @@
 	  new = community_uniq_sort (merge);
 	  community_free (merge);
 
+	  /* HACK: if the old community is not intern'd,
+	   * we should free it here, or all reference to it may be lost.
+	   * Really need to cleanup attribute caching sometime.
+	   */
+	  if (old->refcnt == 0)
+	    community_free (old);
+
 	  if (new->size == 0)
 	    {
 	      binfo->attr->community = NULL;
@@ -1552,10 +1559,10 @@
       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);
     }
@@ -1571,7 +1578,7 @@
   ecom = ecommunity_str2com (arg, ECOMMUNITY_ROUTE_TARGET, 0);
   if (! ecom)
     return NULL;
-  return ecom;
+  return ecommunity_intern (ecom);
 }
 
 /* Free function for set community. */
@@ -1579,7 +1586,7 @@
 route_set_ecommunity_rt_free (void *rule)
 {
   struct ecommunity *ecom = rule;
-  ecommunity_free (ecom);
+  ecommunity_unintern (&ecom);
 }
 
 /* Set community rule structure. */
@@ -1598,7 +1605,7 @@
 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)
@@ -1609,8 +1616,19 @@
       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;
 }
@@ -1625,7 +1643,7 @@
   if (! ecom)
     return NULL;
   
-  return ecom;
+  return ecommunity_intern (ecom);
 }
 
 /* Free function for set community. */
@@ -1633,7 +1651,7 @@
 route_set_ecommunity_soo_free (void *rule)
 {
   struct ecommunity *ecom = rule;
-  ecommunity_free (ecom);
+  ecommunity_unintern (&ecom);
 }
 
 /* Set community rule structure. */
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
index 91cab60..a249c23 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -350,7 +350,6 @@
       if (new->p.prefixlen != p->prefixlen)
 	{
 	  match = new;
-	  bgp_lock_node (match);
 	  new = bgp_node_set (table, p);
 	  set_link (match, new);
 	  table->count++;
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 9cb3018..f65bb15 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -213,6 +213,12 @@
     case BGP_ERR_TCPSIG_FAILED:
       str = "Error while applying TCP-Sig to session(s)";
       break;
+    case BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK:
+      str = "ebgp-multihop and ttl-security cannot be configured together";
+      break;
+    case BGP_ERR_NO_IBGP_WITH_TTLHACK:
+      str = "ttl-security only allowed for EBGP peers";
+      break;
     }
   if (str)
     {
@@ -2636,9 +2642,7 @@
   else
     VTY_GET_INTEGER_RANGE ("TTL", ttl, ttl_str, 1, 255);
 
-  peer_ebgp_multihop_set (peer, ttl);
-
-  return CMD_SUCCESS;
+  return bgp_vty_return (vty,  peer_ebgp_multihop_set (peer, ttl));
 }
 
 static int
@@ -2650,9 +2654,7 @@
   if (! peer)
     return CMD_WARNING;
 
-  peer_ebgp_multihop_unset (peer);
-
-  return CMD_SUCCESS;
+  return bgp_vty_return (vty, peer_ebgp_multihop_unset (peer));
 }
 
 /* neighbor ebgp-multihop. */
@@ -3954,6 +3956,42 @@
   return bgp_vty_return (vty, ret);
 }
 
+DEFUN (neighbor_ttl_security,
+       neighbor_ttl_security_cmd,
+       NEIGHBOR_CMD2 "ttl-security hops <1-254>",
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Specify the maximum number of hops to the BGP peer\n")
+{
+  struct peer *peer;
+  int gtsm_hops;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+    
+  VTY_GET_INTEGER_RANGE ("", gtsm_hops, argv[1], 1, 254);
+
+  return bgp_vty_return (vty, peer_ttl_security_hops_set (peer, gtsm_hops));
+}
+
+DEFUN (no_neighbor_ttl_security,
+       no_neighbor_ttl_security_cmd,
+       NO_NEIGHBOR_CMD2 "ttl-security hops <1-254>",
+       NO_STR
+       NEIGHBOR_STR
+       NEIGHBOR_ADDR_STR2
+       "Specify the maximum number of hops to the BGP peer\n")
+{
+  struct peer *peer;
+
+  peer = peer_and_group_lookup_vty (vty, argv[0]);
+  if (! peer)
+    return CMD_WARNING;
+
+  return bgp_vty_return (vty, peer_ttl_security_hops_unset (peer));
+}
+
 /* Address family configuration.  */
 DEFUN (address_family_ipv4,
        address_family_ipv4_cmd,
@@ -6856,6 +6894,16 @@
   return bgp_show_summary_vty (vty, NULL, AFI_IP, SAFI_UNICAST);
 }
 
+ALIAS (show_ip_bgp_ipv4_summary,
+       show_bgp_ipv4_safi_summary_cmd,
+       "show bgp ipv4 (unicast|multicast) summary",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Summary of BGP neighbor status\n")
+
 DEFUN (show_ip_bgp_instance_ipv4_summary,
        show_ip_bgp_instance_ipv4_summary_cmd,
        "show ip bgp view WORD ipv4 (unicast|multicast) summary",
@@ -6875,6 +6923,18 @@
     return bgp_show_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST);
 }
 
+ALIAS (show_ip_bgp_instance_ipv4_summary,
+       show_bgp_instance_ipv4_safi_summary_cmd,
+       "show bgp view WORD ipv4 (unicast|multicast) summary",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Summary of BGP neighbor status\n")
+
 DEFUN (show_ip_bgp_vpnv4_all_summary,
        show_ip_bgp_vpnv4_all_summary_cmd,
        "show ip bgp vpnv4 all summary",
@@ -6953,6 +7013,40 @@
        "Address family\n"
        "Summary of BGP neighbor status\n")
 
+DEFUN (show_bgp_ipv6_safi_summary,
+       show_bgp_ipv6_safi_summary_cmd,
+       "show bgp ipv6 (unicast|multicast) summary",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Summary of BGP neighbor status\n")
+{
+  if (strncmp (argv[0], "m", 1) == 0)
+    return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_MULTICAST);
+
+  return bgp_show_summary_vty (vty, NULL, AFI_IP6, SAFI_UNICAST);
+}
+
+DEFUN (show_bgp_instance_ipv6_safi_summary,
+       show_bgp_instance_ipv6_safi_summary_cmd,
+       "show bgp view WORD ipv6 (unicast|multicast) summary",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Summary of BGP neighbor status\n")
+{
+  if (strncmp (argv[1], "m", 1) == 0)
+    return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_MULTICAST);
+
+  return bgp_show_summary_vty (vty, argv[0], AFI_IP6, SAFI_UNICAST);
+}
+
 /* old command */
 DEFUN (show_ipv6_bgp_summary, 
        show_ipv6_bgp_summary_cmd,
@@ -7544,10 +7638,16 @@
 		 p->host, VTY_NEWLINE);
     }
 
-  /* EBGP Multihop */
-  if (peer_sort (p) != BGP_PEER_IBGP && p->ttl > 1)
-    vty_out (vty, "  External BGP neighbor may be up to %d hops away.%s",
-	     p->ttl, VTY_NEWLINE);
+  /* EBGP Multihop and GTSM */
+  if (peer_sort (p) != BGP_PEER_IBGP)
+    {
+      if (p->gtsm_hops > 0)
+	vty_out (vty, "  External BGP neighbor may be up to %d hops away.%s",
+		 p->gtsm_hops, VTY_NEWLINE);
+      else if (p->ttl > 1)
+	vty_out (vty, "  External BGP neighbor may be up to %d hops away.%s",
+		 p->ttl, VTY_NEWLINE);
+    }
 
   /* Local address. */
   if (p->su_local)
@@ -8154,6 +8254,41 @@
   return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, SAFI_UNICAST);
 }
 
+DEFUN (show_bgp_instance_ipv4_safi_rsclient_summary,
+       show_bgp_instance_ipv4_safi_rsclient_summary_cmd,
+       "show bgp view WORD ipv4 (unicast|multicast) rsclient summary",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Clients\n"
+       "Summary of all Route Server Clients\n")
+{
+  safi_t safi;
+
+  if (argc == 2) {
+    safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+    return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP, safi);
+  } else {
+    safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+    return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP, safi);
+  }
+}
+
+ALIAS (show_bgp_instance_ipv4_safi_rsclient_summary,
+       show_bgp_ipv4_safi_rsclient_summary_cmd,
+       "show bgp ipv4 (unicast|multicast) rsclient summary",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Clients\n"
+       "Summary of all Route Server Clients\n")
+
 #ifdef HAVE_IPV6
 DEFUN (show_bgp_rsclient_summary,
        show_bgp_rsclient_summary_cmd,
@@ -8198,6 +8333,42 @@
        "Address family\n"
        "Information about Route Server Clients\n"
        "Summary of all Route Server Clients\n")
+
+DEFUN (show_bgp_instance_ipv6_safi_rsclient_summary,
+       show_bgp_instance_ipv6_safi_rsclient_summary_cmd,
+       "show bgp view WORD ipv6 (unicast|multicast) rsclient summary",
+       SHOW_STR
+       BGP_STR
+       "BGP view\n"
+       "View name\n"
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Clients\n"
+       "Summary of all Route Server Clients\n")
+{
+  safi_t safi;
+
+  if (argc == 2) {
+    safi = (strncmp (argv[1], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+    return bgp_show_rsclient_summary_vty (vty, argv[0], AFI_IP6, safi);
+  } else {
+    safi = (strncmp (argv[0], "m", 1) == 0) ? SAFI_MULTICAST : SAFI_UNICAST;
+    return bgp_show_rsclient_summary_vty (vty, NULL, AFI_IP6, safi);
+  }
+}
+
+ALIAS (show_bgp_instance_ipv6_safi_rsclient_summary,
+       show_bgp_ipv6_safi_rsclient_summary_cmd,
+       "show bgp ipv6 (unicast|multicast) rsclient summary",
+       SHOW_STR
+       BGP_STR
+       "Address family\n"
+       "Address Family modifier\n"
+       "Address Family modifier\n"
+       "Information about Route Server Clients\n"
+       "Summary of all Route Server Clients\n")
+
 #endif /* HAVE IPV6 */
 
 /* Redistribute VTY commands.  */
@@ -9627,38 +9798,50 @@
   install_element (VIEW_NODE, &show_ip_bgp_summary_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_instance_summary_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_summary_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_safi_summary_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_summary_cmd);
+  install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_summary_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_vpnv4_all_summary_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd);
 #ifdef HAVE_IPV6
   install_element (VIEW_NODE, &show_bgp_summary_cmd);
   install_element (VIEW_NODE, &show_bgp_instance_summary_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv6_summary_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_safi_summary_cmd);
   install_element (VIEW_NODE, &show_bgp_instance_ipv6_summary_cmd);
+  install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_summary_cmd);
 #endif /* HAVE_IPV6 */
   install_element (RESTRICTED_NODE, &show_ip_bgp_summary_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_instance_summary_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_summary_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_summary_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_summary_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_summary_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_all_summary_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd);
 #ifdef HAVE_IPV6
   install_element (RESTRICTED_NODE, &show_bgp_summary_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_instance_summary_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv6_summary_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_summary_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_summary_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_summary_cmd);
 #endif /* HAVE_IPV6 */
   install_element (ENABLE_NODE, &show_ip_bgp_summary_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_instance_summary_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_ipv4_summary_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv4_safi_summary_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_summary_cmd);
+  install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_summary_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_all_summary_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_vpnv4_rd_summary_cmd);
 #ifdef HAVE_IPV6
   install_element (ENABLE_NODE, &show_bgp_summary_cmd);
   install_element (ENABLE_NODE, &show_bgp_instance_summary_cmd);
   install_element (ENABLE_NODE, &show_bgp_ipv6_summary_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_safi_summary_cmd);
   install_element (ENABLE_NODE, &show_bgp_instance_ipv6_summary_cmd);
+  install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_summary_cmd);
 #endif /* HAVE_IPV6 */
 
   /* "show ip bgp neighbors" commands. */
@@ -9722,28 +9905,40 @@
   install_element (VIEW_NODE, &show_ip_bgp_instance_rsclient_summary_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd);
   install_element (VIEW_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd);
+  install_element (VIEW_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_rsclient_summary_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_instance_rsclient_summary_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd);
   install_element (RESTRICTED_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_rsclient_summary_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_instance_rsclient_summary_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_ipv4_rsclient_summary_cmd);
   install_element (ENABLE_NODE, &show_ip_bgp_instance_ipv4_rsclient_summary_cmd);
+  install_element (ENABLE_NODE, &show_bgp_instance_ipv4_safi_rsclient_summary_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv4_safi_rsclient_summary_cmd);
 
 #ifdef HAVE_IPV6
   install_element (VIEW_NODE, &show_bgp_rsclient_summary_cmd);
   install_element (VIEW_NODE, &show_bgp_ipv6_rsclient_summary_cmd);
   install_element (VIEW_NODE, &show_bgp_instance_rsclient_summary_cmd);
   install_element (VIEW_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd);
+  install_element (VIEW_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd);
+  install_element (VIEW_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_rsclient_summary_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_ipv6_rsclient_summary_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_instance_rsclient_summary_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd);
+  install_element (RESTRICTED_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd);
   install_element (ENABLE_NODE, &show_bgp_rsclient_summary_cmd);
   install_element (ENABLE_NODE, &show_bgp_ipv6_rsclient_summary_cmd);
   install_element (ENABLE_NODE, &show_bgp_instance_rsclient_summary_cmd);
   install_element (ENABLE_NODE, &show_bgp_instance_ipv6_rsclient_summary_cmd);
+  install_element (ENABLE_NODE, &show_bgp_instance_ipv6_safi_rsclient_summary_cmd);
+  install_element (ENABLE_NODE, &show_bgp_ipv6_safi_rsclient_summary_cmd);
 #endif /* HAVE_IPV6 */
 
   /* "show ip bgp paths" commands. */
@@ -9784,6 +9979,10 @@
   install_element (BGP_IPV6_NODE, &no_bgp_redistribute_ipv6_metric_rmap_cmd);
 #endif /* HAVE_IPV6 */
 
+  /* ttl_security commands */
+  install_element (BGP_NODE, &neighbor_ttl_security_cmd);
+  install_element (BGP_NODE, &no_neighbor_ttl_security_cmd);
+
   /* "show bgp memory" commands. */
   install_element (VIEW_NODE, &show_bgp_memory_cmd);
   install_element (RESTRICTED_NODE, &show_bgp_memory_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index d7af349..76c519c 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -232,12 +232,10 @@
 {
   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 @@
   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);
@@ -310,12 +308,10 @@
 {
   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. */
@@ -338,7 +334,7 @@
   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);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 0d462db..5dc014b 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -695,7 +695,7 @@
     }
 }
 
-static inline void
+static void
 peer_free (struct peer *peer)
 {
   assert (peer->status == Deleted);
@@ -1379,6 +1379,7 @@
   group->conf->group = group;
   group->conf->as = 0; 
   group->conf->ttl = 1;
+  group->conf->gtsm_hops = 0;
   group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV;
   UNSET_FLAG (group->conf->config, PEER_CONFIG_TIMER);
   UNSET_FLAG (group->conf->config, PEER_CONFIG_CONNECT);
@@ -1416,6 +1417,9 @@
   /* TTL */
   peer->ttl = conf->ttl;
 
+  /* GTSM hops */
+  peer->gtsm_hops = conf->gtsm_hops;
+
   /* Weight */
   peer->weight = conf->weight;
 
@@ -2664,10 +2668,36 @@
 {
   struct peer_group *group;
   struct listnode *node, *nnode;
+  struct peer *peer1;
 
   if (peer_sort (peer) == BGP_PEER_IBGP)
     return 0;
 
+  /* see comment in peer_ttl_security_hops_set() */
+  if (ttl != MAXTTL)
+    {
+      if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+        {
+          group = peer->group;
+          if (group->conf->gtsm_hops != 0)
+            return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+
+          for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1))
+            {
+              if (peer_sort (peer1) == BGP_PEER_IBGP)
+                continue;
+
+              if (peer1->gtsm_hops != 0)
+                return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+            }
+        }
+      else
+        {
+          if (peer->gtsm_hops != 0)
+            return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+        }
+    }
+
   peer->ttl = ttl;
 
   if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
@@ -2701,6 +2731,9 @@
   if (peer_sort (peer) == BGP_PEER_IBGP)
     return 0;
 
+  if (peer->gtsm_hops != 0 && peer->ttl != MAXTTL)
+      return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+
   if (peer_group_active (peer))
     peer->ttl = peer->group->conf->ttl;
   else
@@ -4332,6 +4365,137 @@
   return 0;
 }
 
+/* Set # of hops between us and BGP peer. */
+int
+peer_ttl_security_hops_set (struct peer *peer, int gtsm_hops)
+{
+  struct peer_group *group;
+  struct listnode *node, *nnode;
+  struct peer *peer1;
+  int ret;
+
+  zlog_debug ("peer_ttl_security_hops_set: set gtsm_hops to %d for %s", gtsm_hops, peer->host);
+
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+    return BGP_ERR_NO_IBGP_WITH_TTLHACK;
+
+  /* We cannot configure ttl-security hops when ebgp-multihop is already
+     set.  For non peer-groups, the check is simple.  For peer-groups, it's
+     slightly messy, because we need to check both the peer-group structure
+     and all peer-group members for any trace of ebgp-multihop configuration
+     before actually applying the ttl-security rules.  Cisco really made a
+     mess of this configuration parameter, and OpenBGPD got it right.
+  */
+  
+  if (peer->gtsm_hops == 0) {
+    if (CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+      {
+        group = peer->group;
+        if (group->conf->ttl != 1)
+          return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+
+        for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer1))
+          {
+            if (peer_sort (peer1) == BGP_PEER_IBGP)
+              continue;
+
+            if (peer1->ttl != 1)
+              return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+          }
+      }
+    else
+      {
+        if (peer->ttl != 1)
+          return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK;
+      }
+    /* specify MAXTTL on outgoing packets */
+    ret = peer_ebgp_multihop_set (peer, MAXTTL);
+    if (ret != 0)
+      return ret;
+  }
+  
+  peer->gtsm_hops = gtsm_hops;
+
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP)
+	sockopt_minttl (peer->su.sa.sa_family, peer->fd, MAXTTL + 1 - gtsm_hops);
+    }
+  else
+    {
+      group = peer->group;
+      for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
+	{
+	  if (peer_sort (peer) == BGP_PEER_IBGP)
+	    continue;
+
+	  peer->gtsm_hops = group->conf->gtsm_hops;
+
+	  /* Change setting of existing peer
+	   *   established then change value (may break connectivity)
+	   *   not established yet (teardown session and restart)
+	   *   no session then do nothing (will get handled by next connection)
+	   */
+	  if (peer->status == Established)
+	    {
+	      if (peer->fd >= 0 && peer->gtsm_hops != 0)
+		sockopt_minttl (peer->su.sa.sa_family, peer->fd,
+				MAXTTL + 1 - peer->gtsm_hops);
+	    }
+	  else if (peer->status < Established)
+	    {
+	      if (BGP_DEBUG (events, EVENTS))
+		zlog_debug ("%s Min-ttl changed", peer->host);
+	      BGP_EVENT_ADD (peer, BGP_Stop);
+	    }
+	}
+    }
+
+  return 0;
+}
+
+int
+peer_ttl_security_hops_unset (struct peer *peer)
+{
+  struct peer_group *group;
+  struct listnode *node, *nnode;
+  struct peer *opeer;
+
+  zlog_debug ("peer_ttl_security_hops_unset: set gtsm_hops to zero for %s", peer->host);
+
+  if (peer_sort (peer) == BGP_PEER_IBGP)
+      return 0;
+
+  /* if a peer-group member, then reset to peer-group default rather than 0 */
+  if (peer_group_active (peer))
+    peer->gtsm_hops = peer->group->conf->gtsm_hops;
+  else
+    peer->gtsm_hops = 0;
+
+  opeer = peer;
+  if (! CHECK_FLAG (peer->sflags, PEER_STATUS_GROUP))
+    {
+      if (peer->fd >= 0 && peer_sort (peer) != BGP_PEER_IBGP)
+	sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
+    }
+  else
+    {
+      group = peer->group;
+      for (ALL_LIST_ELEMENTS (group->peer, node, nnode, peer))
+	{
+	  if (peer_sort (peer) == BGP_PEER_IBGP)
+	    continue;
+
+	  peer->gtsm_hops = 0;
+	  
+	  if (peer->fd >= 0)
+	    sockopt_minttl (peer->su.sa.sa_family, peer->fd, 0);
+	}
+    }
+
+  return peer_ebgp_multihop_unset (opeer);
+}
+
 int
 peer_clear (struct peer *peer)
 {
@@ -4557,12 +4721,10 @@
 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;
@@ -4636,12 +4798,19 @@
 	  vty_out (vty, " neighbor %s passive%s", addr, VTY_NEWLINE);
 
       /* EBGP multihop.  */
-      if (peer_sort (peer) != BGP_PEER_IBGP && peer->ttl != 1)
+      if (peer_sort (peer) != BGP_PEER_IBGP && peer->ttl != 1 &&
+                   !(peer->gtsm_hops != 0 && peer->ttl == MAXTTL))
         if (! peer_group_active (peer) ||
 	    g_peer->ttl != peer->ttl)
 	  vty_out (vty, " neighbor %s ebgp-multihop %d%s", addr, peer->ttl,
 		   VTY_NEWLINE);
 
+     /* ttl-security hops */
+      if (peer_sort (peer) != BGP_PEER_IBGP && peer->gtsm_hops != 0)
+        if (! peer_group_active (peer) || g_peer->gtsm_hops != peer->gtsm_hops)
+          vty_out (vty, " neighbor %s ttl-security hops %d%s", addr,
+                   peer->gtsm_hops, VTY_NEWLINE);
+
       /* disable-connected-check.  */
       if (CHECK_FLAG (peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK))
 	if (! peer_group_active (peer) ||
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 91773e3..892e7de 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -303,6 +303,7 @@
   /* Peer information */
   int fd;			/* File descriptor */
   int ttl;			/* TTL of TCP connection to the peer. */
+  int gtsm_hops;		/* minimum hopcount to peer */
   char *desc;			/* Description of the peer. */
   unsigned short port;          /* Destination port for peer */
   char *host;			/* Printable address of the peer. */
@@ -801,7 +802,9 @@
 #define BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP  -27
 #define BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS    -28
 #define BGP_ERR_TCPSIG_FAILED			-29
-#define BGP_ERR_MAX                             -30
+#define BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK	-30
+#define BGP_ERR_NO_IBGP_WITH_TTLHACK		-31
+#define BGP_ERR_MAX				-32
 
 extern struct bgp_master *bm;
 
@@ -954,4 +957,7 @@
 extern int peer_clear (struct peer *);
 extern int peer_clear_soft (struct peer *, afi_t, safi_t, enum bgp_clear_type);
 
+extern int peer_ttl_security_hops_set (struct peer *, int);
+extern int peer_ttl_security_hops_unset (struct peer *);
+
 #endif /* _QUAGGA_BGPD_H */
diff --git a/configure.ac b/configure.ac
index 676c5dc..4e5b535 100755
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@
 ##
 AC_PREREQ(2.53)
 
-AC_INIT(Quagga, 0.99.17.6, [https://bugzilla.quagga.net])
+AC_INIT(Quagga, 0.99.20, [https://bugzilla.quagga.net])
 AC_CONFIG_SRCDIR(lib/zebra.h)
 AC_CONFIG_MACRO_DIR([m4])
 
@@ -218,15 +218,14 @@
 AC_ARG_ENABLE(tcp-zebra,
 [  --enable-tcp-zebra      enable TCP/IP socket connection between zebra and protocol daemon])
 AC_ARG_ENABLE(opaque-lsa,
-[  --enable-opaque-lsa     enable OSPF Opaque-LSA with OSPFAPI support (RFC2370)])
+  AC_HELP_STRING([--disable-opaque-lsa],[do not build OSPF Opaque-LSA with OSPFAPI support (RFC2370)]))
 AC_ARG_ENABLE(ospfapi,
-[  --disable-ospfapi       do not build OSPFAPI to access the OSPF LSA Database, 
-                          (this is the default if --enable-opaque-lsa is not set)])
+[  --disable-ospfapi       do not build OSPFAPI to access the OSPF LSA Database])
 AC_ARG_ENABLE(ospfclient,
 [  --disable-ospfclient    do not build OSPFAPI client for OSPFAPI, 
                           (this is the default if --disable-ospfapi is set)])
 AC_ARG_ENABLE(ospf-te,
-[  --enable-ospf-te        enable Traffic Engineering Extension to OSPF])
+  AC_HELP_STRING([--disable-ospf-te],[disable Traffic Engineering Extension to OSPF]))
 AC_ARG_ENABLE(multipath,
 [  --enable-multipath=ARG  enable multipath function, ARG must be digit])
 AC_ARG_ENABLE(user,
@@ -291,11 +290,11 @@
   AC_DEFINE(HAVE_TCP_ZEBRA,,Use TCP for zebra communication)
 fi
 
-if test "${enable_opaque_lsa}" = "yes"; then
+if test "${enable_opaque_lsa}" != "no"; then
   AC_DEFINE(HAVE_OPAQUE_LSA,,OSPF Opaque LSA)
 fi
 
-if test "${enable_ospf_te}" = "yes"; then
+if test "${enable_ospf_te}" != "no"; then
   AC_DEFINE(HAVE_OPAQUE_LSA,,OSPF Opaque LSA)
   AC_DEFINE(HAVE_OSPF_TE,,OSPF TE)
 fi
@@ -1243,7 +1242,7 @@
 fi
 
 OSPFCLIENT=""
-if test "${enable_opaque_lsa}" = "yes"; then
+if test "${enable_opaque_lsa}" != "no"; then
   if test "${enable_ospfapi}" != "no";then
     AC_DEFINE(SUPPORT_OSPF_API,,OSPFAPI)
 
diff --git a/lib/command.c b/lib/command.c
index ebb50b4..4f6d184 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -3648,6 +3648,8 @@
       install_element (VIEW_NODE, &show_thread_cpu_cmd);
       install_element (ENABLE_NODE, &show_thread_cpu_cmd);
       install_element (RESTRICTED_NODE, &show_thread_cpu_cmd);
+      
+      install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
       install_element (VIEW_NODE, &show_work_queues_cmd);
       install_element (ENABLE_NODE, &show_work_queues_cmd);
     }
diff --git a/lib/distribute.c b/lib/distribute.c
index 7f84b80..0488903 100644
--- a/lib/distribute.c
+++ b/lib/distribute.c
@@ -114,16 +114,11 @@
 }
 
 static unsigned int
-distribute_hash_make (struct distribute *dist)
+distribute_hash_make (void *arg)
 {
-  unsigned int i, key;
+  const struct distribute *dist = arg;
 
-  key = 0;
-  if (dist->ifname)
-    for (i = 0; i < strlen (dist->ifname); i++)
-      key += dist->ifname[i];
-
-  return key;
+  return dist->ifname ? string_hash_make (dist->ifname) : 0;
 }
 
 /* If two distribute-list have same value then return 1 else return
@@ -304,7 +299,6 @@
        "Filter outgoing routing updates\n")
 {
   enum distribute_type type;
-  struct distribute *dist;
 
   /* Check of distribute list type. */
   if (strncmp (argv[1], "i", 1) == 0)
@@ -319,7 +313,7 @@
     }
 
   /* Get interface name corresponding distribute list. */
-  dist = distribute_list_set (NULL, type, argv[0]);
+  distribute_list_set (NULL, type, argv[0]);
 
   return CMD_SUCCESS;
 }
@@ -384,7 +378,6 @@
        "Interface name\n")
 {
   enum distribute_type type;
-  struct distribute *dist;
 
   /* Check of distribute list type. */
   if (strncmp (argv[1], "i", 1) == 0)
@@ -398,7 +391,7 @@
     }
 
   /* Get interface name corresponding distribute list. */
-  dist = distribute_list_set (argv[2], type, argv[0]);
+  distribute_list_set (argv[2], type, argv[0]);
 
   return CMD_SUCCESS;
 }       
@@ -463,7 +456,6 @@
        "Filter outgoing routing updates\n")
 {
   enum distribute_type type;
-  struct distribute *dist;
 
   /* Check of distribute list type. */
   if (strncmp (argv[1], "i", 1) == 0)
@@ -478,7 +470,7 @@
     }
 
   /* Get interface name corresponding distribute list. */
-  dist = distribute_list_prefix_set (NULL, type, argv[0]);
+  distribute_list_prefix_set (NULL, type, argv[0]);
 
   return CMD_SUCCESS;
 }       
@@ -546,7 +538,6 @@
        "Interface name\n")
 {
   enum distribute_type type;
-  struct distribute *dist;
 
   /* Check of distribute list type. */
   if (strncmp (argv[1], "i", 1) == 0)
@@ -561,7 +552,7 @@
     }
 
   /* Get interface name corresponding distribute list. */
-  dist = distribute_list_prefix_set (argv[2], type, argv[0]);
+  distribute_list_prefix_set (argv[2], type, argv[0]);
 
   return CMD_SUCCESS;
 }       
@@ -763,7 +754,7 @@
 void
 distribute_list_init (int node)
 {
-  disthash = hash_create ((unsigned int (*) (void *)) distribute_hash_make,
+  disthash = hash_create (distribute_hash_make,
                           (int (*) (const void *, const void *)) distribute_cmp);
 
   if(node==RIP_NODE) {
diff --git a/lib/hash.c b/lib/hash.c
index 672327e..6db79ea 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -101,6 +101,17 @@
   return hash_get (hash, data, NULL);
 }
 
+/* Simple Bernstein hash which is simple and fast for common case */
+unsigned int string_hash_make (const char *str)
+{
+  unsigned int hash = 0;
+
+  while (*str)
+    hash = (hash * 33) ^ (unsigned int) *str++;
+
+  return hash;
+}
+
 /* This function release registered value from specified hash.  When
    release is successfully finished, return the data pointer in the
    hash backet.  */
diff --git a/lib/hash.h b/lib/hash.h
index f4b1c23..4cb772e 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -70,4 +70,6 @@
 extern void hash_clean (struct hash *, void (*) (void *));
 extern void hash_free (struct hash *);
 
+extern unsigned int string_hash_make (const char *);
+
 #endif /* _ZEBRA_HASH_H */
diff --git a/lib/if.c b/lib/if.c
index 31c60e3..1e99ffb 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -426,16 +426,20 @@
 static void
 if_dump (const struct interface *ifp)
 {
-  zlog_info ("Interface %s index %d metric %d mtu %d "
+  struct listnode *node;
+  struct connected *c;
+
+  for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, c))
+    zlog_info ("Interface %s index %d metric %d mtu %d "
 #ifdef HAVE_IPV6
-             "mtu6 %d "
+               "mtu6 %d "
 #endif /* HAVE_IPV6 */
-             "%s",
-	     ifp->name, ifp->ifindex, ifp->metric, ifp->mtu, 
+               "%s",
+               ifp->name, ifp->ifindex, ifp->metric, ifp->mtu, 
 #ifdef HAVE_IPV6
-	     ifp->mtu6,
+               ifp->mtu6,
 #endif /* HAVE_IPV6 */
-	     if_flag_dump (ifp->flags));
+               if_flag_dump (ifp->flags));
 }
 
 /* Interface printing for all interface. */
diff --git a/lib/if_rmap.c b/lib/if_rmap.c
index ddc62fd..7d049b8 100644
--- a/lib/if_rmap.c
+++ b/lib/if_rmap.c
@@ -109,14 +109,9 @@
 static unsigned int
 if_rmap_hash_make (void *data)
 {
-  struct if_rmap *if_rmap = data;
-  unsigned int i, key;
+  const struct if_rmap *if_rmap = data;
 
-  key = 0;
-  for (i = 0; i < strlen (if_rmap->ifname); i++)
-    key += if_rmap->ifname[i];
-
-  return key;
+  return string_hash_make (if_rmap->ifname);
 }
 
 static int
@@ -212,7 +207,6 @@
        "Route map interface name\n")
 {
   enum if_rmap_type type;
-  struct if_rmap *if_rmap;
 
   if (strncmp (argv[1], "i", 1) == 0)
     type = IF_RMAP_IN;
@@ -224,7 +218,7 @@
       return CMD_WARNING;
     }
 
-  if_rmap = if_rmap_set (argv[2], type, argv[0]);
+  if_rmap_set (argv[2], type, argv[0]);
 
   return CMD_SUCCESS;
 }      
diff --git a/lib/memory.c b/lib/memory.c
index 4bac31d..4090fd9 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -111,6 +111,9 @@
   memory = realloc (ptr, size);
   if (memory == NULL)
     zerror ("realloc", type, size);
+  if (ptr == NULL)
+    alloc_inc (type);
+
   return memory;
 }
 
@@ -123,8 +126,11 @@
 void
 zfree (int type, void *ptr)
 {
-  alloc_dec (type);
-  free (ptr);
+  if (ptr != NULL)
+    {
+      alloc_dec (type);
+      free (ptr);
+    }
 }
 
 /*
diff --git a/lib/memtypes.c b/lib/memtypes.c
index d0ce8c5..d2bc1c6 100644
--- a/lib/memtypes.c
+++ b/lib/memtypes.c
@@ -106,6 +106,7 @@
   { MTYPE_BGP_NODE,		"BGP node"			},
   { MTYPE_BGP_ROUTE,		"BGP route"			},
   { MTYPE_BGP_ROUTE_EXTRA,	"BGP ancillary route info"	},
+  { MTYPE_BGP_CONN,		"BGP connected"			},
   { MTYPE_BGP_STATIC,		"BGP static"			},
   { MTYPE_BGP_ADVERTISE_ATTR,	"BGP adv attr"			},
   { MTYPE_BGP_ADVERTISE,	"BGP adv"			},
diff --git a/lib/prefix.c b/lib/prefix.c
index ceda08d..5e8cff0 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -2317,6 +2317,21 @@
 
 #define MASKBIT(offset)  ((0xff << (PNBBY - (offset))) & 0xff)
 
+unsigned int
+prefix_bit (const u_char *prefix, const u_char prefixlen)
+{
+  unsigned int offset = prefixlen / 8;
+  unsigned int shift  = 7 - (prefixlen % 8);
+  
+  return (prefix[offset] >> shift) & 1;
+}
+
+unsigned int
+prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen)
+{
+  return prefix_bit((const u_char *) &prefix->s6_addr, prefixlen);
+}
+
 /* Address Famiy Identifier to Address Family converter. */
 int
 afi2family (afi_t afi)
diff --git a/lib/prefix.h b/lib/prefix.h
index dab4202..7f0d360 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -128,26 +128,14 @@
 /* Prefix's family member. */
 #define PREFIX_FAMILY(p)  ((p)->family)
 
-/* Check bit of the prefix. */
-static inline unsigned int
-prefix_bit (const u_char *prefix, const u_char prefixlen)
-{
-  unsigned int offset = prefixlen / 8;
-  unsigned int shift  = 7 - (prefixlen % 8);
-
-  return (prefix[offset] >> shift) & 1;
-}
-
-static inline unsigned int
-prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen)
-{
-  return prefix_bit((const u_char *) &prefix->s6_addr, prefixlen);
-}
-
 /* Prototypes. */
 extern int afi2family (afi_t);
 extern afi_t family2afi (int);
 
+/* Check bit of the prefix. */
+extern unsigned int prefix_bit (const u_char *prefix, const u_char prefixlen);
+extern unsigned int prefix6_bit (const struct in6_addr *prefix, const u_char prefixlen);
+
 extern struct prefix *prefix_new (void);
 extern void prefix_free (struct prefix *);
 extern const char *prefix_family_str (const struct prefix *);
diff --git a/lib/sockunion.c b/lib/sockunion.c
index 10224a0..5977052 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -527,6 +527,46 @@
 }
 
 int
+sockopt_cork (int sock, int onoff)
+{
+#ifdef TCP_CORK
+  return setsockopt (sock, IPPROTO_TCP, TCP_CORK, &onoff, sizeof(onoff));
+#else
+  return 0;
+#endif
+}
+
+int
+sockopt_minttl (int family, int sock, int minttl)
+{
+#ifdef IP_MINTTL
+  if (family == AF_INET)
+    {
+      int ret = setsockopt (sock, IPPROTO_IP, IP_MINTTL, &minttl, sizeof(minttl));
+      if (ret < 0)
+	  zlog (NULL, LOG_WARNING,
+		"can't set sockopt IP_MINTTL to %d on socket %d: %s",
+		minttl, sock, safe_strerror (errno));
+      return ret;
+    }
+#endif /* IP_MINTTL */
+#ifdef IPV6_MINHOPCNT
+  if (family == AF_INET6)
+    {
+      int ret = setsockopt (sock, IPPROTO_IPV6, IPV6_MINHOPCNT, &minttl, sizeof(minttl));
+      if (ret < 0)
+	  zlog (NULL, LOG_WARNING,
+		"can't set sockopt IPV6_MINHOPCNT to %d on socket %d: %s",
+		minttl, sock, safe_strerror (errno));
+      return ret;
+    }
+#endif
+
+  errno = EOPNOTSUPP;
+  return -1;
+}
+
+int
 sockopt_v6only (int family, int sock)
 {
   int ret, on = 1;
diff --git a/lib/sockunion.h b/lib/sockunion.h
index db145cf..4531f62 100644
--- a/lib/sockunion.h
+++ b/lib/sockunion.h
@@ -103,6 +103,8 @@
 extern int sockunion_bind (int sock, union sockunion *, 
                            unsigned short, union sockunion *);
 extern int sockopt_ttl (int family, int sock, int ttl);
+extern int sockopt_minttl (int family, int sock, int minttl);
+extern int sockopt_cork (int sock, int onoff);
 extern int sockunion_socket (union sockunion *su);
 extern const char *inet_sutop (union sockunion *su, char *str);
 extern enum connect_result sockunion_connect (int fd, union sockunion *su, 
diff --git a/lib/table.c b/lib/table.c
index 04df3af..e40e670 100644
--- a/lib/table.c
+++ b/lib/table.c
@@ -209,6 +209,10 @@
     {
       if (node->info)
 	matched = node;
+      
+      if (node->p.prefixlen == p->prefixlen)
+        break;
+      
       node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
     }
 
@@ -260,8 +264,8 @@
   while (node && node->p.prefixlen <= p->prefixlen && 
 	 prefix_match (&node->p, p))
     {
-      if (node->p.prefixlen == p->prefixlen && node->info)
-	return route_lock_node (node);
+      if (node->p.prefixlen == p->prefixlen)
+        return node->info ? route_lock_node (node) : NULL;
 
       node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
     }
@@ -283,10 +287,8 @@
 	 prefix_match (&node->p, p))
     {
       if (node->p.prefixlen == p->prefixlen)
-	{
-	  route_lock_node (node);
-	  return node;
-	}
+        return route_lock_node (node);
+      
       match = node;
       node = node->link[prefix_bit(&p->u.prefix, node->p.prefixlen)];
     }
diff --git a/lib/thread.c b/lib/thread.c
index e89af54..6d3c3cb 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -248,7 +248,7 @@
   XFREE (MTYPE_THREAD_STATS, hist);
 }
 
-static inline void 
+static void 
 vty_out_cpu_thread_history(struct vty* vty,
 			   struct cpu_thread_history *a)
 {
@@ -303,7 +303,7 @@
   void *args[3] = {&tmp, vty, &filter};
 
   memset(&tmp, 0, sizeof tmp);
-  tmp.funcname = "TOTAL";
+  tmp.funcname = (char *)"TOTAL";
   tmp.types = filter;
 
 #ifdef HAVE_RUSAGE
@@ -382,6 +382,89 @@
   cpu_record_print(vty, filter);
   return CMD_SUCCESS;
 }
+
+static void
+cpu_record_hash_clear (struct hash_backet *bucket, 
+		      void *args)
+{
+  thread_type *filter = args;
+  struct cpu_thread_history *a = bucket->data;
+  
+  a = bucket->data;
+  if ( !(a->types & *filter) )
+       return;
+  
+  hash_release (cpu_record, bucket->data);
+}
+
+static void
+cpu_record_clear (thread_type filter)
+{
+  thread_type *tmp = &filter;
+  hash_iterate (cpu_record,
+	        (void (*) (struct hash_backet*,void*)) cpu_record_hash_clear,
+	        tmp);
+}
+
+DEFUN(clear_thread_cpu,
+      clear_thread_cpu_cmd,
+      "clear thread cpu [FILTER]",
+      "Clear stored data\n"
+      "Thread information\n"
+      "Thread CPU usage\n"
+      "Display filter (rwtexb)\n")
+{
+  int i = 0;
+  thread_type filter = (thread_type) -1U;
+
+  if (argc > 0)
+    {
+      filter = 0;
+      while (argv[0][i] != '\0')
+	{
+	  switch ( argv[0][i] )
+	    {
+	    case 'r':
+	    case 'R':
+	      filter |= (1 << THREAD_READ);
+	      break;
+	    case 'w':
+	    case 'W':
+	      filter |= (1 << THREAD_WRITE);
+	      break;
+	    case 't':
+	    case 'T':
+	      filter |= (1 << THREAD_TIMER);
+	      break;
+	    case 'e':
+	    case 'E':
+	      filter |= (1 << THREAD_EVENT);
+	      break;
+	    case 'x':
+	    case 'X':
+	      filter |= (1 << THREAD_EXECUTE);
+	      break;
+	    case 'b':
+	    case 'B':
+	      filter |= (1 << THREAD_BACKGROUND);
+	      break;
+	    default:
+	      break;
+	    }
+	  ++i;
+	}
+      if (filter == 0)
+	{
+	  vty_out(vty, "Invalid filter \"%s\" specified,"
+                  " must contain at least one of 'RWTEXB'%s",
+		  argv[0], VTY_NEWLINE);
+	  return CMD_WARNING;
+	}
+    }
+
+  cpu_record_clear (filter);
+  return CMD_SUCCESS;
+}
 
 /* List allocation and head/tail print out. */
 static void
@@ -525,7 +608,7 @@
 }
 
 /* Thread list is empty or not.  */
-static inline int
+static int
 thread_empty (struct thread_list *list)
 {
   return  list->head ? 0 : 1;
@@ -903,6 +986,24 @@
   return ready;
 }
 
+/* process a list en masse, e.g. for event thread lists */
+static unsigned int
+thread_process (struct thread_list *list)
+{
+  struct thread *thread;
+  unsigned int ready = 0;
+  
+  for (thread = list->head; thread; thread = thread->next)
+    {
+      thread_list_delete (list, thread);
+      thread->type = THREAD_READY;
+      thread_list_add (&thread->master->ready, thread);
+      ready++;
+    }
+  return ready;
+}
+
+
 /* Fetch next ready thread. */
 struct thread *
 thread_fetch (struct thread_master *m, struct thread *fetch)
@@ -911,41 +1012,48 @@
   fd_set readfd;
   fd_set writefd;
   fd_set exceptfd;
-  struct timeval timer_val;
+  struct timeval timer_val = { .tv_sec = 0, .tv_usec = 0 };
   struct timeval timer_val_bg;
-  struct timeval *timer_wait;
+  struct timeval *timer_wait = &timer_val;
   struct timeval *timer_wait_bg;
 
   while (1)
     {
       int num = 0;
       
-      /* Signals are highest priority */
+      /* Signals pre-empt everything */
       quagga_sigevent_process ();
        
-      /* Normal event are the next highest priority.  */
-      if ((thread = thread_trim_head (&m->event)) != NULL)
-        return thread_run (m, thread, fetch);
-      
-      /* If there are any ready threads from previous scheduler runs,
-       * process top of them.  
+      /* Drain the ready queue of already scheduled jobs, before scheduling
+       * more.
        */
       if ((thread = thread_trim_head (&m->ready)) != NULL)
         return thread_run (m, thread, fetch);
       
+      /* To be fair to all kinds of threads, and avoid starvation, we
+       * need to be careful to consider all thread types for scheduling
+       * in each quanta. I.e. we should not return early from here on.
+       */
+       
+      /* Normal event are the next highest priority.  */
+      thread_process (&m->event);
+      
       /* Structure copy.  */
       readfd = m->readfd;
       writefd = m->writefd;
       exceptfd = m->exceptfd;
       
       /* Calculate select wait timer if nothing else to do */
-      quagga_get_relative (NULL);
-      timer_wait = thread_timer_wait (&m->timer, &timer_val);
-      timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
-      
-      if (timer_wait_bg &&
-	  (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
-	timer_wait = timer_wait_bg;
+      if (m->ready.count == 0)
+        {
+          quagga_get_relative (NULL);
+          timer_wait = thread_timer_wait (&m->timer, &timer_val);
+          timer_wait_bg = thread_timer_wait (&m->background, &timer_val_bg);
+          
+          if (timer_wait_bg &&
+              (!timer_wait || (timeval_cmp (*timer_wait, *timer_wait_bg) > 0)))
+            timer_wait = timer_wait_bg;
+        }
       
       num = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
       
diff --git a/lib/thread.h b/lib/thread.h
index b52bc54..978aa6b 100644
--- a/lib/thread.h
+++ b/lib/thread.h
@@ -82,7 +82,7 @@
 struct cpu_thread_history 
 {
   int (*func)(struct thread *);
-  const char *funcname;
+  char *funcname;
   unsigned int total_calls;
   struct time_stats
   {
@@ -197,6 +197,7 @@
 /* Internal libzebra exports */
 extern void thread_getrusage (RUSAGE_T *);
 extern struct cmd_element show_thread_cpu_cmd;
+extern struct cmd_element clear_thread_cpu_cmd;
 
 /* replacements for the system gettimeofday(), clock_gettime() and
  * time() functions, providing support for non-decrementing clock on
diff --git a/lib/vty.c b/lib/vty.c
index d9eb921..83bd678 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -1685,7 +1685,6 @@
 vty_accept (struct thread *thread)
 {
   int vty_sock;
-  struct vty *vty;
   union sockunion su;
   int ret;
   unsigned int on;
@@ -1770,7 +1769,7 @@
   if (bufp)
     XFREE (MTYPE_TMP, bufp);
 
-  vty = vty_create (vty_sock, &su);
+  vty_create (vty_sock, &su);
 
   return 0;
 }
diff --git a/lib/workqueue.c b/lib/workqueue.c
index 7c811ed..61643bf 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -103,7 +103,7 @@
   return;
 }
 
-static inline int
+static int
 work_queue_schedule (struct work_queue *wq, unsigned int delay)
 {
   /* if appropriate, schedule work queue thread */
@@ -341,7 +341,7 @@
 
 stats:
 
-#define WQ_HYSTERIS_FACTOR 2
+#define WQ_HYSTERESIS_FACTOR 4
 
   /* we yielded, check whether granularity should be reduced */
   if (yielded && (cycles < wq->cycles.granularity))
@@ -349,17 +349,18 @@
       wq->cycles.granularity = ((cycles > 0) ? cycles 
                                              : WORK_QUEUE_MIN_GRANULARITY);
     }
-  
-  if (cycles >= (wq->cycles.granularity))
+  /* otherwise, should granularity increase? */
+  else if (cycles >= (wq->cycles.granularity))
     {
       if (cycles > wq->cycles.best)
         wq->cycles.best = cycles;
       
-      /* along with yielded check, provides hysteris for granularity */
-      if (cycles > (wq->cycles.granularity * WQ_HYSTERIS_FACTOR * 2))
-        wq->cycles.granularity *= WQ_HYSTERIS_FACTOR; /* quick ramp-up */
-      else if (cycles > (wq->cycles.granularity * WQ_HYSTERIS_FACTOR))
-        wq->cycles.granularity += WQ_HYSTERIS_FACTOR;
+      /* along with yielded check, provides hysteresis for granularity */
+      if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR
+                                           * WQ_HYSTERESIS_FACTOR))
+        wq->cycles.granularity *= WQ_HYSTERESIS_FACTOR; /* quick ramp-up */
+      else if (cycles > (wq->cycles.granularity * WQ_HYSTERESIS_FACTOR))
+        wq->cycles.granularity += WQ_HYSTERESIS_FACTOR;
     }
 #undef WQ_HYSTERIS_FACTOR
   
diff --git a/lib/zclient.c b/lib/zclient.c
index 37ee242..12d113e 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -837,7 +837,6 @@
 static int
 zclient_read (struct thread *thread)
 {
-  int ret;
   size_t already;
   uint16_t length, command;
   uint8_t marker, version;
@@ -932,47 +931,47 @@
     {
     case ZEBRA_ROUTER_ID_UPDATE:
       if (zclient->router_id_update)
-	ret = (*zclient->router_id_update) (command, zclient, length);
+	(*zclient->router_id_update) (command, zclient, length);
       break;
     case ZEBRA_INTERFACE_ADD:
       if (zclient->interface_add)
-	ret = (*zclient->interface_add) (command, zclient, length);
+	(*zclient->interface_add) (command, zclient, length);
       break;
     case ZEBRA_INTERFACE_DELETE:
       if (zclient->interface_delete)
-	ret = (*zclient->interface_delete) (command, zclient, length);
+	(*zclient->interface_delete) (command, zclient, length);
       break;
     case ZEBRA_INTERFACE_ADDRESS_ADD:
       if (zclient->interface_address_add)
-	ret = (*zclient->interface_address_add) (command, zclient, length);
+	(*zclient->interface_address_add) (command, zclient, length);
       break;
     case ZEBRA_INTERFACE_ADDRESS_DELETE:
       if (zclient->interface_address_delete)
-	ret = (*zclient->interface_address_delete) (command, zclient, length);
+	(*zclient->interface_address_delete) (command, zclient, length);
       break;
     case ZEBRA_INTERFACE_UP:
       if (zclient->interface_up)
-	ret = (*zclient->interface_up) (command, zclient, length);
+	(*zclient->interface_up) (command, zclient, length);
       break;
     case ZEBRA_INTERFACE_DOWN:
       if (zclient->interface_down)
-	ret = (*zclient->interface_down) (command, zclient, length);
+	(*zclient->interface_down) (command, zclient, length);
       break;
     case ZEBRA_IPV4_ROUTE_ADD:
       if (zclient->ipv4_route_add)
-	ret = (*zclient->ipv4_route_add) (command, zclient, length);
+	(*zclient->ipv4_route_add) (command, zclient, length);
       break;
     case ZEBRA_IPV4_ROUTE_DELETE:
       if (zclient->ipv4_route_delete)
-	ret = (*zclient->ipv4_route_delete) (command, zclient, length);
+	(*zclient->ipv4_route_delete) (command, zclient, length);
       break;
     case ZEBRA_IPV6_ROUTE_ADD:
       if (zclient->ipv6_route_add)
-	ret = (*zclient->ipv6_route_add) (command, zclient, length);
+	(*zclient->ipv6_route_add) (command, zclient, length);
       break;
     case ZEBRA_IPV6_ROUTE_DELETE:
       if (zclient->ipv6_route_delete)
-	ret = (*zclient->ipv6_route_delete) (command, zclient, length);
+	(*zclient->ipv6_route_delete) (command, zclient, length);
       break;
     default:
       break;
diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c
index 65fcb59..d40bd97 100644
--- a/ospf6d/ospf6_main.c
+++ b/ospf6d/ospf6_main.c
@@ -131,7 +131,7 @@
   exit (status);
 }
 
-static void
+static void __attribute__ ((noreturn))
 ospf6_exit (int status)
 {
   extern struct ospf6 *ospf6;
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index 0a8ac3e..881771a 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -132,6 +132,9 @@
   struct interface *ifp;
 
   ifp = zebra_interface_state_read (zclient->ibuf);
+  if (ifp == NULL)
+    return 0;
+  
   if (IS_OSPF6_DEBUG_ZEBRA (RECV))
     zlog_debug ("Zebra Interface state change: "
                 "%s index %d flags %llx metric %d mtu %d",
diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c
index d06a34a..b7cc20d 100644
--- a/ospfd/ospf_abr.c
+++ b/ospfd/ospf_abr.c
@@ -565,8 +565,7 @@
       if (IS_DEBUG_OSPF_EVENT)
 	zlog_debug ("ospf_check_abr_status(): new router flags: %x",new_flags);
       ospf->flags = new_flags;
-      OSPF_TIMER_ON (ospf->t_router_lsa_update,
-		     ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY);
+      ospf_router_lsa_update (ospf);
     }
 }
 
@@ -751,7 +750,7 @@
             zlog_debug ("ospf_abr_announce_network_to_area(): "
                        "refreshing summary");
           set_metric (old, cost);
-          lsa = ospf_summary_lsa_refresh (area->ospf, old);
+          lsa = ospf_lsa_refresh (area->ospf, old);
           
           if (!lsa)
             {
@@ -1139,7 +1138,7 @@
       if (old) 
 	{ 
 	  set_metric (old, cost);
-	  lsa = ospf_summary_asbr_lsa_refresh (area->ospf, old);
+	  lsa = ospf_lsa_refresh (area->ospf, old);
 	}
       else
 	lsa = ospf_summary_asbr_lsa_originate (p, cost, area);
diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c
index 7738319..fc3b51d 100644
--- a/ospfd/ospf_api.c
+++ b/ospfd/ospf_api.c
@@ -219,7 +219,7 @@
 #else /* ORIGINAL_CODING */
   /* API message common header part. */
   zlog_debug
-    ("API-msg [%s]: type(%d),len(%d),seq(%lu),data(%p),size(%lu)",
+    ("API-msg [%s]: type(%d),len(%d),seq(%lu),data(%p),size(%zd)",
      ospf_api_typename (msg->hdr.msgtype), msg->hdr.msgtype, 
      ntohs (msg->hdr.msglen), (unsigned long) ntohl (msg->hdr.msgseq),
      STREAM_DATA (msg->s), STREAM_SIZE (msg->s));
diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c
index 15fd2e5..2a9003b 100644
--- a/ospfd/ospf_apiserver.c
+++ b/ospfd/ospf_apiserver.c
@@ -1831,7 +1831,7 @@
 
 /* Periodically refresh opaque LSAs so that they do not expire in
    other routers. */
-void
+struct ospf_lsa *
 ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa)
 {
   struct ospf_apiserver *apiserv;
@@ -1904,7 +1904,7 @@
     }
 
 out:
-  return;
+  return new;
 }
 
 
diff --git a/ospfd/ospf_apiserver.h b/ospfd/ospf_apiserver.h
index 9a8ae25..b60f56b 100644
--- a/ospfd/ospf_apiserver.h
+++ b/ospfd/ospf_apiserver.h
@@ -180,7 +180,7 @@
 extern void ospf_apiserver_config_write_if (struct vty *vty, struct interface *ifp);
 extern void ospf_apiserver_show_info (struct vty *vty, struct ospf_lsa *lsa);
 extern int ospf_ospf_apiserver_lsa_originator (void *arg);
-extern void ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa);
+extern struct ospf_lsa *ospf_apiserver_lsa_refresher (struct ospf_lsa *lsa);
 extern void ospf_apiserver_flush_opaque_lsa (struct ospf_apiserver *apiserv,
 				      u_char lsa_type, u_char opaque_type);
 
diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c
index 9d2aedb..a23b4f2 100644
--- a/ospfd/ospf_asbr.c
+++ b/ospfd/ospf_asbr.c
@@ -264,8 +264,7 @@
 
   /* Transition from/to status ASBR, schedule timer. */
   ospf_spf_calculate_schedule (ospf);
-  OSPF_TIMER_ON (ospf->t_router_lsa_update,
-		 ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY);
+  ospf_router_lsa_update (ospf);
 }
 
 void
diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c
index 7b7a798..6a72e31 100644
--- a/ospfd/ospf_ase.c
+++ b/ospfd/ospf_ase.c
@@ -450,7 +450,7 @@
 
   /* if there is a Intra/Inter area route to the N
      do not install external route */
-  if (NULL != (rn = route_node_lookup (ospf->new_table,
+  if ((rn = route_node_lookup (ospf->new_table,
 			      (struct prefix *) &p)))
     {
       route_unlock_node(rn);
@@ -462,7 +462,7 @@
     }
   /* Find a route to the same dest */
   /* If there is no route, create new one. */
-  if (NULL != (rn = route_node_lookup (ospf->new_external_route,
+  if ((rn = route_node_lookup (ospf->new_external_route,
 			       (struct prefix *) &p)))
       route_unlock_node(rn);
 
@@ -717,7 +717,6 @@
 
   /* We assume that if LSA is deleted from DB
      is is also deleted from this RT */
-
   listnode_add (lst, ospf_lsa_lock (lsa)); /* external_lsas lst */
 }
 
@@ -798,7 +797,8 @@
     }
 
   rn = route_node_lookup (ospf->external_lsas, (struct prefix *) &p);
-  assert (rn && rn->info);
+  assert (rn); 
+  assert (rn->info);
   lsas = rn->info;
   route_unlock_node (rn);
 
diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c
index f72087b..2ebae89 100644
--- a/ospfd/ospf_flood.c
+++ b/ospfd/ospf_flood.c
@@ -135,7 +135,7 @@
       /* Originate a new instance and schedule flooding */
       if (area->router_lsa_self)
 	area->router_lsa_self->data->ls_seqnum = new->data->ls_seqnum;
-      ospf_router_lsa_timer_add (area);
+      ospf_router_lsa_update_area (area);
       return;
     case OSPF_NETWORK_LSA:
 #ifdef HAVE_OPAQUE_LSA
@@ -171,7 +171,7 @@
             if (oi->network_lsa_self)
 	      oi->network_lsa_self->data->ls_seqnum = new->data->ls_seqnum;
             /* Schedule network-LSA origination. */
-            ospf_network_lsa_timer_add (oi);
+            ospf_network_lsa_update (oi);
             return;
           }
       break;
@@ -992,3 +992,33 @@
   ospf_flood_through_as (ospf, NULL, lsa);
   ospf_lsa_maxage (ospf, lsa);
 }
+
+void
+ospf_lsa_flush (struct ospf *ospf, struct ospf_lsa *lsa)
+{
+  lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+  
+  switch (lsa->data->type)
+    {
+      case OSPF_ROUTER_LSA:
+      case OSPF_NETWORK_LSA:
+      case OSPF_SUMMARY_LSA:
+      case OSPF_ASBR_SUMMARY_LSA:
+      case OSPF_AS_NSSA_LSA:
+#ifdef HAVE_OPAQUE_LSA
+      case OSPF_OPAQUE_LINK_LSA:
+      case OSPF_OPAQUE_AREA_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+        ospf_lsa_flush_area (lsa, lsa->area);
+        break;
+      case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+      case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+        ospf_lsa_flush_as (ospf, lsa);
+        break;
+      default:
+        zlog_info ("%s: Unknown LSA type %u", __func__, lsa->data->type);
+        break;
+    }
+}
diff --git a/ospfd/ospf_flood.h b/ospfd/ospf_flood.h
index 5382e8f..1ab11b8 100644
--- a/ospfd/ospf_flood.h
+++ b/ospfd/ospf_flood.h
@@ -66,6 +66,7 @@
 extern void ospf_flood_lsa_as (struct ospf_lsa *);
 extern void ospf_lsa_flush_area (struct ospf_lsa *, struct ospf_area *);
 extern void ospf_lsa_flush_as (struct ospf *, struct ospf_lsa *);
+extern void ospf_lsa_flush (struct ospf *, struct ospf_lsa *);
 extern struct external_info *ospf_external_info_check (struct ospf_lsa *);
 
 extern void ospf_lsdb_init (struct ospf_lsdb *);
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index afe3acf..dc0787d 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -97,7 +97,7 @@
       if (oi->output_cost != newcost)
 	{
 	  oi->output_cost = newcost;
-	  ospf_router_lsa_timer_add (oi->area);
+	  ospf_router_lsa_update_area (oi->area);
 	}
     }
 }
@@ -219,9 +219,6 @@
   ospf_add_to_if (ifp, oi);
   listnode_add (ospf->oiflist, oi);
   
-  /* Clear self-originated network-LSA. */
-  oi->network_lsa_self = NULL;
-
   /* Initialize neighbor list. */
   oi->nbrs = route_table_init ();
 
@@ -301,10 +298,6 @@
   ospf_nbr_delete (oi->nbr_self);
   oi->nbr_self = ospf_nbr_new (oi);
   ospf_nbr_add_self (oi);
-  
-  ospf_lsa_unlock (&oi->network_lsa_self);
-  oi->network_lsa_self = NULL;
-  OSPF_TIMER_OFF (oi->t_network_lsa_self);
 }
 
 void
@@ -335,6 +328,8 @@
   listnode_delete (oi->ospf->oiflist, oi);
   listnode_delete (oi->area->oiflist, oi);
 
+  thread_cancel_event (master, oi);
+
   memset (oi, 0, sizeof (*oi));
   XFREE (MTYPE_OSPF_IF, oi);
 }
@@ -534,6 +529,8 @@
 
   oip->auth_crypt = list_new ();
   
+  oip->network_lsa_seqnum = htonl(OSPF_INITIAL_SEQUENCE_NUMBER);
+
   return oip;
 }
 
@@ -572,7 +569,8 @@
       !OSPF_IF_PARAM_CONFIGURED (oip, type) &&
       !OSPF_IF_PARAM_CONFIGURED (oip, auth_simple) &&
       !OSPF_IF_PARAM_CONFIGURED (oip, auth_type) &&
-      listcount (oip->auth_crypt) == 0)
+      listcount (oip->auth_crypt) == 0 &&
+      ntohl (oip->network_lsa_seqnum) != OSPF_INITIAL_SEQUENCE_NUMBER)
     {
       ospf_del_if_params (oip);
       rn->info = NULL;
@@ -1121,8 +1119,8 @@
              if (IS_DEBUG_OSPF (ism, ISM_EVENTS))
                zlog_debug ("ospf_vl_up_check: VL cost change,"
                           " scheduling router lsa refresh");
-             if(ospf->backbone)
-               ospf_router_lsa_timer_add (ospf->backbone);
+             if (ospf->backbone)
+               ospf_router_lsa_update_area (ospf->backbone);
              else if (IS_DEBUG_OSPF (ism, ISM_EVENTS))
                zlog_debug ("ospf_vl_up_check: VL cost change, no backbone!");
            }
diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h
index ab0b758..6db8877 100644
--- a/ospfd/ospf_interface.h
+++ b/ospfd/ospf_interface.h
@@ -73,6 +73,9 @@
   
   DECLARE_IF_PARAM (struct list *, auth_crypt);    /* List of Auth cryptographic data. */
   DECLARE_IF_PARAM (int, auth_type);               /* OSPF authentication type */
+  
+  /* Other, non-configuration state */
+  u_int32_t network_lsa_seqnum;		/* Network LSA seqnum */
 };
 
 enum
@@ -167,6 +170,7 @@
 
   /* Configured varables. */
   struct ospf_if_params *params;
+  
   u_int32_t crypt_seqnum;		/* Cryptographic Sequence Number */ 
   u_int32_t output_cost;	        /* Acutual Interface Output Cost */
 
@@ -206,8 +210,6 @@
   struct thread *t_ls_ack;              /* timer */
   struct thread *t_ls_ack_direct;       /* event */
   struct thread *t_ls_upd_event;        /* event */
-  struct thread *t_network_lsa_self;    /* self-originated network-LSA
-                                           reflesh thread. timer */
 #ifdef HAVE_OPAQUE_LSA
   struct thread *t_opaque_lsa_self;     /* Type-9 Opaque-LSAs */
 #endif /* HAVE_OPAQUE_LSA */
diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c
index 3172587..db53882 100644
--- a/ospfd/ospf_ism.c
+++ b/ospfd/ospf_ism.c
@@ -578,20 +578,17 @@
     oi->area->act_ints++;
 
   /* schedule router-LSA originate. */
-  ospf_router_lsa_timer_add (oi->area);
+  ospf_router_lsa_update_area (oi->area);
 
   /* Originate network-LSA. */
   if (old_state != ISM_DR && state == ISM_DR)
-    ospf_network_lsa_timer_add (oi);
+    ospf_network_lsa_update (oi);
   else if (old_state == ISM_DR && state != ISM_DR)
     {
       /* Free self originated network LSA. */
       lsa = oi->network_lsa_self;
       if (lsa)
-	{
-	  ospf_lsa_flush_area (lsa, oi->area);
-	  OSPF_TIMER_OFF (oi->t_network_lsa_self);
-	}
+        ospf_lsa_flush_area (lsa, oi->area);
 
       ospf_lsa_unlock (&oi->network_lsa_self);
       oi->network_lsa_self = NULL;
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 2f50676..d5959eb 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -372,7 +372,7 @@
 
   lsah = (struct lsa_header *) STREAM_DATA (s);
 
-  lsah->ls_age = htons (0);
+  lsah->ls_age = htons (OSPF_LSA_INITIAL_AGE);
   lsah->options = options;
   lsah->type = type;
   lsah->id = id;
@@ -741,12 +741,12 @@
   
   UNSET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED);
   
-  ospf_router_lsa_timer_add (area);
+  ospf_router_lsa_update_area (area);
   
   return 0;
 }
 
-inline static void
+static void
 ospf_stub_router_check (struct ospf_area *area)
 {
   /* area must either be administratively configured to be stub
@@ -885,6 +885,9 @@
   /* Delete LSA from neighbor retransmit-list. */
   ospf_ls_retransmit_delete_nbr_area (area, lsa);
 
+  /* Unregister LSA from refresh-list */
+  ospf_refresher_unregister_lsa (area->ospf, lsa);
+  
   /* Create new router-LSA instance. */
   if ( (new = ospf_router_lsa_new (area)) == NULL)
     {
@@ -910,20 +913,15 @@
   return NULL;
 }
 
-static int
-ospf_router_lsa_timer (struct thread *t)
+int
+ospf_router_lsa_update_area (struct ospf_area *area)
 {
-  struct ospf_area *area;
-
   if (IS_DEBUG_OSPF_EVENT)
-    zlog_debug ("Timer[router-LSA]: (router-LSA Refresh expire)");
-
-  area = THREAD_ARG (t);
-  area->t_router_lsa_self = NULL;
+    zlog_debug ("[router-LSA]: (router-LSA area update)");
 
   /* Now refresh router-LSA. */
   if (area->router_lsa_self)
-    ospf_router_lsa_refresh (area->router_lsa_self);
+    ospf_lsa_refresh (area->ospf, area->router_lsa_self);
   /* Newly originate router-LSA. */
   else
     ospf_router_lsa_originate (area);
@@ -931,50 +929,15 @@
   return 0;
 }
 
-void
-ospf_router_lsa_timer_add (struct ospf_area *area)
-{
-  /* Keep area's self-originated router-LSA. */
-  struct ospf_lsa *lsa = area->router_lsa_self;
-
-  /* Cancel previously scheduled router-LSA timer. */
-  if (area->t_router_lsa_self)
-    if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
-      zlog_debug ("LSA[Type1]: Cancel previous router-LSA timer");
-
-  OSPF_TIMER_OFF (area->t_router_lsa_self);
-
-  /* If router-LSA is originated previously, check the interval time. */
-  if (lsa)
-    {
-      int delay;
-      if ((delay = ospf_lsa_refresh_delay (lsa)) > 0)
-        {
-	  OSPF_AREA_TIMER_ON (area->t_router_lsa_self,
-			      ospf_router_lsa_timer, delay);
-	  return;
-        }
-    }
-
-  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
-    zlog_debug ("LSA[Type1]: Scheduling router-LSA origination right away");
-
-  /* Immediately refresh router-LSA. */
-  OSPF_AREA_TIMER_ON (area->t_router_lsa_self, ospf_router_lsa_timer, 0);
-}
-
 int
-ospf_router_lsa_update_timer (struct thread *thread)
+ospf_router_lsa_update (struct ospf *ospf)
 {
-  struct ospf *ospf = THREAD_ARG (thread);
   struct listnode *node, *nnode;
   struct ospf_area *area;
 
   if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
     zlog_debug ("Timer[router-LSA Update]: (timer expire)");
 
-  ospf->t_router_lsa_update = NULL;
-
   for (ALL_LIST_ELEMENTS (ospf->areas, node, nnode, area))
     {
       struct ospf_lsa *lsa = area->router_lsa_self;
@@ -999,19 +962,20 @@
 	  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
 	    zlog_debug("LSA[Type%d:%s]: Refresh router-LSA for Area %s",
 		      lsa->data->type, inet_ntoa (lsa->data->id), area_str);
+          ospf_refresher_unregister_lsa (ospf, lsa);
 	  ospf_lsa_flush_area (lsa, area);
 	  ospf_lsa_unlock (&area->router_lsa_self);
 	  area->router_lsa_self = NULL;
 
 	  /* Refresh router-LSA, (not install) and flood through area. */
-	  ospf_router_lsa_timer_add (area);
+	  ospf_router_lsa_update_area (area);
 	}
       else
 	{
 	  rl = (struct router_lsa *) lsa->data;
 	  /* Refresh router-LSA, (not install) and flood through area. */
 	  if (rl->flags != ospf->flags)
-	    ospf_router_lsa_timer_add (area);
+	    ospf_router_lsa_update_area (area);
 	}
     }
 
@@ -1048,6 +1012,7 @@
   struct stream *s;
   struct ospf_lsa *new;
   struct lsa_header *lsah;
+  struct ospf_if_params *oip;
   int length;
 
   /* If there are no neighbours on this network (the net is stub),
@@ -1086,20 +1051,42 @@
   new->data = ospf_lsa_data_new (length);
   memcpy (new->data, lsah, length);
   stream_free (s);
-
+  
+  /* Remember prior network LSA sequence numbers, even if we stop
+   * originating one for this oi, to try avoid re-originating LSAs with a
+   * prior sequence number, and thus speed up adjency forming & convergence.
+   */
+  if ((oip = ospf_lookup_if_params (oi->ifp, oi->address->u.prefix4)))
+    {
+      new->data->ls_seqnum = oip->network_lsa_seqnum;
+      new->data->ls_seqnum = lsa_seqnum_increment (new);
+    }
+  else
+    {
+      oip = ospf_get_if_params (oi->ifp, oi->address->u.prefix4);
+      ospf_if_update_params (oi->ifp, oi->address->u.prefix4);
+    }
+  oip->network_lsa_seqnum = new->data->ls_seqnum;
+  
   return new;
 }
 
 /* Originate network-LSA. */
-static struct ospf_lsa *
-ospf_network_lsa_originate (struct ospf_interface *oi)
+void
+ospf_network_lsa_update (struct ospf_interface *oi)
 {
   struct ospf_lsa *new;
-
+  
+  if (oi->network_lsa_self != NULL)
+    {
+      ospf_lsa_refresh (oi->ospf, oi->network_lsa_self);
+      return;
+    }
+  
   /* Create new network-LSA instance. */
   new = ospf_network_lsa_new (oi);
   if (new == NULL)
-    return NULL;
+    return;
 
   /* Install LSA to LSDB. */
   new = ospf_lsa_install (oi->ospf, oi, new);
@@ -1117,28 +1104,51 @@
       ospf_lsa_header_dump (new->data);
     }
 
-  return new;
+  return;
 }
 
-int
-ospf_network_lsa_refresh (struct ospf_lsa *lsa, struct ospf_interface *oi)
+static struct ospf_lsa *
+ospf_network_lsa_refresh (struct ospf_lsa *lsa)
 {
   struct ospf_area *area = lsa->area;
-  struct ospf_lsa *new;
-
+  struct ospf_lsa *new, *new2;
+  struct ospf_if_params *oip;
+  struct ospf_interface *oi;
+  
   assert (lsa->data);
-
+  
+  /* Retrieve the oi for the network LSA */
+  oi = ospf_if_lookup_by_local_addr (area->ospf, NULL, lsa->data->id);
+  if (oi == NULL)
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+        {
+          zlog_debug ("LSA[Type%d:%s]: network-LSA refresh: "
+                      "no oi found, ick, ignoring.",
+		      lsa->data->type, inet_ntoa (lsa->data->id));
+          ospf_lsa_header_dump (lsa->data);
+        }
+      return NULL;
+    }
   /* Delete LSA from neighbor retransmit-list. */
   ospf_ls_retransmit_delete_nbr_area (area, lsa);
 
+  /* Unregister LSA from refresh-list */
+  ospf_refresher_unregister_lsa (area->ospf, lsa);
+  
   /* Create new network-LSA instance. */
   new = ospf_network_lsa_new (oi);
   if (new == NULL)
-    return -1;
-  new->data->ls_seqnum = lsa_seqnum_increment (lsa);
+    return NULL;
+  
+  oip = ospf_lookup_if_params (oi->ifp, oi->address->u.prefix4);
+  assert (oip != NULL);
+  oip->network_lsa_seqnum = new->data->ls_seqnum = lsa_seqnum_increment (lsa);
 
-  ospf_lsa_install (area->ospf, oi, new);
-
+  new2 = ospf_lsa_install (area->ospf, oi, new);
+  
+  assert (new2 == new);
+  
   /* Flood LSA through aera. */
   ospf_flood_through_area (area, NULL, new);
 
@@ -1149,60 +1159,8 @@
       ospf_lsa_header_dump (new->data);
     }
 
-  return 0;
+  return new;
 }
-
-static int
-ospf_network_lsa_refresh_timer (struct thread *t)
-{
-  struct ospf_interface *oi;
-
-  oi = THREAD_ARG (t);
-  oi->t_network_lsa_self = NULL;
-
-  if (oi->network_lsa_self)
-    /* Now refresh network-LSA. */
-    ospf_network_lsa_refresh (oi->network_lsa_self, oi);
-  else
-    /* Newly create network-LSA. */
-    ospf_network_lsa_originate (oi);
-
-  return 0;
-}
-
-void
-ospf_network_lsa_timer_add (struct ospf_interface *oi)
-{
-  /* Keep interface's self-originated network-LSA. */
-  struct ospf_lsa *lsa = oi->network_lsa_self;
-
-  /* Cancel previously schedules network-LSA timer. */
-  if (oi->t_network_lsa_self)
-    if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
-      zlog_debug ("LSA[Type2]: Cancel previous network-LSA timer");
-  OSPF_TIMER_OFF (oi->t_network_lsa_self);
-
-  /* If network-LSA is originated previously, check the interval time. */
-  if (lsa)
-    {
-      int delay;
-      if ((delay = ospf_lsa_refresh_delay (lsa)) > 0)
-        {
-          oi->t_network_lsa_self =
-            thread_add_timer (master, ospf_network_lsa_refresh_timer,
-			      oi, delay);
-          return;
-        }
-    }
-
-  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
-    zlog_debug ("Scheduling network-LSA origination right away");
-
-  /* Immediately refresh network-LSA. */
-  oi->t_network_lsa_self =
-    thread_add_event (master, ospf_network_lsa_refresh_timer, oi, 0);
-}
-
 
 static void
 stream_put_ospf_metric (struct stream *s, u_int32_t metric_value)
@@ -1326,7 +1284,7 @@
   return new;
 }
 
-struct ospf_lsa*
+static struct ospf_lsa*
 ospf_summary_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa)
 {
   struct ospf_lsa *new;
@@ -1473,7 +1431,7 @@
   return new;
 }
 
-struct ospf_lsa*
+static struct ospf_lsa*
 ospf_summary_asbr_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa)
 {
   struct ospf_lsa *new;
@@ -2299,6 +2257,7 @@
 	{
 	  if (IS_DEBUG_OSPF_EVENT)
 	    zlog_debug ("LSA[Type5:0.0.0.0]: Flush AS-external-LSA");
+          ospf_refresher_unregister_lsa (ospf, lsa);
 	  ospf_lsa_flush_as (ospf, lsa);
 	}
     }
@@ -2327,7 +2286,7 @@
 }
 
 /* Refresh AS-external-LSA. */
-void
+struct ospf_lsa *
 ospf_external_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa,
 			   struct external_info *ei, int force)
 {
@@ -2343,7 +2302,7 @@
                    lsa->data->type, inet_ntoa (lsa->data->id));
       ospf_external_lsa_flush (ospf, ei->type, &ei->p,
 			       ei->ifindex /*, ei->nexthop */);
-      return;
+      return NULL;
     }
 
   if (!changed && !force)
@@ -2351,7 +2310,7 @@
       if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
         zlog_debug ("LSA[Type%d:%s]: Not refreshed, not changed/forced",
                    lsa->data->type, inet_ntoa (lsa->data->id));
-      return;
+      return NULL;
     }
 
   /* Delete LSA from neighbor retransmit-list. */
@@ -2367,7 +2326,7 @@
       if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
 	zlog_debug ("LSA[Type%d:%s]: Could not be refreshed", lsa->data->type,
 		   inet_ntoa (lsa->data->id));
-      return;
+      return NULL;
     }
   
   new->data->ls_seqnum = lsa_seqnum_increment (lsa);
@@ -2396,7 +2355,7 @@
       ospf_lsa_header_dump (new->data);
     }
 
-  return;
+  return new;
 }
 
 
@@ -2404,8 +2363,8 @@
 
 /* Install router-LSA to an area. */
 static struct ospf_lsa *
-ospf_router_lsa_install (struct ospf *ospf,
-			 struct ospf_lsa *new, int rt_recalc)
+ospf_router_lsa_install (struct ospf *ospf, struct ospf_lsa *new,
+                         int rt_recalc)
 {
   struct ospf_area *area = new->area;
 
@@ -2424,15 +2383,11 @@
       if (CHECK_FLAG (new->flags, OSPF_LSA_RECEIVED))
 	return new; /* ignore stale LSA */
 
-      /* Set router-LSA refresh timer. */
-      OSPF_TIMER_OFF (area->t_router_lsa_self);
-      OSPF_AREA_TIMER_ON (area->t_router_lsa_self,
-                          ospf_router_lsa_timer, OSPF_LS_REFRESH_TIME);
-
       /* Set self-originated router-LSA. */
       ospf_lsa_unlock (&area->router_lsa_self);
       area->router_lsa_self = ospf_lsa_lock (new);
 
+      ospf_refresher_register_lsa (ospf, new);
     }
   if (rt_recalc)
     ospf_spf_calculate_schedule (ospf);
@@ -2465,15 +2420,9 @@
       if (CHECK_FLAG (new->flags, OSPF_LSA_RECEIVED))
 	return new; /* ignore stale LSA */
 
-      /* Set LSRefresh timer. */
-      OSPF_TIMER_OFF (oi->t_network_lsa_self);
-
-      OSPF_INTERFACE_TIMER_ON (oi->t_network_lsa_self,
-			       ospf_network_lsa_refresh_timer,
-			       OSPF_LS_REFRESH_TIME);
-
       ospf_lsa_unlock (&oi->network_lsa_self);
       oi->network_lsa_self = ospf_lsa_lock (new);
+      ospf_refresher_register_lsa (ospf, new);
     }
   if (rt_recalc)
     ospf_spf_calculate_schedule (ospf);
@@ -2721,7 +2670,8 @@
           if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
             {
       	      zlog_debug ("ospf_lsa_install() Premature Aging "
-		         "lsa 0x%lx", (u_long)lsa);
+		         "lsa 0x%p, seqnum 0x%x",
+		         lsa, ntohl(lsa->data->ls_seqnum));
       	      ospf_lsa_header_dump (lsa->data);
             }
         }
@@ -2826,7 +2776,7 @@
                    new->data->type, 
                    inet_ntoa (new->data->id), 
                    lsa);
-      ospf_lsa_maxage (ospf, lsa);
+      ospf_lsa_flush (ospf, lsa);
     }
 
   return new;
@@ -2858,35 +2808,6 @@
 }
 
 
-#ifdef ORIGINAL_CODING
-/* This function flood the maxaged LSA to DR. */
-void
-ospf_maxage_flood (struct ospf_lsa *lsa)
-{
-  switch (lsa->data->type)
-    {
-    case OSPF_ROUTER_LSA:
-    case OSPF_NETWORK_LSA:
-    case OSPF_SUMMARY_LSA:
-    case OSPF_ASBR_SUMMARY_LSA:
-    case OSPF_AS_NSSA_LSA:
-#ifdef HAVE_OPAQUE_LSA
-    case OSPF_OPAQUE_LINK_LSA:
-    case OSPF_OPAQUE_AREA_LSA:
-#endif /* HAVE_OPAQUE_LSA */
-      ospf_flood_through_area (lsa->area, NULL, lsa);
-      break;
-    case OSPF_AS_EXTERNAL_LSA:
-#ifdef HAVE_OPAQUE_LSA
-    case OSPF_OPAQUE_AS_LSA:
-#endif /* HAVE_OPAQUE_LSA */
-      ospf_flood_through_as (NULL, lsa);
-      break;
-    default:
-      break;
-    }
-}
-#endif /* ORIGINAL_CODING */
 
 static int
 ospf_maxage_lsa_remover (struct thread *thread)
@@ -2911,7 +2832,11 @@
             reschedule = 1;
             continue;
           }
-
+        
+        /* TODO: maybe convert this function to a work-queue */
+        if (thread_should_yield (thread))
+          OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, 0);
+          
         /* Remove LSA from the LSDB */
         if (IS_LSA_SELF (lsa))
           if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
@@ -2922,19 +2847,11 @@
           zlog_debug ("LSA[Type%d:%s]: MaxAge LSA removed from list",
                      lsa->data->type, inet_ntoa (lsa->data->id));
 
-	/* Flood max age LSA. */
-#ifdef ORIGINAL_CODING
-	ospf_maxage_flood (lsa);
-#else /* ORIGINAL_CODING */
-        ospf_flood_through (ospf, NULL, lsa);
-#endif /* ORIGINAL_CODING */
-
-	if (lsa->flags & OSPF_LSA_PREMATURE_AGE)  
+	if (CHECK_FLAG (lsa->flags, OSPF_LSA_PREMATURE_AGE))
           {
             if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
-              zlog_debug ("originating new router lsa for lsa 0x%lx \n", 
-                         (u_long)lsa);
-            ospf_router_lsa_originate(lsa->area);
+              zlog_debug ("originating new lsa for lsa 0x%p\n", lsa);
+            ospf_lsa_refresh (ospf, lsa);
           }
 
 	/* Remove from lsdb. */
@@ -2953,7 +2870,8 @@
         neighbor Link state retransmission lists and b) none of the router's
         neighbors are in states Exchange or Loading. */
   if (reschedule)
-    OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, 2);
+    OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover,
+                   ospf->maxage_delay);
 
   return 0;
 }
@@ -2971,6 +2889,11 @@
     }
 }
 
+/* Add LSA onto the MaxAge list, and schedule for removal.
+ * This does *not* lead to the LSA being flooded, that must be taken
+ * care of elsewhere, see, e.g., ospf_lsa_flush* (which are callers of this
+ * function).
+ */
 void
 ospf_lsa_maxage (struct ospf *ospf, struct ospf_lsa *lsa)
 {
@@ -2990,7 +2913,8 @@
   if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
     zlog_debug ("LSA[%s]: MaxAge LSA remover scheduled.", dump_lsa_key (lsa));
 
-  OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover, 2);
+  OSPF_TIMER_ON (ospf->t_maxage, ospf_maxage_lsa_remover,
+                 ospf->maxage_delay);
 }
 
 static int
@@ -3035,6 +2959,10 @@
 	ospf_lsa_maxage (ospf, lsa);
       }
 
+  if (IS_LSA_MAXAGE (lsa) && !ospf_lsa_is_self_originated (ospf, lsa))
+    if (LS_AGE (lsa) > OSPF_LSA_MAXAGE + 30)
+      printf ("Eek! Shouldn't happen!\n");
+
   return 0;
 }
 
@@ -3353,6 +3281,7 @@
   switch (lsa->data->type)
     {
 #ifdef HAVE_OPAQUE_LSA
+    /* Opaque wants to be notified of flushes */
     case OSPF_OPAQUE_LINK_LSA:
     case OSPF_OPAQUE_AREA_LSA:
     case OSPF_OPAQUE_AS_LSA:
@@ -3360,7 +3289,8 @@
       break;
 #endif /* HAVE_OPAQUE_LSA */
     default:
-      ospf_lsa_maxage (ospf, lsa);
+      ospf_refresher_unregister_lsa (ospf, lsa);
+      ospf_lsa_flush (ospf, lsa);
       break;
     }
 
@@ -3383,12 +3313,13 @@
       if ((lsa = area->router_lsa_self) != NULL)
         {
           if (IS_DEBUG_OSPF_EVENT)
-            zlog_debug ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id));
-
+            zlog_debug ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH",
+                        lsa->data->type, inet_ntoa (lsa->data->id));
+          
+          ospf_refresher_unregister_lsa (ospf, lsa);
           ospf_lsa_flush_area (lsa, area);
           ospf_lsa_unlock (&area->router_lsa_self);
           area->router_lsa_self = NULL;
-          OSPF_TIMER_OFF (area->t_router_lsa_self);
         }
 
       for (ALL_LIST_ELEMENTS (area->oiflist, node2, nnode2, oi))
@@ -3398,12 +3329,13 @@
                &&   oi->full_nbrs > 0)
             {
               if (IS_DEBUG_OSPF_EVENT)
-                zlog_debug ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id));
-
+                zlog_debug ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH",
+                            lsa->data->type, inet_ntoa (lsa->data->id));
+              
+              ospf_refresher_unregister_lsa (ospf, oi->network_lsa_self);
               ospf_lsa_flush_area (oi->network_lsa_self, area);
               ospf_lsa_unlock (&oi->network_lsa_self);
               oi->network_lsa_self = NULL;
-              OSPF_TIMER_OFF (oi->t_network_lsa_self);
             }
 
           if (oi->type != OSPF_IFTYPE_VIRTUALLINK
@@ -3603,23 +3535,29 @@
 
 
 /* LSA Refreshment functions. */
-static void
+struct ospf_lsa *
 ospf_lsa_refresh (struct ospf *ospf, struct ospf_lsa *lsa)
 {
   struct external_info *ei;
+  struct ospf_lsa *new = NULL;
+  assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF));
   assert (IS_LSA_SELF (lsa));
+  assert (lsa->lock > 0);
 
   switch (lsa->data->type)
     {
       /* Router and Network LSAs are processed differently. */
     case OSPF_ROUTER_LSA:
+      new = ospf_router_lsa_refresh (lsa);
+      break;
     case OSPF_NETWORK_LSA: 
+      new = ospf_network_lsa_refresh (lsa);
       break;
     case OSPF_SUMMARY_LSA:
-      ospf_summary_lsa_refresh (ospf, lsa);
+      new = ospf_summary_lsa_refresh (ospf, lsa);
       break;
     case OSPF_ASBR_SUMMARY_LSA:
-      ospf_summary_asbr_lsa_refresh (ospf, lsa);
+      new = ospf_summary_asbr_lsa_refresh (ospf, lsa);
       break;
     case OSPF_AS_EXTERNAL_LSA:
       /* Translated from NSSA Type-5s are refreshed when 
@@ -3629,7 +3567,7 @@
         break;
       ei = ospf_external_info_check (lsa);
       if (ei)
-        ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_FORCE);
+        new = ospf_external_lsa_refresh (ospf, lsa, ei, LSA_REFRESH_FORCE);
       else
         ospf_lsa_flush_as (ospf, lsa);
       break;
@@ -3637,12 +3575,13 @@
     case OSPF_OPAQUE_LINK_LSA:
     case OSPF_OPAQUE_AREA_LSA:
     case OSPF_OPAQUE_AS_LSA:
-      ospf_opaque_lsa_refresh (lsa);
+      new = ospf_opaque_lsa_refresh (lsa);
       break;
 #endif /* HAVE_OPAQUE_LSA */
     default:
       break;
     }
+  return new;
 }
 
 void
@@ -3650,6 +3589,7 @@
 {
   u_int16_t index, current_index;
   
+  assert (lsa->lock > 0);
   assert (IS_LSA_SELF (lsa));
 
   if (lsa->refresh_list < 0)
@@ -3668,11 +3608,11 @@
       if (delay < 0)
 	delay = 0;
 
-      current_index = ospf->lsa_refresh_queue.index +
-	(quagga_time (NULL) - ospf->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY;
+      current_index = ospf->lsa_refresh_queue.index + (quagga_time (NULL)
+                - ospf->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY;
       
       index = (current_index + delay/OSPF_LSA_REFRESHER_GRANULARITY)
-	% (OSPF_LSA_REFRESHER_SLOTS);
+	      % (OSPF_LSA_REFRESHER_SLOTS);
 
       if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
 	zlog_debug ("LSA[Refresh]: lsa %s with age %d added to index %d",
@@ -3684,7 +3624,7 @@
       lsa->refresh_list = index;
       if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
         zlog_debug ("LSA[Refresh:%s]: ospf_refresher_register_lsa(): "
-                   "setting refresh_list on lsa %p (index %u)", 
+                   "setting refresh_list on lsa %p (slod %d)", 
                    inet_ntoa (lsa->data->id), lsa, index);
     }
 }
@@ -3692,6 +3632,7 @@
 void
 ospf_refresher_unregister_lsa (struct ospf *ospf, struct ospf_lsa *lsa)
 {
+  assert (lsa->lock > 0);
   assert (IS_LSA_SELF (lsa));
   if (lsa->refresh_list >= 0)
     {
@@ -3728,8 +3669,9 @@
      modulus. */
   ospf->lsa_refresh_queue.index =
    ((unsigned long)(ospf->lsa_refresh_queue.index +
-		    (quagga_time (NULL) - ospf->lsa_refresher_started) /
-		    OSPF_LSA_REFRESHER_GRANULARITY)) % OSPF_LSA_REFRESHER_SLOTS;
+		    (quagga_time (NULL) - ospf->lsa_refresher_started)
+		    / OSPF_LSA_REFRESHER_GRANULARITY))
+		    % OSPF_LSA_REFRESHER_SLOTS;
 
   if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
     zlog_debug ("LSA[Refresh]: ospf_lsa_refresh_walker(): next index %d",
@@ -3744,6 +3686,8 @@
 
       refresh_list = ospf->lsa_refresh_queue.qs [i];
       
+      assert (i >= 0);
+
       ospf->lsa_refresh_queue.qs [i] = NULL;
 
       if (refresh_list)
@@ -3755,8 +3699,8 @@
 		           "refresh lsa %p (slot %d)", 
 		           inet_ntoa (lsa->data->id), lsa, i);
 	      
+	      assert (lsa->lock > 0);
 	      list_delete_node (refresh_list, node);
-	      ospf_lsa_unlock (&lsa); /* lsa_refresh_queue */
 	      lsa->refresh_list = -1;
 	      listnode_add (lsa_to_refresh, lsa);
 	    }
@@ -3769,7 +3713,11 @@
   ospf->lsa_refresher_started = quagga_time (NULL);
 
   for (ALL_LIST_ELEMENTS (lsa_to_refresh, node, nnode, lsa))
-    ospf_lsa_refresh (ospf, lsa);
+    {
+      ospf_lsa_refresh (ospf, lsa);
+      assert (lsa->lock > 0);
+      ospf_lsa_unlock (&lsa); /* lsa_refresh_queue & temp for lsa_to_refresh*/
+    }
   
   list_delete (lsa_to_refresh);
   
diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h
index 6b2ba22..f364840 100644
--- a/ospfd/ospf_lsa.h
+++ b/ospfd/ospf_lsa.h
@@ -115,11 +115,9 @@
 
   /* Refreshement List or Queue */
   int refresh_list;
-
-#ifdef HAVE_OPAQUE_LSA
-  /* For Type-9 Opaque-LSAs, reference to ospf-interface is required. */
+  
+  /* For Type-9 Opaque-LSAs */
   struct ospf_interface *oi;
-#endif /* HAVE_OPAQUE_LSA */
 };
 
 /* OSPF LSA Link Type. */
@@ -255,19 +253,16 @@
 extern void ospf_lsa_data_free (struct lsa_header *);
 
 /* Prototype for various LSAs */
-extern int ospf_router_lsa_update_timer (struct thread *);
-extern void ospf_router_lsa_timer_add (struct ospf_area *);
+extern int ospf_router_lsa_update (struct ospf *);
+extern int ospf_router_lsa_update_area (struct ospf_area *);
 
-extern int ospf_network_lsa_refresh (struct ospf_lsa *, struct ospf_interface *);
-extern void ospf_network_lsa_timer_add (struct ospf_interface *);
+extern void ospf_network_lsa_update (struct ospf_interface *);
 
 extern struct ospf_lsa *ospf_summary_lsa_originate (struct prefix_ipv4 *, u_int32_t,
 					     struct ospf_area *);
 extern struct ospf_lsa *ospf_summary_asbr_lsa_originate (struct prefix_ipv4 *,
 						  u_int32_t,
 						  struct ospf_area *);
-extern struct ospf_lsa *ospf_summary_lsa_refresh (struct ospf *, struct ospf_lsa *);
-extern struct ospf_lsa *ospf_summary_asbr_lsa_refresh (struct ospf *, struct ospf_lsa *);
 
 extern struct ospf_lsa *ospf_lsa_install (struct ospf *,
 				   struct ospf_interface *, struct ospf_lsa *);
@@ -302,12 +297,15 @@
 extern u_int32_t get_metric (u_char *);
 
 extern int ospf_lsa_maxage_walker (struct thread *);
-
+extern struct ospf_lsa *ospf_lsa_refresh (struct ospf *, struct ospf_lsa *);
+ 
 extern void ospf_external_lsa_refresh_default (struct ospf *);
 
 extern void ospf_external_lsa_refresh_type (struct ospf *, u_char, int);
-extern void ospf_external_lsa_refresh (struct ospf *, struct ospf_lsa *,
-				struct external_info *, int);
+extern struct ospf_lsa *ospf_external_lsa_refresh (struct ospf *,
+                                                   struct ospf_lsa *,
+                                                   struct external_info *,
+                                                   int);
 extern struct in_addr ospf_lsa_unique_id (struct ospf *, struct ospf_lsdb *, u_char,
 				   struct prefix_ipv4 *);
 extern void ospf_schedule_lsa_flood_area (struct ospf_area *, struct ospf_lsa *);
diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c
index c906f05..ea9a352 100644
--- a/ospfd/ospf_lsdb.c
+++ b/ospfd/ospf_lsdb.c
@@ -120,7 +120,10 @@
   
   /* nothing to do? */
   if (rn->info && rn->info == lsa)
-    return;
+    {
+      route_unlock_node (rn);
+      return;
+    }
   
   /* purge old entry? */
   if (rn->info)
@@ -162,12 +165,13 @@
       return;
     }
   
+  assert (lsa->data->type < OSPF_MAX_LSA);
   table = lsdb->type[lsa->data->type].db;
   lsdb_prefix_set (&lp, lsa);
-  rn = route_node_lookup (table, (struct prefix *) &lp);
-  if (rn && (rn->info == lsa))
+  if ((rn = route_node_lookup (table, (struct prefix *) &lp)))
     {
-      ospf_lsdb_delete_entry (lsdb, rn);
+      if (rn->info == lsa)
+        ospf_lsdb_delete_entry (lsdb, rn);
       route_unlock_node (rn); /* route_node_lookup */
     }
 }
@@ -274,7 +278,8 @@
       rn = route_top (table);
   else
     {
-      rn = route_node_get (table, (struct prefix *) &lp);
+      if ((rn = route_node_lookup (table, (struct prefix *) &lp)) == NULL)
+        return NULL;
       rn = route_next (rn);
     }
 
diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c
index 15fff34..cbc3171 100644
--- a/ospfd/ospf_nsm.c
+++ b/ospfd/ospf_nsm.c
@@ -162,7 +162,7 @@
 
 /* OSPF NSM functions. */
 static int
-nsm_hello_received (struct ospf_neighbor *nbr)
+nsm_packet_received (struct ospf_neighbor *nbr)
 {
   /* Start or Restart Inactivity Timer. */
   OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
@@ -216,7 +216,7 @@
     {
     case OSPF_OPAQUE_LINK_LSA:
       /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
-      if (lsa->oi != nbr->oi)
+      if (nbr->oi && ospf_if_exists (lsa->oi) != nbr->oi)
           return 0;
       break;
     case OSPF_OPAQUE_AREA_LSA:
@@ -408,7 +408,7 @@
   {
     /* DependUpon: dummy state. */
     { NULL,                    NSM_DependUpon }, /* NoEvent           */
-    { NULL,                    NSM_DependUpon }, /* HelloReceived     */
+    { NULL,                    NSM_DependUpon }, /* PacketReceived    */
     { NULL,                    NSM_DependUpon }, /* Start             */
     { NULL,                    NSM_DependUpon }, /* 2-WayReceived     */
     { NULL,                    NSM_DependUpon }, /* NegotiationDone   */
@@ -425,7 +425,7 @@
   {
     /* Deleted: dummy state. */
     { NULL,                    NSM_Deleted    }, /* NoEvent           */
-    { NULL,                    NSM_Deleted    }, /* HelloReceived     */
+    { NULL,                    NSM_Deleted    }, /* PacketReceived    */
     { NULL,                    NSM_Deleted    }, /* Start             */
     { NULL,                    NSM_Deleted    }, /* 2-WayReceived     */
     { NULL,                    NSM_Deleted    }, /* NegotiationDone   */
@@ -442,7 +442,7 @@
   {
     /* Down: */
     { NULL,                    NSM_DependUpon }, /* NoEvent           */
-    { nsm_hello_received,      NSM_Init       }, /* HelloReceived     */
+    { nsm_packet_received,     NSM_Init       }, /* PacketReceived    */
     { nsm_start,               NSM_Attempt    }, /* Start             */
     { NULL,                    NSM_Down       }, /* 2-WayReceived     */
     { NULL,                    NSM_Down       }, /* NegotiationDone   */
@@ -459,7 +459,7 @@
   {
     /* Attempt: */
     { NULL,                    NSM_DependUpon }, /* NoEvent           */
-    { nsm_hello_received,      NSM_Init       }, /* HelloReceived     */
+    { nsm_packet_received,     NSM_Init       }, /* PacketReceived    */
     { NULL,                    NSM_Attempt    }, /* Start             */
     { NULL,                    NSM_Attempt    }, /* 2-WayReceived     */
     { NULL,                    NSM_Attempt    }, /* NegotiationDone   */
@@ -476,7 +476,7 @@
   {
     /* Init: */
     { NULL,                    NSM_DependUpon }, /* NoEvent           */
-    { nsm_hello_received,      NSM_Init       }, /* HelloReceived     */
+    { nsm_packet_received,     NSM_Init      }, /* PacketReceived    */
     { NULL,                    NSM_Init       }, /* Start             */
     { nsm_twoway_received,     NSM_DependUpon }, /* 2-WayReceived     */
     { NULL,                    NSM_Init       }, /* NegotiationDone   */
@@ -493,7 +493,7 @@
   {
     /* 2-Way: */
     { NULL,                    NSM_DependUpon }, /* NoEvent           */
-    { nsm_hello_received,      NSM_TwoWay     }, /* HelloReceived     */
+    { nsm_packet_received,     NSM_TwoWay     }, /* HelloReceived     */
     { NULL,                    NSM_TwoWay     }, /* Start             */
     { NULL,                    NSM_TwoWay     }, /* 2-WayReceived     */
     { NULL,                    NSM_TwoWay     }, /* NegotiationDone   */
@@ -510,7 +510,7 @@
   {
     /* ExStart: */
     { NULL,                    NSM_DependUpon }, /* NoEvent           */
-    { nsm_hello_received,      NSM_ExStart    }, /* HelloReceived     */
+    { nsm_packet_received,     NSM_ExStart    }, /* PacaketReceived   */
     { NULL,                    NSM_ExStart    }, /* Start             */
     { NULL,                    NSM_ExStart    }, /* 2-WayReceived     */
     { nsm_negotiation_done,    NSM_Exchange   }, /* NegotiationDone   */
@@ -527,7 +527,7 @@
   {
     /* Exchange: */
     { NULL,                    NSM_DependUpon }, /* NoEvent           */
-    { nsm_hello_received,      NSM_Exchange   }, /* HelloReceived     */
+    { nsm_packet_received,     NSM_Exchange   }, /* PacketReceived    */
     { NULL,                    NSM_Exchange   }, /* Start             */
     { NULL,                    NSM_Exchange   }, /* 2-WayReceived     */
     { NULL,                    NSM_Exchange   }, /* NegotiationDone   */
@@ -544,7 +544,7 @@
   {
     /* Loading: */
     { NULL,                    NSM_DependUpon }, /* NoEvent           */
-    { nsm_hello_received,      NSM_Loading    }, /* HelloReceived     */
+    { nsm_packet_received,     NSM_Loading    }, /* PacketReceived    */
     { NULL,                    NSM_Loading    }, /* Start             */
     { NULL,                    NSM_Loading    }, /* 2-WayReceived     */
     { NULL,                    NSM_Loading    }, /* NegotiationDone   */
@@ -560,7 +560,7 @@
   },
   { /* Full: */
     { NULL,                    NSM_DependUpon }, /* NoEvent           */
-    { nsm_hello_received,      NSM_Full       }, /* HelloReceived     */
+    { nsm_packet_received,     NSM_Full       }, /* PacketReceived    */
     { NULL,                    NSM_Full       }, /* Start             */
     { NULL,                    NSM_Full       }, /* 2-WayReceived     */
     { NULL,                    NSM_Full       }, /* NegotiationDone   */
@@ -579,7 +579,7 @@
 static const char *ospf_nsm_event_str[] =
 {
   "NoEvent",
-  "HelloReceived",
+  "PacketReceived",
   "Start",
   "2-WayReceived",
   "NegotiationDone",
@@ -711,7 +711,7 @@
 		 LOOKUP(ospf_nsm_state_msg, old_state),
 		 LOOKUP(ospf_nsm_state_msg, state));
 
-      ospf_router_lsa_timer_add (oi->area);
+      ospf_router_lsa_update_area (oi->area);
 
       if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
 	{
@@ -719,7 +719,7 @@
 	    ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
 	  
 	  if (vl_area)
-	    ospf_router_lsa_timer_add (vl_area);
+	    ospf_router_lsa_update_area (vl_area);
 	}
 
       /* Originate network-LSA. */
@@ -730,10 +730,9 @@
 	      ospf_lsa_flush_area (oi->network_lsa_self, oi->area);
 	      ospf_lsa_unlock (&oi->network_lsa_self);
 	      oi->network_lsa_self = NULL;
-	      OSPF_TIMER_OFF (oi->t_network_lsa_self);
 	    }
 	  else
-	    ospf_network_lsa_timer_add (oi);
+	    ospf_network_lsa_update (oi);
 	}
     }
 
diff --git a/ospfd/ospf_nsm.h b/ospfd/ospf_nsm.h
index 1121dae..4f2ae80 100644
--- a/ospfd/ospf_nsm.h
+++ b/ospfd/ospf_nsm.h
@@ -39,7 +39,7 @@
 
 /* OSPF Neighbor State Machine Event. */
 #define NSM_NoEvent	        0
-#define NSM_HelloReceived	1
+#define NSM_PacketReceived	1 /* HelloReceived in the protocol */
 #define NSM_Start		2
 #define NSM_TwoWayReceived	3
 #define NSM_NegotiationDone	4
diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c
index 0b6ac4c..aa126e1 100644
--- a/ospfd/ospf_opaque.c
+++ b/ospfd/ospf_opaque.c
@@ -251,7 +251,7 @@
   void (* config_write_debug )(struct vty *vty);
   void (* show_opaque_info   )(struct vty *vty, struct ospf_lsa *lsa);
   int  (* lsa_originator)(void *arg);
-  void (* lsa_refresher )(struct ospf_lsa *lsa);
+  struct ospf_lsa *(* lsa_refresher )(struct ospf_lsa *lsa);
   int (* new_lsa_hook)(struct ospf_lsa *lsa);
   int (* del_lsa_hook)(struct ospf_lsa *lsa);
 };
@@ -354,7 +354,7 @@
   void (* config_write_debug )(struct vty *vty),
   void (* show_opaque_info   )(struct vty *vty, struct ospf_lsa *lsa),
   int  (* lsa_originator)(void *arg),
-  void (* lsa_refresher )(struct ospf_lsa *lsa),
+  struct ospf_lsa *(* lsa_refresher )(struct ospf_lsa *lsa),
   int (* new_lsa_hook)(struct ospf_lsa *lsa),
   int (* del_lsa_hook)(struct ospf_lsa *lsa))
 {
@@ -1608,12 +1608,13 @@
   return new;
 }
 
-void
+struct ospf_lsa *
 ospf_opaque_lsa_refresh (struct ospf_lsa *lsa)
 {
   struct ospf *ospf;
   struct ospf_opaque_functab *functab;
-
+  struct ospf_lsa *new = NULL;
+  
   ospf = ospf_lookup ();
 
   if ((functab = ospf_opaque_functab_lookup (lsa)) == NULL
@@ -1630,12 +1631,12 @@
         zlog_debug ("LSA[Type%d:%s]: Flush stray Opaque-LSA", lsa->data->type, inet_ntoa (lsa->data->id));
 
       lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
-      ospf_lsa_maxage (ospf, lsa);
+      ospf_lsa_flush (ospf, lsa);
     }
   else
-    (* functab->lsa_refresher)(lsa);
+    new = (* functab->lsa_refresher)(lsa);
 
-  return;
+  return new;
 }
 
 /*------------------------------------------------------------------------*
@@ -2108,7 +2109,7 @@
     zlog_debug ("Schedule Type-%u Opaque-LSA to FLUSH: [opaque-type=%u, opaque-id=%x]", lsa->data->type, GET_OPAQUE_TYPE (ntohl (lsa->data->id.s_addr)), GET_OPAQUE_ID (ntohl (lsa->data->id.s_addr)));
 
   /* This lsa will be flushed and removed eventually. */
-  ospf_lsa_maxage (lsa0->area->ospf, lsa);
+  ospf_lsa_flush (lsa0->area->ospf, lsa);
 
 out:
   return;
diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h
index f49fe46..2273064 100644
--- a/ospfd/ospf_opaque.h
+++ b/ospfd/ospf_opaque.h
@@ -120,7 +120,7 @@
   void (* config_write_debug )(struct vty *vty),
   void (* show_opaque_info   )(struct vty *vty, struct ospf_lsa *lsa),
   int  (* lsa_originator)(void *arg),
-  void (* lsa_refresher )(struct ospf_lsa *lsa),
+  struct ospf_lsa *(* lsa_refresher )(struct ospf_lsa *lsa),
   int (* new_lsa_hook)(struct ospf_lsa *lsa),
   int (* del_lsa_hook)(struct ospf_lsa *lsa)
 );
@@ -143,7 +143,7 @@
 						int *init_delay);
 extern struct ospf_lsa *ospf_opaque_lsa_install (struct ospf_lsa *,
 						 int rt_recalc);
-extern void ospf_opaque_lsa_refresh (struct ospf_lsa *lsa);
+extern struct ospf_lsa *ospf_opaque_lsa_refresh (struct ospf_lsa *lsa);
 
 extern void ospf_opaque_lsa_reoriginate_schedule (void *lsa_type_dependent,
 						  u_char lsa_type,
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 994d362..b714c27 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -125,6 +125,20 @@
   fifo->count++;
 }
 
+/* Add new packet to head of fifo. */
+static void
+ospf_fifo_push_head (struct ospf_fifo *fifo, struct ospf_packet *op)
+{
+  op->next = fifo->head;
+  
+  if (fifo->tail == NULL)
+    fifo->tail = op;
+  
+  fifo->head = op;
+  
+  fifo->count++;
+}
+
 /* Delete first packet from fifo. */
 struct ospf_packet *
 ospf_fifo_pop (struct ospf_fifo *fifo)
@@ -199,6 +213,27 @@
   /* ospf_fifo_debug (oi->obuf); */
 }
 
+static void
+ospf_packet_add_top (struct ospf_interface *oi, struct ospf_packet *op)
+{
+  if (!oi->obuf)
+    {
+      zlog_err("ospf_packet_add(interface %s in state %d [%s], packet type %s, "
+	       "destination %s) called with NULL obuf, ignoring "
+	       "(please report this bug)!\n",
+	       IF_NAME(oi), oi->state, LOOKUP (ospf_ism_state_msg, oi->state),
+	       ospf_packet_type_str[stream_getc_from(op->s, 1)],
+	       inet_ntoa (op->dst));
+      return;
+    }
+
+  /* Add packet to head of queue. */
+  ospf_fifo_push_head (oi->obuf, op);
+
+  /* Debug of packet fifo*/
+  /* ospf_fifo_debug (oi->obuf); */
+}
+
 void
 ospf_packet_delete (struct ospf_interface *oi)
 {
@@ -231,7 +266,7 @@
 }
 
 /* XXX inline */
-static inline unsigned int
+static unsigned int
 ospf_packet_authspace (struct ospf_interface *oi)
 {
   int auth = 0;
@@ -653,6 +688,13 @@
   iph.ip_tos = IPTOS_PREC_INTERNETCONTROL;
   iph.ip_len = (iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) + op->length;
 
+#if defined(__DragonFly__)
+  /*
+   * DragonFly's raw socket expects ip_len/ip_off in network byte order.
+   */
+  iph.ip_len = htons(iph.ip_len);
+#endif
+
 #ifdef WANT_OSPF_WRITE_FRAGMENT
   /* XXX-MT: not thread-safe at all..
    * XXX: this presumes this is only programme sending OSPF packets 
@@ -881,7 +923,7 @@
   old_state = nbr->state;
 
   /* Add event to thread. */
-  OSPF_NSM_EVENT_EXECUTE (nbr, NSM_HelloReceived);
+  OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
 
   /*  RFC2328  Section 9.5.1
       If the router is not eligible to become Designated Router,
@@ -901,7 +943,7 @@
   if (oi->type == OSPF_IFTYPE_NBMA &&
       (old_state == NSM_Down || old_state == NSM_Attempt))
     {
-      OSPF_NSM_EVENT_EXECUTE (nbr, NSM_OneWayReceived);
+      OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_OneWayReceived);
       nbr->priority = hello->priority;
       nbr->d_router = hello->d_router;
       nbr->bd_router = hello->bd_router;
@@ -911,12 +953,12 @@
   if (ospf_nbr_bidirectional (&oi->ospf->router_id, hello->neighbors,
 			      size - OSPF_HELLO_MIN_SIZE))
     {
-      OSPF_NSM_EVENT_EXECUTE (nbr, NSM_TwoWayReceived);
+      OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_TwoWayReceived);
       nbr->options |= hello->options;
     }
   else
     {
-      OSPF_NSM_EVENT_EXECUTE (nbr, NSM_OneWayReceived);
+      OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_OneWayReceived);
       /* Set neighbor information. */
       nbr->priority = hello->priority;
       nbr->d_router = hello->d_router;
@@ -1191,6 +1233,9 @@
     }
 #endif /* HAVE_OPAQUE_LSA */
 
+  /* Add event to thread. */
+  OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
+
   /* Process DD packet by neighbor status. */
   switch (nbr->state)
     {
@@ -1412,6 +1457,9 @@
       return;
     }
 
+  /* Add event to thread. */
+  OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
+
   /* Neighbor State should be Exchange or later. */
   if (nbr->state != NSM_Exchange &&
       nbr->state != NSM_Loading &&
@@ -1649,6 +1697,9 @@
       return;
     }
 
+  /* Add event to thread. */
+  OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
+
   /* Check neighbor state. */
   if (nbr->state < NSM_Exchange)
     {
@@ -1951,7 +2002,7 @@
 	      quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
 	      
 	      if (tv_cmp (tv_sub (now, current->tv_orig), 
-			  int2tv (OSPF_MIN_LS_ARRIVAL)) > 0)
+			  int2tv (OSPF_MIN_LS_ARRIVAL)) >= 0)
 		/* Trap NSSA type later.*/
 		ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT);
 	      DISCARD_LSA (lsa, 8);
@@ -1982,6 +2033,9 @@
       return;
     }
 
+  /* Add event to thread. */
+  OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
+
   if (nbr->state < NSM_Exchange)
     {
       zlog_warn ("Link State Acknowledgment: "
@@ -2085,6 +2139,15 @@
   ip_len = ip_len + (iph->ip_hl << 2);
 #endif
   
+#if defined(__DragonFly__)
+  /*
+   * in DragonFly's raw socket, ip_len/ip_off are read 
+   * in network byte order.
+   * As OpenBSD < 200311 adjust ip_len to strip IP header size!
+   */
+  ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2);
+#endif
+
   ifindex = getsockopt_ifindex (AF_INET, &msgh);
   
   *ifp = if_lookup_by_index (ifindex);
@@ -2150,7 +2213,7 @@
   return NULL;
 }
 
-static inline int
+static int
 ospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh)
 {
   /* Check match the Area ID of the receiving interface. */
@@ -2978,8 +3041,8 @@
   return length;
 }
 
-void
-ospf_hello_send_sub (struct ospf_interface *oi, struct in_addr *addr)
+static void
+ospf_hello_send_sub (struct ospf_interface *oi, in_addr_t addr)
 {
   struct ospf_packet *op;
   u_int16_t length = OSPF_HEADER_SIZE;
@@ -2998,10 +3061,12 @@
   /* Set packet length. */
   op->length = length;
 
-  op->dst.s_addr = addr->s_addr;
+  op->dst.s_addr = addr;
 
-  /* Add packet to the interface output queue. */
-  ospf_packet_add (oi, op);
+  /* Add packet to the top of the interface output queue, so that they
+   * can't get delayed by things like long queues of LS Update packets
+   */
+  ospf_packet_add_top (oi, op);
 
   /* Hook thread to write packet. */
   OSPF_ISM_WRITE_ON (oi->ospf);
@@ -3032,7 +3097,7 @@
       && oi->state != ISM_DR && oi->state != ISM_Backup)
     return;
 
-  ospf_hello_send_sub (oi, &nbr_nbma->addr);
+  ospf_hello_send_sub (oi, nbr_nbma->addr.s_addr);
 }
 
 int
@@ -3071,7 +3136,7 @@
     zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (hello-reply timer expire)",
 	  IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
 
-  ospf_hello_send_sub (nbr->oi, &nbr->address.u.prefix4);
+  ospf_hello_send_sub (nbr->oi, nbr->address.u.prefix4.s_addr);
 
   return 0;
 }
@@ -3080,27 +3145,10 @@
 void
 ospf_hello_send (struct ospf_interface *oi)
 {
-  struct ospf_packet *op;
-  u_int16_t length = OSPF_HEADER_SIZE;
-
   /* If this is passive interface, do not send OSPF Hello. */
   if (OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_PASSIVE)
     return;
 
-  op = ospf_packet_new (oi->ifp->mtu);
-
-  /* Prepare OSPF common header. */
-  ospf_make_header (OSPF_MSG_HELLO, oi, op->s);
-
-  /* Prepare OSPF Hello body. */
-  length += ospf_make_hello (oi, op->s);
-
-  /* Fill OSPF header. */
-  ospf_fill_header (oi, op->s, length);
-
-  /* Set packet length. */
-  op->length = length;
-
   if (oi->type == OSPF_IFTYPE_NBMA)
     {
       struct ospf_neighbor *nbr;
@@ -3130,34 +3178,16 @@
 		if (nbr->priority == 0 && oi->state == ISM_DROther)
 		  continue;
 		/* if oi->state == Waiting, send hello to all neighbors */
-		{
-		  struct ospf_packet *op_dup;
-
-		  op_dup = ospf_packet_dup(op);
-		  op_dup->dst = nbr->address.u.prefix4;
-
-		  /* Add packet to the interface output queue. */
-		  ospf_packet_add (oi, op_dup);
-
-		  OSPF_ISM_WRITE_ON (oi->ospf);
-		}
-
+		ospf_hello_send_sub (oi, nbr->address.u.prefix4.s_addr);
 	      }
-      ospf_packet_free (op);
     }
   else
     {
       /* Decide destination address. */
       if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
-	op->dst.s_addr = oi->vl_data->peer_addr.s_addr;
-      else 
-	op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
-
-      /* Add packet to the interface output queue. */
-      ospf_packet_add (oi, op);
-
-      /* Hook thread to write packet. */
-      OSPF_ISM_WRITE_ON (oi->ospf);
+        ospf_hello_send_sub (oi, oi->vl_data->peer_addr.s_addr);
+      else
+        ospf_hello_send_sub (oi, htonl (OSPF_ALLSPFROUTERS));
     }
 }
 
diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h
index 7b3d686..9a47208 100644
--- a/ospfd/ospf_packet.h
+++ b/ospfd/ospf_packet.h
@@ -162,6 +162,5 @@
 extern int ospf_ls_ack_timer (struct thread *);
 extern int ospf_poll_timer (struct thread *);
 extern int ospf_hello_reply_timer (struct thread *);
-extern void ospf_hello_send_sub (struct ospf_interface *, struct in_addr *);
 
 #endif /* _ZEBRA_OSPF_PACKET_H */
diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c
index c5ec0ad..24e8105 100644
--- a/ospfd/ospf_te.c
+++ b/ospfd/ospf_te.c
@@ -133,7 +133,7 @@
 static void ospf_mpls_te_config_write_if (struct vty *vty, struct interface *ifp);
 static void ospf_mpls_te_show_info (struct vty *vty, struct ospf_lsa *lsa);
 static int ospf_mpls_te_lsa_originate (void *arg);
-static void ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa);
+static struct ospf_lsa *ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa);
 static void ospf_mpls_te_lsa_schedule (struct mpls_te_link *lp, enum sched_opcode);
 
 static void del_mpls_te_link (void *val);
@@ -1009,7 +1009,7 @@
   return rc;
 }
 
-static void
+static struct ospf_lsa *
 ospf_mpls_te_lsa_refresh (struct ospf_lsa *lsa)
 {
   struct mpls_te_link *lp;
@@ -1070,7 +1070,7 @@
     }
 
 out:
-  return;
+  return new;
 }
 
 static void
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index f68adb2..97c8e8d 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -2913,7 +2913,13 @@
 		       inet_ntoa (nbr->address.u.prefix4), VTY_NEWLINE);
 	    }
 	}
-
+      
+      /* Next network-LSA sequence number we'll use, if we're elected DR */
+      if (oi->params && ntohl (oi->params->network_lsa_seqnum)
+                          != OSPF_INITIAL_SEQUENCE_NUMBER)
+        vty_out (vty, "  Saved Network-LSA sequence number 0x%x%s",
+                 ntohl (oi->params->network_lsa_seqnum), VTY_NEWLINE);
+      
       vty_out (vty, "  Multicast group memberships:");
       if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)
           || OI_MEMBER_CHECK(oi, MEMBER_DROUTERS))
@@ -7012,7 +7018,7 @@
       SET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED);
       
       if (!CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED))
-          ospf_router_lsa_timer_add (area);
+          ospf_router_lsa_update_area (area);
     }
   return CMD_SUCCESS;
 }
@@ -7038,7 +7044,7 @@
           && !area->t_stub_router)
         {
           UNSET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED);
-          ospf_router_lsa_timer_add (area);
+          ospf_router_lsa_update_area (area);
         }
     }
   return CMD_SUCCESS;
@@ -7091,7 +7097,7 @@
       if (!CHECK_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED))
         {
           UNSET_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED);
-          ospf_router_lsa_timer_add (area);
+          ospf_router_lsa_update_area (area);
         }
     }
   return CMD_SUCCESS;
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index c250fe9..e840513 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -131,8 +131,8 @@
 	  ospf->external_origin = 0;
 	}
 
-      OSPF_TIMER_ON (ospf->t_router_lsa_update,
-		     ospf_router_lsa_update_timer, OSPF_LSA_UPDATE_DELAY);
+      /* update router-lsa's for each area */
+      ospf_router_lsa_update (ospf);
       
       /* update ospf_interface's */
       for (ALL_LIST_ELEMENTS_RO (om->iflist, node, ifp))
@@ -199,6 +199,7 @@
   new->spf_hold_multiplier = 1;
 
   /* MaxAge init. */
+  new->maxage_delay = OSFP_LSA_MAXAGE_REMOVE_DELAY_DEFAULT;
   new->maxage_lsa = list_new ();
   new->t_maxage_walker =
     thread_add_timer (master, ospf_lsa_maxage_walker,
@@ -337,7 +338,7 @@
           SET_FLAG (area->stub_router_state, OSPF_AREA_ADMIN_STUB_ROUTED);
           
           if (!CHECK_FLAG (area->stub_router_state, OSPF_AREA_IS_STUB_ROUTED))
-              ospf_router_lsa_timer_add (area);
+            ospf_router_lsa_update_area (area);
         }
       timeout = ospf->stub_router_shutdown_time;
     }
@@ -473,7 +474,6 @@
 
   /* Cancel all timers. */
   OSPF_TIMER_OFF (ospf->t_external_lsa);
-  OSPF_TIMER_OFF (ospf->t_router_lsa_update);
   OSPF_TIMER_OFF (ospf->t_spf_calc);
   OSPF_TIMER_OFF (ospf->t_ase_calc);
   OSPF_TIMER_OFF (ospf->t_maxage);
@@ -631,7 +631,6 @@
     free (IMPORT_NAME (area));
 
   /* Cancel timer. */
-  OSPF_TIMER_OFF (area->t_router_lsa_self);
   OSPF_TIMER_OFF (area->t_stub_router);
 #ifdef HAVE_OPAQUE_LSA
   OSPF_TIMER_OFF (area->t_opaque_lsa_self);
@@ -1041,7 +1040,7 @@
       break;
     }
 
-  ospf_router_lsa_timer_add (area);
+  ospf_router_lsa_update_area (area);
   ospf_schedule_abr_task (area->ospf);
 }
 
@@ -1052,7 +1051,7 @@
     return 0;
 
   area->shortcut_configured = mode;
-  ospf_router_lsa_timer_add (area);
+  ospf_router_lsa_update_area (area);
   ospf_schedule_abr_task (ospf);
 
   ospf_area_check_free (ospf, area->area_id);
@@ -1064,7 +1063,7 @@
 ospf_area_shortcut_unset (struct ospf *ospf, struct ospf_area *area)
 {
   area->shortcut_configured = OSPF_SHORTCUT_DEFAULT;
-  ospf_router_lsa_timer_add (area);
+  ospf_router_lsa_update_area (area);
   ospf_area_check_free (ospf, area->area_id);
   ospf_schedule_abr_task (ospf);
 
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index 6eeaaf9..7a56d16 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -58,6 +58,7 @@
 #endif
 #define OSPF_MIN_LS_INTERVAL                     5
 #define OSPF_MIN_LS_ARRIVAL                      1
+#define OSPF_LSA_INITIAL_AGE                     0	/* useful for debug */
 #define OSPF_LSA_MAXAGE                       3600
 #define OSPF_CHECK_AGE                         300
 #define OSPF_LSA_MAXAGE_DIFF                   900
@@ -66,7 +67,6 @@
 #define OSPF_INITIAL_SEQUENCE_NUMBER    0x80000001
 #define OSPF_MAX_SEQUENCE_NUMBER        0x7fffffff
 
-#define OSPF_LSA_MAXAGE_CHECK_INTERVAL          30
 #define OSPF_NSSA_TRANS_STABLE_DEFAULT		40
 
 #define OSPF_ALLSPFROUTERS              0xe0000005      /* 224.0.0.5 */
@@ -247,7 +247,6 @@
   int redistribute;                     /* Num of redistributed protocols. */
 
   /* Threads. */
-  struct thread *t_router_lsa_update;   /* router-LSA update timer. */
   struct thread *t_abr_task;            /* ABR task timer. */
   struct thread *t_asbr_check;          /* ASBR check timer. */
   struct thread *t_distribute_update;   /* Distirbute list update timer. */
@@ -257,8 +256,13 @@
 #ifdef HAVE_OPAQUE_LSA
   struct thread *t_opaque_lsa_self;	/* Type-11 Opaque-LSAs origin event. */
 #endif /* HAVE_OPAQUE_LSA */
+
+#define OSFP_LSA_MAXAGE_REMOVE_DELAY_DEFAULT	60
+  unsigned int maxage_delay;		/* Delay on Maxage remover timer, sec */
   struct thread *t_maxage;              /* MaxAge LSA remover timer. */
+#define OSPF_LSA_MAXAGE_CHECK_INTERVAL		30
   struct thread *t_maxage_walker;       /* MaxAge LSA checking timer. */
+
   struct thread *t_deferred_shutdown;	/* deferred/stub-router shutdown timer*/
 
   struct thread *t_write;
@@ -429,7 +433,6 @@
   struct vertex *spf;
 
   /* Threads. */
-  struct thread *t_router_lsa_self;/* Self-originated router-LSA timer. */
   struct thread *t_stub_router;    /* Stub-router timer */
 #ifdef HAVE_OPAQUE_LSA
   struct thread *t_opaque_lsa_self;	/* Type-10 Opaque-LSAs origin. */
diff --git a/tests/aspath_test.c b/tests/aspath_test.c
index 9e51e8d..4a2ce9a 100644
--- a/tests/aspath_test.c
+++ b/tests/aspath_test.c
@@ -6,6 +6,7 @@
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_aspath.h"
+#include "bgpd/bgp_attr.h"
 
 #define VT100_RESET "\x1b[0m"
 #define VT100_RED "\x1b[31m"
@@ -407,7 +408,7 @@
     "#ASNs = 0, data = seq(8466 3 52737 4096 3456)",
     { 0x2,0x0, 0x21,0x12, 0x00,0x03, 0xce,0x01, 0x10,0x00, 0x0d,0x80 },
     12,
-    { "", "",
+    { NULL, NULL,
       0, 0, 0, 0, 0, 0 },
   },
   { /* 26  */ 
@@ -417,10 +418,190 @@
       0x2,0x2, 0x10,0x00, 0x0d,0x80 },
     14
     ,
-    { "", "",
+    { NULL, NULL,
       0, 0, 0, 0, 0, 0 },
   },
-  { NULL, NULL, {0}, 0, { NULL, 0, 0 } }
+  { /* 27  */ 
+    "invalid segment type",
+    "type=8(4096 3456)",
+    { 0x8,0x2, 0x10,0x00, 0x0d,0x80 },
+    14
+    ,
+    { NULL, NULL,
+      0, 0, 0, 0, 0, 0 },
+  },  { NULL, NULL, {0}, 0, { NULL, 0, 0 } }
+};
+
+/* */
+static struct aspath_tests {
+  const char *desc;
+  const struct test_segment *segment;
+  const char *shouldbe;  /* String it should evaluate to */
+  const enum as4 { AS4_DATA, AS2_DATA }
+          as4; 	/* whether data should be as4 or not (ie as2) */
+  const int result;	/* expected result for bgp_attr_parse */
+  const int cap;	/* capabilities to set for peer */
+  const char attrheader [1024];
+  size_t len;
+} aspath_tests [] =
+{
+  /* 0 */
+  {
+    "basic test",
+    &test_segments[0],
+    "8466 3 52737 4096",
+    AS2_DATA, 0,
+    0,
+    { BGP_ATTR_FLAG_TRANS,
+      BGP_ATTR_AS_PATH, 
+      10,
+    },
+    3,
+  },
+  /* 1 */
+  {
+    "length too short",
+    &test_segments[0],
+    "8466 3 52737 4096",
+    AS2_DATA, -1,
+    0,
+    { BGP_ATTR_FLAG_TRANS,
+      BGP_ATTR_AS_PATH, 
+      8,
+    },
+    3,
+  },
+  /* 2 */
+  {
+    "length too long",
+    &test_segments[0],
+    "8466 3 52737 4096",
+    AS2_DATA, -1,
+    0,
+    { BGP_ATTR_FLAG_TRANS,
+      BGP_ATTR_AS_PATH, 
+      12,
+    },
+    3,
+  },
+  /* 3 */
+  {
+    "incorrect flag",
+    &test_segments[0],
+    "8466 3 52737 4096",
+    AS2_DATA, -1,
+    0,
+    { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL,
+      BGP_ATTR_AS_PATH, 
+      10,
+    },
+    3,
+  },
+  /* 4 */
+  {
+    "as4_path, with as2 format data",
+    &test_segments[0],
+    "8466 3 52737 4096",
+    AS2_DATA, -1,
+    0,
+    { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL,
+      BGP_ATTR_AS4_PATH, 
+      10,
+    },
+    3,
+  },
+  /* 5 */
+  {
+    "as4, with incorrect attr length",
+    &test_segments[0],
+    "8466 3 52737 4096",
+    AS4_DATA, -1,
+    PEER_CAP_AS4_RCV,
+    { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL,
+      BGP_ATTR_AS4_PATH, 
+      10,
+    },
+    3,
+  },
+  /* 6 */
+  {
+    "basic 4-byte as-path",
+    &test_segments[0],
+    "8466 3 52737 4096",
+    AS4_DATA, 0,
+    PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV,
+    { BGP_ATTR_FLAG_TRANS,
+      BGP_ATTR_AS_PATH, 
+      18,
+    },
+    3,
+  },
+  /* 7 */
+  {
+    "4b AS_PATH: too short",
+    &test_segments[0],
+    "8466 3 52737 4096",
+    AS4_DATA, -1,
+    PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV,
+    { BGP_ATTR_FLAG_TRANS,
+      BGP_ATTR_AS_PATH, 
+      16,
+    },
+    3,
+  },
+  /* 8 */
+  {
+    "4b AS_PATH: too long",
+    &test_segments[0],
+    "8466 3 52737 4096",
+    AS4_DATA, -1,
+    PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV,
+    { BGP_ATTR_FLAG_TRANS,
+      BGP_ATTR_AS_PATH, 
+      20,
+    },
+    3,
+  },
+  /* 9 */
+  {
+    "4b AS_PATH: too long2",
+    &test_segments[0],
+    "8466 3 52737 4096",
+    AS4_DATA, -1,
+    PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV,
+    { BGP_ATTR_FLAG_TRANS,
+      BGP_ATTR_AS_PATH, 
+      22,
+    },
+    3,
+  },
+  /* 10 */
+  {
+    "4b AS_PATH: bad flags",
+    &test_segments[0],
+    "8466 3 52737 4096",
+    AS4_DATA, -1,
+    PEER_CAP_AS4_RCV|PEER_CAP_AS4_ADV,
+    { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL,
+      BGP_ATTR_AS_PATH, 
+      18,
+    },
+    3,
+  },
+  /* 11 */
+  {
+    "4b AS_PATH: confed",
+    &test_segments[6],
+    "8466 3 52737 4096",
+    AS4_DATA, -1,
+    PEER_CAP_AS4_ADV,
+    { BGP_ATTR_FLAG_TRANS|BGP_ATTR_FLAG_OPTIONAL,
+      BGP_ATTR_AS4_PATH, 
+      14,
+    },
+    3,
+  },
+  { NULL, NULL, NULL, 0, 0, 0, { 0 }, 0 },
 };
 
 /* prepending tests */
@@ -430,21 +611,25 @@
   struct test_spec sp;
 } prepend_tests[] = 
 {
+  /* 0 */
   { &test_segments[0], &test_segments[1],
     { "8466 3 52737 4096 8722 4",
       "8466 3 52737 4096 8722 4",
       6, 0, NOT_ALL_PRIVATE, 4096, 1, 8466 },
   },
+  /* 1 */
   { &test_segments[1], &test_segments[3],
     { "8722 4 8482 51457 {5204}",
       "8722 4 8482 51457 {5204}",
       5, 0, NOT_ALL_PRIVATE, 5204, 1, 8722 }
   },
+  /* 2 */
   { &test_segments[3], &test_segments[4],
     { "8482 51457 {5204} 8467 59649 {4196,48658} {17322,30745}",
       "8482 51457 {5204} 8467 59649 {4196,48658} {17322,30745}",
       7, 0, NOT_ALL_PRIVATE, 5204, 1, 8482 },
   },
+  /* 3 */
   { &test_segments[4], &test_segments[5],
     { "8467 59649 {4196,48658} {17322,30745} 6435 59408 21665"
       " {2457,4369,61697} 1842 41590 51793",
@@ -452,11 +637,13 @@
       " {2457,4369,61697} 1842 41590 51793",
       11, 0, NOT_ALL_PRIVATE, 61697, 1, 8467 }
   },
+  /* 4 */
   { &test_segments[5], &test_segments[6],
-    { "6435 59408 21665 {2457,4369,61697} 1842 41590 51793 (123 456 789)",
-      "6435 59408 21665 {2457,4369,61697} 1842 41590 51793 (123 456 789)",
-      7, 3, NOT_ALL_PRIVATE, 123, 1, 6435 },
+    { "6435 59408 21665 {2457,4369,61697} 1842 41590 51793",
+      "6435 59408 21665 {2457,4369,61697} 1842 41590 51793",
+      7, 0, NOT_ALL_PRIVATE, 1842, 1, 6435 },
   },
+  /* 5 */
   { &test_segments[6], &test_segments[7],
     { "(123 456 789) (123 456 789) (111 222)",
       "",
@@ -649,7 +836,7 @@
       s = stream_new (len);
       stream_put (s, data, len);
     }
-  as = aspath_parse (s, len, use32bit, 0);
+  as = aspath_parse (s, len, use32bit);
   
   if (s)
     stream_free (s);
@@ -682,6 +869,12 @@
   static struct stream *s;
   struct aspath *asinout, *asconfeddel, *asstr, *as4;
   
+  if (as == NULL && sp->shouldbe == NULL)
+    {
+      printf ("Correctly failed to parse\n");
+      return fails;
+    }
+  
   out = aspath_snmp_pathseg (as, &bytes);
   asinout = make_aspath (out, bytes, 0);
   
@@ -826,7 +1019,7 @@
   printf ("%s: %s\n", t->name, t->desc);
 
   asp = make_aspath (t->asdata, t->len, 0);
-
+  
   printf ("aspath: %s\nvalidating...:\n", aspath_print (asp));
 
   if (!validate (asp, &t->sp))
@@ -835,7 +1028,9 @@
     printf (FAILED "\n");
   
   printf ("\n");
-  aspath_unintern (asp);
+  
+  if (asp)
+    aspath_unintern (asp);
 }
 
 /* prepend testing */
@@ -891,7 +1086,8 @@
     printf (FAILED "!\n");
   
   printf ("\n");
-  aspath_unintern (asp1);
+  if (asp1)
+    aspath_unintern (asp1);
   aspath_free (asp2);
 }
 
@@ -993,30 +1189,106 @@
       aspath_unintern (asp2);
     }
 }
-     
+
+static int
+handle_attr_test (struct aspath_tests *t)
+{
+  struct bgp bgp = { 0 }; 
+  struct peer peer = { 0 };
+  struct attr attr = { 0 };  
+  int ret;
+  int initfail = failed;
+  struct aspath *asp;
+  size_t datalen;
+  
+  asp = make_aspath (t->segment->asdata, t->segment->len, 0);
+    
+  peer.ibuf = stream_new (BGP_MAX_PACKET_SIZE);
+  peer.obuf = stream_fifo_new ();
+  peer.bgp = &bgp;
+  peer.host = (char *)"none";
+  peer.fd = -1;
+  peer.cap = t->cap;
+  
+  stream_write (peer.ibuf, t->attrheader, t->len);
+  datalen = aspath_put (peer.ibuf, asp, t->as4 == AS4_DATA);
+  
+  ret = bgp_attr_parse (&peer, &attr, t->len + datalen, NULL, NULL);
+  
+  if (ret != t->result)
+    {
+      printf ("bgp_attr_parse returned %d, expected %d\n", ret, t->result);
+      printf ("datalen %d\n", datalen);
+      failed++;
+    }
+  if (ret != 0)
+    goto out;
+  
+  if (attr.aspath == NULL)
+    {
+      printf ("aspath is NULL!\n");
+      failed++;
+    }
+  if (attr.aspath && strcmp (attr.aspath->str, t->shouldbe))
+    {
+      printf ("attr str and 'shouldbe' mismatched!\n"
+              "attr str:  %s\n"
+              "shouldbe:  %s\n",
+              attr.aspath->str, t->shouldbe);
+      failed++;
+    }
+
+out:
+  if (attr.aspath)
+    aspath_unintern (attr.aspath);
+  if (asp)
+    aspath_unintern (asp);
+  return failed - initfail;
+}
+
+static void
+attr_test (struct aspath_tests *t)
+{
+    printf ("%s\n", t->desc);
+    printf ("%s\n\n", handle_attr_test (t) ? FAILED : OK);  
+}
+
 int
 main (void)
 {
   int i = 0;
-  aspath_init();
+  bgp_master_init ();
+  master = bm->master;
+  bgp_attr_init ();
+  
   while (test_segments[i].name)
     {
+      printf ("test %u\n", i);
       parse_test (&test_segments[i]);
       empty_prepend_test (&test_segments[i++]);
     }
   
   i = 0;
   while (prepend_tests[i].test1)
-    prepend_test (&prepend_tests[i++]);
+    {
+      printf ("prepend test %u\n", i);
+      prepend_test (&prepend_tests[i++]);
+    }
   
   i = 0;
   while (aggregate_tests[i].test1)
-    aggregate_test (&aggregate_tests[i++]);
+    {
+      printf ("aggregate test %u\n", i);
+      aggregate_test (&aggregate_tests[i++]);
+    }
   
   i = 0;
   
   while (reconcile_tests[i].test1)
-    as4_reconcile_test (&reconcile_tests[i++]);
+    {
+      printf ("reconcile test %u\n", i);
+      as4_reconcile_test (&reconcile_tests[i++]);
+    }
   
   i = 0;
   
@@ -1026,6 +1298,14 @@
   
   empty_get_test();
   
+  i = 0;
+  
+  while (aspath_tests[i].desc)
+    {
+      printf ("aspath_attr test %d\n", i);
+      attr_test (&aspath_tests[i++]);
+    }
+  
   printf ("failures: %d\n", failed);
   printf ("aspath count: %ld\n", aspath_count());
   
diff --git a/tools/multiple-bgpd.sh b/tools/multiple-bgpd.sh
index 028ad69..d6a38ed 100644
--- a/tools/multiple-bgpd.sh
+++ b/tools/multiple-bgpd.sh
@@ -25,13 +25,14 @@
 		NEXTAS=$((${ASBASE} + $NEXT))
 		PREVADDR="${PREFIX}${PREV}"
 		PREVAS=$((${ASBASE} + $PREV))
+		ASN=$((64560+${H}))
 		
 		# Edit config to suit.
 		cat > "$CONF" <<- EOF
 			password whatever
 			service advanced-vty
 			!
-			router bgp $((64560+${H}))
+			router bgp ${ASN}
 			 bgp router-id ${ADDR}
 			 network 10.${H}.1.0/24 pathlimit 1
 			 network 10.${H}.2.0/24 pathlimit 2
@@ -40,6 +41,7 @@
 			 neighbor default update-source ${ADDR}
 			 neighbor default capability orf prefix-list both
 			 neighbor default soft-reconfiguration inbound
+			 neighbor default route-map test out
 			 neighbor ${NEXTADDR} remote-as ${NEXTAS}
 			 neighbor ${NEXTADDR} peer-group default
 			 neighbor ${PREVADDR} remote-as ${PREVAS}
@@ -53,10 +55,15 @@
 			 neighbor default activate
 			 neighbor default capability orf prefix-list both
 			 neighbor default default-originate
+			 neighbor default route-map test out
 			 neighbor ${NEXTADDR} peer-group default
 			 neighbor ${PREVADDR} peer-group default
 			 exit-address-family
 			!
+			route-map test permit 10
+			 set extcommunity rt ${ASN}:1
+			 set extcommunity soo ${ASN}:2
+			 set community ${ASN}:1
 			line vty
 			!
 			end
diff --git a/zebra/interface.c b/zebra/interface.c
index 03e7ff7..933d642 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -216,7 +216,7 @@
  * interface will affect only the primary interface/address on Solaris.
  ************************End Solaris flags hacks ***********************
  */
-static inline void
+static void
 if_flags_mangle (struct interface *ifp, uint64_t *newflags)
 {
 #ifdef SUNOS_5
diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c
index 8742b62..6403830 100644
--- a/zebra/irdp_interface.c
+++ b/zebra/irdp_interface.c
@@ -99,14 +99,11 @@
 	  u_int32_t group, 
 	  int add_leave)
 {
-  struct zebra_if *zi;
   struct ip_mreq m;
   struct prefix *p;
   int ret;
   char b1[INET_ADDRSTRLEN];
 
-  zi = ifp->info;
-
   memset (&m, 0, sizeof (m));
   m.imr_multiaddr.s_addr = htonl (group);
   p = irdp_get_prefix(ifp);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index eb9eae3..a09e459 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -1827,11 +1827,7 @@
 static int
 kernel_read (struct thread *thread)
 {
-  int ret;
-  int sock;
-
-  sock = THREAD_FD (thread);
-  ret = netlink_parse_info (netlink_information_fetch, &netlink);
+  netlink_parse_info (netlink_information_fetch, &netlink);
   thread_add_read (zebrad.master, kernel_read, NULL, netlink.sock);
 
   return 0;