netdev
[Top] [All Lists]

[RFC 2.6.10 20/22] typhoon: add management of outbound bundles

To: netdev@xxxxxxxxxxx
Subject: [RFC 2.6.10 20/22] typhoon: add management of outbound bundles
From: David Dillow <dave@xxxxxxxxxxxxxx>
Date: Thu, 30 Dec 2004 03:48:37 -0500
Cc: linux-kernel@xxxxxxxxxxxxxxx, dave@xxxxxxxxxxxxxx
References: <20041230035000.28@xxxxxxxxxxxxxxxxxx>
Sender: netdev-bounce@xxxxxxxxxxx
# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2004/12/30 01:04:39-05:00 dave@xxxxxxxxxxxxxx 
#   Add the offloading of outbound bundles.
#   
#   This is a tricky business, because there are restrictions on
#   the types and order of the xfrms we can offload. Some combinations
#   also yield incorrect results, so we have to reduce the amount of
#   offloading we do in those cases.
#   
#   Signed-off-by: David Dillow <dave@xxxxxxxxxxxxxx>
# 
# drivers/net/typhoon.c
#   2004/12/30 01:04:20-05:00 dave@xxxxxxxxxxxxxx +134 -0
#   Add the offloading of outbound bundles.
#   
#   This is a tricky business, because there are restrictions on
#   the types and order of the xfrms we can offload. Some combinations
#   also yield incorrect results, so we have to reduce the amount of
#   offloading we do in those cases.
#   
#   Signed-off-by: David Dillow <dave@xxxxxxxxxxxxxx>
# 
diff -Nru a/drivers/net/typhoon.c b/drivers/net/typhoon.c
--- a/drivers/net/typhoon.c     2004-12-30 01:08:06 -05:00
+++ b/drivers/net/typhoon.c     2004-12-30 01:08:06 -05:00
@@ -2587,6 +2587,140 @@
        spin_unlock_bh(&tp->offload_lock);
 }
 
+static inline int
+typhoon_max_offload(struct xfrm_bundle_list *xbl)
+{
+       /* Pre-scan the bundle to avoid offloading problematic sequences.
+        * Only reduces the offload level to keep as much advantage as
+        * possible.
+        *
+        * For 03.001.002 -- still problematic for 03.001.008, but need
+        *      re-verify symptoms.
+        *
+        * inner AH tunnel, outer AH transport
+        *      --> 3XP seems to put the inner hash at the wrong location
+        * inner AH tunnel, outer ESP tunnel
+        *      --> 3XP corrupts outer hash, maybe wrong place?
+        * inner AH transport, outer ESP tunnel
+        *      --> 3XP seems to encrypt the wrong portion of the packet
+        * inner ESP transport, outer AH tunnel
+        *      --> 3XP lockup, requires reset
+        */
+       struct xfrm_bundle_list *bundle;
+       struct dst_entry *dst;
+       struct xfrm_state *x;
+       int last_was_ah = 0, last_was_tunnel = 0;
+       int max_level = 2;
+       int proto;
+
+       list_for_each_entry_reverse(bundle, &xbl->node, node) {
+               dst = bundle->dst;
+               x = dst->xfrm;
+
+               proto = x ? x->type->proto : IPPROTO_IP;
+
+               if(proto == IPPROTO_AH && x->props.mode &&
+                                       (last_was_ah ^ last_was_tunnel))
+                       goto problem_offload;
+
+               if(proto == IPPROTO_AH && !x->props.mode &&
+                                       (!last_was_ah && last_was_tunnel))
+                       goto problem_offload;
+
+               if(proto == IPPROTO_ESP && last_was_ah && last_was_tunnel)
+                       goto problem_offload;
+
+               last_was_ah = (proto == IPPROTO_AH) ? 1 : 0;
+               last_was_tunnel = x ? x->props.mode : 0;
+               continue;
+
+problem_offload:
+               max_level--;
+               break;
+       }
+
+       return max_level;
+}
+
+static void
+typhoon_xfrm_bundle_add(struct net_device *dev, struct xfrm_bundle_list *xbl)
+{
+       /* Walk from the outermost dst back up the chain, offloading
+        * until we hit something we cannot deal with.
+        */
+       struct typhoon *tp = netdev_priv(dev);
+       struct xfrm_bundle_list *bundle;
+       struct dst_entry *dst;
+       struct xfrm_state *x;
+       struct xfrm_offload *xol;
+       struct typhoon_xfrm_offload *txo;
+       int proto;
+       int level = 0, max_level;
+       int last = -1;
+
+       smp_rmb();
+       if(tp->card_state != Running)
+               return;
+
+       max_level = typhoon_max_offload(xbl);
+
+       list_for_each_entry_reverse(bundle, &xbl->node, node) {
+               dst = bundle->dst;
+               x = dst->xfrm;
+
+               /* Only support IPv4 */
+               if(dst->ops->family != AF_INET)
+                       goto cannot_offload;
+
+               proto = x ? x->type->proto : IPPROTO_IP;
+
+               switch(proto) {
+               case IPPROTO_IP:
+               case IPPROTO_IPIP:
+                       if(last == IPPROTO_IP || last == IPPROTO_IPIP)
+                               goto cannot_offload;
+                       if(level)
+                               level++;
+                       last = proto;
+                       continue;
+               case IPPROTO_ESP:
+                       if(last != IPPROTO_AH)
+                               level++;
+                       break;
+               case IPPROTO_AH:
+                       level++;
+                       break;
+               default:
+                       goto cannot_offload;
+               }
+
+               last = proto;
+               if(level > max_level)
+                       goto cannot_offload;
+
+               if(dst->xfrm_offload)
+                       continue;
+
+               xol = xfrm_offload_get(x, dev);
+               if(!xol) {
+                       xol = typhoon_offload_ipsec(tp, x);
+                       if(xol)
+                               xfrm_offload_hold(xol);
+               }
+
+               if(!xol)
+                       goto cannot_offload;
+
+               dst->xfrm_offload = xol;
+               txo = xfrm_offload_priv(xol);
+               if(txo->tunnel)
+                       last = IPPROTO_IPIP;
+       }
+
+cannot_offload:
+       return;
+}
+
 static void
 typhoon_tx_timeout(struct net_device *dev)
 {

<Prev in Thread] Current Thread [Next in Thread>