summaryrefslogtreecommitdiffstats
path: root/sys/netgraph/ng_pppoe.c
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2008-01-31 22:42:37 +0000
committermav <mav@FreeBSD.org>2008-01-31 22:42:37 +0000
commit5af3bb221fe5d30a3b599cf21d96287ee1cf413f (patch)
treeaa31530a558000eea95bc2cf6bd16b9b690cdedd /sys/netgraph/ng_pppoe.c
parent9dcd92a86766c881bd5611e2c540271ec24be046 (diff)
downloadFreeBSD-src-5af3bb221fe5d30a3b599cf21d96287ee1cf413f.zip
FreeBSD-src-5af3bb221fe5d30a3b599cf21d96287ee1cf413f.tar.gz
Implement Session-ID hashing to improve receive performance scalability
for big number of concurrent sessions.
Diffstat (limited to 'sys/netgraph/ng_pppoe.c')
-rw-r--r--sys/netgraph/ng_pppoe.c101
1 files changed, 70 insertions, 31 deletions
diff --git a/sys/netgraph/ng_pppoe.c b/sys/netgraph/ng_pppoe.c
index b9bcb64..7c6807d 100644
--- a/sys/netgraph/ng_pppoe.c
+++ b/sys/netgraph/ng_pppoe.c
@@ -64,7 +64,6 @@ MALLOC_DEFINE(M_NETGRAPH_PPPOE, "netgraph_pppoe", "netgraph pppoe node");
#endif
#define SIGNOFF "session closed"
-#define OFFSETOF(s, e) ((char *)&((s *)0)->e - (char *)((s *)0))
/*
* This section contains the netgraph method declarations for the
@@ -236,9 +235,18 @@ struct sess_con {
ng_ID_t creator; /* who to notify */
struct pppoe_full_hdr pkt_hdr; /* used when connected */
negp neg; /* used when negotiating */
+ TAILQ_ENTRY(sess_con) sessions;
};
typedef struct sess_con *sessp;
+#define SESSHASHSIZE 0x0100
+#define SESSHASH(x) (((x) ^ ((x) >> 8)) & (SESSHASHSIZE - 1))
+
+struct sess_hash_entry {
+ struct mtx mtx;
+ TAILQ_HEAD(hhead, sess_con) head;
+};
+
/*
* Information we store for each node
*/
@@ -252,6 +260,7 @@ struct PPPoE {
#define COMPAT_3COM 0x00000001
#define COMPAT_DLINK 0x00000002
struct ether_header eh;
+ struct sess_hash_entry sesshash[SESSHASHSIZE];
};
typedef struct PPPoE *priv_p;
@@ -548,34 +557,52 @@ pppoe_find_svc(node_p node, const char *svc_name, int svc_len)
}
/**************************************************************************
- * Routine to find a particular session that matches an incoming packet. *
+ * Routines to find a particular session that matches an incoming packet. *
**************************************************************************/
-static hook_p
-pppoe_findsession(node_p node, const struct pppoe_full_hdr *wh)
+/* Add specified session to hash. */
+static void
+pppoe_addsession(sessp sp)
{
- hook_p hook = NULL;
- uint16_t session = ntohs(wh->ph.sid);
+ const priv_p privp = NG_NODE_PRIVATE(NG_HOOK_NODE(sp->hook));
+ uint16_t hash = SESSHASH(sp->Session_ID);
- /*
- * Find matching peer/session combination.
- */
- LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
- sessp sp = NG_HOOK_PRIVATE(hook);
+ mtx_lock(&privp->sesshash[hash].mtx);
+ TAILQ_INSERT_HEAD(&privp->sesshash[hash].head, sp, sessions);
+ mtx_unlock(&privp->sesshash[hash].mtx);
+}
- /* Skip any nonsession hook. */
- if (sp == NULL)
- continue;
+/* Delete specified session from hash. */
+static void
+pppoe_delsession(sessp sp)
+{
+ const priv_p privp = NG_NODE_PRIVATE(NG_HOOK_NODE(sp->hook));
+ uint16_t hash = SESSHASH(sp->Session_ID);
+
+ mtx_lock(&privp->sesshash[hash].mtx);
+ TAILQ_REMOVE(&privp->sesshash[hash].head, sp, sessions);
+ mtx_unlock(&privp->sesshash[hash].mtx);
+}
+
+/* Find matching peer/session combination. */
+static sessp
+pppoe_findsession(priv_p privp, const struct pppoe_full_hdr *wh)
+{
+ uint16_t session = ntohs(wh->ph.sid);
+ uint16_t hash = SESSHASH(session);
+ sessp sp = NULL;
+
+ mtx_lock(&privp->sesshash[hash].mtx);
+ TAILQ_FOREACH(sp, &privp->sesshash[hash].head, sessions) {
if (sp->Session_ID == session &&
- (sp->state == PPPOE_CONNECTED ||
- sp->state == PPPOE_NEWCONNECTED) &&
bcmp(sp->pkt_hdr.eh.ether_dhost,
wh->eh.ether_shost, ETHER_ADDR_LEN) == 0) {
break;
}
}
+ mtx_unlock(&privp->sesshash[hash].mtx);
CTR3(KTR_NET, "%20s: matched %p for %d", __func__, hook, session);
- return (hook);
+ return (sp);
}
static hook_p
@@ -608,7 +635,8 @@ pppoe_finduniq(node_p node, const struct pppoe_tag *tag)
static int
ng_pppoe_constructor(node_p node)
{
- priv_p privp;
+ priv_p privp;
+ int i;
/* Initialize private descriptor. */
privp = malloc(sizeof(*privp), M_NETGRAPH_PPPOE, M_NOWAIT | M_ZERO);
@@ -623,6 +651,11 @@ ng_pppoe_constructor(node_p node)
memset(&privp->eh.ether_dhost, 0xff, ETHER_ADDR_LEN);
privp->eh.ether_type = ETHERTYPE_PPPOE_DISC;
+ for (i = 0; i < SESSHASHSIZE; i++) {
+ mtx_init(&privp->sesshash[i].mtx, "PPPoE hash mutex", NULL, MTX_DEF);
+ TAILQ_INIT(&privp->sesshash[i].head);
+ }
+
CTR3(KTR_NET, "%20s: created node [%x] (%p)",
__func__, node->nd_ID, node);
@@ -1505,16 +1538,17 @@ ng_pppoe_rcvdata_ether(hook_p hook, item_p item)
* We should still have a copy of it.
*/
sp->state = PPPOE_SOFFER;
- }
- if (sp->state != PPPOE_SOFFER)
+ } else if (sp->state != PPPOE_SOFFER)
LEAVE (ENETUNREACH);
neg = sp->neg;
ng_uncallout(&neg->handle, node);
neg->pkt->pkt_header.ph.code = PADS_CODE;
- if (sp->Session_ID == 0)
+ if (sp->Session_ID == 0) {
neg->pkt->pkt_header.ph.sid =
htons(sp->Session_ID
= get_new_sid(node));
+ pppoe_addsession(sp);
+ }
send_sessionid(sp);
neg->timeout = 0;
/*
@@ -1584,6 +1618,7 @@ ng_pppoe_rcvdata_ether(hook_p hook, item_p item)
ng_uncallout(&neg->handle, node);
neg->pkt->pkt_header.ph.sid = wh->ph.sid;
sp->Session_ID = ntohs(wh->ph.sid);
+ pppoe_addsession(sp);
send_sessionid(sp);
neg->timeout = 0;
sp->state = PPPOE_CONNECTED;
@@ -1609,11 +1644,11 @@ ng_pppoe_rcvdata_ether(hook_p hook, item_p item)
/*
* Find matching peer/session combination.
*/
- sendhook = pppoe_findsession(node, wh);
- if (sendhook == NULL)
+ sp = pppoe_findsession(privp, wh);
+ if (sp == NULL)
LEAVE(ENETUNREACH);
/* Disconnect that hook. */
- ng_rmhook_self(sendhook);
+ ng_rmhook_self(sp->hook);
break;
default:
LEAVE(EPFNOSUPPORT);
@@ -1624,10 +1659,9 @@ ng_pppoe_rcvdata_ether(hook_p hook, item_p item)
/*
* Find matching peer/session combination.
*/
- sendhook = pppoe_findsession(node, wh);
- if (sendhook == NULL)
+ sp = pppoe_findsession(privp, wh);
+ if (sp == NULL)
LEAVE (ENETUNREACH);
- sp = NG_HOOK_PRIVATE(sendhook);
m_adj(m, sizeof(*wh));
/* If packet too short, dump it. */
@@ -1654,7 +1688,7 @@ ng_pppoe_rcvdata_ether(hook_p hook, item_p item)
LEAVE (ENETUNREACH);
}
}
- NG_FWD_NEW_DATA(error, item, sendhook, m);
+ NG_FWD_NEW_DATA(error, item, sp->hook, m);
break;
default:
LEAVE(EPFNOSUPPORT);
@@ -1692,11 +1726,14 @@ ng_pppoe_rcvdata_debug(hook_p hook, item_p item)
static int
ng_pppoe_shutdown(node_p node)
{
- const priv_p privdata = NG_NODE_PRIVATE(node);
+ const priv_p privp = NG_NODE_PRIVATE(node);
+ int i;
+ for (i = 0; i < SESSHASHSIZE; i++)
+ mtx_destroy(&privp->sesshash[i].mtx);
NG_NODE_SET_PRIVATE(node, NULL);
- NG_NODE_UNREF(privdata->node);
- free(privdata, M_NETGRAPH_PPPOE);
+ NG_NODE_UNREF(privp->node);
+ free(privp, M_NETGRAPH_PPPOE);
return (0);
}
@@ -1776,6 +1813,8 @@ ng_pppoe_disconnect(hook_p hook)
privp->ethernet_hook, m);
}
}
+ if (sp->Session_ID)
+ pppoe_delsession(sp);
/*
* As long as we have somewhere to store the timeout handle,
* we may have a timeout pending.. get rid of it.
OpenPOWER on IntegriCloud