dccp: Policy-based packet dequeueing infrastructure
This patch adds a generic infrastructure for policy-based dequeueing of TX packets and provides two policies: * a simple FIFO policy (which is the default) and * a priority based policy (set via socket options). Both policies honour the tx_qlen sysctl for the maximum size of the write queue (can be overridden via socket options). The priority policy uses skb->priority internally to assign an u32 priority identifier, using the same ranking as SO_PRIORITY. The skb->priority field is set to 0 when the packet leaves DCCP. The priority is supplied as ancillary data using cmsg(3), the patch also provides the requisite parsing routines. Signed-off-by: Tomasz Grobelny <tomasz@grobelny.oswiecenia.net> Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
This commit is contained in:
committed by
Gerrit Renker
parent
cfa969e385
commit
871a2c16c2
@@ -185,6 +185,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
|
||||
dp->dccps_role = DCCP_ROLE_UNDEFINED;
|
||||
dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT;
|
||||
dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1;
|
||||
dp->dccps_tx_qlen = sysctl_dccp_tx_qlen;
|
||||
|
||||
dccp_init_xmit_timers(sk);
|
||||
|
||||
@@ -532,6 +533,20 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
|
||||
case DCCP_SOCKOPT_RECV_CSCOV:
|
||||
err = dccp_setsockopt_cscov(sk, val, true);
|
||||
break;
|
||||
case DCCP_SOCKOPT_QPOLICY_ID:
|
||||
if (sk->sk_state != DCCP_CLOSED)
|
||||
err = -EISCONN;
|
||||
else if (val < 0 || val >= DCCPQ_POLICY_MAX)
|
||||
err = -EINVAL;
|
||||
else
|
||||
dp->dccps_qpolicy = val;
|
||||
break;
|
||||
case DCCP_SOCKOPT_QPOLICY_TXQLEN:
|
||||
if (val < 0)
|
||||
err = -EINVAL;
|
||||
else
|
||||
dp->dccps_tx_qlen = val;
|
||||
break;
|
||||
default:
|
||||
err = -ENOPROTOOPT;
|
||||
break;
|
||||
@@ -639,6 +654,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
|
||||
case DCCP_SOCKOPT_RECV_CSCOV:
|
||||
val = dp->dccps_pcrlen;
|
||||
break;
|
||||
case DCCP_SOCKOPT_QPOLICY_ID:
|
||||
val = dp->dccps_qpolicy;
|
||||
break;
|
||||
case DCCP_SOCKOPT_QPOLICY_TXQLEN:
|
||||
val = dp->dccps_tx_qlen;
|
||||
break;
|
||||
case 128 ... 191:
|
||||
return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
|
||||
len, (u32 __user *)optval, optlen);
|
||||
@@ -681,6 +702,43 @@ int compat_dccp_getsockopt(struct sock *sk, int level, int optname,
|
||||
EXPORT_SYMBOL_GPL(compat_dccp_getsockopt);
|
||||
#endif
|
||||
|
||||
static int dccp_msghdr_parse(struct msghdr *msg, struct sk_buff *skb)
|
||||
{
|
||||
struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
|
||||
|
||||
/*
|
||||
* Assign an (opaque) qpolicy priority value to skb->priority.
|
||||
*
|
||||
* We are overloading this skb field for use with the qpolicy subystem.
|
||||
* The skb->priority is normally used for the SO_PRIORITY option, which
|
||||
* is initialised from sk_priority. Since the assignment of sk_priority
|
||||
* to skb->priority happens later (on layer 3), we overload this field
|
||||
* for use with queueing priorities as long as the skb is on layer 4.
|
||||
* The default priority value (if nothing is set) is 0.
|
||||
*/
|
||||
skb->priority = 0;
|
||||
|
||||
for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
|
||||
if (!CMSG_OK(msg, cmsg))
|
||||
return -EINVAL;
|
||||
|
||||
if (cmsg->cmsg_level != SOL_DCCP)
|
||||
continue;
|
||||
|
||||
switch (cmsg->cmsg_type) {
|
||||
case DCCP_SCM_PRIORITY:
|
||||
if (cmsg->cmsg_len != CMSG_LEN(sizeof(__u32)))
|
||||
return -EINVAL;
|
||||
skb->priority = *(__u32 *)CMSG_DATA(cmsg);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
||||
size_t len)
|
||||
{
|
||||
@@ -696,8 +754,7 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
if (sysctl_dccp_tx_qlen &&
|
||||
(sk->sk_write_queue.qlen >= sysctl_dccp_tx_qlen)) {
|
||||
if (dccp_qpolicy_full(sk)) {
|
||||
rc = -EAGAIN;
|
||||
goto out_release;
|
||||
}
|
||||
@@ -725,7 +782,11 @@ 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);
|
||||
rc = dccp_msghdr_parse(msg, skb);
|
||||
if (rc != 0)
|
||||
goto out_discard;
|
||||
|
||||
dccp_qpolicy_push(sk, skb);
|
||||
/*
|
||||
* The xmit_timer is set if the TX CCID is rate-based and will expire
|
||||
* when congestion control permits to release further packets into the
|
||||
|
Reference in New Issue
Block a user