summaryrefslogtreecommitdiffstats
path: root/sys/netgraph/ng_socket.c
diff options
context:
space:
mode:
authorglebius <glebius@FreeBSD.org>2012-01-23 16:43:13 +0000
committerglebius <glebius@FreeBSD.org>2012-01-23 16:43:13 +0000
commit09b7b48405f73979d884c854decab97c9b85b266 (patch)
tree9f93c1c6462a8a90d4240ad1ce0cd102fc8430c6 /sys/netgraph/ng_socket.c
parent18321230d6cae24968b5414a59466336822cc449 (diff)
downloadFreeBSD-src-09b7b48405f73979d884c854decab97c9b85b266.zip
FreeBSD-src-09b7b48405f73979d884c854decab97c9b85b266.tar.gz
Provide a findhook method for ng_socket(4). The node stores a
hash with names of its hooks. It starts with size of 16, and grows when number of hooks reaches twice the current size. A failure to grow (memory is allocated with M_NOWAIT) isn't fatal, however. I used standard hash(9) function for the hash. With 25000 hooks named in the mpd (ports/net/mpd5) manner of "b%u", the distributions is the following: 72.1% entries consist of one element, 22.1% consist of two, 5.2% consist of three and 0.6% of four. Speedup in a synthetic test that creates 25000 hooks and then runs through a long cyclce dereferencing them in a random order is over 25 times.
Diffstat (limited to 'sys/netgraph/ng_socket.c')
-rw-r--r--sys/netgraph/ng_socket.c103
1 files changed, 101 insertions, 2 deletions
diff --git a/sys/netgraph/ng_socket.c b/sys/netgraph/ng_socket.c
index 7276d37..f997d49 100644
--- a/sys/netgraph/ng_socket.c
+++ b/sys/netgraph/ng_socket.c
@@ -51,6 +51,7 @@
#include <sys/param.h>
#include <sys/domain.h>
+#include <sys/hash.h>
#include <sys/kernel.h>
#include <sys/linker.h>
#include <sys/lock.h>
@@ -112,6 +113,7 @@ static ng_rcvmsg_t ngs_rcvmsg;
static ng_shutdown_t ngs_shutdown;
static ng_newhook_t ngs_newhook;
static ng_connect_t ngs_connect;
+static ng_findhook_t ngs_findhook;
static ng_rcvdata_t ngs_rcvdata;
static ng_disconnect_t ngs_disconnect;
@@ -137,6 +139,7 @@ static struct ng_type typestruct = {
.shutdown = ngs_shutdown,
.newhook = ngs_newhook,
.connect = ngs_connect,
+ .findhook = ngs_findhook,
.rcvdata = ngs_rcvdata,
.disconnect = ngs_disconnect,
};
@@ -162,11 +165,19 @@ static struct mtx ngsocketlist_mtx;
#define TRAP_ERROR
#endif
+struct hookpriv {
+ LIST_ENTRY(hookpriv) next;
+ hook_p hook;
+};
+LIST_HEAD(ngshash, hookpriv);
+
/* Per-node private data */
struct ngsock {
struct ng_node *node; /* the associated netgraph node */
struct ngpcb *datasock; /* optional data socket */
struct ngpcb *ctlsock; /* optional control socket */
+ struct ngshash *hash; /* hash for hook names */
+ u_long hmask; /* hash mask */
int flags;
int refs;
struct mtx mtx; /* mtx to wait on */
@@ -537,8 +548,14 @@ ng_attach_cntl(struct socket *so)
return (error);
}
- /* Allocate node private info */
+ /*
+ * Allocate node private info and hash. We start
+ * with 16 hash entries, however we may grow later
+ * in ngs_newhook(). We can't predict how much hooks
+ * does this node plan to have.
+ */
priv = malloc(sizeof(*priv), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO);
+ priv->hash = hashinit(16, M_NETGRAPH_SOCK, &priv->hmask);
/* Initialize mutex. */
mtx_init(&priv->mtx, "ng_socket", NULL, MTX_DEF);
@@ -643,6 +660,7 @@ ng_socket_free_priv(struct ngsock *priv)
if (priv->refs == 0) {
mtx_destroy(&priv->mtx);
+ hashdestroy(priv->hash, M_NETGRAPH_SOCK, priv->hmask);
free(priv, M_NETGRAPH_SOCK);
return;
}
@@ -752,6 +770,35 @@ ngs_constructor(node_p nodep)
return (EINVAL);
}
+static void
+ngs_rehash(node_p node)
+{
+ struct ngsock *priv = NG_NODE_PRIVATE(node);
+ struct ngshash *new;
+ struct hookpriv *hp;
+ hook_p hook;
+ uint32_t h;
+ u_long hmask;
+
+ new = hashinit_flags((priv->hmask + 1) * 2, M_NETGRAPH_SOCK, &hmask,
+ HASH_NOWAIT);
+ if (new == NULL)
+ return;
+
+ LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
+ hp = NG_HOOK_PRIVATE(hook);
+#ifdef INVARIANTS
+ LIST_REMOVE(hp, next);
+#endif
+ h = hash32_str(NG_HOOK_NAME(hook), HASHINIT) & hmask;
+ LIST_INSERT_HEAD(&new[h], hp, next);
+ }
+
+ hashdestroy(priv->hash, M_NETGRAPH_SOCK, priv->hmask);
+ priv->hash = new;
+ priv->hmask = hmask;
+}
+
/*
* We allow any hook to be connected to the node.
* There is no per-hook private information though.
@@ -759,7 +806,20 @@ ngs_constructor(node_p nodep)
static int
ngs_newhook(node_p node, hook_p hook, const char *name)
{
- NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node));
+ struct ngsock *const priv = NG_NODE_PRIVATE(node);
+ struct hookpriv *hp;
+ uint32_t h;
+
+ hp = malloc(sizeof(*hp), M_NETGRAPH_SOCK, M_NOWAIT);
+ if (hp == NULL)
+ return (ENOMEM);
+ if (node->nd_numhooks * 2 > priv->hmask)
+ ngs_rehash(node);
+ hp->hook = hook;
+ h = hash32_str(name, HASHINIT) & priv->hmask;
+ LIST_INSERT_HEAD(&priv->hash[h], hp, next);
+ NG_HOOK_SET_PRIVATE(hook, hp);
+
return (0);
}
@@ -781,6 +841,41 @@ ngs_connect(hook_p hook)
return (0);
}
+/* Look up hook by name */
+static hook_p
+ngs_findhook(node_p node, const char *name)
+{
+ struct ngsock *priv = NG_NODE_PRIVATE(node);
+ struct hookpriv *hp;
+ uint32_t h;
+
+ /*
+ * Microoptimisations for a ng_socket with no
+ * hooks, or with a single hook, which is a
+ * common case.
+ */
+ if (node->nd_numhooks == 0)
+ return (NULL);
+ if (node->nd_numhooks == 1) {
+ hook_p hook;
+
+ hook = LIST_FIRST(&node->nd_hooks);
+
+ if (strcmp(NG_HOOK_NAME(hook), name) == 0)
+ return (hook);
+ else
+ return (NULL);
+ }
+
+ h = hash32_str(name, HASHINIT) & priv->hmask;
+
+ LIST_FOREACH(hp, &priv->hash[h], next)
+ if (strcmp(NG_HOOK_NAME(hp->hook), name) == 0)
+ return (hp->hook);
+
+ return (NULL);
+}
+
/*
* Incoming messages get passed up to the control socket.
* Unless they are for us specifically (socket_type)
@@ -948,6 +1043,10 @@ ngs_disconnect(hook_p hook)
{
node_p node = NG_HOOK_NODE(hook);
struct ngsock *const priv = NG_NODE_PRIVATE(node);
+ struct hookpriv *hp = NG_HOOK_PRIVATE(hook);
+
+ LIST_REMOVE(hp, next);
+ free(hp, M_NETGRAPH_SOCK);
if ((priv->datasock) && (priv->datasock->ng_socket)) {
if (NG_NODE_NUMHOOKS(node) == 1)
OpenPOWER on IntegriCloud