--- Copyright (c) 2010, Lawrence Stewart --- All rights reserved. --- --- Redistribution and use in source and binary forms, with or without --- modification, are permitted provided that the following conditions --- are met: --- 1. Redistributions of source code must retain the above copyright --- notice, this list of conditions and the following disclaimer. --- 2. Redistributions in binary form must reproduce the above copyright --- notice, this list of conditions and the following disclaimer in the --- documentation and/or other materials provided with the distribution. --- 3. The names of the authors, "Swinburne University of Technology" and the --- "Centre for Advanced Internet Architectures" may not be used to endorse --- or promote products derived from this software without specific --- prior written permission. --- --- THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS \`\`AS IS'' AND --- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE --- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE --- ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE --- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL --- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS --- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) --- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT --- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY --- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF --- SUCH DAMAGE. --- --- CAIA Khelp Framework v0.1.1 --- --- This patch was created against revision 209905 of the FreeBSD 9-CURRENT. --- --- To obtain the correct revision of the FreeBSD source tree that this patch --- applies to, and store it in the local directory "/path/to/src", run: --- --- svn co -r 209905 http://svn.freebsd.org/base/head --- --- Make sure the base system you are installing onto is already running --- FreeBSD 9.x before continuing. --- --- Issuing the following commands will result in a running Khelp framework --- capable system: --- --- cd /path/to/src --- patch -p1 < /path/to/caia_khelp_v0.1.1_9.x.r209905.patch --- cd /path/to/src/ --- make buildworld buildkernel installkernel installworld --- mergemaster -iF -m /path/to/src --- reboot --- --- The Khelp framework patch was first released in 2010 by Lawrence Stewart --- whilst studying at Swinburne University's Centre for Advanced Internet --- Architectures, Melbourne, Australia. The work is released as part --- of the NewTCP research project. More details are available at: --- http://caia.swin.edu.au/urp/newtcp/ --- --- Lawrence Stewart is currently the sole maintainer. --- All contact regarding this patch should be directed to him --- via email: lastewart@swin.edu.au --- diff -r 7159011c25ae sys/conf/files --- a/sys/conf/files Sun Jul 11 20:33:39 2010 +0000 +++ b/sys/conf/files Tue Aug 03 10:15:11 2010 +1000 @@ -2097,9 +2097,11 @@ kern/kern_fail.c standard kern/kern_fork.c standard kern/kern_gzio.c optional gzio +kern/kern_hhook.c standard kern/kern_idle.c standard kern/kern_intr.c standard kern/kern_jail.c standard +kern/kern_khelp.c standard kern/kern_kthread.c standard kern/kern_ktr.c optional ktr kern/kern_ktrace.c standard diff -r 7159011c25ae sys/kern/kern_hhook.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/kern/kern_hhook.c Tue Aug 03 10:15:11 2010 +1000 @@ -0,0 +1,301 @@ +/*- + * Copyright (c) 2010 Lawrence Stewart + * All rights reserved. + * + * This software was developed at the Centre for Advanced Internet + * Architectures, Swinburne University, by Lawrence Stewart, + * made possible in part by a grant from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + + +#define RLOCK_HHOOK_HEAD 0x01 +#define WLOCK_HHOOK_HEAD 0x02 + +MALLOC_DECLARE(M_HHOOK); +MALLOC_DEFINE(M_HHOOK, "helper hook related memory", "Blah"); + +struct hhook { + hhook_func_t h_func; + void *h_udata; + struct helper *h_helper; + STAILQ_ENTRY(hhook) h_next; +}; + +typedef STAILQ_HEAD(hhook_list, hhook) hhook_list_t; + +struct hhook_head { + int hh_type; + int hh_id; + int hh_nhooks; + hhook_list_t hh_hooks; + struct rmlock hh_lock; + LIST_ENTRY(hhook_head) hh_next; +}; + +LIST_HEAD(hhookheadhead, hhook_head); +VNET_DEFINE(struct hhookheadhead, hhook_head_list); +#define V_hhook_head_list VNET(hhook_head_list) + +static struct mtx hhook_head_list_lock; +MTX_SYSINIT(hhookheadlistlock, &hhook_head_list_lock, "hhook_head list lock", + MTX_DEF); + +static struct hhook_head * get_hhook_head(int hhook_type, int hhook_id, + struct rm_priotracker* rmpt, int flags); + + +/* + * Public KPI functions + */ +int +register_hhook_head(int hhook_type, int hhook_id, int flags) +{ + struct hhook_head *hh; + + HHOOK_HEAD_LIST_LOCK(); + hh = get_hhook_head(hhook_type, hhook_id, NULL, 0); + + if (hh != NULL) + return (EEXIST); + + hh = malloc(sizeof(struct hhook_head), M_HHOOK, + M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT)); + + if (hh == NULL) + return (ENOMEM); + + printf("About to register hhook_head %p with type: %d and id: %d\n", hh, + hhook_type, hhook_id); + + hh->hh_type = hhook_type; + hh->hh_id = hhook_id; + hh->hh_nhooks = 0; + STAILQ_INIT(&hh->hh_hooks); + HHOOK_HEAD_LOCK_INIT(hh); + + LIST_INSERT_HEAD(&V_hhook_head_list, hh, hh_next); + HHOOK_HEAD_LIST_UNLOCK(); + return (0); +} + +int +deregister_hhook_head(int hhook_type, int hhook_id) +{ + struct hhook_head *hh; + struct hhook *tmp, *tmp2; + int error = 0; + + HHOOK_HEAD_LIST_LOCK(); + hh = get_hhook_head(hhook_type, hhook_id, NULL, WLOCK_HHOOK_HEAD); + + if (hh == NULL) + error = ENOENT; + else { + LIST_REMOVE(hh, hh_next); + + STAILQ_FOREACH_SAFE(tmp, &hh->hh_hooks, h_next, tmp2) { + free(tmp, M_HHOOK); + } + + HHOOK_HEAD_WUNLOCK(hh); + HHOOK_HEAD_LOCK_DESTROY(hh); + free(hh, M_HHOOK); + } + + HHOOK_HEAD_LIST_UNLOCK(); + return (error); +} + +int +register_hhook(int hhook_type, int hhook_id, struct helper *helper, + hhook_func_t hook, void *udata, int flags) +{ + struct hhook *h, *tmp; + struct hhook_head *hh; + int error = 0; + + h = malloc(sizeof(struct hhook), M_HHOOK, + M_ZERO | ((flags & HHOOK_WAITOK) ? M_WAITOK : M_NOWAIT)); + + if (h == NULL) + return (ENOMEM); + + h->h_helper = helper; + h->h_func = hook; + h->h_udata = udata; + + hh = get_hhook_head(hhook_type, hhook_id, NULL, WLOCK_HHOOK_HEAD); + + if (hh == NULL) { + free(h, M_HHOOK); + return (ENOENT); + } + + STAILQ_FOREACH(tmp, &hh->hh_hooks, h_next) { + if (tmp->h_func == hook && tmp->h_udata == udata) { + error = EEXIST; + break; + } + } + + if (!error) { + STAILQ_INSERT_TAIL(&hh->hh_hooks, h, h_next); + hh->hh_nhooks++; + } + else + free(h, M_HHOOK); + + HHOOK_HEAD_WUNLOCK(hh); + + return (error); +} + +int +deregister_hhook(int hhook_type, int hhook_id, hhook_func_t hook, void *udata, + int flags) +{ + struct hhook *tmp; + struct hhook_head *hh; + + hh = get_hhook_head(hhook_type, hhook_id, NULL, WLOCK_HHOOK_HEAD); + + if (hh == NULL) + return (ENOENT); + + STAILQ_FOREACH(tmp, &hh->hh_hooks, h_next) { + if (tmp->h_func == hook && tmp->h_udata == udata) { + STAILQ_REMOVE(&hh->hh_hooks, tmp, hhook, h_next); + free(tmp, M_HHOOK); + hh->hh_nhooks--; + break; + } + } + + HHOOK_HEAD_WUNLOCK(hh); + return (0); +} + +void +run_hhooks(int hhook_type, int hhook_id, void *ctx_data, + struct helper_dblocks *hdbs) +{ + struct hhook_head *hh; + struct hhook *tmp; + struct rm_priotracker rmpt; + int i = 0; + void *dblock = NULL; + uint32_t nblocks = hdbs->nblocks; + + hh = get_hhook_head(hhook_type, hhook_id, &rmpt, RLOCK_HHOOK_HEAD); + + if (hh == NULL) + return; + + STAILQ_FOREACH(tmp, &hh->hh_hooks, h_next) { + //printf("Running hook %p for helper %d\n", tmp, + //tmp->h_helper->id); + if (tmp->h_helper->h_flags & HELPER_NEEDS_DBLOCK) { + if (nblocks == 0 + || i >= nblocks + || tmp->h_helper->h_id != hdbs->blocks[i].hd_id) + continue; + dblock = hdbs->blocks[i].hd_block; + i++; + } + tmp->h_func(tmp->h_udata, ctx_data, dblock, hdbs); + dblock = NULL; + } + + HHOOK_HEAD_RUNLOCK(hh, &rmpt); +} + + +/* + * Private KPI functions + */ +static struct hhook_head * +get_hhook_head(int hhook_type, int hhook_id, struct rm_priotracker *rmpt, + int flags) +{ + struct hhook_head *tmp, *ret = NULL; + + /*KASSERT(HHOOK_HEAD_LIST_LOCK_ASSERT(), ("hhook_head_list_lock not + * locked"));*/ + + LIST_FOREACH(tmp, &V_hhook_head_list, hh_next) { + if (tmp->hh_type == hhook_type && tmp->hh_id == hhook_id) { + ret = tmp; + if (flags & RLOCK_HHOOK_HEAD) + HHOOK_HEAD_RLOCK(ret, rmpt); + else if (flags & WLOCK_HHOOK_HEAD) + HHOOK_HEAD_WLOCK(ret); + break; + } + } + + return (ret); +} + +static int +vnet_hhook_init(const void *unused) +{ + + LIST_INIT(&V_hhook_head_list); + return (0); +} + +static int +vnet_hhook_uninit(const void *unused) +{ + + return (0); +} + +#define HHOOK_SYSINIT_ORDER SI_SUB_PROTO_BEGIN +#define HHOOK_MODEVENT_ORDER (SI_ORDER_FIRST) +#define HHOOK_VNET_ORDER (HHOOK_MODEVENT_ORDER + 2) + +VNET_SYSINIT(vnet_hhook_init, HHOOK_SYSINIT_ORDER, HHOOK_VNET_ORDER, + vnet_hhook_init, NULL); + +VNET_SYSUNINIT(vnet_hhook_uninit, HHOOK_SYSINIT_ORDER, HHOOK_VNET_ORDER, + vnet_hhook_uninit, NULL); + diff -r 7159011c25ae sys/kern/kern_khelp.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/kern/kern_khelp.c Tue Aug 03 10:15:11 2010 +1000 @@ -0,0 +1,276 @@ +/*- + * Copyright (c) 2010 Lawrence Stewart + * All rights reserved. + * + * This software was developed at the Centre for Advanced Internet + * Architectures, Swinburne University, by Lawrence Stewart, + * made possible in part by a grant from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static struct rwlock helper_list_lock; +RW_SYSINIT(helperlistlock, &helper_list_lock, "helper list lock"); + +static STAILQ_HEAD(helper_head, helper) helpers = STAILQ_HEAD_INITIALIZER(helpers); + +static int num_dblocks = 0; + +/* Monotonically increasing ID assigned to helpers on registration. */ +static int32_t helper_id = 0; + +static struct helper * get_helper(int32_t id); + +/* + * Public KPI functions. + */ +int +init_helper_dblocks(struct helper_dblocks *hdbs) +{ + struct helper *h; + struct helper_dblock *dblock; + int i = 0, error = 0; + + KASSERT(hdbs != NULL, ("struct helper_dblocks not initialised!")); + + HELPER_LIST_RLOCK(); + + if (num_dblocks == 0) { + HELPER_LIST_RUNLOCK(); + return (0); + } + + /* XXXLAS: Should only allocate for helpers of the appropriate class. */ + hdbs->blocks = malloc(num_dblocks * sizeof(struct helper_dblock), M_HELPER, + M_NOWAIT | M_ZERO); + + if (hdbs->blocks != NULL) { + /*printf("Malloced ptr %p for %d data blocks\n", hdbs->blocks, + num_dblocks);*/ + STAILQ_FOREACH(h, &helpers, h_next) { + if (h->h_flags & HELPER_NEEDS_DBLOCK) { + dblock = hdbs->blocks+i; + /*printf("Current dblock ptr: %p\n", dblock);*/ + dblock->hd_block = uma_zalloc(h->h_zone, + M_NOWAIT); + /* + if (dblock[i]->block == NULL) { + XXX: Free all previous dblocks. + error = ENOMEM + break; + } + */ + dblock->hd_id = h->h_id; + /*printf("dblock[%d]: id=%d, block=%p\n", i, + dblock->hd_id, dblock->hd_block);*/ + i++; + refcount_acquire(&h->h_refcount); + } + } + hdbs->nblocks = i; + } else + error = ENOMEM; + + HELPER_LIST_RUNLOCK(); + return (error); +} + +int +destroy_helper_dblocks(struct helper_dblocks *hdbs) +{ + struct helper *h; + int32_t nblocks = hdbs->nblocks; + + HELPER_LIST_WLOCK(); + + for (nblocks--; nblocks >= 0; nblocks--) { + if ((h = get_helper(hdbs->blocks[nblocks].hd_id)) != NULL) { + refcount_release(&h->h_refcount); + /*printf("destroy() freeing hdbs->blocks[%d] with ptr %p\n", + nblocks, hdbs->blocks[nblocks].hd_block);*/ + uma_zfree(h->h_zone, hdbs->blocks[nblocks].hd_block); + } + } + + HELPER_LIST_WUNLOCK(); + free(hdbs->blocks, M_HELPER); + return (0); +} + +int +register_helper(struct helper *h) +{ + HELPER_LIST_WLOCK(); + if (h->h_flags | HELPER_NEEDS_DBLOCK) + num_dblocks++; + + refcount_init(&h->h_refcount, 0); + h->h_id = helper_id++; + STAILQ_INSERT_TAIL(&helpers, h, h_next); + HELPER_LIST_WUNLOCK(); + printf("Registered \"%s\" helper (mem %p)\n", h->h_name, h); + return (0); +} + +int +deregister_helper(struct helper *h) +{ + int error = 0; + + /* + HHOOK_WLOCK + Remove this helper's hooks + HHOOK_WUNLOCK + */ + + HELPER_LIST_WLOCK(); + if (h->h_refcount > 0) + error = EBUSY; + + if (!error) { + STAILQ_REMOVE(&helpers, h, helper, h_next); + if (h->h_flags | HELPER_NEEDS_DBLOCK) + num_dblocks--; + printf("Deregistered \"%s\" helper (mem %p)\n", h->h_name, h); + } + HELPER_LIST_WUNLOCK(); + return (error); +} + +int32_t +get_helper_id(char *hname) +{ + struct helper *h; + int32_t id = -1; + + HELPER_LIST_RLOCK(); + STAILQ_FOREACH(h, &helpers, h_next) { + if (strncmp(h->h_name, hname, HELPER_NAME_MAXLEN) == 0) { + id = h->h_id; + break; + } + } + HELPER_LIST_RUNLOCK(); + return (id); +} + +void * +get_helper_dblock(struct helper_dblocks *hdbs, int32_t id) +{ + uint32_t nblocks = hdbs->nblocks; + + for (nblocks--; nblocks >= 0; nblocks--) { + if (hdbs->blocks[nblocks].hd_id == id) + return (hdbs->blocks[nblocks].hd_block); + } + return (NULL); +} + +/* + * Private KPI functions. + */ +static struct helper * +get_helper(int32_t id) +{ + struct helper *h; + + HELPER_LIST_LOCK_ASSERT(); + + STAILQ_FOREACH(h, &helpers, h_next) { + if (h->h_id == id) + return (h); + } + return (NULL); +} + +/* + * Handles kld related events. Returns 0 on success, non-zero on failure. + */ +int +helper_modevent(module_t mod, int event_type, void *data) +{ + int error = 0; + struct helper_modevent_data *hmd = (struct helper_modevent_data *)data; + + switch(event_type) { + case MOD_LOAD: + if (hmd->helper->h_flags & HELPER_NEEDS_DBLOCK) { + if (hmd->uma_zsize <= 0) { + printf("Use DECLARE_HELPER_UMA() instead!\n"); + error = EDOOFUS; + break; + } + hmd->helper->h_zone = + uma_zcreate(hmd->name, hmd->uma_zsize, + hmd->umactor, hmd->umadtor, NULL, NULL, 0, + 0); + if (hmd->helper->h_zone == NULL) { + error = ENOMEM; + break; + } + } + strlcpy(hmd->helper->h_name, hmd->name, + HELPER_NAME_MAXLEN); + if (hmd->helper->mod_init != NULL) + error = hmd->helper->mod_init(); + if (!error) + error = register_helper(hmd->helper); + break; + + case MOD_QUIESCE: + error = deregister_helper(hmd->helper); + if (!error) { + uma_zdestroy(hmd->helper->h_zone); + if (hmd->helper->mod_destroy != NULL) + hmd->helper->mod_destroy(); + } else + printf("Helper's refcount != 0, can't unload\n"); + break; + + case MOD_SHUTDOWN: + case MOD_UNLOAD: + break; + + default: + error = EINVAL; + break; + } + + return (error); +} diff -r 7159011c25ae sys/netinet/tcp_input.c --- a/sys/netinet/tcp_input.c Sun Jul 11 20:33:39 2010 +0000 +++ b/sys/netinet/tcp_input.c Tue Aug 03 10:15:11 2010 +1000 @@ -40,6 +40,7 @@ #include #include +#include #include #include #include /* for proc0 declaration */ @@ -1076,7 +1077,7 @@ int rstreason, todrop, win; u_long tiwin; struct tcpopt to; - + struct tcp_hhook_data hhook_data; #ifdef TCPDEBUG /* * The size of tcp_saveipgen must be the size of the max ip header, @@ -1323,6 +1324,15 @@ } tcp_xmit_bandwidth_limit(tp, th->th_ack); acked = th->th_ack - tp->snd_una; + + /* run necessary helper hooks for TCP_ESTABLISHED */ + hhook_data.new_sacked_bytes = 0; + hhook_data.tp = tp; + hhook_data.th = th; + hhook_data.to = &to; + run_hhooks(HHOOK_TYPE_TCP, HHOOK_TCP_ESTABLISHED_IN, + &hhook_data, tp->hdbs); + TCPSTAT_INC(tcps_rcvackpack); TCPSTAT_ADD(tcps_rcvackbyte, acked); sbdrop(&so->so_snd, acked); @@ -2021,10 +2031,21 @@ TCPSTAT_INC(tcps_rcvacktoomuch); goto dropafterack; } + hhook_data.new_sacked_bytes = 0; if ((tp->t_flags & TF_SACK_PERMIT) && ((to.to_flags & TOF_SACK) || - !TAILQ_EMPTY(&tp->snd_holes))) + !TAILQ_EMPTY(&tp->snd_holes))) { tcp_sack_doack(tp, &to, th->th_ack); + /* XXXDH: should only be one if a productive SACK */ + hhook_data.new_sacked_bytes = 1; + } + + hhook_data.tp = tp; + hhook_data.th = th; + hhook_data.to = &to; + run_hhooks(HHOOK_TYPE_TCP, HHOOK_TCP_ESTABLISHED_IN, + &hhook_data, tp->hdbs); + if (SEQ_LEQ(th->th_ack, tp->snd_una)) { if (tlen == 0 && tiwin == tp->snd_wnd) { TCPSTAT_INC(tcps_rcvdupack); diff -r 7159011c25ae sys/netinet/tcp_output.c --- a/sys/netinet/tcp_output.c Sun Jul 11 20:33:39 2010 +0000 +++ b/sys/netinet/tcp_output.c Tue Aug 03 10:15:11 2010 +1000 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -155,6 +156,7 @@ struct sackhole *p; int tso = 0; struct tcpopt to; + struct tcp_hhook_data hhook_data; #if 0 int maxburst = TCP_MAXBURST; #endif @@ -1124,6 +1126,15 @@ tp->snd_max = tp->snd_nxt + len; } + hhook_data.th = th; + hhook_data.tp = tp; + hhook_data.to = &to; + hhook_data.len = len; + hhook_data.tso = tso; + run_hhooks(HHOOK_TYPE_TCP, HHOOK_TCP_ESTABLISHED_OUT, &hhook_data, + tp->hdbs); + + #ifdef TCPDEBUG /* * Trace. diff -r 7159011c25ae sys/netinet/tcp_sack.c --- a/sys/netinet/tcp_sack.c Sun Jul 11 20:33:39 2010 +0000 +++ b/sys/netinet/tcp_sack.c Tue Aug 03 10:15:11 2010 +1000 @@ -425,6 +425,7 @@ * are received. */ sblkp = &sack_blocks[num_sack_blks - 1]; /* Last SACK block */ + tp->sackhint.last_sack_ack = sblkp->end; if (SEQ_LT(tp->snd_fack, sblkp->start)) { /* * The highest SACK block is beyond fack. Append new SACK diff -r 7159011c25ae sys/netinet/tcp_subr.c --- a/sys/netinet/tcp_subr.c Sun Jul 11 20:33:39 2010 +0000 +++ b/sys/netinet/tcp_subr.c Tue Aug 03 10:15:11 2010 +1000 @@ -41,7 +41,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -288,6 +290,7 @@ struct tcpcb_mem { struct tcpcb tcb; struct tcp_timer tt; + struct helper_dblocks hdbs; }; static VNET_DEFINE(uma_zone_t, tcpcb_zone); @@ -327,6 +330,13 @@ { int hashsize; + if (register_hhook_head(HHOOK_TYPE_TCP, HHOOK_TCP_ESTABLISHED_IN, + HHOOK_NOWAIT) != 0) + printf("%s: WARNING: unable to register helper hook\n", __func__); + if (register_hhook_head(HHOOK_TYPE_TCP, HHOOK_TCP_ESTABLISHED_OUT, + HHOOK_NOWAIT) != 0) + printf("%s: WARNING: unable to register helper hook\n", __func__); + hashsize = TCBHASHSIZE; TUNABLE_INT_FETCH("net.inet.tcp.tcbhashsize", &hashsize); if (!powerof2(hashsize)) { @@ -692,6 +702,14 @@ if (tm == NULL) return (NULL); tp = &tm->tcb; + + tp->hdbs = &tm->hdbs; + tp->hdbs->class = HELPER_CLASS_TCP; + if (init_helper_dblocks(tp->hdbs)) { + uma_zfree(V_tcpcb_zone, tm); + return (NULL); + } + #ifdef VIMAGE tp->t_vnet = inp->inp_vnet; #endif @@ -866,8 +884,9 @@ } /* Disconnect offload device, if any. */ tcp_offload_detach(tp); - tcp_free_sackholes(tp); + destroy_helper_dblocks(tp->hdbs); + inp->inp_ppcb = NULL; tp->t_inpcb = NULL; uma_zfree(V_tcpcb_zone, tp); diff -r 7159011c25ae sys/netinet/tcp_var.h --- a/sys/netinet/tcp_var.h Sun Jul 11 20:33:39 2010 +0000 +++ b/sys/netinet/tcp_var.h Tue Aug 03 10:15:11 2010 +1000 @@ -74,7 +74,7 @@ struct sackhint { struct sackhole *nexthole; int sack_bytes_rexmit; - + tcp_seq last_sack_ack; /* Last sack block acked with current pkt - used for enhanced RTT calculations*/ int ispare; /* explicit pad for 64bit alignment */ uint64_t _pad[2]; /* 1 sacked_bytes, 1 TBD */ }; @@ -199,10 +199,10 @@ struct toe_usrreqs *t_tu; /* offload operations vector */ void *t_toe; /* TOE pcb pointer */ int t_bytes_acked; /* # bytes acked during current RTT */ - int t_ispare; /* explicit pad for 64bit alignment */ void *t_pspare2[6]; /* 2 CC / 4 TBD */ uint64_t _pad[12]; /* 7 UTO, 5 TBD (1-2 CC/RTT?) */ + struct helper_dblocks *hdbs; }; /* @@ -240,6 +240,22 @@ #define EXIT_FASTRECOVERY(tp) tp->t_flags &= ~TF_FASTRECOVERY /* + * TCP specific helper hook point identifiers. + */ +#define HHOOK_TCP_ESTABLISHED_IN 1 +#define HHOOK_TCP_ESTABLISHED_OUT 2 + +struct tcp_hhook_data { + struct tcpcb *tp; + struct tcphdr *th; + struct tcpopt *to; + long len; + int tso; + tcp_seq curack; + int new_sacked_bytes; +}; + +/* * Flags for the t_oobflags field. */ #define TCPOOB_HAVEDATA 0x01 diff -r 7159011c25ae sys/sys/hhook.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/sys/hhook.h Tue Aug 03 10:15:11 2010 +1000 @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2010 Lawrence Stewart + * All rights reserved. + * + * This software was developed at the Centre for Advanced Internet + * Architectures, Swinburne University, by Lawrence Stewart, + * made possible in part by a grant from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_HHOOK_H_ +#define _SYS_HHOOK_H_ + +#define HHOOK_WAITOK 0x01 +#define HHOOK_NOWAIT 0x02 + +#define HHOOK_TYPE_TCP 1 + +struct helper; +struct helper_dblocks; +struct hhook_head; + +typedef void (*hhook_func_t)(void *udata, void *ctx_data, void *helper_dblock, + struct helper_dblocks *hdbs); + +int register_hhook_head(int hhook_type, int hhook_id, int flags); +int deregister_hhook_head(int hhook_type, int hhook_id); +int register_hhook(int hhook_type, int hhook_id, struct helper *helper, + hhook_func_t hook, void *udata, int flags); +int deregister_hhook(int hhook_type, int hhook_id, hhook_func_t hook, + void *udata, int flags); +void run_hhooks(int hhook_type, int hhook_id, void *ctx_data, + struct helper_dblocks *hdbs); + +#define HHOOK_HEAD_LIST_LOCK() mtx_lock(&hhook_head_list_lock) +#define HHOOK_HEAD_LIST_UNLOCK() mtx_unlock(&hhook_head_list_lock) +#define HHOOK_HEAD_LIST_LOCK_ASSERT() mtx_assert(&hhook_head_list_lock, MA_OWNED) + +#define HHOOK_HEAD_LOCK_INIT(hh) rm_init(&(hh)->hh_lock, "hhook_head rm lock") +#define HHOOK_HEAD_LOCK_DESTROY(hh) rm_destroy(&(hh)->hh_lock) +#define HHOOK_HEAD_WLOCK(hh) rm_wlock(&(hh)->hh_lock) +#define HHOOK_HEAD_WUNLOCK(hh) rm_wunlock(&(hh)->hh_lock) +#define HHOOK_HEAD_RLOCK(hh,rmpt) rm_rlock(&(hh)->hh_lock, (rmpt)) +#define HHOOK_HEAD_RUNLOCK(hh,rmpt) rm_runlock(&(hh)->hh_lock, (rmpt)) + +#endif /* _SYS_HHOOK_H_ */ + diff -r 7159011c25ae sys/sys/khelp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/sys/khelp.h Tue Aug 03 10:15:11 2010 +1000 @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2010 Lawrence Stewart + * All rights reserved. + * + * This software was developed at the Centre for Advanced Internet + * Architectures, Swinburne University, by Lawrence Stewart, + * made possible in part by a grant from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_KHELP_H_ +#define _SYS_KHELP_H_ + +/* XXX: Couldn't find a way around this. */ +#include + +struct helper_dblock { + int32_t hd_id; + void *hd_block; +}; + +struct helper_dblocks { + struct helper_dblock *blocks; + int32_t nblocks; + uint32_t class; +}; + +struct helper { + int (*mod_init) (void); + int (*mod_destroy) (void); + uma_zone_t h_zone; +#define HELPER_NAME_MAXLEN 16 + char h_name[HELPER_NAME_MAXLEN]; + uint16_t h_flags; + uint32_t h_class; + int32_t h_id; + volatile uint32_t h_refcount; + STAILQ_ENTRY(helper) h_next; +}; + +/* Helper flags */ +#define HELPER_NEEDS_DBLOCK 0x0001 + +/* Helper classes */ +#define HELPER_CLASS_TCP 0x00000001 + +int init_helper_dblocks(struct helper_dblocks *hdbs); +int destroy_helper_dblocks(struct helper_dblocks *hdbs); +int register_helper(struct helper *h); +int deregister_helper(struct helper *h); +int32_t get_helper_id(char *hname); +void * get_helper_dblock(struct helper_dblocks *hdbs, int32_t id); + +#define HELPER_LIST_WLOCK() rw_wlock(&helper_list_lock) +#define HELPER_LIST_WUNLOCK() rw_wunlock(&helper_list_lock) +#define HELPER_LIST_RLOCK() rw_rlock(&helper_list_lock) +#define HELPER_LIST_RUNLOCK() rw_runlock(&helper_list_lock) +#define HELPER_LIST_LOCK_ASSERT() rw_assert(&helper_list_lock, RA_LOCKED) + +#endif /* _SYS_KHELP_H_ */ diff -r 7159011c25ae sys/sys/module_khelp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/sys/module_khelp.h Tue Aug 03 10:15:11 2010 +1000 @@ -0,0 +1,81 @@ +/*- + * Copyright (c) 2010 Lawrence Stewart + * All rights reserved. + * + * This software was developed at the Centre for Advanced Internet + * Architectures, Swinburne University, by Lawrence Stewart, + * made possible in part by a grant from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_MODULE_KHELP_H_ +#define _SYS_MODULE_KHELP_H_ + +struct helper_modevent_data { + char name[HELPER_NAME_MAXLEN]; + struct helper *helper; + int uma_zsize; + uma_ctor umactor; + uma_dtor umadtor; +}; + +#define DECLARE_HELPER(hname, hdata, version) \ + static struct helper_modevent_data hmd_##hname = { \ + .name = #hname, \ + .helper = hdata \ + }; \ + static moduledata_t h_##hname = { \ + .name = #hname, \ + .evhand = helper_modevent, \ + .priv = &hmd_##hname \ + }; \ + DECLARE_MODULE(hname, h_##hname, SI_SUB_PROTO_IFATTACHDOMAIN, \ + SI_ORDER_ANY); \ + MODULE_VERSION(hname, version) + +#define DECLARE_HELPER_UMA(hname, hdata, version, size, ctor, dtor) \ + static struct helper_modevent_data hmd_##hname = { \ + .name = #hname, \ + .helper = hdata, \ + .uma_zsize = size, \ + .umactor = ctor, \ + .umadtor = dtor \ + }; \ + static moduledata_t h_##hname = { \ + .name = #hname, \ + .evhand = helper_modevent, \ + .priv = &hmd_##hname \ + }; \ + DECLARE_MODULE(hname, h_##hname, SI_SUB_PROTO_IFATTACHDOMAIN, \ + SI_ORDER_ANY); \ + MODULE_VERSION(hname, version) + +int helper_modevent(module_t mod, int type, void *data); + +MALLOC_DECLARE(M_HELPER); +MALLOC_DEFINE(M_HELPER, "helper data", "Blah"); + + +#endif /* _SYS_MODULE_KHELP_H_ */