summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>2017-10-03 18:20:17 -0400
committerDavid S. Miller <davem@davemloft.net>2017-10-03 19:27:29 -0400
commitac1ed8b82cd60ba8e7d84103ac1414b8c577c485 (patch)
tree23144fff13a5bb0ac5a84f429fd8ac768b49a214
parent637784ade221a3c8a7ecd0f583eddd95d6276b9a (diff)
sctp: introduce round robin stream scheduler
This patch introduces RFC Draft ndata section 3.2 Priority Based Scheduler (SCTP_SS_RR). Works by maintaining a list of enqueued streams and tracking the last one used to send data. When the datamsg is done, it switches to the next stream. See-also: https://tools.ietf.org/html/draft-ietf-tsvwg-sctp-ndata-13 Tested-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/sctp/structs.h11
-rw-r--r--include/uapi/linux/sctp.h3
-rw-r--r--net/sctp/Makefile3
-rw-r--r--net/sctp/stream_sched.c2
-rw-r--r--net/sctp/stream_sched_rr.c201
5 files changed, 218 insertions, 2 deletions
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 40eb8d66a37c..16f949eef52f 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1348,6 +1348,10 @@ struct sctp_stream_out_ext {
1348 struct list_head prio_list; 1348 struct list_head prio_list;
1349 struct sctp_stream_priorities *prio_head; 1349 struct sctp_stream_priorities *prio_head;
1350 }; 1350 };
1351 /* Fields used by RR scheduler */
1352 struct {
1353 struct list_head rr_list;
1354 };
1351 }; 1355 };
1352}; 1356};
1353 1357
@@ -1374,6 +1378,13 @@ struct sctp_stream {
1374 /* List of priorities scheduled */ 1378 /* List of priorities scheduled */
1375 struct list_head prio_list; 1379 struct list_head prio_list;
1376 }; 1380 };
1381 /* Fields used by RR scheduler */
1382 struct {
1383 /* List of streams scheduled */
1384 struct list_head rr_list;
1385 /* The next stream stream in line */
1386 struct sctp_stream_out_ext *rr_next;
1387 };
1377 }; 1388 };
1378}; 1389};
1379 1390
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
index 850fa8b29d7e..6cd7d416ca40 100644
--- a/include/uapi/linux/sctp.h
+++ b/include/uapi/linux/sctp.h
@@ -1100,7 +1100,8 @@ struct sctp_add_streams {
1100enum sctp_sched_type { 1100enum sctp_sched_type {
1101 SCTP_SS_FCFS, 1101 SCTP_SS_FCFS,
1102 SCTP_SS_PRIO, 1102 SCTP_SS_PRIO,
1103 SCTP_SS_MAX = SCTP_SS_PRIO 1103 SCTP_SS_RR,
1104 SCTP_SS_MAX = SCTP_SS_RR
1104}; 1105};
1105 1106
1106#endif /* _UAPI_SCTP_H */ 1107#endif /* _UAPI_SCTP_H */
diff --git a/net/sctp/Makefile b/net/sctp/Makefile
index 647c9cfd4e95..bf90c5397719 100644
--- a/net/sctp/Makefile
+++ b/net/sctp/Makefile
@@ -12,7 +12,8 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
12 inqueue.o outqueue.o ulpqueue.o \ 12 inqueue.o outqueue.o ulpqueue.o \
13 tsnmap.o bind_addr.o socket.o primitive.o \ 13 tsnmap.o bind_addr.o socket.o primitive.o \
14 output.o input.o debug.o stream.o auth.o \ 14 output.o input.o debug.o stream.o auth.o \
15 offload.o stream_sched.o stream_sched_prio.o 15 offload.o stream_sched.o stream_sched_prio.o \
16 stream_sched_rr.o
16 17
17sctp_probe-y := probe.o 18sctp_probe-y := probe.o
18 19
diff --git a/net/sctp/stream_sched.c b/net/sctp/stream_sched.c
index 115ddb765169..03513a9fa110 100644
--- a/net/sctp/stream_sched.c
+++ b/net/sctp/stream_sched.c
@@ -122,10 +122,12 @@ static struct sctp_sched_ops sctp_sched_fcfs = {
122/* API to other parts of the stack */ 122/* API to other parts of the stack */
123 123
124extern struct sctp_sched_ops sctp_sched_prio; 124extern struct sctp_sched_ops sctp_sched_prio;
125extern struct sctp_sched_ops sctp_sched_rr;
125 126
126struct sctp_sched_ops *sctp_sched_ops[] = { 127struct sctp_sched_ops *sctp_sched_ops[] = {
127 &sctp_sched_fcfs, 128 &sctp_sched_fcfs,
128 &sctp_sched_prio, 129 &sctp_sched_prio,
130 &sctp_sched_rr,
129}; 131};
130 132
131int sctp_sched_set_sched(struct sctp_association *asoc, 133int sctp_sched_set_sched(struct sctp_association *asoc,
diff --git a/net/sctp/stream_sched_rr.c b/net/sctp/stream_sched_rr.c
new file mode 100644
index 000000000000..7612a438c5b9
--- /dev/null
+++ b/net/sctp/stream_sched_rr.c
@@ -0,0 +1,201 @@
1/* SCTP kernel implementation
2 * (C) Copyright Red Hat Inc. 2017
3 *
4 * This file is part of the SCTP kernel implementation
5 *
6 * These functions manipulate sctp stream queue/scheduling.
7 *
8 * This SCTP implementation is free software;
9 * you can redistribute it and/or modify it under the terms of
10 * the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * This SCTP implementation is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * ************************
17 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 * See the GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with GNU CC; see the file COPYING. If not, see
22 * <http://www.gnu.org/licenses/>.
23 *
24 * Please send any bug reports or fixes you make to the
25 * email addresched(es):
26 * lksctp developers <linux-sctp@vger.kernel.org>
27 *
28 * Written or modified by:
29 * Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
30 */
31
32#include <linux/list.h>
33#include <net/sctp/sctp.h>
34#include <net/sctp/sm.h>
35#include <net/sctp/stream_sched.h>
36
37/* Priority handling
38 * RFC DRAFT ndata section 3.2
39 */
40static void sctp_sched_rr_unsched_all(struct sctp_stream *stream);
41
42static void sctp_sched_rr_next_stream(struct sctp_stream *stream)
43{
44 struct list_head *pos;
45
46 pos = stream->rr_next->rr_list.next;
47 if (pos == &stream->rr_list)
48 pos = pos->next;
49 stream->rr_next = list_entry(pos, struct sctp_stream_out_ext, rr_list);
50}
51
52static void sctp_sched_rr_unsched(struct sctp_stream *stream,
53 struct sctp_stream_out_ext *soute)
54{
55 if (stream->rr_next == soute)
56 /* Try to move to the next stream */
57 sctp_sched_rr_next_stream(stream);
58
59 list_del_init(&soute->rr_list);
60
61 /* If we have no other stream queued, clear next */
62 if (list_empty(&stream->rr_list))
63 stream->rr_next = NULL;
64}
65
66static void sctp_sched_rr_sched(struct sctp_stream *stream,
67 struct sctp_stream_out_ext *soute)
68{
69 if (!list_empty(&soute->rr_list))
70 /* Already scheduled. */
71 return;
72
73 /* Schedule the stream */
74 list_add_tail(&soute->rr_list, &stream->rr_list);
75
76 if (!stream->rr_next)
77 stream->rr_next = soute;
78}
79
80static int sctp_sched_rr_set(struct sctp_stream *stream, __u16 sid,
81 __u16 prio, gfp_t gfp)
82{
83 return 0;
84}
85
86static int sctp_sched_rr_get(struct sctp_stream *stream, __u16 sid,
87 __u16 *value)
88{
89 return 0;
90}
91
92static int sctp_sched_rr_init(struct sctp_stream *stream)
93{
94 INIT_LIST_HEAD(&stream->rr_list);
95 stream->rr_next = NULL;
96
97 return 0;
98}
99
100static int sctp_sched_rr_init_sid(struct sctp_stream *stream, __u16 sid,
101 gfp_t gfp)
102{
103 INIT_LIST_HEAD(&stream->out[sid].ext->rr_list);
104
105 return 0;
106}
107
108static void sctp_sched_rr_free(struct sctp_stream *stream)
109{
110 sctp_sched_rr_unsched_all(stream);
111}
112
113static void sctp_sched_rr_enqueue(struct sctp_outq *q,
114 struct sctp_datamsg *msg)
115{
116 struct sctp_stream *stream;
117 struct sctp_chunk *ch;
118 __u16 sid;
119
120 ch = list_first_entry(&msg->chunks, struct sctp_chunk, frag_list);
121 sid = sctp_chunk_stream_no(ch);
122 stream = &q->asoc->stream;
123 sctp_sched_rr_sched(stream, stream->out[sid].ext);
124}
125
126static struct sctp_chunk *sctp_sched_rr_dequeue(struct sctp_outq *q)
127{
128 struct sctp_stream *stream = &q->asoc->stream;
129 struct sctp_stream_out_ext *soute;
130 struct sctp_chunk *ch = NULL;
131
132 /* Bail out quickly if queue is empty */
133 if (list_empty(&q->out_chunk_list))
134 goto out;
135
136 /* Find which chunk is next */
137 if (stream->out_curr)
138 soute = stream->out_curr->ext;
139 else
140 soute = stream->rr_next;
141 ch = list_entry(soute->outq.next, struct sctp_chunk, stream_list);
142
143 sctp_sched_dequeue_common(q, ch);
144
145out:
146 return ch;
147}
148
149static void sctp_sched_rr_dequeue_done(struct sctp_outq *q,
150 struct sctp_chunk *ch)
151{
152 struct sctp_stream_out_ext *soute;
153 __u16 sid;
154
155 /* Last chunk on that msg, move to the next stream */
156 sid = sctp_chunk_stream_no(ch);
157 soute = q->asoc->stream.out[sid].ext;
158
159 sctp_sched_rr_next_stream(&q->asoc->stream);
160
161 if (list_empty(&soute->outq))
162 sctp_sched_rr_unsched(&q->asoc->stream, soute);
163}
164
165static void sctp_sched_rr_sched_all(struct sctp_stream *stream)
166{
167 struct sctp_association *asoc;
168 struct sctp_stream_out_ext *soute;
169 struct sctp_chunk *ch;
170
171 asoc = container_of(stream, struct sctp_association, stream);
172 list_for_each_entry(ch, &asoc->outqueue.out_chunk_list, list) {
173 __u16 sid;
174
175 sid = sctp_chunk_stream_no(ch);
176 soute = stream->out[sid].ext;
177 if (soute)
178 sctp_sched_rr_sched(stream, soute);
179 }
180}
181
182static void sctp_sched_rr_unsched_all(struct sctp_stream *stream)
183{
184 struct sctp_stream_out_ext *soute, *tmp;
185
186 list_for_each_entry_safe(soute, tmp, &stream->rr_list, rr_list)
187 sctp_sched_rr_unsched(stream, soute);
188}
189
190struct sctp_sched_ops sctp_sched_rr = {
191 .set = sctp_sched_rr_set,
192 .get = sctp_sched_rr_get,
193 .init = sctp_sched_rr_init,
194 .init_sid = sctp_sched_rr_init_sid,
195 .free = sctp_sched_rr_free,
196 .enqueue = sctp_sched_rr_enqueue,
197 .dequeue = sctp_sched_rr_dequeue,
198 .dequeue_done = sctp_sched_rr_dequeue_done,
199 .sched_all = sctp_sched_rr_sched_all,
200 .unsched_all = sctp_sched_rr_unsched_all,
201};