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.
This commit is contained in:
Alexander Motin 2008-03-16 21:33:12 +00:00
parent 709446e782
commit 4e7597635f

View File

@ -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 */