Skip to content

Commit ac1ed8b

Browse files
marceloleitnerdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: Marcelo Ricardo Leitner <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 637784a commit ac1ed8b

File tree

5 files changed

+218
-2
lines changed

5 files changed

+218
-2
lines changed

include/net/sctp/structs.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,10 @@ struct sctp_stream_out_ext {
13481348
struct list_head prio_list;
13491349
struct sctp_stream_priorities *prio_head;
13501350
};
1351+
/* Fields used by RR scheduler */
1352+
struct {
1353+
struct list_head rr_list;
1354+
};
13511355
};
13521356
};
13531357

@@ -1374,6 +1378,13 @@ struct sctp_stream {
13741378
/* List of priorities scheduled */
13751379
struct list_head prio_list;
13761380
};
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+
};
13771388
};
13781389
};
13791390

include/uapi/linux/sctp.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1100,7 +1100,8 @@ struct sctp_add_streams {
11001100
enum sctp_sched_type {
11011101
SCTP_SS_FCFS,
11021102
SCTP_SS_PRIO,
1103-
SCTP_SS_MAX = SCTP_SS_PRIO
1103+
SCTP_SS_RR,
1104+
SCTP_SS_MAX = SCTP_SS_RR
11041105
};
11051106

11061107
#endif /* _UAPI_SCTP_H */

net/sctp/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
1212
inqueue.o outqueue.o ulpqueue.o \
1313
tsnmap.o bind_addr.o socket.o primitive.o \
1414
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
1617

1718
sctp_probe-y := probe.o
1819

net/sctp/stream_sched.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,10 +122,12 @@ static struct sctp_sched_ops sctp_sched_fcfs = {
122122
/* API to other parts of the stack */
123123

124124
extern struct sctp_sched_ops sctp_sched_prio;
125+
extern struct sctp_sched_ops sctp_sched_rr;
125126

126127
struct sctp_sched_ops *sctp_sched_ops[] = {
127128
&sctp_sched_fcfs,
128129
&sctp_sched_prio,
130+
&sctp_sched_rr,
129131
};
130132

131133
int sctp_sched_set_sched(struct sctp_association *asoc,

net/sctp/stream_sched_rr.c

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 <[email protected]>
27+
*
28+
* Written or modified by:
29+
* Marcelo Ricardo Leitner <[email protected]>
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+
*/
40+
static void sctp_sched_rr_unsched_all(struct sctp_stream *stream);
41+
42+
static 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+
52+
static 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+
66+
static 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+
80+
static int sctp_sched_rr_set(struct sctp_stream *stream, __u16 sid,
81+
__u16 prio, gfp_t gfp)
82+
{
83+
return 0;
84+
}
85+
86+
static int sctp_sched_rr_get(struct sctp_stream *stream, __u16 sid,
87+
__u16 *value)
88+
{
89+
return 0;
90+
}
91+
92+
static 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+
100+
static 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+
108+
static void sctp_sched_rr_free(struct sctp_stream *stream)
109+
{
110+
sctp_sched_rr_unsched_all(stream);
111+
}
112+
113+
static 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+
126+
static 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+
145+
out:
146+
return ch;
147+
}
148+
149+
static 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+
165+
static 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+
182+
static 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+
190+
struct 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+
};

0 commit comments

Comments
 (0)