1 /* SCTP kernel implementation
2 * (C) Copyright Red Hat Inc. 2017
4 * This file is part of the SCTP kernel implementation
6 * These functions manipulate sctp stream queue/scheduling.
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)
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.
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/>.
24 * Please send any bug reports or fixes you make to the
25 * email addresched(es):
26 * lksctp developers <linux-sctp@vger.kernel.org>
28 * Written or modified by:
29 * Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
32 #include <linux/list.h>
33 #include <net/sctp/sctp.h>
34 #include <net/sctp/sm.h>
35 #include <net/sctp/stream_sched.h>
38 * RFC DRAFT ndata section 3.2
40 static void sctp_sched_rr_unsched_all(struct sctp_stream
*stream
);
42 static void sctp_sched_rr_next_stream(struct sctp_stream
*stream
)
44 struct list_head
*pos
;
46 pos
= stream
->rr_next
->rr_list
.next
;
47 if (pos
== &stream
->rr_list
)
49 stream
->rr_next
= list_entry(pos
, struct sctp_stream_out_ext
, rr_list
);
52 static void sctp_sched_rr_unsched(struct sctp_stream
*stream
,
53 struct sctp_stream_out_ext
*soute
)
55 if (stream
->rr_next
== soute
)
56 /* Try to move to the next stream */
57 sctp_sched_rr_next_stream(stream
);
59 list_del_init(&soute
->rr_list
);
61 /* If we have no other stream queued, clear next */
62 if (list_empty(&stream
->rr_list
))
63 stream
->rr_next
= NULL
;
66 static void sctp_sched_rr_sched(struct sctp_stream
*stream
,
67 struct sctp_stream_out_ext
*soute
)
69 if (!list_empty(&soute
->rr_list
))
70 /* Already scheduled. */
73 /* Schedule the stream */
74 list_add_tail(&soute
->rr_list
, &stream
->rr_list
);
77 stream
->rr_next
= soute
;
80 static int sctp_sched_rr_set(struct sctp_stream
*stream
, __u16 sid
,
81 __u16 prio
, gfp_t gfp
)
86 static int sctp_sched_rr_get(struct sctp_stream
*stream
, __u16 sid
,
92 static int sctp_sched_rr_init(struct sctp_stream
*stream
)
94 INIT_LIST_HEAD(&stream
->rr_list
);
95 stream
->rr_next
= NULL
;
100 static int sctp_sched_rr_init_sid(struct sctp_stream
*stream
, __u16 sid
,
103 INIT_LIST_HEAD(&stream
->out
[sid
].ext
->rr_list
);
108 static void sctp_sched_rr_free(struct sctp_stream
*stream
)
110 sctp_sched_rr_unsched_all(stream
);
113 static void sctp_sched_rr_enqueue(struct sctp_outq
*q
,
114 struct sctp_datamsg
*msg
)
116 struct sctp_stream
*stream
;
117 struct sctp_chunk
*ch
;
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
);
126 static struct sctp_chunk
*sctp_sched_rr_dequeue(struct sctp_outq
*q
)
128 struct sctp_stream
*stream
= &q
->asoc
->stream
;
129 struct sctp_stream_out_ext
*soute
;
130 struct sctp_chunk
*ch
= NULL
;
132 /* Bail out quickly if queue is empty */
133 if (list_empty(&q
->out_chunk_list
))
136 /* Find which chunk is next */
137 if (stream
->out_curr
)
138 soute
= stream
->out_curr
->ext
;
140 soute
= stream
->rr_next
;
141 ch
= list_entry(soute
->outq
.next
, struct sctp_chunk
, stream_list
);
143 sctp_sched_dequeue_common(q
, ch
);
149 static void sctp_sched_rr_dequeue_done(struct sctp_outq
*q
,
150 struct sctp_chunk
*ch
)
152 struct sctp_stream_out_ext
*soute
;
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
;
159 sctp_sched_rr_next_stream(&q
->asoc
->stream
);
161 if (list_empty(&soute
->outq
))
162 sctp_sched_rr_unsched(&q
->asoc
->stream
, soute
);
165 static void sctp_sched_rr_sched_all(struct sctp_stream
*stream
)
167 struct sctp_association
*asoc
;
168 struct sctp_stream_out_ext
*soute
;
169 struct sctp_chunk
*ch
;
171 asoc
= container_of(stream
, struct sctp_association
, stream
);
172 list_for_each_entry(ch
, &asoc
->outqueue
.out_chunk_list
, list
) {
175 sid
= sctp_chunk_stream_no(ch
);
176 soute
= stream
->out
[sid
].ext
;
178 sctp_sched_rr_sched(stream
, soute
);
182 static void sctp_sched_rr_unsched_all(struct sctp_stream
*stream
)
184 struct sctp_stream_out_ext
*soute
, *tmp
;
186 list_for_each_entry_safe(soute
, tmp
, &stream
->rr_list
, rr_list
)
187 sctp_sched_rr_unsched(stream
, soute
);
190 static 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
,
203 void sctp_sched_ops_rr_init(void)
205 sctp_sched_ops_register(SCTP_SS_RR
, &sctp_sched_rr
);