Skip to content

Commit 1c32c5a

Browse files
herbertxdavem330
authored andcommitted
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 <[email protected]> Acked-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 1470ddf commit 1c32c5a

File tree

2 files changed

+67
-14
lines changed

2 files changed

+67
-14
lines changed

include/net/ip.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,24 @@ extern int ip_append_data(struct sock *sk,
116116
extern int ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb);
117117
extern ssize_t ip_append_page(struct sock *sk, struct page *page,
118118
int offset, size_t size, int flags);
119+
extern struct sk_buff *__ip_make_skb(struct sock *sk,
120+
struct sk_buff_head *queue,
121+
struct inet_cork *cork);
122+
extern int ip_send_skb(struct sk_buff *skb);
119123
extern int ip_push_pending_frames(struct sock *sk);
120124
extern void ip_flush_pending_frames(struct sock *sk);
125+
extern 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+
133+
static 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+
}
121137

122138
/* datagram.c */
123139
extern int ip4_datagram_connect(struct sock *sk,

net/ipv4/ip_output.c

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,9 +1267,9 @@ static void ip_cork_release(struct inet_cork *cork)
12671267
* Combined all pending IP fragments on the socket as one IP datagram
12681268
* and push them out.
12691269
*/
1270-
static int __ip_push_pending_frames(struct sock *sk,
1271-
struct sk_buff_head *queue,
1272-
struct inet_cork *cork)
1270+
struct sk_buff *__ip_make_skb(struct sock *sk,
1271+
struct sk_buff_head *queue,
1272+
struct inet_cork *cork)
12731273
{
12741274
struct sk_buff *skb, *tmp_skb;
12751275
struct sk_buff **tail_skb;
@@ -1280,7 +1280,6 @@ static int __ip_push_pending_frames(struct sock *sk,
12801280
struct iphdr *iph;
12811281
__be16 df = 0;
12821282
__u8 ttl;
1283-
int err = 0;
12841283

12851284
if ((skb = __skb_dequeue(queue)) == NULL)
12861285
goto out;
@@ -1351,28 +1350,37 @@ static int __ip_push_pending_frames(struct sock *sk,
13511350
icmp_out_count(net, ((struct icmphdr *)
13521351
skb_transport_header(skb))->type);
13531352

1354-
/* Netfilter gets whole the not fragmented skb. */
1353+
ip_cork_release(cork);
1354+
out:
1355+
return skb;
1356+
}
1357+
1358+
int ip_send_skb(struct sk_buff *skb)
1359+
{
1360+
struct net *net = sock_net(skb->sk);
1361+
int err;
1362+
13551363
err = ip_local_out(skb);
13561364
if (err) {
13571365
if (err > 0)
13581366
err = net_xmit_errno(err);
13591367
if (err)
1360-
goto error;
1368+
IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
13611369
}
13621370

1363-
out:
1364-
ip_cork_release(cork);
13651371
return err;
1366-
1367-
error:
1368-
IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
1369-
goto out;
13701372
}
13711373

13721374
int ip_push_pending_frames(struct sock *sk)
13731375
{
1374-
return __ip_push_pending_frames(sk, &sk->sk_write_queue,
1375-
&inet_sk(sk)->cork);
1376+
struct sk_buff *skb;
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);
13761384
}
13771385

13781386
/*
@@ -1395,6 +1403,35 @@ void ip_flush_pending_frames(struct sock *sk)
13951403
__ip_flush_pending_frames(sk, &sk->sk_write_queue, &inet_sk(sk)->cork);
13961404
}
13971405

1406+
struct 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+
}
13981435

13991436
/*
14001437
* Fetch data from kernel space and fill in checksum if needed.

0 commit comments

Comments
 (0)