t_key key;
        unsigned char bits;             /* 2log(KEYLENGTH) bits needed */
        unsigned char pos;              /* 2log(KEYLENGTH) bits needed */
+       unsigned char slen;
        struct tnode __rcu *parent;
        struct rcu_head rcu;
        union {
                 * as the nodes are searched
                 */
                l->key = key;
+               l->slen = 0;
                l->pos = 0;
                /* set bits to 0 indicating we are not a tnode */
                l->bits = 0;
 
        if (tn) {
                tn->parent = NULL;
+               tn->slen = pos;
                tn->pos = pos;
                tn->bits = bits;
                tn->key = (shift < KEYLENGTH) ? (key >> shift) << shift : 0;
        else if (!wasfull && isfull)
                tn->full_children++;
 
+       if (n && (tn->slen < n->slen))
+               tn->slen = n->slen;
+
        rcu_assign_pointer(tn->child[i], n);
 }
 
        return 0;
 }
 
+static unsigned char update_suffix(struct tnode *tn)
+{
+       unsigned char slen = tn->pos;
+       unsigned long stride, i;
+
+       /* search though the list of children looking for nodes that might
+        * have a suffix greater than the one we currently have.  This is
+        * why we start with a stride of 2 since a stride of 1 would
+        * represent the nodes with suffix length equal to tn->pos
+        */
+       for (i = 0, stride = 0x2ul ; i < tnode_child_length(tn); i += stride) {
+               struct tnode *n = tnode_get_child(tn, i);
+
+               if (!n || (n->slen <= slen))
+                       continue;
+
+               /* update stride and slen based on new value */
+               stride <<= (n->slen - slen);
+               slen = n->slen;
+               i &= ~(stride - 1);
+
+               /* if slen covers all but the last bit we can stop here
+                * there will be nothing longer than that since only node
+                * 0 and 1 << (bits - 1) could have that as their suffix
+                * length.
+                */
+               if ((slen + 1) >= (tn->pos + tn->bits))
+                       break;
+       }
+
+       tn->slen = slen;
+
+       return slen;
+}
+
 /* From "Implementing a dynamic compressed trie" by Stefan Nilsson of
  * the Helsinki University of Technology and Matti Tikkanen of Nokia
  * Telecommunications, page 6:
                /* drop dead node */
                tnode_free_init(tn);
                tnode_free(tn);
+               return;
+       }
+
+       /* Return if at least one deflate was run */
+       if (max_work != MAX_WORK)
+               return;
+
+       /* push the suffix length to the parent node */
+       if (tn->slen > tn->pos) {
+               unsigned char slen = update_suffix(tn);
+
+               if (tp && (slen > tp->slen))
+                       tp->slen = slen;
        }
 }
 
        return &li->falh;
 }
 
-static void insert_leaf_info(struct hlist_head *head, struct leaf_info *new)
+static void leaf_pull_suffix(struct tnode *l)
+{
+       struct tnode *tp = node_parent(l);
+
+       while (tp && (tp->slen > tp->pos) && (tp->slen > l->slen)) {
+               if (update_suffix(tp) > l->slen)
+                       break;
+               tp = node_parent(tp);
+       }
+}
+
+static void leaf_push_suffix(struct tnode *l)
 {
+       struct tnode *tn = node_parent(l);
+
+       /* if this is a new leaf then tn will be NULL and we can sort
+        * out parent suffix lengths as a part of trie_rebalance
+        */
+       while (tn && (tn->slen < l->slen)) {
+               tn->slen = l->slen;
+               tn = node_parent(tn);
+       }
+}
+
+static void remove_leaf_info(struct tnode *l, struct leaf_info *old)
+{
+       struct hlist_node *prev;
+
+       /* record the location of the pointer to this object */
+       prev = rtnl_dereference(hlist_pprev_rcu(&old->hlist));
+
+       /* remove the leaf info from the list */
+       hlist_del_rcu(&old->hlist);
+
+       /* if we emptied the list this leaf will be freed and we can sort
+        * out parent suffix lengths as a part of trie_rebalance
+        */
+       if (hlist_empty(&l->list))
+               return;
+
+       /* if we removed the tail then we need to update slen */
+       if (!rcu_access_pointer(hlist_next_rcu(prev))) {
+               struct leaf_info *li = hlist_entry(prev, typeof(*li), hlist);
+
+               l->slen = KEYLENGTH - li->plen;
+               leaf_pull_suffix(l);
+       }
+}
+
+static void insert_leaf_info(struct tnode *l, struct leaf_info *new)
+{
+       struct hlist_head *head = &l->list;
        struct leaf_info *li = NULL, *last = NULL;
 
        if (hlist_empty(head)) {
                else
                        hlist_add_before_rcu(&new->hlist, &li->hlist);
        }
+
+       /* if we added to the tail node then we need to update slen */
+       if (!rcu_access_pointer(hlist_next_rcu(&new->hlist))) {
+               l->slen = KEYLENGTH - new->plen;
+               leaf_push_suffix(l);
+       }
 }
 
 /* rcu_read_lock needs to be hold by caller from readside */
                /* we have found a leaf. Prefixes have already been compared */
                if (IS_LEAF(n)) {
                        /* Case 1: n is a leaf, and prefixes match*/
-                       insert_leaf_info(&n->list, li);
+                       insert_leaf_info(n, li);
                        return fa_head;
                }
 
                return NULL;
        }
 
-       insert_leaf_info(&l->list, li);
+       insert_leaf_info(l, li);
 
        /* Case 2: n is a LEAF or a TNODE and the key doesn't match.
         *
                /* only record pn and cindex if we are going to be chopping
                 * bits later.  Otherwise we are just wasting cycles.
                 */
-               if (index) {
+               if (n->slen > n->pos) {
                        pn = n;
                        cindex = index;
                }
                 * between the key and the prefix exist in the region of
                 * the lsb and higher in the prefix.
                 */
-               if (unlikely(prefix_mismatch(key, n)))
+               if (unlikely(prefix_mismatch(key, n)) || (n->slen == n->pos))
                        goto backtrace;
 
                /* exit out and process leaf */
                tb->tb_num_default--;
 
        if (list_empty(fa_head)) {
-               hlist_del_rcu(&li->hlist);
+               remove_leaf_info(l, li);
                free_leaf_info(li);
        }