aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Stewart <rrs@FreeBSD.org>2011-02-03 10:05:30 +0000
committerRandall Stewart <rrs@FreeBSD.org>2011-02-03 10:05:30 +0000
commitbfc46083b947607dbe5fcfee86dacc4cade9e743 (patch)
treef375c5a4b89f181396c6ef9e9820df7334aca5ec
parent7f6563d13c6223aae8d64a5a29a71e61de3d31ae (diff)
downloadsrc-bfc46083b947607dbe5fcfee86dacc4cade9e743.tar.gz
src-bfc46083b947607dbe5fcfee86dacc4cade9e743.zip
Adds an experimental option to create a pool of
threads. These serve as input threads and are queued packets based on the V-tag number. This is similar to what a modern card can do with queue's for TCP... but alas modern cards know nothing about SCTP. MFC after: 3 months (maybe)
Notes
Notes: svn path=/head/; revision=218211
-rw-r--r--sys/conf/options1
-rw-r--r--sys/netinet/sctp_bsd_addr.c1
-rw-r--r--sys/netinet/sctp_constants.h2
-rw-r--r--sys/netinet/sctp_input.c31
-rw-r--r--sys/netinet/sctp_lock_bsd.h42
-rw-r--r--sys/netinet/sctp_os_bsd.h1
-rw-r--r--sys/netinet/sctp_pcb.c149
-rw-r--r--sys/netinet/sctp_pcb.h6
-rw-r--r--sys/netinet/sctp_structs.h25
9 files changed, 254 insertions, 4 deletions
diff --git a/sys/conf/options b/sys/conf/options
index 440f89fdc539..b3d076f1e473 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -439,6 +439,7 @@ SCTP_PACKET_LOGGING opt_sctp.h # Log to a packet buffer last N packets
SCTP_LTRACE_CHUNKS opt_sctp.h # Log to KTR chunks processed
SCTP_LTRACE_ERRORS opt_sctp.h # Log to KTR error returns.
SCTP_USE_PERCPU_STAT opt_sctp.h # Use per cpu stats.
+SCTP_MCORE_INPUT opt_sctp.h # Have multiple input threads for input mbufs
#
#
#
diff --git a/sys/netinet/sctp_bsd_addr.c b/sys/netinet/sctp_bsd_addr.c
index 216a6d3eb239..7ce3c153ec21 100644
--- a/sys/netinet/sctp_bsd_addr.c
+++ b/sys/netinet/sctp_bsd_addr.c
@@ -68,6 +68,7 @@ MALLOC_DEFINE(SCTP_M_TIMW, "sctp_timw", "sctp time block");
MALLOC_DEFINE(SCTP_M_MVRF, "sctp_mvrf", "sctp mvrf pcb list");
MALLOC_DEFINE(SCTP_M_ITER, "sctp_iter", "sctp iterator control");
MALLOC_DEFINE(SCTP_M_SOCKOPT, "sctp_socko", "sctp socket option");
+MALLOC_DEFINE(SCTP_M_MCORE, "sctp_mcore", "sctp mcore queue");
/* Global NON-VNET structure that controls the iterator */
struct iterator_control sctp_it_ctl;
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index 02468da5a77a..e9e5080ab7ad 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -91,6 +91,8 @@ __FBSDID("$FreeBSD$");
#define SCTP_KTRHEAD_NAME "sctp_iterator"
#define SCTP_KTHREAD_PAGES 0
+#define SCTP_MCORE_NAME "sctp_core_worker"
+
/* If you support Multi-VRF how big to
* make the initial array of VRF's to.
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index dd6410af4612..e4a77095eebb 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_timer.h>
#include <netinet/sctp_crc32.h>
#include <netinet/udp.h>
+#include <sys/smp.h>
@@ -5921,10 +5922,32 @@ bad:
}
return;
}
+
+
void
-sctp_input(i_pak, off)
- struct mbuf *i_pak;
- int off;
+sctp_input(struct mbuf *m, int off)
{
- sctp_input_with_port(i_pak, off, 0);
+#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP)
+ struct ip *ip;
+ struct sctphdr *sh;
+ int offset;
+ int cpu_to_use;
+
+ if (mp_ncpus > 1) {
+ ip = mtod(m, struct ip *);
+ offset = off + sizeof(*sh);
+ if (SCTP_BUF_LEN(m) < offset) {
+ if ((m = m_pullup(m, offset)) == 0) {
+ SCTP_STAT_INCR(sctps_hdrops);
+ return;
+ }
+ ip = mtod(m, struct ip *);
+ }
+ sh = (struct sctphdr *)((caddr_t)ip + off);
+ cpu_to_use = ntohl(sh->v_tag) % mp_ncpus;
+ sctp_queue_to_mcore(m, off, cpu_to_use);
+ return;
+ }
+#endif
+ sctp_input_with_port(m, off, 0);
}
diff --git a/sys/netinet/sctp_lock_bsd.h b/sys/netinet/sctp_lock_bsd.h
index dd9c2ce57f73..99d0a33d7096 100644
--- a/sys/netinet/sctp_lock_bsd.h
+++ b/sys/netinet/sctp_lock_bsd.h
@@ -97,6 +97,48 @@ extern int sctp_logoff_stuff;
rw_rlock(&SCTP_BASE_INFO(ipi_ep_mtx)); \
} while (0)
+#define SCTP_MCORE_QLOCK_INIT(cpstr) do { \
+ mtx_init(&(cpstr)->que_mtx, \
+ "sctp-mcore_queue","queue_lock", \
+ MTX_DEF|MTX_DUPOK); \
+} while (0)
+
+#define SCTP_MCORE_QLOCK(cpstr) do { \
+ mtx_lock(&(cpstr)->que_mtx); \
+} while (0)
+
+#define SCTP_MCORE_QUNLOCK(cpstr) do { \
+ mtx_unlock(&(cpstr)->que_mtx); \
+} while (0)
+
+#define SCTP_MCORE_QDESTROY(cpstr) do { \
+ if(mtx_owned(&(cpstr)->core_mtx)) { \
+ mtx_unlock(&(cpstr)->que_mtx); \
+ } \
+ mtx_destroy(&(cpstr)->que_mtx); \
+} while (0)
+
+
+#define SCTP_MCORE_LOCK_INIT(cpstr) do { \
+ mtx_init(&(cpstr)->core_mtx, \
+ "sctp-cpulck","cpu_proc_lock", \
+ MTX_DEF|MTX_DUPOK); \
+} while (0)
+
+#define SCTP_MCORE_LOCK(cpstr) do { \
+ mtx_lock(&(cpstr)->core_mtx); \
+} while (0)
+
+#define SCTP_MCORE_UNLOCK(cpstr) do { \
+ mtx_unlock(&(cpstr)->core_mtx); \
+} while (0)
+
+#define SCTP_MCORE_DESTROY(cpstr) do { \
+ if(mtx_owned(&(cpstr)->core_mtx)) { \
+ mtx_unlock(&(cpstr)->core_mtx); \
+ } \
+ mtx_destroy(&(cpstr)->core_mtx); \
+} while (0)
#define SCTP_INP_INFO_WLOCK() do { \
rw_wlock(&SCTP_BASE_INFO(ipi_ep_mtx)); \
diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h
index 171c38e1cfc1..fc8b1d43b71f 100644
--- a/sys/netinet/sctp_os_bsd.h
+++ b/sys/netinet/sctp_os_bsd.h
@@ -123,6 +123,7 @@ MALLOC_DECLARE(SCTP_M_TIMW);
MALLOC_DECLARE(SCTP_M_MVRF);
MALLOC_DECLARE(SCTP_M_ITER);
MALLOC_DECLARE(SCTP_M_SOCKOPT);
+MALLOC_DECLARE(SCTP_M_MCORE);
#if defined(SCTP_LOCAL_TRACE_BUF)
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 310b294df8e8..d9efe175a773 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -47,6 +47,9 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_bsd_addr.h>
#include <netinet/sctp_dtrace_define.h>
#include <netinet/udp.h>
+#include <sys/sched.h>
+#include <sys/smp.h>
+#include <sys/unistd.h>
VNET_DEFINE(struct sctp_base_info, system_base_info);
@@ -5435,6 +5438,148 @@ sctp_del_local_addr_restricted(struct sctp_tcb *stcb, struct sctp_ifa *ifa)
static int sctp_max_number_of_assoc = SCTP_MAX_NUM_OF_ASOC;
static int sctp_scale_up_for_address = SCTP_SCALE_FOR_ADDR;
+
+
+#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP)
+struct sctp_mcore_ctrl *sctp_mcore_workers = NULL;
+
+void
+sctp_queue_to_mcore(struct mbuf *m, int off, int cpu_to_use)
+{
+ /* Queue a packet to a processor for the specified core */
+ struct sctp_mcore_queue *qent;
+ struct sctp_mcore_ctrl *wkq;
+ int need_wake = 0;
+
+ if (sctp_mcore_workers == NULL) {
+ /* Something went way bad during setup */
+ sctp_input_with_port(m, off, 0);
+ return;
+ }
+ SCTP_MALLOC(qent, struct sctp_mcore_queue *,
+ (sizeof(struct sctp_mcore_queue)),
+ SCTP_M_MCORE);
+ if (qent == NULL) {
+ /* This is trouble */
+ sctp_input_with_port(m, off, 0);
+ return;
+ }
+ qent->vn = curvnet;
+ qent->m = m;
+ qent->off = off;
+ qent->v6 = 0;
+ wkq = &sctp_mcore_workers[cpu_to_use];
+ SCTP_MCORE_QLOCK(wkq);
+
+ TAILQ_INSERT_TAIL(&wkq->que, qent, next);
+ if (wkq->running == 0) {
+ need_wake = 1;
+ }
+ SCTP_MCORE_QUNLOCK(wkq);
+ if (need_wake) {
+ wakeup(&wkq->running);
+ }
+}
+
+static void
+sctp_mcore_thread(void *arg)
+{
+
+ struct sctp_mcore_ctrl *wkq;
+ struct sctp_mcore_queue *qent;
+
+ wkq = (struct sctp_mcore_ctrl *)arg;
+ struct mbuf *m;
+ int off, v6;
+
+ /* Wait for first tickle */
+ SCTP_MCORE_LOCK(wkq);
+ wkq->running = 0;
+ msleep(&wkq->running,
+ &wkq->core_mtx,
+ 0, "wait for pkt", 0);
+ SCTP_MCORE_UNLOCK(wkq);
+
+ /* Bind to our cpu */
+ thread_lock(curthread);
+ sched_bind(curthread, wkq->cpuid);
+ thread_unlock(curthread);
+
+ /* Now lets start working */
+ SCTP_MCORE_LOCK(wkq);
+ /* Now grab lock and go */
+ while (1) {
+ SCTP_MCORE_QLOCK(wkq);
+skip_sleep:
+ wkq->running = 1;
+ qent = TAILQ_FIRST(&wkq->que);
+ if (qent) {
+ TAILQ_REMOVE(&wkq->que, qent, next);
+ SCTP_MCORE_QUNLOCK(wkq);
+ CURVNET_SET(qent->vn);
+ m = qent->m;
+ off = qent->off;
+ v6 = qent->v6;
+ SCTP_FREE(qent, SCTP_M_MCORE);
+ if (v6 == 0) {
+ sctp_input_with_port(m, off, 0);
+ } else {
+ printf("V6 not yet supported\n");
+ sctp_m_freem(m);
+ }
+ CURVNET_RESTORE();
+ SCTP_MCORE_QLOCK(wkq);
+ }
+ wkq->running = 0;
+ if (!TAILQ_EMPTY(&wkq->que)) {
+ goto skip_sleep;
+ }
+ SCTP_MCORE_QUNLOCK(wkq);
+ msleep(&wkq->running,
+ &wkq->core_mtx,
+ 0, "wait for pkt", 0);
+ };
+}
+
+static void
+sctp_startup_mcore_threads(void)
+{
+ int i;
+
+ if (mp_ncpus == 1)
+ return;
+
+ SCTP_MALLOC(sctp_mcore_workers, struct sctp_mcore_ctrl *,
+ (mp_ncpus * sizeof(struct sctp_mcore_ctrl)),
+ SCTP_M_MCORE);
+ if (sctp_mcore_workers == NULL) {
+ /* TSNH I hope */
+ return;
+ }
+ memset(sctp_mcore_workers, 0, (mp_ncpus *
+ sizeof(struct sctp_mcore_ctrl)));
+ /* Init the structures */
+ for (i = 0; i < mp_ncpus; i++) {
+ TAILQ_INIT(&sctp_mcore_workers[i].que);
+ SCTP_MCORE_LOCK_INIT(&sctp_mcore_workers[i]);
+ SCTP_MCORE_QLOCK_INIT(&sctp_mcore_workers[i]);
+ sctp_mcore_workers[i].cpuid = i;
+ }
+ /* Now start them all */
+ for (i = 0; i < mp_ncpus; i++) {
+ (void)kproc_create(sctp_mcore_thread,
+ (void *)&sctp_mcore_workers[i],
+ &sctp_mcore_workers[i].thread_proc,
+ RFPROC,
+ SCTP_KTHREAD_PAGES,
+ SCTP_MCORE_NAME);
+
+ }
+}
+
+#endif
+
+
void
sctp_pcb_init()
{
@@ -5565,6 +5710,10 @@ sctp_pcb_init()
sctp_startup_iterator();
+#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP)
+ sctp_startup_mcore_threads();
+#endif
+
/*
* INIT the default VRF which for BSD is the only one, other O/S's
* may have more. But initially they must start with one and then
diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h
index cbb185a227d8..fb7857e39fc5 100644
--- a/sys/netinet/sctp_pcb.h
+++ b/sys/netinet/sctp_pcb.h
@@ -624,6 +624,12 @@ sctp_initiate_iterator(inp_func inpf,
struct sctp_inpcb *,
uint8_t co_off);
+#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP)
+void
+ sctp_queue_to_mcore(struct mbuf *m, int off, int cpu_to_use);
+
+#endif
+
#ifdef INVARIANTS
void
sctp_validate_no_locks(struct sctp_inpcb *inp);
diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h
index 64491dd8cb3f..759a6bc2b35a 100644
--- a/sys/netinet/sctp_structs.h
+++ b/sys/netinet/sctp_structs.h
@@ -106,6 +106,31 @@ typedef void (*asoc_func) (struct sctp_inpcb *, struct sctp_tcb *, void *ptr,
typedef int (*inp_func) (struct sctp_inpcb *, void *ptr, uint32_t val);
typedef void (*end_func) (void *ptr, uint32_t val);
+#if defined(__FreeBSD__) && defined(SCTP_MCORE_INPUT) && defined(SMP)
+/* whats on the mcore control struct */
+struct sctp_mcore_queue {
+ TAILQ_ENTRY(sctp_mcore_queue) next;
+ struct vnet *vn;
+ struct mbuf *m;
+ int off;
+ int v6;
+};
+
+TAILQ_HEAD(sctp_mcore_qhead, sctp_mcore_queue);
+
+struct sctp_mcore_ctrl {
+ SCTP_PROCESS_STRUCT thread_proc;
+ struct sctp_mcore_qhead que;
+ struct mtx core_mtx;
+ struct mtx que_mtx;
+ int running;
+ int cpuid;
+};
+
+
+#endif
+
+
struct sctp_iterator {
TAILQ_ENTRY(sctp_iterator) sctp_nxt_itr;
struct vnet *vn;