[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <AANLkTimanFQ-gbcqNnygBvuQiFUk0SJrKFxjiOEAlesi@mail.gmail.com>
Date: Wed, 2 Jun 2010 22:42:25 -0700
From: Yaogong Wang <ywang15@...u.edu>
To: linux-sctp@...r.kernel.org,
Vlad Yasevich <vladislav.yasevich@...com>,
Sridhar Samudrala <sri@...ibm.com>
Cc: linux-kernel@...r.kernel.org
Subject: [PATCH 2/6] sctp multistream scheduling: provide pluggable SCTP
scheduling framework
Provide a general interface for implementing new SCTP multistream
scheduling algorithms as kernel modules.
Signed-off-by: Yaogong Wang <ywang15@...u.edu>
---
diff -uprN -X linux-2.6.32.8/Documentation/dontdiff
p1/include/net/sctp/structs.h p2/include/net/sctp/structs.h
--- p1/include/net/sctp/structs.h 2010-05-28 10:33:12.000000000 -0700
+++ p2/include/net/sctp/structs.h 2010-06-02 13:02:14.000000000 -0700
@@ -1158,7 +1158,7 @@ struct sctp_outq {
struct sctp_association *asoc;
/* Data pending that has never been transmitted. */
- struct list_head out_chunk_list;
+ struct list_head *out_chunk_list;
unsigned out_qlen; /* Total length of queued data chunks. */
@@ -1199,7 +1199,7 @@ struct sctp_outq {
char malloced;
};
-void sctp_outq_init(struct sctp_association *, struct sctp_outq *);
+int sctp_outq_init(struct sctp_association *, struct sctp_outq *, gfp_t gfp);
void sctp_outq_teardown(struct sctp_outq *);
void sctp_outq_free(struct sctp_outq*);
int sctp_outq_tail(struct sctp_outq *, struct sctp_chunk *chunk);
diff -uprN -X linux-2.6.32.8/Documentation/dontdiff
p1/net/sctp/Makefile p2/net/sctp/Makefile
--- p1/net/sctp/Makefile 2010-05-28 10:05:50.000000000 -0700
+++ p2/net/sctp/Makefile 2010-06-02 12:55:13.000000000 -0700
@@ -9,7 +9,7 @@ sctp-y := sm_statetable.o sm_statefuns.o
transport.o chunk.o sm_make_chunk.o ulpevent.o \
inqueue.o outqueue.o ulpqueue.o command.o \
tsnmap.o bind_addr.o socket.o primitive.o \
- output.o input.o debug.o ssnmap.o auth.o
+ output.o input.o debug.o ssnmap.o auth.o sched.o
sctp-$(CONFIG_SCTP_DBG_OBJCNT) += objcnt.o
sctp-$(CONFIG_PROC_FS) += proc.o
diff -uprN -X linux-2.6.32.8/Documentation/dontdiff
p1/net/sctp/associola.c p2/net/sctp/associola.c
--- p1/net/sctp/associola.c 2010-05-28 10:05:50.000000000 -0700
+++ p2/net/sctp/associola.c 2010-06-02 12:56:23.000000000 -0700
@@ -185,6 +185,9 @@ static struct sctp_association *sctp_ass
asoc->max_init_timeo =
msecs_to_jiffies(sp->initmsg.sinit_max_init_timeo);
+ /* Multistream scheduling */
+ asoc->sched_ops = sp->sched_ops;
+
/* Allocate storage for the ssnmap after the inbound and outbound
* streams have been negotiated during Init.
*/
@@ -280,7 +283,9 @@ static struct sctp_association *sctp_ass
sctp_inq_set_th_handler(&asoc->base.inqueue, sctp_assoc_bh_rcv);
/* Create an output queue. */
- sctp_outq_init(asoc, &asoc->outqueue);
+ err = sctp_outq_init(asoc, &asoc->outqueue, gfp);
+ if (err)
+ goto fail_init;
if (!sctp_ulpq_init(&asoc->ulpq, asoc))
goto fail_init;
diff -uprN -X linux-2.6.32.8/Documentation/dontdiff
p1/net/sctp/outqueue.c p2/net/sctp/outqueue.c
--- p1/net/sctp/outqueue.c 2010-05-28 10:05:50.000000000 -0700
+++ p2/net/sctp/outqueue.c 2010-06-02 12:55:13.000000000 -0700
@@ -73,38 +73,6 @@ static void sctp_generate_fwdtsn(struct
static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout);
-/* Add data to the front of the queue. */
-static inline void sctp_outq_head_data(struct sctp_outq *q,
- struct sctp_chunk *ch)
-{
- list_add(&ch->list, &q->out_chunk_list);
- q->out_qlen += ch->skb->len;
- return;
-}
-
-/* Take data from the front of the queue. */
-static inline struct sctp_chunk *sctp_outq_dequeue_data(struct sctp_outq *q)
-{
- struct sctp_chunk *ch = NULL;
-
- if (!list_empty(&q->out_chunk_list)) {
- struct list_head *entry = q->out_chunk_list.next;
-
- ch = list_entry(entry, struct sctp_chunk, list);
- list_del_init(entry);
- q->out_qlen -= ch->skb->len;
- }
- return ch;
-}
-/* Add data chunk to the end of the queue. */
-static inline void sctp_outq_tail_data(struct sctp_outq *q,
- struct sctp_chunk *ch)
-{
- list_add_tail(&ch->list, &q->out_chunk_list);
- q->out_qlen += ch->skb->len;
- return;
-}
-
/*
* SFR-CACC algorithm:
* D) If count_of_newacks is greater than or equal to 2
@@ -201,10 +169,15 @@ static inline int sctp_cacc_skip(struct
* You still need to define handlers if you really want to DO
* something with this structure...
*/
-void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
+int sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q,
+ gfp_t gfp)
{
- q->asoc = asoc;
- INIT_LIST_HEAD(&q->out_chunk_list);
+ int err = 0;
+
+ q->asoc = asoc;
+ err = q->asoc->sched_ops->init(q, gfp);
+ if (err)
+ goto fail_init;
INIT_LIST_HEAD(&q->control_chunk_list);
INIT_LIST_HEAD(&q->retransmit);
INIT_LIST_HEAD(&q->sacked);
@@ -217,6 +190,9 @@ void sctp_outq_init(struct sctp_associat
q->malloced = 0;
q->out_qlen = 0;
+
+fail_init:
+ return err;
}
/* Free the outqueue structure and any related pending chunks.
@@ -267,7 +243,7 @@ void sctp_outq_teardown(struct sctp_outq
}
/* Throw away any leftover data chunks. */
- while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
+ while ((chunk = q->asoc->sched_ops->dequeue_data(q)) != NULL) {
/* Mark as send failure. */
sctp_chunk_fail(chunk, q->error);
@@ -289,6 +265,8 @@ void sctp_outq_free(struct sctp_outq *q)
/* Throw away leftover chunks. */
sctp_outq_teardown(q);
+ q->asoc->sched_ops->release(q);
+
/* If we were kmalloc()'d, free the memory. */
if (q->malloced)
kfree(q);
@@ -334,7 +312,7 @@ int sctp_outq_tail(struct sctp_outq *q,
sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type))
: "Illegal Chunk");
- sctp_outq_tail_data(q, chunk);
+ q->asoc->sched_ops->enqueue_tail_data(q, chunk);
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
SCTP_INC_STATS(SCTP_MIB_OUTUNORDERCHUNKS);
else
@@ -922,7 +900,7 @@ static int sctp_outq_flush(struct sctp_o
}
/* Finally, transmit new packets. */
- while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
+ while ((chunk = q->asoc->sched_ops->dequeue_data(q)) != NULL) {
/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
* stream identifier.
*/
@@ -996,7 +974,7 @@ static int sctp_outq_flush(struct sctp_o
"not transmit TSN: 0x%x, status: %d\n",
ntohl(chunk->subh.data_hdr->tsn),
status);
- sctp_outq_head_data(q, chunk);
+ q->asoc->sched_ops->enqueue_head_data(q, chunk);
goto sctp_flush_out;
break;
@@ -1252,7 +1230,7 @@ int sctp_outq_sack(struct sctp_outq *q,
/* See if all chunks are acked.
* Make sure the empty queue handler will get run later.
*/
- q->empty = (list_empty(&q->out_chunk_list) &&
+ q->empty = (q->asoc->sched_ops->is_empty(q) &&
list_empty(&q->retransmit));
if (!q->empty)
goto finish;
diff -uprN -X linux-2.6.32.8/Documentation/dontdiff
p1/net/sctp/sched.c p2/net/sctp/sched.c
--- p1/net/sctp/sched.c 1969-12-31 16:00:00.000000000 -0800
+++ p2/net/sctp/sched.c 2010-06-02 12:59:40.000000000 -0700
@@ -0,0 +1,116 @@
+/*
+ * Plugable SCTP scheduling support and FCFS
+ * Based on ideas from pluggable TCP congestion control.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <net/sctp/sctp.h>
+
+static DEFINE_SPINLOCK(sctp_sched_list_lock);
+static LIST_HEAD(sctp_sched_list);
+
+/* Simple linear search, don't expect many entries! */
+static struct sctp_sched_ops *sctp_sched_find(const char *name)
+{
+ struct sctp_sched_ops *e;
+
+ list_for_each_entry_rcu(e, &sctp_sched_list, list) {
+ if (strcmp(e->name, name) == 0)
+ return e;
+ }
+
+ return NULL;
+}
+
+/*
+ * Attach new scheduling algorithm to the list
+ * of available options.
+ */
+int sctp_register_sched(struct sctp_sched_ops *sched)
+{
+ int ret = 0;
+
+ /* all algorithms must implement enqueue and dequeue ops */
+ if (!sched->init || !sched->release || !sched->is_empty
+ || !sched->enqueue_head_data || !sched->enqueue_tail_data
+ || !sched->dequeue_data) {
+ printk(KERN_ERR "SCTP %s does not implement required ops\n",
+ sched->name);
+ return -EINVAL;
+ }
+
+ spin_lock(&sctp_sched_list_lock);
+ if (sctp_sched_find(sched->name)) {
+ printk(KERN_NOTICE "SCTP %s already registered\n", sched->name);
+ ret = -EEXIST;
+ } else {
+ list_add_tail_rcu(&sched->list, &sctp_sched_list);
+ printk(KERN_INFO "SCTP %s registered\n", sched->name);
+ }
+ spin_unlock(&sctp_sched_list_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sctp_register_sched);
+
+/*
+ * Remove scheduling algorithm, called from
+ * the module's remove function. Module ref counts are used
+ * to ensure that this can't be done till all sockets using
+ * that method are closed.
+ */
+void sctp_unregister_sched(struct sctp_sched_ops *sched)
+{
+ spin_lock(&sctp_sched_list_lock);
+ list_del_rcu(&sched->list);
+ spin_unlock(&sctp_sched_list_lock);
+}
+EXPORT_SYMBOL_GPL(sctp_unregister_sched);
+
+/* Manage refcounts on socket close. */
+void sctp_cleanup_sched(struct sock *sk)
+{
+ module_put(sctp_sk(sk)->sched_ops->owner);
+}
+
+/* Change scheduling algorithm for socket */
+int sctp_set_sched(struct sock *sk, const char *name)
+{
+ struct sctp_sock *sp = sctp_sk(sk);
+ struct sctp_sched_ops *sched;
+ int err = 0;
+
+ rcu_read_lock();
+ sched = sctp_sched_find(name);
+
+ /* no change asking for existing value */
+ if (sched == sp->sched_ops)
+ goto out;
+
+#ifdef CONFIG_MODULES
+ /* not found attempt to autoload module */
+ if (!sched && capable(CAP_NET_ADMIN)) {
+ rcu_read_unlock();
+ request_module("sctp_%s", name);
+ rcu_read_lock();
+ sched = sctp_sched_find(name);
+ }
+#endif
+ if (!sched)
+ err = -ENOENT;
+
+ else if (!try_module_get(sched->owner))
+ err = -EBUSY;
+
+ else {
+ sctp_cleanup_sched(sk);
+ sp->sched_ops = sched;
+ }
+out:
+ rcu_read_unlock();
+ return err;
+}
+
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists