aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2011-02-28 21:36:47 -0500
committerDavid S. Miller <davem@davemloft.net>2011-03-01 15:35:03 -0500
commit1c32c5ad6fac8cee1a77449f5abf211e911ff830 (patch)
tree6a7384abb34068adb298beb1967b11201d52ed48
parent1470ddf7f8cecf776921e5ccee72e3d2b3d60cbc (diff)
inet: Add ip_make_skb and ip_finish_skb
This patch adds the helper ip_make_skb which is like ip_append_data and ip_push_pending_frames all rolled into one, except that it does not send the skb produced. The sending part is carried out by ip_send_skb, which the transport protocol can call after it has tweaked the skb. It is meant to be called in cases where corking is not used should have a one-to-one correspondence to sendmsg. This patch also adds the helper ip_finish_skb which is meant to be replace ip_push_pending_frames when corking is required. Previously the protocol stack would peek at the socket write queue and add its header to the first packet. With ip_finish_skb, the protocol stack can directly operate on the final skb instead, just like the non-corking case with ip_make_skb. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/ip.h16
-rw-r--r--net/ipv4/ip_output.c65
2 files changed, 67 insertions, 14 deletions
diff --git a/include/net/ip.h b/include/net/ip.h
index 67fac78a186b..a4f631108c54 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -116,8 +116,24 @@ extern int ip_append_data(struct sock *sk,
116extern int ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb); 116extern int ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb);
117extern ssize_t ip_append_page(struct sock *sk, struct page *page, 117extern ssize_t ip_append_page(struct sock *sk, struct page *page,
118 int offset, size_t size, int flags); 118 int offset, size_t size, int flags);
119extern struct sk_buff *__ip_make_skb(struct sock *sk,
120 struct sk_buff_head *queue,
121 struct inet_cork *cork);
122extern int ip_send_skb(struct sk_buff *skb);
119extern int ip_push_pending_frames(struct sock *sk); 123extern int ip_push_pending_frames(struct sock *sk);
120extern void ip_flush_pending_frames(struct sock *sk); 124extern void ip_flush_pending_frames(struct sock *sk);
125extern struct sk_buff *ip_make_skb(struct sock *sk,
126 int getfrag(void *from, char *to, int offset, int len,
127 int odd, struct sk_buff *skb),
128 void *from, int length, int transhdrlen,
129 struct ipcm_cookie *ipc,
130 struct rtable **rtp,
131 unsigned int flags);
132
133static inline struct sk_buff *ip_finish_skb(struct sock *sk)
134{
135 return __ip_make_skb(sk, &sk->sk_write_queue, &inet_sk(sk)->cork);
136}
121 137
122/* datagram.c */ 138/* datagram.c */
123extern int ip4_datagram_connect(struct sock *sk, 139extern int ip4_datagram_connect(struct sock *sk,
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 1dd5ecc9a27e..460308c35028 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1267,9 +1267,9 @@ static void ip_cork_release(struct inet_cork *cork)
1267 * Combined all pending IP fragments on the socket as one IP datagram 1267 * Combined all pending IP fragments on the socket as one IP datagram
1268 * and push them out. 1268 * and push them out.
1269 */ 1269 */
1270static int __ip_push_pending_frames(struct sock *sk, 1270struct sk_buff *__ip_make_skb(struct sock *sk,
1271 struct sk_buff_head *queue, 1271 struct sk_buff_head *queue,
1272 struct inet_cork *cork) 1272 struct inet_cork *cork)
1273{ 1273{
1274 struct sk_buff *skb, *tmp_skb; 1274 struct sk_buff *skb, *tmp_skb;
1275 struct sk_buff **tail_skb; 1275 struct sk_buff **tail_skb;
@@ -1280,7 +1280,6 @@ static int __ip_push_pending_frames(struct sock *sk,
1280 struct iphdr *iph; 1280 struct iphdr *iph;
1281 __be16 df = 0; 1281 __be16 df = 0;
1282 __u8 ttl; 1282 __u8 ttl;
1283 int err = 0;
1284 1283
1285 if ((skb = __skb_dequeue(queue)) == NULL) 1284 if ((skb = __skb_dequeue(queue)) == NULL)
1286 goto out; 1285 goto out;
@@ -1351,28 +1350,37 @@ static int __ip_push_pending_frames(struct sock *sk,
1351 icmp_out_count(net, ((struct icmphdr *) 1350 icmp_out_count(net, ((struct icmphdr *)
1352 skb_transport_header(skb))->type); 1351 skb_transport_header(skb))->type);
1353 1352
1354 /* Netfilter gets whole the not fragmented skb. */ 1353 ip_cork_release(cork);
1354out:
1355 return skb;
1356}
1357
1358int ip_send_skb(struct sk_buff *skb)
1359{
1360 struct net *net = sock_net(skb->sk);
1361 int err;
1362
1355 err = ip_local_out(skb); 1363 err = ip_local_out(skb);
1356 if (err) { 1364 if (err) {
1357 if (err > 0) 1365 if (err > 0)
1358 err = net_xmit_errno(err); 1366 err = net_xmit_errno(err);
1359 if (err) 1367 if (err)
1360 goto error; 1368 IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
1361 } 1369 }
1362 1370
1363out:
1364 ip_cork_release(cork);
1365 return err; 1371 return err;
1366
1367error:
1368 IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
1369 goto out;
1370} 1372}
1371 1373
1372int ip_push_pending_frames(struct sock *sk) 1374int ip_push_pending_frames(struct sock *sk)
1373{ 1375{
1374 return __ip_push_pending_frames(sk, &sk->sk_write_queue, 1376 struct sk_buff *skb;
1375 &inet_sk(sk)->cork); 1377
1378 skb = ip_finish_skb(sk);
1379 if (!skb)
1380 return 0;
1381
1382 /* Netfilter gets whole the not fragmented skb. */
1383 return ip_send_skb(skb);
1376} 1384}
1377 1385
1378/* 1386/*
@@ -1395,6 +1403,35 @@ void ip_flush_pending_frames(struct sock *sk)
1395 __ip_flush_pending_frames(sk, &sk->sk_write_queue, &inet_sk(sk)->cork); 1403 __ip_flush_pending_frames(sk, &sk->sk_write_queue, &inet_sk(sk)->cork);
1396} 1404}
1397 1405
1406struct sk_buff *ip_make_skb(struct sock *sk,
1407 int getfrag(void *from, char *to, int offset,
1408 int len, int odd, struct sk_buff *skb),
1409 void *from, int length, int transhdrlen,
1410 struct ipcm_cookie *ipc, struct rtable **rtp,
1411 unsigned int flags)
1412{
1413 struct inet_cork cork = {};
1414 struct sk_buff_head queue;
1415 int err;
1416
1417 if (flags & MSG_PROBE)
1418 return NULL;
1419
1420 __skb_queue_head_init(&queue);
1421
1422 err = ip_setup_cork(sk, &cork, ipc, rtp);
1423 if (err)
1424 return ERR_PTR(err);
1425
1426 err = __ip_append_data(sk, &queue, &cork, getfrag,
1427 from, length, transhdrlen, flags);
1428 if (err) {
1429 __ip_flush_pending_frames(sk, &queue, &cork);
1430 return ERR_PTR(err);
1431 }
1432
1433 return __ip_make_skb(sk, &queue, &cork);
1434}
1398 1435
1399/* 1436/*
1400 * Fetch data from kernel space and fill in checksum if needed. 1437 * Fetch data from kernel space and fill in checksum if needed.