Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753272Ab0FCFmc (ORCPT ); Thu, 3 Jun 2010 01:42:32 -0400 Received: from mail-pw0-f46.google.com ([209.85.160.46]:58115 "EHLO mail-pw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753019Ab0FCFm0 (ORCPT ); Thu, 3 Jun 2010 01:42:26 -0400 DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:sender:date:x-google-sender-auth:message-id:subject :from:to:cc:content-type; b=KsH81t6Rc/OkIKBrUDq+bjeIRlnY09MgX51xBq21JkTXidOHnuIviqRkJNBsw041+L oZSG3/mgpSeWmwSTFI/pa68TEg08HM/2CKdJh+/XtJn+C9cXeTKIWwkgC3irvvkakOcV lIksqGNRaVGTZMsH9RO+TzCFqIUeLDOLDRpzo= MIME-Version: 1.0 Date: Wed, 2 Jun 2010 22:42:25 -0700 X-Google-Sender-Auth: OVKATQO_ZqtpnnwIjoosVELH9pE Message-ID: Subject: [PATCH 2/6] sctp multistream scheduling: provide pluggable SCTP scheduling framework From: Yaogong Wang To: linux-sctp@vger.kernel.org, Vlad Yasevich , Sridhar Samudrala Cc: linux-kernel@vger.kernel.org Content-Type: text/plain; charset=ISO-8859-1 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 9727 Lines: 317 Provide a general interface for implementing new SCTP multistream scheduling algorithms as kernel modules. Signed-off-by: Yaogong Wang --- 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 +#include +#include +#include + +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@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/