summaryrefslogtreecommitdiffstats
path: root/sys/netgraph/ng_l2tp.c
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2008-03-16 21:33:12 +0000
committermav <mav@FreeBSD.org>2008-03-16 21:33:12 +0000
commitc3b3361aa8323a81611ff4e1447358040a995709 (patch)
tree19cb49785e598aca2cba06a14151aab028f52206 /sys/netgraph/ng_l2tp.c
parent4ef010fa268dc6bcc40905f1ac5c17c21a92a5ed (diff)
downloadFreeBSD-src-c3b3361aa8323a81611ff4e1447358040a995709.zip
FreeBSD-src-c3b3361aa8323a81611ff4e1447358040a995709.tar.gz
Add session ID hashing to speedup incoming packets dispatch in case
of many connections working via the same tunnel. For example, in case of full "client <-> LAC <-> LNS" setup.
Diffstat (limited to 'sys/netgraph/ng_l2tp.c')
-rw-r--r--sys/netgraph/ng_l2tp.c85
1 files changed, 47 insertions, 38 deletions
diff --git a/sys/netgraph/ng_l2tp.c b/sys/netgraph/ng_l2tp.c
index 64fe0e3..1eeb1dc 100644
--- a/sys/netgraph/ng_l2tp.c
+++ b/sys/netgraph/ng_l2tp.c
@@ -100,6 +100,20 @@ MALLOC_DEFINE(M_NETGRAPH_L2TP, "netgraph_l2tp", "netgraph l2tp node");
/* Compare sequence numbers using circular math */
#define L2TP_SEQ_DIFF(x, y) ((int)((int16_t)(x) - (int16_t)(y)))
+#define SESSHASHSIZE 0x0020
+#define SESSHASH(x) (((x) ^ ((x) >> 8)) & (SESSHASHSIZE - 1))
+
+/* Hook private data (data session hooks only) */
+struct ng_l2tp_hook_private {
+ struct ng_l2tp_sess_config conf; /* hook/session config */
+ struct ng_l2tp_session_stats stats; /* per sessions statistics */
+ hook_p hook; /* hook reference */
+ u_int16_t ns; /* data ns sequence number */
+ u_int16_t nr; /* data nr sequence number */
+ LIST_ENTRY(ng_l2tp_hook_private) sessions;
+};
+typedef struct ng_l2tp_hook_private *hookpriv_p;
+
/*
* Sequence number state
*
@@ -141,18 +155,10 @@ struct ng_l2tp_private {
struct ng_l2tp_stats stats; /* node statistics */
struct l2tp_seq seq; /* ctrl sequence number state */
ng_ID_t ftarget; /* failure message target */
+ LIST_HEAD(, ng_l2tp_hook_private) sesshash[SESSHASHSIZE];
};
typedef struct ng_l2tp_private *priv_p;
-/* Hook private data (data session hooks only) */
-struct ng_l2tp_hook_private {
- struct ng_l2tp_sess_config conf; /* hook/session config */
- struct ng_l2tp_session_stats stats; /* per sessions statistics */
- u_int16_t ns; /* data ns sequence number */
- u_int16_t nr; /* data nr sequence number */
-};
-typedef struct ng_l2tp_hook_private *hookpriv_p;
-
/* Netgraph node methods */
static ng_constructor_t ng_l2tp_constructor;
static ng_rcvmsg_t ng_l2tp_rcvmsg;
@@ -179,7 +185,7 @@ static void ng_l2tp_seq_xack_timeout(node_p node, hook_p hook,
static void ng_l2tp_seq_rack_timeout(node_p node, hook_p hook,
void *arg1, int arg2);
-static ng_fn_eachhook ng_l2tp_find_session;
+static hookpriv_p ng_l2tp_find_session(priv_p privp, u_int16_t sid);
static ng_fn_eachhook ng_l2tp_reset_session;
#ifdef INVARIANTS
@@ -355,6 +361,7 @@ static int
ng_l2tp_constructor(node_p node)
{
priv_p priv;
+ int i;
/* Allocate private structure */
MALLOC(priv, priv_p, sizeof(*priv), M_NETGRAPH_L2TP, M_NOWAIT | M_ZERO);
@@ -371,6 +378,9 @@ ng_l2tp_constructor(node_p node)
/* Initialize sequence number state */
ng_l2tp_seq_init(priv);
+ for (i = 0; i < SESSHASHSIZE; i++)
+ LIST_INIT(&priv->sesshash[i]);
+
/* Done */
return (0);
}
@@ -398,6 +408,7 @@ ng_l2tp_newhook(node_p node, hook_p hook, const char *name)
static const char hexdig[16] = "0123456789abcdef";
u_int16_t session_id;
hookpriv_p hpriv;
+ uint16_t hash;
const char *hex;
int i;
int j;
@@ -424,7 +435,10 @@ ng_l2tp_newhook(node_p node, hook_p hook, const char *name)
hpriv->conf.session_id = htons(session_id);
hpriv->conf.control_dseq = L2TP_CONTROL_DSEQ;
hpriv->conf.enable_dseq = L2TP_ENABLE_DSEQ;
+ hpriv->hook = hook;
NG_HOOK_SET_PRIVATE(hook, hpriv);
+ hash = SESSHASH(hpriv->conf.session_id);
+ LIST_INSERT_HEAD(&priv->sesshash[hash], hpriv, sessions);
}
/* Done */
@@ -502,7 +516,6 @@ ng_l2tp_rcvmsg(node_p node, item_p item, hook_p lasthook)
struct ng_l2tp_sess_config *const conf =
(struct ng_l2tp_sess_config *)msg->data;
hookpriv_p hpriv;
- hook_p hook;
/* Check for invalid or illegal config. */
if (msg->header.arglen != sizeof(*conf)) {
@@ -515,13 +528,11 @@ ng_l2tp_rcvmsg(node_p node, item_p item, hook_p lasthook)
conf->peer_id = htons(conf->peer_id);
/* Find matching hook */
- NG_NODE_FOREACH_HOOK(node, ng_l2tp_find_session,
- (void *)(uintptr_t)conf->session_id, hook);
- if (hook == NULL) {
+ hpriv = ng_l2tp_find_session(priv, conf->session_id);
+ if (hpriv == NULL) {
error = ENOENT;
break;
}
- hpriv = NG_HOOK_PRIVATE(hook);
/* Update hook's config */
hpriv->conf = *conf;
@@ -532,7 +543,6 @@ ng_l2tp_rcvmsg(node_p node, item_p item, hook_p lasthook)
struct ng_l2tp_sess_config *conf;
u_int16_t session_id;
hookpriv_p hpriv;
- hook_p hook;
/* Get session ID */
if (msg->header.arglen != sizeof(session_id)) {
@@ -543,13 +553,11 @@ ng_l2tp_rcvmsg(node_p node, item_p item, hook_p lasthook)
session_id = htons(session_id);
/* Find matching hook */
- NG_NODE_FOREACH_HOOK(node, ng_l2tp_find_session,
- (void *)(uintptr_t)session_id, hook);
- if (hook == NULL) {
+ hpriv = ng_l2tp_find_session(priv, session_id);
+ if (hpriv == NULL) {
error = ENOENT;
break;
}
- hpriv = NG_HOOK_PRIVATE(hook);
/* Send response */
NG_MKRESPONSE(resp, msg, sizeof(hpriv->conf), M_NOWAIT);
@@ -589,7 +597,6 @@ ng_l2tp_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
uint16_t session_id;
hookpriv_p hpriv;
- hook_p hook;
/* Get session ID. */
if (msg->header.arglen != sizeof(session_id)) {
@@ -600,13 +607,11 @@ ng_l2tp_rcvmsg(node_p node, item_p item, hook_p lasthook)
session_id = htons(session_id);
/* Find matching hook. */
- NG_NODE_FOREACH_HOOK(node, ng_l2tp_find_session,
- (void *)(uintptr_t)session_id, hook);
- if (hook == NULL) {
+ hpriv = ng_l2tp_find_session(priv, session_id);
+ if (hpriv == NULL) {
error = ENOENT;
break;
}
- hpriv = NG_HOOK_PRIVATE(hook);
if (msg->header.cmd != NGM_L2TP_CLR_SESSION_STATS) {
NG_MKRESPONSE(resp, msg,
@@ -700,7 +705,9 @@ ng_l2tp_disconnect(hook_p hook)
else if (hook == priv->lower)
priv->lower = NULL;
else {
- FREE(NG_HOOK_PRIVATE(hook), M_NETGRAPH_L2TP);
+ const hookpriv_p hpriv = NG_HOOK_PRIVATE(hook);
+ LIST_REMOVE(hpriv, sessions);
+ FREE(hpriv, M_NETGRAPH_L2TP);
NG_HOOK_SET_PRIVATE(hook, NULL);
}
@@ -715,17 +722,20 @@ ng_l2tp_disconnect(hook_p hook)
*************************************************************************/
/*
- * Find the hook with a given session ID.
+ * Find the hook with a given session ID (in network order).
*/
-static int
-ng_l2tp_find_session(hook_p hook, void *arg)
+static hookpriv_p
+ng_l2tp_find_session(priv_p privp, u_int16_t sid)
{
- const hookpriv_p hpriv = NG_HOOK_PRIVATE(hook);
- const u_int16_t sid = (u_int16_t)(uintptr_t)arg;
+ uint16_t hash = SESSHASH(sid);
+ hookpriv_p hpriv = NULL;
- if (hpriv == NULL || hpriv->conf.session_id != sid)
- return (-1);
- return (0);
+ LIST_FOREACH(hpriv, &privp->sesshash[hash], sessions) {
+ if (hpriv->conf.session_id == sid)
+ break;
+ }
+
+ return (hpriv);
}
/*
@@ -861,15 +871,14 @@ ng_l2tp_rcvdata_lower(hook_p h, item_p item)
/* Check session ID (for data packets only) */
if ((hdr & L2TP_HDR_CTRL) == 0) {
- NG_NODE_FOREACH_HOOK(node, ng_l2tp_find_session,
- (void *)(uintptr_t)ids[1], hook);
- if (hook == NULL) {
+ hpriv = ng_l2tp_find_session(priv, ids[1]);
+ if (hpriv == NULL) {
priv->stats.recvUnknownSID++;
NG_FREE_ITEM(item);
NG_FREE_M(m);
ERROUT(ENOTCONN);
}
- hpriv = NG_HOOK_PRIVATE(hook);
+ hook = hpriv->hook;
}
/* Get Ns, Nr fields if present */
OpenPOWER on IntegriCloud