Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /* SCTP kernel implementation
0003  * (C) Copyright Red Hat Inc. 2017
0004  *
0005  * This file is part of the SCTP kernel implementation
0006  *
0007  * These functions manipulate sctp stream queue/scheduling.
0008  *
0009  * Please send any bug reports or fixes you make to the
0010  * email addresched(es):
0011  *    lksctp developers <linux-sctp@vger.kernel.org>
0012  *
0013  * Written or modified by:
0014  *    Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
0015  */
0016 
0017 #include <linux/list.h>
0018 #include <net/sctp/sctp.h>
0019 #include <net/sctp/sm.h>
0020 #include <net/sctp/stream_sched.h>
0021 
0022 /* Priority handling
0023  * RFC DRAFT ndata section 3.2
0024  */
0025 static void sctp_sched_rr_unsched_all(struct sctp_stream *stream);
0026 
0027 static void sctp_sched_rr_next_stream(struct sctp_stream *stream)
0028 {
0029     struct list_head *pos;
0030 
0031     pos = stream->rr_next->rr_list.next;
0032     if (pos == &stream->rr_list)
0033         pos = pos->next;
0034     stream->rr_next = list_entry(pos, struct sctp_stream_out_ext, rr_list);
0035 }
0036 
0037 static void sctp_sched_rr_unsched(struct sctp_stream *stream,
0038                   struct sctp_stream_out_ext *soute)
0039 {
0040     if (stream->rr_next == soute)
0041         /* Try to move to the next stream */
0042         sctp_sched_rr_next_stream(stream);
0043 
0044     list_del_init(&soute->rr_list);
0045 
0046     /* If we have no other stream queued, clear next */
0047     if (list_empty(&stream->rr_list))
0048         stream->rr_next = NULL;
0049 }
0050 
0051 static void sctp_sched_rr_sched(struct sctp_stream *stream,
0052                 struct sctp_stream_out_ext *soute)
0053 {
0054     if (!list_empty(&soute->rr_list))
0055         /* Already scheduled. */
0056         return;
0057 
0058     /* Schedule the stream */
0059     list_add_tail(&soute->rr_list, &stream->rr_list);
0060 
0061     if (!stream->rr_next)
0062         stream->rr_next = soute;
0063 }
0064 
0065 static int sctp_sched_rr_set(struct sctp_stream *stream, __u16 sid,
0066                  __u16 prio, gfp_t gfp)
0067 {
0068     return 0;
0069 }
0070 
0071 static int sctp_sched_rr_get(struct sctp_stream *stream, __u16 sid,
0072                  __u16 *value)
0073 {
0074     return 0;
0075 }
0076 
0077 static int sctp_sched_rr_init(struct sctp_stream *stream)
0078 {
0079     INIT_LIST_HEAD(&stream->rr_list);
0080     stream->rr_next = NULL;
0081 
0082     return 0;
0083 }
0084 
0085 static int sctp_sched_rr_init_sid(struct sctp_stream *stream, __u16 sid,
0086                   gfp_t gfp)
0087 {
0088     INIT_LIST_HEAD(&SCTP_SO(stream, sid)->ext->rr_list);
0089 
0090     return 0;
0091 }
0092 
0093 static void sctp_sched_rr_free(struct sctp_stream *stream)
0094 {
0095     sctp_sched_rr_unsched_all(stream);
0096 }
0097 
0098 static void sctp_sched_rr_enqueue(struct sctp_outq *q,
0099                   struct sctp_datamsg *msg)
0100 {
0101     struct sctp_stream *stream;
0102     struct sctp_chunk *ch;
0103     __u16 sid;
0104 
0105     ch = list_first_entry(&msg->chunks, struct sctp_chunk, frag_list);
0106     sid = sctp_chunk_stream_no(ch);
0107     stream = &q->asoc->stream;
0108     sctp_sched_rr_sched(stream, SCTP_SO(stream, sid)->ext);
0109 }
0110 
0111 static struct sctp_chunk *sctp_sched_rr_dequeue(struct sctp_outq *q)
0112 {
0113     struct sctp_stream *stream = &q->asoc->stream;
0114     struct sctp_stream_out_ext *soute;
0115     struct sctp_chunk *ch = NULL;
0116 
0117     /* Bail out quickly if queue is empty */
0118     if (list_empty(&q->out_chunk_list))
0119         goto out;
0120 
0121     /* Find which chunk is next */
0122     if (stream->out_curr)
0123         soute = stream->out_curr->ext;
0124     else
0125         soute = stream->rr_next;
0126     ch = list_entry(soute->outq.next, struct sctp_chunk, stream_list);
0127 
0128     sctp_sched_dequeue_common(q, ch);
0129 
0130 out:
0131     return ch;
0132 }
0133 
0134 static void sctp_sched_rr_dequeue_done(struct sctp_outq *q,
0135                        struct sctp_chunk *ch)
0136 {
0137     struct sctp_stream_out_ext *soute;
0138     __u16 sid;
0139 
0140     /* Last chunk on that msg, move to the next stream */
0141     sid = sctp_chunk_stream_no(ch);
0142     soute = SCTP_SO(&q->asoc->stream, sid)->ext;
0143 
0144     sctp_sched_rr_next_stream(&q->asoc->stream);
0145 
0146     if (list_empty(&soute->outq))
0147         sctp_sched_rr_unsched(&q->asoc->stream, soute);
0148 }
0149 
0150 static void sctp_sched_rr_sched_all(struct sctp_stream *stream)
0151 {
0152     struct sctp_association *asoc;
0153     struct sctp_stream_out_ext *soute;
0154     struct sctp_chunk *ch;
0155 
0156     asoc = container_of(stream, struct sctp_association, stream);
0157     list_for_each_entry(ch, &asoc->outqueue.out_chunk_list, list) {
0158         __u16 sid;
0159 
0160         sid = sctp_chunk_stream_no(ch);
0161         soute = SCTP_SO(stream, sid)->ext;
0162         if (soute)
0163             sctp_sched_rr_sched(stream, soute);
0164     }
0165 }
0166 
0167 static void sctp_sched_rr_unsched_all(struct sctp_stream *stream)
0168 {
0169     struct sctp_stream_out_ext *soute, *tmp;
0170 
0171     list_for_each_entry_safe(soute, tmp, &stream->rr_list, rr_list)
0172         sctp_sched_rr_unsched(stream, soute);
0173 }
0174 
0175 static struct sctp_sched_ops sctp_sched_rr = {
0176     .set = sctp_sched_rr_set,
0177     .get = sctp_sched_rr_get,
0178     .init = sctp_sched_rr_init,
0179     .init_sid = sctp_sched_rr_init_sid,
0180     .free = sctp_sched_rr_free,
0181     .enqueue = sctp_sched_rr_enqueue,
0182     .dequeue = sctp_sched_rr_dequeue,
0183     .dequeue_done = sctp_sched_rr_dequeue_done,
0184     .sched_all = sctp_sched_rr_sched_all,
0185     .unsched_all = sctp_sched_rr_unsched_all,
0186 };
0187 
0188 void sctp_sched_ops_rr_init(void)
0189 {
0190     sctp_sched_ops_register(SCTP_SS_RR, &sctp_sched_rr);
0191 }