aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/proto.c
diff options
context:
space:
mode:
authorTomasz Grobelny <tomasz@grobelny.oswiecenia.net>2008-09-04 01:30:19 -0400
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:45:39 -0400
commitd6da3511d6b558d0b017777b61dc08b8fbc06ea4 (patch)
tree473f9131b9e641d803bfbea174cf1dfc45aea3ca /net/dccp/proto.c
parentddab05568eaa70fc92b2aae957136f188f724e9c (diff)
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>
Diffstat (limited to 'net/dccp/proto.c')
-rw-r--r--net/dccp/proto.c67
1 files changed, 64 insertions, 3 deletions
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 8c125ffab1c5..b56efdd2a421 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -189,6 +189,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
189 dp->dccps_rate_last = jiffies; 189 dp->dccps_rate_last = jiffies;
190 dp->dccps_role = DCCP_ROLE_UNDEFINED; 190 dp->dccps_role = DCCP_ROLE_UNDEFINED;
191 dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT; 191 dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT;
192 dp->dccps_tx_qlen = sysctl_dccp_tx_qlen;
192 193
193 dccp_init_xmit_timers(sk); 194 dccp_init_xmit_timers(sk);
194 195
@@ -541,6 +542,20 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
541 case DCCP_SOCKOPT_RECV_CSCOV: 542 case DCCP_SOCKOPT_RECV_CSCOV:
542 err = dccp_setsockopt_cscov(sk, val, true); 543 err = dccp_setsockopt_cscov(sk, val, true);
543 break; 544 break;
545 case DCCP_SOCKOPT_QPOLICY_ID:
546 if (sk->sk_state != DCCP_CLOSED)
547 err = -EISCONN;
548 else if (val < 0 || val >= DCCPQ_POLICY_MAX)
549 err = -EINVAL;
550 else
551 dp->dccps_qpolicy = val;
552 break;
553 case DCCP_SOCKOPT_QPOLICY_TXQLEN:
554 if (val < 0)
555 err = -EINVAL;
556 else
557 dp->dccps_tx_qlen = val;
558 break;
544 default: 559 default:
545 err = -ENOPROTOOPT; 560 err = -ENOPROTOOPT;
546 break; 561 break;
@@ -648,6 +663,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
648 case DCCP_SOCKOPT_RECV_CSCOV: 663 case DCCP_SOCKOPT_RECV_CSCOV:
649 val = dp->dccps_pcrlen; 664 val = dp->dccps_pcrlen;
650 break; 665 break;
666 case DCCP_SOCKOPT_QPOLICY_ID:
667 val = dp->dccps_qpolicy;
668 break;
669 case DCCP_SOCKOPT_QPOLICY_TXQLEN:
670 val = dp->dccps_tx_qlen;
671 break;
651 case 128 ... 191: 672 case 128 ... 191:
652 return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, 673 return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
653 len, (u32 __user *)optval, optlen); 674 len, (u32 __user *)optval, optlen);
@@ -690,6 +711,43 @@ int compat_dccp_getsockopt(struct sock *sk, int level, int optname,
690EXPORT_SYMBOL_GPL(compat_dccp_getsockopt); 711EXPORT_SYMBOL_GPL(compat_dccp_getsockopt);
691#endif 712#endif
692 713
714static int dccp_msghdr_parse(struct msghdr *msg, struct sk_buff *skb)
715{
716 struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
717
718 /*
719 * Assign an (opaque) qpolicy priority value to skb->priority.
720 *
721 * We are overloading this skb field for use with the qpolicy subystem.
722 * The skb->priority is normally used for the SO_PRIORITY option, which
723 * is initialised from sk_priority. Since the assignment of sk_priority
724 * to skb->priority happens later (on layer 3), we overload this field
725 * for use with queueing priorities as long as the skb is on layer 4.
726 * The default priority value (if nothing is set) is 0.
727 */
728 skb->priority = 0;
729
730 for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
731
732 if (!CMSG_OK(msg, cmsg))
733 return -EINVAL;
734
735 if (cmsg->cmsg_level != SOL_DCCP)
736 continue;
737
738 switch (cmsg->cmsg_type) {
739 case DCCP_SCM_PRIORITY:
740 if (cmsg->cmsg_len != CMSG_LEN(sizeof(__u32)))
741 return -EINVAL;
742 skb->priority = *(__u32 *)CMSG_DATA(cmsg);
743 break;
744 default:
745 return -EINVAL;
746 }
747 }
748 return 0;
749}
750
693int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 751int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
694 size_t len) 752 size_t len)
695{ 753{
@@ -705,8 +763,7 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
705 763
706 lock_sock(sk); 764 lock_sock(sk);
707 765
708 if (sysctl_dccp_tx_qlen && 766 if (dccp_qpolicy_full(sk)) {
709 (sk->sk_write_queue.qlen >= sysctl_dccp_tx_qlen)) {
710 rc = -EAGAIN; 767 rc = -EAGAIN;
711 goto out_release; 768 goto out_release;
712 } 769 }
@@ -734,7 +791,11 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
734 if (rc != 0) 791 if (rc != 0)
735 goto out_discard; 792 goto out_discard;
736 793
737 skb_queue_tail(&sk->sk_write_queue, skb); 794 rc = dccp_msghdr_parse(msg, skb);
795 if (rc != 0)
796 goto out_discard;
797
798 dccp_qpolicy_push(sk, skb);
738 dccp_write_xmit(sk); 799 dccp_write_xmit(sk);
739out_release: 800out_release:
740 release_sock(sk); 801 release_sock(sk);