aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ip_output.c')
-rw-r--r--net/ipv4/ip_output.c67
1 files changed, 56 insertions, 11 deletions
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 1a0755fea491..a52f50187b54 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -101,17 +101,17 @@ int __ip_local_out(struct sk_buff *skb)
101 skb_dst(skb)->dev, dst_output); 101 skb_dst(skb)->dev, dst_output);
102} 102}
103 103
104int ip_local_out(struct sk_buff *skb) 104int ip_local_out_sk(struct sock *sk, struct sk_buff *skb)
105{ 105{
106 int err; 106 int err;
107 107
108 err = __ip_local_out(skb); 108 err = __ip_local_out(skb);
109 if (likely(err == 1)) 109 if (likely(err == 1))
110 err = dst_output(skb); 110 err = dst_output_sk(sk, skb);
111 111
112 return err; 112 return err;
113} 113}
114EXPORT_SYMBOL_GPL(ip_local_out); 114EXPORT_SYMBOL_GPL(ip_local_out_sk);
115 115
116static inline int ip_select_ttl(struct inet_sock *inet, struct dst_entry *dst) 116static inline int ip_select_ttl(struct inet_sock *inet, struct dst_entry *dst)
117{ 117{
@@ -211,6 +211,48 @@ static inline int ip_finish_output2(struct sk_buff *skb)
211 return -EINVAL; 211 return -EINVAL;
212} 212}
213 213
214static int ip_finish_output_gso(struct sk_buff *skb)
215{
216 netdev_features_t features;
217 struct sk_buff *segs;
218 int ret = 0;
219
220 /* common case: locally created skb or seglen is <= mtu */
221 if (((IPCB(skb)->flags & IPSKB_FORWARDED) == 0) ||
222 skb_gso_network_seglen(skb) <= ip_skb_dst_mtu(skb))
223 return ip_finish_output2(skb);
224
225 /* Slowpath - GSO segment length is exceeding the dst MTU.
226 *
227 * This can happen in two cases:
228 * 1) TCP GRO packet, DF bit not set
229 * 2) skb arrived via virtio-net, we thus get TSO/GSO skbs directly
230 * from host network stack.
231 */
232 features = netif_skb_features(skb);
233 segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
234 if (IS_ERR(segs)) {
235 kfree_skb(skb);
236 return -ENOMEM;
237 }
238
239 consume_skb(skb);
240
241 do {
242 struct sk_buff *nskb = segs->next;
243 int err;
244
245 segs->next = NULL;
246 err = ip_fragment(segs, ip_finish_output2);
247
248 if (err && ret == 0)
249 ret = err;
250 segs = nskb;
251 } while (segs);
252
253 return ret;
254}
255
214static int ip_finish_output(struct sk_buff *skb) 256static int ip_finish_output(struct sk_buff *skb)
215{ 257{
216#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) 258#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
@@ -220,15 +262,17 @@ static int ip_finish_output(struct sk_buff *skb)
220 return dst_output(skb); 262 return dst_output(skb);
221 } 263 }
222#endif 264#endif
223 if (skb->len > ip_skb_dst_mtu(skb) && !skb_is_gso(skb)) 265 if (skb_is_gso(skb))
266 return ip_finish_output_gso(skb);
267
268 if (skb->len > ip_skb_dst_mtu(skb))
224 return ip_fragment(skb, ip_finish_output2); 269 return ip_fragment(skb, ip_finish_output2);
225 else 270
226 return ip_finish_output2(skb); 271 return ip_finish_output2(skb);
227} 272}
228 273
229int ip_mc_output(struct sk_buff *skb) 274int ip_mc_output(struct sock *sk, struct sk_buff *skb)
230{ 275{
231 struct sock *sk = skb->sk;
232 struct rtable *rt = skb_rtable(skb); 276 struct rtable *rt = skb_rtable(skb);
233 struct net_device *dev = rt->dst.dev; 277 struct net_device *dev = rt->dst.dev;
234 278
@@ -287,7 +331,7 @@ int ip_mc_output(struct sk_buff *skb)
287 !(IPCB(skb)->flags & IPSKB_REROUTED)); 331 !(IPCB(skb)->flags & IPSKB_REROUTED));
288} 332}
289 333
290int ip_output(struct sk_buff *skb) 334int ip_output(struct sock *sk, struct sk_buff *skb)
291{ 335{
292 struct net_device *dev = skb_dst(skb)->dev; 336 struct net_device *dev = skb_dst(skb)->dev;
293 337
@@ -315,9 +359,9 @@ static void ip_copy_addrs(struct iphdr *iph, const struct flowi4 *fl4)
315 sizeof(fl4->saddr) + sizeof(fl4->daddr)); 359 sizeof(fl4->saddr) + sizeof(fl4->daddr));
316} 360}
317 361
318int ip_queue_xmit(struct sk_buff *skb, struct flowi *fl) 362/* Note: skb->sk can be different from sk, in case of tunnels */
363int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl)
319{ 364{
320 struct sock *sk = skb->sk;
321 struct inet_sock *inet = inet_sk(sk); 365 struct inet_sock *inet = inet_sk(sk);
322 struct ip_options_rcu *inet_opt; 366 struct ip_options_rcu *inet_opt;
323 struct flowi4 *fl4; 367 struct flowi4 *fl4;
@@ -389,6 +433,7 @@ packet_routed:
389 ip_select_ident_more(skb, &rt->dst, sk, 433 ip_select_ident_more(skb, &rt->dst, sk,
390 (skb_shinfo(skb)->gso_segs ?: 1) - 1); 434 (skb_shinfo(skb)->gso_segs ?: 1) - 1);
391 435
436 /* TODO : should we use skb->sk here instead of sk ? */
392 skb->priority = sk->sk_priority; 437 skb->priority = sk->sk_priority;
393 skb->mark = sk->sk_mark; 438 skb->mark = sk->sk_mark;
394 439