Skip to content

Commit dc841e3

Browse files
Gerrit Renkerdavem330
Gerrit Renker
authored andcommitted
dccp: Extend CCID packet dequeueing interface
This extends the packet dequeuing interface of dccp_write_xmit() to allow 1. CCIDs to take care of timing when the next packet may be sent; 2. delayed sending (as before, with an inter-packet gap up to 65.535 seconds). The main purpose is to take CCID-2 out of its polling mode (when it is network- limited, it tries every millisecond to send, without interruption). The mode of operation for (2) is as follows: * new packet is enqueued via dccp_sendmsg() => dccp_write_xmit(), * ccid_hc_tx_send_packet() detects that it may not send (e.g. window full), * it signals this condition via `CCID_PACKET_WILL_DEQUEUE_LATER', * dccp_write_xmit() returns without further action; * after some time the wait-condition for CCID becomes true, * that CCID schedules the tasklet, * tasklet function calls ccid_hc_tx_send_packet() via dccp_write_xmit(), * since the wait-condition is now true, ccid_hc_tx_packet() returns "send now", * packet is sent, and possibly more (since dccp_write_xmit() loops). Code reuse: the taskled function calls dccp_write_xmit(), the timer function reduces to a wrapper around the same code. Signed-off-by: Gerrit Renker <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent fe84f41 commit dc841e3

File tree

3 files changed

+89
-58
lines changed

3 files changed

+89
-58
lines changed

include/linux/dccp.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,8 @@ struct dccp_ackvec;
462462
* @dccps_hc_rx_insert_options - receiver wants to add options when acking
463463
* @dccps_hc_tx_insert_options - sender wants to add options when sending
464464
* @dccps_server_timewait - server holds timewait state on close (RFC 4340, 8.3)
465-
* @dccps_xmit_timer - timer for when CCID is not ready to send
465+
* @dccps_xmitlet - tasklet scheduled by the TX CCID to dequeue data packets
466+
* @dccps_xmit_timer - used by the TX CCID to delay sending (rate-based pacing)
466467
* @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs)
467468
*/
468469
struct dccp_sock {
@@ -502,6 +503,7 @@ struct dccp_sock {
502503
__u8 dccps_hc_rx_insert_options:1;
503504
__u8 dccps_hc_tx_insert_options:1;
504505
__u8 dccps_server_timewait:1;
506+
struct tasklet_struct dccps_xmitlet;
505507
struct timer_list dccps_xmit_timer;
506508
};
507509

net/dccp/output.c

Lines changed: 72 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -254,63 +254,89 @@ static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb, int delay)
254254
goto out;
255255
}
256256

257+
/**
258+
* dccp_xmit_packet - Send data packet under control of CCID
259+
* Transmits next-queued payload and informs CCID to account for the packet.
260+
*/
261+
static void dccp_xmit_packet(struct sock *sk)
262+
{
263+
int err, len;
264+
struct dccp_sock *dp = dccp_sk(sk);
265+
struct sk_buff *skb = skb_dequeue(&sk->sk_write_queue);
266+
267+
if (unlikely(skb == NULL))
268+
return;
269+
len = skb->len;
270+
271+
if (sk->sk_state == DCCP_PARTOPEN) {
272+
const u32 cur_mps = dp->dccps_mss_cache - DCCP_FEATNEG_OVERHEAD;
273+
/*
274+
* See 8.1.5 - Handshake Completion.
275+
*
276+
* For robustness we resend Confirm options until the client has
277+
* entered OPEN. During the initial feature negotiation, the MPS
278+
* is smaller than usual, reduced by the Change/Confirm options.
279+
*/
280+
if (!list_empty(&dp->dccps_featneg) && len > cur_mps) {
281+
DCCP_WARN("Payload too large (%d) for featneg.\n", len);
282+
dccp_send_ack(sk);
283+
dccp_feat_list_purge(&dp->dccps_featneg);
284+
}
285+
286+
inet_csk_schedule_ack(sk);
287+
inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
288+
inet_csk(sk)->icsk_rto,
289+
DCCP_RTO_MAX);
290+
DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_DATAACK;
291+
} else if (dccp_ack_pending(sk)) {
292+
DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_DATAACK;
293+
} else {
294+
DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_DATA;
295+
}
296+
297+
err = dccp_transmit_skb(sk, skb);
298+
if (err)
299+
dccp_pr_debug("transmit_skb() returned err=%d\n", err);
300+
/*
301+
* Register this one as sent even if an error occurred. To the remote
302+
* end a local packet drop is indistinguishable from network loss, i.e.
303+
* any local drop will eventually be reported via receiver feedback.
304+
*/
305+
ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, len);
306+
}
307+
257308
void dccp_write_xmit(struct sock *sk, int block)
258309
{
259310
struct dccp_sock *dp = dccp_sk(sk);
260311
struct sk_buff *skb;
261312

262313
while ((skb = skb_peek(&sk->sk_write_queue))) {
263-
int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb);
314+
int rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb);
264315

265-
if (err > 0) {
316+
switch (ccid_packet_dequeue_eval(rc)) {
317+
case CCID_PACKET_WILL_DEQUEUE_LATER:
318+
return;
319+
case CCID_PACKET_DELAY:
266320
if (!block) {
267321
sk_reset_timer(sk, &dp->dccps_xmit_timer,
268-
msecs_to_jiffies(err)+jiffies);
322+
msecs_to_jiffies(rc)+jiffies);
323+
return;
324+
}
325+
rc = dccp_wait_for_ccid(sk, skb, rc);
326+
if (rc && rc != -EINTR) {
327+
DCCP_BUG("err=%d after dccp_wait_for_ccid", rc);
328+
skb_dequeue(&sk->sk_write_queue);
329+
kfree_skb(skb);
269330
break;
270-
} else
271-
err = dccp_wait_for_ccid(sk, skb, err);
272-
if (err && err != -EINTR)
273-
DCCP_BUG("err=%d after dccp_wait_for_ccid", err);
274-
}
275-
276-
skb_dequeue(&sk->sk_write_queue);
277-
if (err == 0) {
278-
struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
279-
const int len = skb->len;
280-
281-
if (sk->sk_state == DCCP_PARTOPEN) {
282-
const u32 cur_mps = dp->dccps_mss_cache - DCCP_FEATNEG_OVERHEAD;
283-
/*
284-
* See 8.1.5 - Handshake Completion.
285-
*
286-
* For robustness we resend Confirm options until the client has
287-
* entered OPEN. During the initial feature negotiation, the MPS
288-
* is smaller than usual, reduced by the Change/Confirm options.
289-
*/
290-
if (!list_empty(&dp->dccps_featneg) && len > cur_mps) {
291-
DCCP_WARN("Payload too large (%d) for featneg.\n", len);
292-
dccp_send_ack(sk);
293-
dccp_feat_list_purge(&dp->dccps_featneg);
294-
}
295-
296-
inet_csk_schedule_ack(sk);
297-
inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
298-
inet_csk(sk)->icsk_rto,
299-
DCCP_RTO_MAX);
300-
dcb->dccpd_type = DCCP_PKT_DATAACK;
301-
} else if (dccp_ack_pending(sk))
302-
dcb->dccpd_type = DCCP_PKT_DATAACK;
303-
else
304-
dcb->dccpd_type = DCCP_PKT_DATA;
305-
306-
err = dccp_transmit_skb(sk, skb);
307-
ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, len);
308-
if (err)
309-
DCCP_BUG("err=%d after ccid_hc_tx_packet_sent",
310-
err);
311-
} else {
312-
dccp_pr_debug("packet discarded due to err=%d\n", err);
331+
}
332+
/* fall through */
333+
case CCID_PACKET_SEND_AT_ONCE:
334+
dccp_xmit_packet(sk);
335+
break;
336+
case CCID_PACKET_ERR:
337+
skb_dequeue(&sk->sk_write_queue);
313338
kfree_skb(skb);
339+
dccp_pr_debug("packet discarded due to err=%d\n", rc);
314340
}
315341
}
316342
}

net/dccp/timer.c

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -237,32 +237,35 @@ static void dccp_delack_timer(unsigned long data)
237237
sock_put(sk);
238238
}
239239

240-
/* Transmit-delay timer: used by the CCIDs to delay actual send time */
241-
static void dccp_write_xmit_timer(unsigned long data)
240+
/**
241+
* dccp_write_xmitlet - Workhorse for CCID packet dequeueing interface
242+
* See the comments above %ccid_dequeueing_decision for supported modes.
243+
*/
244+
static void dccp_write_xmitlet(unsigned long data)
242245
{
243246
struct sock *sk = (struct sock *)data;
244-
struct dccp_sock *dp = dccp_sk(sk);
245247

246248
bh_lock_sock(sk);
247249
if (sock_owned_by_user(sk))
248-
sk_reset_timer(sk, &dp->dccps_xmit_timer, jiffies+1);
250+
sk_reset_timer(sk, &dccp_sk(sk)->dccps_xmit_timer, jiffies + 1);
249251
else
250252
dccp_write_xmit(sk, 0);
251253
bh_unlock_sock(sk);
252-
sock_put(sk);
253254
}
254255

255-
static void dccp_init_write_xmit_timer(struct sock *sk)
256+
static void dccp_write_xmit_timer(unsigned long data)
256257
{
257-
struct dccp_sock *dp = dccp_sk(sk);
258-
259-
setup_timer(&dp->dccps_xmit_timer, dccp_write_xmit_timer,
260-
(unsigned long)sk);
258+
dccp_write_xmitlet(data);
259+
sock_put((struct sock *)data);
261260
}
262261

263262
void dccp_init_xmit_timers(struct sock *sk)
264263
{
265-
dccp_init_write_xmit_timer(sk);
264+
struct dccp_sock *dp = dccp_sk(sk);
265+
266+
tasklet_init(&dp->dccps_xmitlet, dccp_write_xmitlet, (unsigned long)sk);
267+
setup_timer(&dp->dccps_xmit_timer, dccp_write_xmit_timer,
268+
(unsigned long)sk);
266269
inet_csk_init_xmit_timers(sk, &dccp_write_timer, &dccp_delack_timer,
267270
&dccp_keepalive_timer);
268271
}

0 commit comments

Comments
 (0)