diff options
author | Tomasz Grobelny <tomasz@grobelny.oswiecenia.net> | 2010-12-04 07:38:01 -0500 |
---|---|---|
committer | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2010-12-07 07:47:12 -0500 |
commit | 871a2c16c21b988688b4ab1a78eadd969765c0a3 (patch) | |
tree | 34ffb3be1402747ef3b7fdb754fb99778bd45728 /net/dccp/qpolicy.c | |
parent | cfa969e385a23e4c85f50e0ed5de25a2e18bf9d4 (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/qpolicy.c')
-rw-r--r-- | net/dccp/qpolicy.c | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/net/dccp/qpolicy.c b/net/dccp/qpolicy.c new file mode 100644 index 000000000000..4b0fd6b11f6d --- /dev/null +++ b/net/dccp/qpolicy.c | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * net/dccp/qpolicy.c | ||
3 | * | ||
4 | * Policy-based packet dequeueing interface for DCCP. | ||
5 | * | ||
6 | * Copyright (c) 2008 Tomasz Grobelny <tomasz@grobelny.oswiecenia.net> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License v2 | ||
10 | * as published by the Free Software Foundation. | ||
11 | */ | ||
12 | #include "dccp.h" | ||
13 | |||
14 | /* | ||
15 | * Simple Dequeueing Policy: | ||
16 | * If tx_qlen is different from 0, enqueue up to tx_qlen elements. | ||
17 | */ | ||
18 | static void qpolicy_simple_push(struct sock *sk, struct sk_buff *skb) | ||
19 | { | ||
20 | skb_queue_tail(&sk->sk_write_queue, skb); | ||
21 | } | ||
22 | |||
23 | static bool qpolicy_simple_full(struct sock *sk) | ||
24 | { | ||
25 | return dccp_sk(sk)->dccps_tx_qlen && | ||
26 | sk->sk_write_queue.qlen >= dccp_sk(sk)->dccps_tx_qlen; | ||
27 | } | ||
28 | |||
29 | static struct sk_buff *qpolicy_simple_top(struct sock *sk) | ||
30 | { | ||
31 | return skb_peek(&sk->sk_write_queue); | ||
32 | } | ||
33 | |||
34 | /* | ||
35 | * Priority-based Dequeueing Policy: | ||
36 | * If tx_qlen is different from 0 and the queue has reached its upper bound | ||
37 | * of tx_qlen elements, replace older packets lowest-priority-first. | ||
38 | */ | ||
39 | static struct sk_buff *qpolicy_prio_best_skb(struct sock *sk) | ||
40 | { | ||
41 | struct sk_buff *skb, *best = NULL; | ||
42 | |||
43 | skb_queue_walk(&sk->sk_write_queue, skb) | ||
44 | if (best == NULL || skb->priority > best->priority) | ||
45 | best = skb; | ||
46 | return best; | ||
47 | } | ||
48 | |||
49 | static struct sk_buff *qpolicy_prio_worst_skb(struct sock *sk) | ||
50 | { | ||
51 | struct sk_buff *skb, *worst = NULL; | ||
52 | |||
53 | skb_queue_walk(&sk->sk_write_queue, skb) | ||
54 | if (worst == NULL || skb->priority < worst->priority) | ||
55 | worst = skb; | ||
56 | return worst; | ||
57 | } | ||
58 | |||
59 | static bool qpolicy_prio_full(struct sock *sk) | ||
60 | { | ||
61 | if (qpolicy_simple_full(sk)) | ||
62 | dccp_qpolicy_drop(sk, qpolicy_prio_worst_skb(sk)); | ||
63 | return false; | ||
64 | } | ||
65 | |||
66 | /** | ||
67 | * struct dccp_qpolicy_operations - TX Packet Dequeueing Interface | ||
68 | * @push: add a new @skb to the write queue | ||
69 | * @full: indicates that no more packets will be admitted | ||
70 | * @top: peeks at whatever the queueing policy defines as its `top' | ||
71 | */ | ||
72 | static struct dccp_qpolicy_operations { | ||
73 | void (*push) (struct sock *sk, struct sk_buff *skb); | ||
74 | bool (*full) (struct sock *sk); | ||
75 | struct sk_buff* (*top) (struct sock *sk); | ||
76 | |||
77 | } qpol_table[DCCPQ_POLICY_MAX] = { | ||
78 | [DCCPQ_POLICY_SIMPLE] = { | ||
79 | .push = qpolicy_simple_push, | ||
80 | .full = qpolicy_simple_full, | ||
81 | .top = qpolicy_simple_top, | ||
82 | }, | ||
83 | [DCCPQ_POLICY_PRIO] = { | ||
84 | .push = qpolicy_simple_push, | ||
85 | .full = qpolicy_prio_full, | ||
86 | .top = qpolicy_prio_best_skb, | ||
87 | }, | ||
88 | }; | ||
89 | |||
90 | /* | ||
91 | * Externally visible interface | ||
92 | */ | ||
93 | void dccp_qpolicy_push(struct sock *sk, struct sk_buff *skb) | ||
94 | { | ||
95 | qpol_table[dccp_sk(sk)->dccps_qpolicy].push(sk, skb); | ||
96 | } | ||
97 | |||
98 | bool dccp_qpolicy_full(struct sock *sk) | ||
99 | { | ||
100 | return qpol_table[dccp_sk(sk)->dccps_qpolicy].full(sk); | ||
101 | } | ||
102 | |||
103 | void dccp_qpolicy_drop(struct sock *sk, struct sk_buff *skb) | ||
104 | { | ||
105 | if (skb != NULL) { | ||
106 | skb_unlink(skb, &sk->sk_write_queue); | ||
107 | kfree_skb(skb); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | struct sk_buff *dccp_qpolicy_top(struct sock *sk) | ||
112 | { | ||
113 | return qpol_table[dccp_sk(sk)->dccps_qpolicy].top(sk); | ||
114 | } | ||
115 | |||
116 | struct sk_buff *dccp_qpolicy_pop(struct sock *sk) | ||
117 | { | ||
118 | struct sk_buff *skb = dccp_qpolicy_top(sk); | ||
119 | |||
120 | if (skb != NULL) { | ||
121 | /* Clear any skb fields that we used internally */ | ||
122 | skb->priority = 0; | ||
123 | skb_unlink(skb, &sk->sk_write_queue); | ||
124 | } | ||
125 | return skb; | ||
126 | } | ||