This is my experimental "send best packet next" code for my research. This is not intended for release into the kernel and should not normally be applied. Signed-off-by: Ian McDonald --- diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index 7edbf70..136b6e9 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -189,4 +189,21 @@ static inline bool ccid3_hc_tx_faster_restart_on( == TFRC_EXT_FASTER_RESTART); } +static inline __s32 xmit_delta(struct sock *sk, struct sk_buff *skb) +{ + struct timeval now; + struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); + __s32 delta; + + do_gettimeofday(&now); + delta = timeval_delta(&(DCCP_SKB_CB(skb)->dccpd_prio.expiry), &now); + delta -= (__s32)(hctx->ccid3hctx_rtt >> 1); + dccp_pr_debug("delta = %d, rtt = %u, method = %u, qlen = %u, priority = %u\n", + delta, hctx->ccid3hctx_rtt, DCCP_SKB_CB(skb)->dccpd_prio.method, sk->sk_write_queue.qlen, + DCCP_SKB_CB(skb)->dccpd_prio.priority); + + return delta; +} + + #endif /* _DCCP_CCID3_H_ */ diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 6c5e95d..ad27cba 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -313,6 +313,12 @@ static inline int dccp_bad_service_code(const struct sock *sk, return !dccp_list_has_service(dp->dccps_service_list, service); } +struct dccp_prio { + struct timeval expiry; + u16 priority; + u16 method; +}; + struct dccp_skb_cb { __u8 dccpd_type:4; __u8 dccpd_ccval:4; @@ -320,6 +326,7 @@ struct dccp_skb_cb { __u16 dccpd_opt_len; __u64 dccpd_seq; __u64 dccpd_ack_seq; + struct dccp_prio dccpd_prio; }; #define DCCP_SKB_CB(__skb) ((struct dccp_skb_cb *)&((__skb)->cb[0])) diff --git a/net/dccp/output.c b/net/dccp/output.c index 6018211..9479e99 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -20,6 +20,7 @@ #include "ackvec.h" #include "ccid.h" #include "dccp.h" +#include "ccids/ccid3.h" static inline void dccp_event_ack_sent(struct sock *sk) { @@ -175,17 +176,15 @@ void dccp_write_space(struct sock *sk) /** * dccp_wait_for_ccid - Wait for ccid to tell us we can send a packet * @sk: socket to wait for - * @skb: current skb to pass on for waiting * @delay: sleep timeout in milliseconds (> 0) * This function is called by default when the socket is closed, and * when a non-zero linger time is set on the socket. For consistency */ -static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb, int delay) +static int dccp_wait_for_ccid(struct sock *sk, int delay) { - struct dccp_sock *dp = dccp_sk(sk); DEFINE_WAIT(wait); unsigned long jiffdelay; - int rc; + int rc = 0; do { dccp_pr_debug("delayed send by %d msec\n", delay); @@ -203,9 +202,7 @@ static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb, int delay) goto do_error; if (signal_pending(current)) goto do_interrupted; - - rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb); - } while ((delay = rc) > 0); + } while (0); out: finish_wait(sk->sk_sleep, &wait); return rc; @@ -221,10 +218,60 @@ do_interrupted: void dccp_write_xmit(struct sock *sk, int block) { struct dccp_sock *dp = dccp_sk(sk); - struct sk_buff *skb; + struct sk_buff *skb, *tail; + bool method5; + + skb = skb_peek(&sk->sk_write_queue); + if (!skb) + return; + + if (DCCP_SKB_CB(skb)->dccpd_prio.method == 5) + method5 = true; + else + method5 = false; while ((skb = skb_peek(&sk->sk_write_queue))) { - int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb); + int err; + __s32 delta; + + if (method5) { + tail = skb_peek_tail(&sk->sk_write_queue); + + if (sk->sk_write_queue.qlen == 1) { +// printk(KERN_CRIT "Only 1 packet in queue. Sending\n"); + goto found_packet; + } + + while (skb != tail) { + delta = xmit_delta(sk, skb); + if (delta < 0) { + skb = skb->next; +// printk(KERN_CRIT "Packet expired - moving to next one\n"); + } else { +// printk(KERN_CRIT "Packet not expired - sending\n"); + goto found_packet; + } + } +// printk(KERN_CRIT "All packets expired - sending first in queue\n"); + skb = skb_peek(&sk->sk_write_queue); + } + + + if (!method5 && DCCP_SKB_CB(skb)->dccpd_prio.priority) { + delta = xmit_delta(sk, skb); + + if (delta < 0) { + if ((DCCP_SKB_CB(skb)->dccpd_prio.method != 1) && (sk->sk_write_queue.qlen == 1)) { + dccp_pr_debug("packet would have expired in write_xmit\n"); + } else { + skb_dequeue(&sk->sk_write_queue); + kfree_skb(skb); + continue; + } + } + } +found_packet: + err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb); if (err > 0) { if (!block) { @@ -232,9 +279,10 @@ void dccp_write_xmit(struct sock *sk, int block) msecs_to_jiffies(err)+jiffies); break; } else - err = dccp_wait_for_ccid(sk, skb, err); + err = dccp_wait_for_ccid(sk, err); if (err && err != -EINTR) DCCP_BUG("err=%d after dccp_wait_for_ccid", err); + continue; } skb_dequeue(&sk->sk_write_queue); diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 4ac6529..4d9b8e2 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -36,6 +36,8 @@ #include "dccp.h" #include "feat.h" +#include "ccids/ccid3.h" + DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly; EXPORT_SYMBOL_GPL(dccp_statistics); @@ -671,6 +673,60 @@ int compat_dccp_getsockopt(struct sock *sk, int level, int optname, EXPORT_SYMBOL_GPL(compat_dccp_getsockopt); #endif +static void dccp_queue_send(struct sock *sk, struct sk_buff *newsk) +{ + /* if priority == 0 then do conventional send + * if method == 1 or 2 then queue in priority queues + * if method == 3 then queue in priority queues but lifo + * if method == 4 then queue in lifo */ + + struct sk_buff *entry; + struct sk_buff_head *list; + unsigned long flags; + __s32 delta; + struct dccp_skb_cb *newcb, *entcb; + + list = &sk->sk_write_queue; + spin_lock_irqsave(&list->lock, flags); + newcb = DCCP_SKB_CB(newsk); + + if (skb_queue_empty(list) || (newcb->dccpd_prio.priority == 0)) { + __skb_queue_tail(list, newsk); + goto out_queue; + } + + if (newcb->dccpd_prio.method == 4) { + __skb_queue_head(list, newsk); + goto out_queue; + } + + entry = list->next; + + while (entry != (struct sk_buff *)list) { + entcb = DCCP_SKB_CB(entry); + /* lower numbers are higher priority */ + if (newcb->dccpd_prio.priority < entcb->dccpd_prio.priority) { + __skb_insert(newsk, entry->prev, entry, list); + goto out_queue; + } + if (entcb->dccpd_prio.priority == newcb->dccpd_prio.priority) { + if (newcb->dccpd_prio.method == 3) { + __skb_insert(newsk, entry->prev, entry, list); + goto out_queue; + } + delta = timeval_delta(&newcb->dccpd_prio.expiry, &entcb->dccpd_prio.expiry); + if (delta < 0) { + __skb_insert(newsk, entry->prev, entry, list); + goto out_queue; + } + } + entry = entry->next; + } + __skb_queue_tail(list, newsk); +out_queue: + spin_unlock_irqrestore(&list->lock, flags); +} + int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len) { @@ -680,6 +736,7 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, struct sk_buff *skb; int rc, size; long timeo; + struct dccp_prio *dcp = (struct dccp_prio *)msg->msg_control; if (len > dp->dccps_mss_cache) return -EMSGSIZE; @@ -688,8 +745,25 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (sysctl_dccp_tx_qlen && (sk->sk_write_queue.qlen >= sysctl_dccp_tx_qlen)) { - rc = -EAGAIN; - goto out_release; + if (dcp->priority && dcp->method == 5) { + __s32 delta; + +// printk(KERN_CRIT "best5 - buffer full qlen = %d\n", sk->sk_write_queue.qlen); + skb = skb_peek(&sk->sk_write_queue); + delta = xmit_delta(sk, skb); + if (delta < 0) { + skb_dequeue(&sk->sk_write_queue); + kfree_skb(skb); +// printk(KERN_CRIT "best5 - old packet discarded\n"); + } else { +// printk(KERN_CRIT "best5 - new packet discarded\n"); + rc = -EAGAIN; + goto out_release; + } + } else { + rc = -EAGAIN; + goto out_release; + } } timeo = sock_sndtimeo(sk, noblock); @@ -715,7 +789,16 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, if (rc != 0) goto out_discard; - skb_queue_tail(&sk->sk_write_queue, skb); + if (dcp) { + DCCP_SKB_CB(skb)->dccpd_prio = *dcp; + dccp_pr_debug("msg prio = %u\n", DCCP_SKB_CB(skb)->dccpd_prio.priority); + } else { + DCCP_SKB_CB(skb)->dccpd_prio.priority = 0; + dccp_pr_debug("no msg control data\n"); + } +// printk(KERN_CRIT "adding packet qlen=%d\n", sk->sk_write_queue.qlen); + dccp_queue_send(sk, skb); + dccp_write_xmit(sk,0); out_release: release_sock(sk);