aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-06-22 06:08:03 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-06-23 05:07:38 -0400
commit09b8f7a93efd4b2c4ef391e2fbf076f28c6d36d6 (patch)
tree7168ac18ce0b765e67f0536e13b8628b1c12ad38
parent37c3185a02d4b85fbe134bf5204535405dd2c957 (diff)
[IPSEC]: Handle GSO packets
This patch segments GSO packets received by the IPsec stack. This can happen when a NIC driver injects GSO packets into the stack which are then forwarded to another host. The primary application of this is going to be Xen where its backend driver may inject GSO packets into dom0. Of course this also can be used by other virtualisation schemes such as VMWare or UML since the tap device could be modified to inject GSO packets received through splice. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/xfrm4_output.c54
-rw-r--r--net/ipv6/xfrm6_output.c39
2 files changed, 83 insertions, 10 deletions
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index ac9d91d4bb05..193363e22932 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -9,6 +9,8 @@
9 */ 9 */
10 10
11#include <linux/compiler.h> 11#include <linux/compiler.h>
12#include <linux/if_ether.h>
13#include <linux/kernel.h>
12#include <linux/skbuff.h> 14#include <linux/skbuff.h>
13#include <linux/spinlock.h> 15#include <linux/spinlock.h>
14#include <linux/netfilter_ipv4.h> 16#include <linux/netfilter_ipv4.h>
@@ -97,16 +99,10 @@ error_nolock:
97 goto out_exit; 99 goto out_exit;
98} 100}
99 101
100static int xfrm4_output_finish(struct sk_buff *skb) 102static int xfrm4_output_finish2(struct sk_buff *skb)
101{ 103{
102 int err; 104 int err;
103 105
104#ifdef CONFIG_NETFILTER
105 if (!skb->dst->xfrm) {
106 IPCB(skb)->flags |= IPSKB_REROUTED;
107 return dst_output(skb);
108 }
109#endif
110 while (likely((err = xfrm4_output_one(skb)) == 0)) { 106 while (likely((err = xfrm4_output_one(skb)) == 0)) {
111 nf_reset(skb); 107 nf_reset(skb);
112 108
@@ -119,7 +115,7 @@ static int xfrm4_output_finish(struct sk_buff *skb)
119 return dst_output(skb); 115 return dst_output(skb);
120 116
121 err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL, 117 err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL,
122 skb->dst->dev, xfrm4_output_finish); 118 skb->dst->dev, xfrm4_output_finish2);
123 if (unlikely(err != 1)) 119 if (unlikely(err != 1))
124 break; 120 break;
125 } 121 }
@@ -127,6 +123,48 @@ static int xfrm4_output_finish(struct sk_buff *skb)
127 return err; 123 return err;
128} 124}
129 125
126static int xfrm4_output_finish(struct sk_buff *skb)
127{
128 struct sk_buff *segs;
129
130#ifdef CONFIG_NETFILTER
131 if (!skb->dst->xfrm) {
132 IPCB(skb)->flags |= IPSKB_REROUTED;
133 return dst_output(skb);
134 }
135#endif
136
137 if (!skb_shinfo(skb)->gso_size)
138 return xfrm4_output_finish2(skb);
139
140 skb->protocol = htons(ETH_P_IP);
141 segs = skb_gso_segment(skb, 0);
142 kfree_skb(skb);
143 if (unlikely(IS_ERR(segs)))
144 return PTR_ERR(segs);
145
146 do {
147 struct sk_buff *nskb = segs->next;
148 int err;
149
150 segs->next = NULL;
151 err = xfrm4_output_finish2(segs);
152
153 if (unlikely(err)) {
154 while ((segs = nskb)) {
155 nskb = segs->next;
156 segs->next = NULL;
157 kfree_skb(segs);
158 }
159 return err;
160 }
161
162 segs = nskb;
163 } while (segs);
164
165 return 0;
166}
167
130int xfrm4_output(struct sk_buff *skb) 168int xfrm4_output(struct sk_buff *skb)
131{ 169{
132 return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev, 170 return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev,
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 16e84254a252..48fccb1eca08 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -94,7 +94,7 @@ error_nolock:
94 goto out_exit; 94 goto out_exit;
95} 95}
96 96
97static int xfrm6_output_finish(struct sk_buff *skb) 97static int xfrm6_output_finish2(struct sk_buff *skb)
98{ 98{
99 int err; 99 int err;
100 100
@@ -110,7 +110,7 @@ static int xfrm6_output_finish(struct sk_buff *skb)
110 return dst_output(skb); 110 return dst_output(skb);
111 111
112 err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL, 112 err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL,
113 skb->dst->dev, xfrm6_output_finish); 113 skb->dst->dev, xfrm6_output_finish2);
114 if (unlikely(err != 1)) 114 if (unlikely(err != 1))
115 break; 115 break;
116 } 116 }
@@ -118,6 +118,41 @@ static int xfrm6_output_finish(struct sk_buff *skb)
118 return err; 118 return err;
119} 119}
120 120
121static int xfrm6_output_finish(struct sk_buff *skb)
122{
123 struct sk_buff *segs;
124
125 if (!skb_shinfo(skb)->gso_size)
126 return xfrm6_output_finish2(skb);
127
128 skb->protocol = htons(ETH_P_IP);
129 segs = skb_gso_segment(skb, 0);
130 kfree_skb(skb);
131 if (unlikely(IS_ERR(segs)))
132 return PTR_ERR(segs);
133
134 do {
135 struct sk_buff *nskb = segs->next;
136 int err;
137
138 segs->next = NULL;
139 err = xfrm6_output_finish2(segs);
140
141 if (unlikely(err)) {
142 while ((segs = nskb)) {
143 nskb = segs->next;
144 segs->next = NULL;
145 kfree_skb(segs);
146 }
147 return err;
148 }
149
150 segs = nskb;
151 } while (segs);
152
153 return 0;
154}
155
121int xfrm6_output(struct sk_buff *skb) 156int xfrm6_output(struct sk_buff *skb)
122{ 157{
123 return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev, 158 return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev,