~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/sctp/stream_sched_fc.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-or-later
  2 /* SCTP kernel implementation
  3  * (C) Copyright Red Hat Inc. 2022
  4  *
  5  * This file is part of the SCTP kernel implementation
  6  *
  7  * These functions manipulate sctp stream queue/scheduling.
  8  *
  9  * Please send any bug reports or fixes you make to the
 10  * email addresched(es):
 11  *    lksctp developers <linux-sctp@vger.kernel.org>
 12  *
 13  * Written or modified by:
 14  *    Xin Long <lucien.xin@gmail.com>
 15  */
 16 
 17 #include <linux/list.h>
 18 #include <net/sctp/sctp.h>
 19 #include <net/sctp/sm.h>
 20 #include <net/sctp/stream_sched.h>
 21 
 22 /* Fair Capacity and Weighted Fair Queueing handling
 23  * RFC 8260 section 3.5 and 3.6
 24  */
 25 static void sctp_sched_fc_unsched_all(struct sctp_stream *stream);
 26 
 27 static int sctp_sched_wfq_set(struct sctp_stream *stream, __u16 sid,
 28                               __u16 weight, gfp_t gfp)
 29 {
 30         struct sctp_stream_out_ext *soute = SCTP_SO(stream, sid)->ext;
 31 
 32         if (!weight)
 33                 return -EINVAL;
 34 
 35         soute->fc_weight = weight;
 36         return 0;
 37 }
 38 
 39 static int sctp_sched_wfq_get(struct sctp_stream *stream, __u16 sid,
 40                               __u16 *value)
 41 {
 42         struct sctp_stream_out_ext *soute = SCTP_SO(stream, sid)->ext;
 43 
 44         *value = soute->fc_weight;
 45         return 0;
 46 }
 47 
 48 static int sctp_sched_fc_set(struct sctp_stream *stream, __u16 sid,
 49                              __u16 weight, gfp_t gfp)
 50 {
 51         return 0;
 52 }
 53 
 54 static int sctp_sched_fc_get(struct sctp_stream *stream, __u16 sid,
 55                              __u16 *value)
 56 {
 57         return 0;
 58 }
 59 
 60 static int sctp_sched_fc_init(struct sctp_stream *stream)
 61 {
 62         INIT_LIST_HEAD(&stream->fc_list);
 63 
 64         return 0;
 65 }
 66 
 67 static int sctp_sched_fc_init_sid(struct sctp_stream *stream, __u16 sid,
 68                                   gfp_t gfp)
 69 {
 70         struct sctp_stream_out_ext *soute = SCTP_SO(stream, sid)->ext;
 71 
 72         INIT_LIST_HEAD(&soute->fc_list);
 73         soute->fc_length = 0;
 74         soute->fc_weight = 1;
 75 
 76         return 0;
 77 }
 78 
 79 static void sctp_sched_fc_free_sid(struct sctp_stream *stream, __u16 sid)
 80 {
 81 }
 82 
 83 static void sctp_sched_fc_sched(struct sctp_stream *stream,
 84                                 struct sctp_stream_out_ext *soute)
 85 {
 86         struct sctp_stream_out_ext *pos;
 87 
 88         if (!list_empty(&soute->fc_list))
 89                 return;
 90 
 91         list_for_each_entry(pos, &stream->fc_list, fc_list)
 92                 if ((__u64)pos->fc_length * soute->fc_weight >=
 93                     (__u64)soute->fc_length * pos->fc_weight)
 94                         break;
 95         list_add_tail(&soute->fc_list, &pos->fc_list);
 96 }
 97 
 98 static void sctp_sched_fc_enqueue(struct sctp_outq *q,
 99                                   struct sctp_datamsg *msg)
100 {
101         struct sctp_stream *stream;
102         struct sctp_chunk *ch;
103         __u16 sid;
104 
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_fc_sched(stream, SCTP_SO(stream, sid)->ext);
109 }
110 
111 static struct sctp_chunk *sctp_sched_fc_dequeue(struct sctp_outq *q)
112 {
113         struct sctp_stream *stream = &q->asoc->stream;
114         struct sctp_stream_out_ext *soute;
115         struct sctp_chunk *ch;
116 
117         /* Bail out quickly if queue is empty */
118         if (list_empty(&q->out_chunk_list))
119                 return NULL;
120 
121         /* Find which chunk is next */
122         if (stream->out_curr)
123                 soute = stream->out_curr->ext;
124         else
125                 soute = list_entry(stream->fc_list.next, struct sctp_stream_out_ext, fc_list);
126         ch = list_entry(soute->outq.next, struct sctp_chunk, stream_list);
127 
128         sctp_sched_dequeue_common(q, ch);
129         return ch;
130 }
131 
132 static void sctp_sched_fc_dequeue_done(struct sctp_outq *q,
133                                        struct sctp_chunk *ch)
134 {
135         struct sctp_stream *stream = &q->asoc->stream;
136         struct sctp_stream_out_ext *soute, *pos;
137         __u16 sid, i;
138 
139         sid = sctp_chunk_stream_no(ch);
140         soute = SCTP_SO(stream, sid)->ext;
141         /* reduce all fc_lengths by U32_MAX / 4 if the current fc_length overflows. */
142         if (soute->fc_length > U32_MAX - ch->skb->len) {
143                 for (i = 0; i < stream->outcnt; i++) {
144                         pos = SCTP_SO(stream, i)->ext;
145                         if (!pos)
146                                 continue;
147                         if (pos->fc_length <= (U32_MAX >> 2)) {
148                                 pos->fc_length = 0;
149                                 continue;
150                         }
151                         pos->fc_length -= (U32_MAX >> 2);
152                 }
153         }
154         soute->fc_length += ch->skb->len;
155 
156         if (list_empty(&soute->outq)) {
157                 list_del_init(&soute->fc_list);
158                 return;
159         }
160 
161         pos = soute;
162         list_for_each_entry_continue(pos, &stream->fc_list, fc_list)
163                 if ((__u64)pos->fc_length * soute->fc_weight >=
164                     (__u64)soute->fc_length * pos->fc_weight)
165                         break;
166         list_move_tail(&soute->fc_list, &pos->fc_list);
167 }
168 
169 static void sctp_sched_fc_sched_all(struct sctp_stream *stream)
170 {
171         struct sctp_association *asoc;
172         struct sctp_chunk *ch;
173 
174         asoc = container_of(stream, struct sctp_association, stream);
175         list_for_each_entry(ch, &asoc->outqueue.out_chunk_list, list) {
176                 __u16 sid = sctp_chunk_stream_no(ch);
177 
178                 if (SCTP_SO(stream, sid)->ext)
179                         sctp_sched_fc_sched(stream, SCTP_SO(stream, sid)->ext);
180         }
181 }
182 
183 static void sctp_sched_fc_unsched_all(struct sctp_stream *stream)
184 {
185         struct sctp_stream_out_ext *soute, *tmp;
186 
187         list_for_each_entry_safe(soute, tmp, &stream->fc_list, fc_list)
188                 list_del_init(&soute->fc_list);
189 }
190 
191 static struct sctp_sched_ops sctp_sched_fc = {
192         .set = sctp_sched_fc_set,
193         .get = sctp_sched_fc_get,
194         .init = sctp_sched_fc_init,
195         .init_sid = sctp_sched_fc_init_sid,
196         .free_sid = sctp_sched_fc_free_sid,
197         .enqueue = sctp_sched_fc_enqueue,
198         .dequeue = sctp_sched_fc_dequeue,
199         .dequeue_done = sctp_sched_fc_dequeue_done,
200         .sched_all = sctp_sched_fc_sched_all,
201         .unsched_all = sctp_sched_fc_unsched_all,
202 };
203 
204 void sctp_sched_ops_fc_init(void)
205 {
206         sctp_sched_ops_register(SCTP_SS_FC, &sctp_sched_fc);
207 }
208 
209 static struct sctp_sched_ops sctp_sched_wfq = {
210         .set = sctp_sched_wfq_set,
211         .get = sctp_sched_wfq_get,
212         .init = sctp_sched_fc_init,
213         .init_sid = sctp_sched_fc_init_sid,
214         .free_sid = sctp_sched_fc_free_sid,
215         .enqueue = sctp_sched_fc_enqueue,
216         .dequeue = sctp_sched_fc_dequeue,
217         .dequeue_done = sctp_sched_fc_dequeue_done,
218         .sched_all = sctp_sched_fc_sched_all,
219         .unsched_all = sctp_sched_fc_unsched_all,
220 };
221 
222 void sctp_sched_ops_wfq_init(void)
223 {
224         sctp_sched_ops_register(SCTP_SS_WFQ, &sctp_sched_wfq);
225 }
226 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php