1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* SCTP kernel implementation
3 * (C) Copyright Red Hat Inc. 2017
5 * This file is part of the SCTP kernel implementation
7 * These functions manipulate sctp stream queue/scheduling.
9 * Please send any bug reports or fixes you make to the
10 * email addresched(es):
11 * lksctp developers <linux-sctp@vger.kernel.org>
13 * Written or modified by:
14 * Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
17 #include <linux/list.h>
18 #include <net/sctp/sctp.h>
19 #include <net/sctp/sm.h>
20 #include <net/sctp/stream_sched.h>
23 * RFC DRAFT ndata section 3.2
25 static void sctp_sched_rr_unsched_all(struct sctp_stream
*stream
);
27 static void sctp_sched_rr_next_stream(struct sctp_stream
*stream
)
29 struct list_head
*pos
;
31 pos
= stream
->rr_next
->rr_list
.next
;
32 if (pos
== &stream
->rr_list
)
34 stream
->rr_next
= list_entry(pos
, struct sctp_stream_out_ext
, rr_list
);
37 static void sctp_sched_rr_unsched(struct sctp_stream
*stream
,
38 struct sctp_stream_out_ext
*soute
)
40 if (stream
->rr_next
== soute
)
41 /* Try to move to the next stream */
42 sctp_sched_rr_next_stream(stream
);
44 list_del_init(&soute
->rr_list
);
46 /* If we have no other stream queued, clear next */
47 if (list_empty(&stream
->rr_list
))
48 stream
->rr_next
= NULL
;
51 static void sctp_sched_rr_sched(struct sctp_stream
*stream
,
52 struct sctp_stream_out_ext
*soute
)
54 if (!list_empty(&soute
->rr_list
))
55 /* Already scheduled. */
58 /* Schedule the stream */
59 list_add_tail(&soute
->rr_list
, &stream
->rr_list
);
62 stream
->rr_next
= soute
;
65 static int sctp_sched_rr_set(struct sctp_stream
*stream
, __u16 sid
,
66 __u16 prio
, gfp_t gfp
)
71 static int sctp_sched_rr_get(struct sctp_stream
*stream
, __u16 sid
,
77 static int sctp_sched_rr_init(struct sctp_stream
*stream
)
79 INIT_LIST_HEAD(&stream
->rr_list
);
80 stream
->rr_next
= NULL
;
85 static int sctp_sched_rr_init_sid(struct sctp_stream
*stream
, __u16 sid
,
88 INIT_LIST_HEAD(&SCTP_SO(stream
, sid
)->ext
->rr_list
);
93 static void sctp_sched_rr_free(struct sctp_stream
*stream
)
95 sctp_sched_rr_unsched_all(stream
);
98 static void sctp_sched_rr_enqueue(struct sctp_outq
*q
,
99 struct sctp_datamsg
*msg
)
101 struct sctp_stream
*stream
;
102 struct sctp_chunk
*ch
;
105 ch
= list_first_entry(&msg
->chunks
, struct sctp_chunk
, frag_list
);
106 sid
= sctp_chunk_stream_no(ch
);
107 stream
= &q
->asoc
->stream
;
108 sctp_sched_rr_sched(stream
, SCTP_SO(stream
, sid
)->ext
);
111 static struct sctp_chunk
*sctp_sched_rr_dequeue(struct sctp_outq
*q
)
113 struct sctp_stream
*stream
= &q
->asoc
->stream
;
114 struct sctp_stream_out_ext
*soute
;
115 struct sctp_chunk
*ch
= NULL
;
117 /* Bail out quickly if queue is empty */
118 if (list_empty(&q
->out_chunk_list
))
121 /* Find which chunk is next */
122 if (stream
->out_curr
)
123 soute
= stream
->out_curr
->ext
;
125 soute
= stream
->rr_next
;
126 ch
= list_entry(soute
->outq
.next
, struct sctp_chunk
, stream_list
);
128 sctp_sched_dequeue_common(q
, ch
);
134 static void sctp_sched_rr_dequeue_done(struct sctp_outq
*q
,
135 struct sctp_chunk
*ch
)
137 struct sctp_stream_out_ext
*soute
;
140 /* Last chunk on that msg, move to the next stream */
141 sid
= sctp_chunk_stream_no(ch
);
142 soute
= SCTP_SO(&q
->asoc
->stream
, sid
)->ext
;
144 sctp_sched_rr_next_stream(&q
->asoc
->stream
);
146 if (list_empty(&soute
->outq
))
147 sctp_sched_rr_unsched(&q
->asoc
->stream
, soute
);
150 static void sctp_sched_rr_sched_all(struct sctp_stream
*stream
)
152 struct sctp_association
*asoc
;
153 struct sctp_stream_out_ext
*soute
;
154 struct sctp_chunk
*ch
;
156 asoc
= container_of(stream
, struct sctp_association
, stream
);
157 list_for_each_entry(ch
, &asoc
->outqueue
.out_chunk_list
, list
) {
160 sid
= sctp_chunk_stream_no(ch
);
161 soute
= SCTP_SO(stream
, sid
)->ext
;
163 sctp_sched_rr_sched(stream
, soute
);
167 static void sctp_sched_rr_unsched_all(struct sctp_stream
*stream
)
169 struct sctp_stream_out_ext
*soute
, *tmp
;
171 list_for_each_entry_safe(soute
, tmp
, &stream
->rr_list
, rr_list
)
172 sctp_sched_rr_unsched(stream
, soute
);
175 static struct sctp_sched_ops sctp_sched_rr
= {
176 .set
= sctp_sched_rr_set
,
177 .get
= sctp_sched_rr_get
,
178 .init
= sctp_sched_rr_init
,
179 .init_sid
= sctp_sched_rr_init_sid
,
180 .free
= sctp_sched_rr_free
,
181 .enqueue
= sctp_sched_rr_enqueue
,
182 .dequeue
= sctp_sched_rr_dequeue
,
183 .dequeue_done
= sctp_sched_rr_dequeue_done
,
184 .sched_all
= sctp_sched_rr_sched_all
,
185 .unsched_all
= sctp_sched_rr_unsched_all
,
188 void sctp_sched_ops_rr_init(void)
190 sctp_sched_ops_register(SCTP_SS_RR
, &sctp_sched_rr
);