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 /* First Come First Serve (a.k.a. FIFO)
0023  * RFC DRAFT ndata Section 3.1
0024  */
0025 static int sctp_sched_fcfs_set(struct sctp_stream *stream, __u16 sid,
0026                    __u16 value, gfp_t gfp)
0027 {
0028     return 0;
0029 }
0030 
0031 static int sctp_sched_fcfs_get(struct sctp_stream *stream, __u16 sid,
0032                    __u16 *value)
0033 {
0034     *value = 0;
0035     return 0;
0036 }
0037 
0038 static int sctp_sched_fcfs_init(struct sctp_stream *stream)
0039 {
0040     return 0;
0041 }
0042 
0043 static int sctp_sched_fcfs_init_sid(struct sctp_stream *stream, __u16 sid,
0044                     gfp_t gfp)
0045 {
0046     return 0;
0047 }
0048 
0049 static void sctp_sched_fcfs_free(struct sctp_stream *stream)
0050 {
0051 }
0052 
0053 static void sctp_sched_fcfs_enqueue(struct sctp_outq *q,
0054                     struct sctp_datamsg *msg)
0055 {
0056 }
0057 
0058 static struct sctp_chunk *sctp_sched_fcfs_dequeue(struct sctp_outq *q)
0059 {
0060     struct sctp_stream *stream = &q->asoc->stream;
0061     struct sctp_chunk *ch = NULL;
0062     struct list_head *entry;
0063 
0064     if (list_empty(&q->out_chunk_list))
0065         goto out;
0066 
0067     if (stream->out_curr) {
0068         ch = list_entry(stream->out_curr->ext->outq.next,
0069                 struct sctp_chunk, stream_list);
0070     } else {
0071         entry = q->out_chunk_list.next;
0072         ch = list_entry(entry, struct sctp_chunk, list);
0073     }
0074 
0075     sctp_sched_dequeue_common(q, ch);
0076 
0077 out:
0078     return ch;
0079 }
0080 
0081 static void sctp_sched_fcfs_dequeue_done(struct sctp_outq *q,
0082                      struct sctp_chunk *chunk)
0083 {
0084 }
0085 
0086 static void sctp_sched_fcfs_sched_all(struct sctp_stream *stream)
0087 {
0088 }
0089 
0090 static void sctp_sched_fcfs_unsched_all(struct sctp_stream *stream)
0091 {
0092 }
0093 
0094 static struct sctp_sched_ops sctp_sched_fcfs = {
0095     .set = sctp_sched_fcfs_set,
0096     .get = sctp_sched_fcfs_get,
0097     .init = sctp_sched_fcfs_init,
0098     .init_sid = sctp_sched_fcfs_init_sid,
0099     .free = sctp_sched_fcfs_free,
0100     .enqueue = sctp_sched_fcfs_enqueue,
0101     .dequeue = sctp_sched_fcfs_dequeue,
0102     .dequeue_done = sctp_sched_fcfs_dequeue_done,
0103     .sched_all = sctp_sched_fcfs_sched_all,
0104     .unsched_all = sctp_sched_fcfs_unsched_all,
0105 };
0106 
0107 static void sctp_sched_ops_fcfs_init(void)
0108 {
0109     sctp_sched_ops_register(SCTP_SS_FCFS, &sctp_sched_fcfs);
0110 }
0111 
0112 /* API to other parts of the stack */
0113 
0114 static struct sctp_sched_ops *sctp_sched_ops[SCTP_SS_MAX + 1];
0115 
0116 void sctp_sched_ops_register(enum sctp_sched_type sched,
0117                  struct sctp_sched_ops *sched_ops)
0118 {
0119     sctp_sched_ops[sched] = sched_ops;
0120 }
0121 
0122 void sctp_sched_ops_init(void)
0123 {
0124     sctp_sched_ops_fcfs_init();
0125     sctp_sched_ops_prio_init();
0126     sctp_sched_ops_rr_init();
0127 }
0128 
0129 int sctp_sched_set_sched(struct sctp_association *asoc,
0130              enum sctp_sched_type sched)
0131 {
0132     struct sctp_sched_ops *n = sctp_sched_ops[sched];
0133     struct sctp_sched_ops *old = asoc->outqueue.sched;
0134     struct sctp_datamsg *msg = NULL;
0135     struct sctp_chunk *ch;
0136     int i, ret = 0;
0137 
0138     if (old == n)
0139         return ret;
0140 
0141     if (sched > SCTP_SS_MAX)
0142         return -EINVAL;
0143 
0144     if (old) {
0145         old->free(&asoc->stream);
0146 
0147         /* Give the next scheduler a clean slate. */
0148         for (i = 0; i < asoc->stream.outcnt; i++) {
0149             struct sctp_stream_out_ext *ext = SCTP_SO(&asoc->stream, i)->ext;
0150 
0151             if (!ext)
0152                 continue;
0153             memset_after(ext, 0, outq);
0154         }
0155     }
0156 
0157     asoc->outqueue.sched = n;
0158     n->init(&asoc->stream);
0159     for (i = 0; i < asoc->stream.outcnt; i++) {
0160         if (!SCTP_SO(&asoc->stream, i)->ext)
0161             continue;
0162 
0163         ret = n->init_sid(&asoc->stream, i, GFP_ATOMIC);
0164         if (ret)
0165             goto err;
0166     }
0167 
0168     /* We have to requeue all chunks already queued. */
0169     list_for_each_entry(ch, &asoc->outqueue.out_chunk_list, list) {
0170         if (ch->msg == msg)
0171             continue;
0172         msg = ch->msg;
0173         n->enqueue(&asoc->outqueue, msg);
0174     }
0175 
0176     return ret;
0177 
0178 err:
0179     n->free(&asoc->stream);
0180     asoc->outqueue.sched = &sctp_sched_fcfs; /* Always safe */
0181 
0182     return ret;
0183 }
0184 
0185 int sctp_sched_get_sched(struct sctp_association *asoc)
0186 {
0187     int i;
0188 
0189     for (i = 0; i <= SCTP_SS_MAX; i++)
0190         if (asoc->outqueue.sched == sctp_sched_ops[i])
0191             return i;
0192 
0193     return 0;
0194 }
0195 
0196 int sctp_sched_set_value(struct sctp_association *asoc, __u16 sid,
0197              __u16 value, gfp_t gfp)
0198 {
0199     if (sid >= asoc->stream.outcnt)
0200         return -EINVAL;
0201 
0202     if (!SCTP_SO(&asoc->stream, sid)->ext) {
0203         int ret;
0204 
0205         ret = sctp_stream_init_ext(&asoc->stream, sid);
0206         if (ret)
0207             return ret;
0208     }
0209 
0210     return asoc->outqueue.sched->set(&asoc->stream, sid, value, gfp);
0211 }
0212 
0213 int sctp_sched_get_value(struct sctp_association *asoc, __u16 sid,
0214              __u16 *value)
0215 {
0216     if (sid >= asoc->stream.outcnt)
0217         return -EINVAL;
0218 
0219     if (!SCTP_SO(&asoc->stream, sid)->ext)
0220         return 0;
0221 
0222     return asoc->outqueue.sched->get(&asoc->stream, sid, value);
0223 }
0224 
0225 void sctp_sched_dequeue_done(struct sctp_outq *q, struct sctp_chunk *ch)
0226 {
0227     if (!list_is_last(&ch->frag_list, &ch->msg->chunks) &&
0228         !q->asoc->peer.intl_capable) {
0229         struct sctp_stream_out *sout;
0230         __u16 sid;
0231 
0232         /* datamsg is not finish, so save it as current one,
0233          * in case application switch scheduler or a higher
0234          * priority stream comes in.
0235          */
0236         sid = sctp_chunk_stream_no(ch);
0237         sout = SCTP_SO(&q->asoc->stream, sid);
0238         q->asoc->stream.out_curr = sout;
0239         return;
0240     }
0241 
0242     q->asoc->stream.out_curr = NULL;
0243     q->sched->dequeue_done(q, ch);
0244 }
0245 
0246 /* Auxiliary functions for the schedulers */
0247 void sctp_sched_dequeue_common(struct sctp_outq *q, struct sctp_chunk *ch)
0248 {
0249     list_del_init(&ch->list);
0250     list_del_init(&ch->stream_list);
0251     q->out_qlen -= ch->skb->len;
0252 }
0253 
0254 int sctp_sched_init_sid(struct sctp_stream *stream, __u16 sid, gfp_t gfp)
0255 {
0256     struct sctp_sched_ops *sched = sctp_sched_ops_from_stream(stream);
0257     struct sctp_stream_out_ext *ext = SCTP_SO(stream, sid)->ext;
0258 
0259     INIT_LIST_HEAD(&ext->outq);
0260     return sched->init_sid(stream, sid, gfp);
0261 }
0262 
0263 struct sctp_sched_ops *sctp_sched_ops_from_stream(struct sctp_stream *stream)
0264 {
0265     struct sctp_association *asoc;
0266 
0267     asoc = container_of(stream, struct sctp_association, stream);
0268 
0269     return asoc->outqueue.sched;
0270 }