svn commit: r241966 - user/andre/tcp_workqueue/sys/net
Andre Oppermann
andre at FreeBSD.org
Tue Oct 23 19:26:50 UTC 2012
Author: andre
Date: Tue Oct 23 19:26:49 2012
New Revision: 241966
URL: http://svn.freebsd.org/changeset/base/241966
Log:
Extend PFIL hooks with explicit hook ordering and reinjecting of
packets into the chain after a particular hook.
Add pfil_add_hook_order() taking a numerical value between 0-255
to specify the relative position of this hook in the list of all
hooks. Lower numbers have higher ordering (ie. will run first).
Within a particular order value the last added will be the first
to run. Three fixed positions are defined:
PFIL_ORDER_FIRST 0
PFIL_ORDER_DEFAULT 200
PFIL_ORDER_LAST 255
Previously the order was non-deterministic and dependent on the
ordering of the add hook calls. The last added would always
become the first to run.
Non-ordering aware pfil consumers using the pfil_add_hook() call
get PFIL_ORDER_DEFAULT assigned resulting in the previous ordering.
The ordering is determined at hookup time by the pfil consumer
and no tool for later manual re-ordering is provided. Most well
known pfil consumers are expected to have a predetermined preferred
position in the order. A tool or sysctl reporting the order of
hooked pfil consumers will be provided later.
Add pfil_run_inject() taking an opaque cookie value obtained with
pfil_get_cookie() after the hook is added. Processing of the hook
chain skips all hooks until after the one with the same cookie.
The cookie is valid as long as this hook remains hooked. If no
cookie is found processing is started with the first hook again.
If the cookie is invalid processing of all hooks is effectively
skipped.
With this pfil hooks consumers can dequeue packets for further
processing and later re-inject them with the next hook.
Modified:
user/andre/tcp_workqueue/sys/net/pfil.c
user/andre/tcp_workqueue/sys/net/pfil.h
Modified: user/andre/tcp_workqueue/sys/net/pfil.c
==============================================================================
--- user/andre/tcp_workqueue/sys/net/pfil.c Tue Oct 23 19:20:50 2012 (r241965)
+++ user/andre/tcp_workqueue/sys/net/pfil.c Tue Oct 23 19:26:49 2012 (r241966)
@@ -49,7 +49,8 @@
static MTX_DEF_SYSINIT(pfil_global_lock, "pfil_head_list lock", MTX_DEF);
-static int pfil_list_add(pfil_list_t *, struct packet_filter_hook *, int);
+static int pfil_list_add(pfil_list_t *, struct packet_filter_hook *, int,
+ uint8_t);
static int pfil_list_remove(pfil_list_t *,
int (*)(void *, struct mbuf **, struct ifnet *, int, struct inpcb *),
@@ -63,11 +64,22 @@ VNET_DEFINE(struct rmlock, pfil_lock);
/*
* pfil_run_hooks() runs the specified packet filter hooks.
+ *
+ * The cookie, if set, skips all hooks before the hook with
+ * the same cookie and continues with the next hook after it.
*/
int
pfil_run_hooks(struct pfil_head *ph, struct mbuf **mp, struct ifnet *ifp,
int dir, struct inpcb *inp)
{
+
+ return (pfil_run_inject(ph, mp, ifp, dir, inp, 0));
+}
+
+int
+pfil_run_inject(struct pfil_head *ph, struct mbuf **mp, struct ifnet *ifp,
+ int dir, struct inpcb *inp, int cookie)
+{
struct rm_priotracker rmpt;
struct packet_filter_hook *pfh;
struct mbuf *m = *mp;
@@ -77,6 +89,12 @@ pfil_run_hooks(struct pfil_head *ph, str
KASSERT(ph->ph_nhooks >= 0, ("Pfil hook count dropped < 0"));
for (pfh = pfil_hook_get(dir, ph); pfh != NULL;
pfh = TAILQ_NEXT(pfh, pfil_link)) {
+ if (cookie != 0) {
+ /* Continue on the next hook. */
+ if (pfh->pfil_cookie == cookie)
+ cookie = 0;
+ continue;
+ }
if (pfh->pfil_func != NULL) {
rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir,
inp);
@@ -213,11 +231,21 @@ pfil_head_get(int type, u_long val)
* PFIL_OUT call me on outgoing packets
* PFIL_ALL call me on all of the above
* PFIL_WAITOK OK to call malloc with M_WAITOK.
+ *
+ * The cookie is simply is a random value that should be unique.
*/
int
pfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *, int,
struct inpcb *), void *arg, int flags, struct pfil_head *ph)
{
+
+ return (pfil_add_hook_order(func, arg, flags, PFIL_ORDER_DEFAULT, ph));
+}
+
+int
+pfil_add_hook_order(int (*func)(void *, struct mbuf **, struct ifnet *, int,
+ struct inpcb *), void *arg, int flags, uint8_t order, struct pfil_head *ph)
+{
struct packet_filter_hook *pfh1 = NULL;
struct packet_filter_hook *pfh2 = NULL;
int err;
@@ -229,6 +257,10 @@ pfil_add_hook(int (*func)(void *, struct
err = ENOMEM;
goto error;
}
+ pfh1->pfil_func = func;
+ pfh1->pfil_arg = arg;
+ pfh1->pfil_cookie = (int)random();
+ pfh1->pfil_order = order;
}
if (flags & PFIL_OUT) {
pfh2 = (struct packet_filter_hook *)malloc(sizeof(*pfh1),
@@ -237,20 +269,20 @@ pfil_add_hook(int (*func)(void *, struct
err = ENOMEM;
goto error;
}
+ pfh2->pfil_func = func;
+ pfh2->pfil_arg = arg;
+ pfh2->pfil_cookie = (int)random();
+ pfh2->pfil_order = order;
}
PFIL_WLOCK(ph);
if (flags & PFIL_IN) {
- pfh1->pfil_func = func;
- pfh1->pfil_arg = arg;
- err = pfil_list_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT);
+ err = pfil_list_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT, order);
if (err)
goto locked_error;
ph->ph_nhooks++;
}
if (flags & PFIL_OUT) {
- pfh2->pfil_func = func;
- pfh2->pfil_arg = arg;
- err = pfil_list_add(&ph->ph_out, pfh2, flags & ~PFIL_IN);
+ err = pfil_list_add(&ph->ph_out, pfh2, flags & ~PFIL_IN, order);
if (err) {
if (flags & PFIL_IN)
pfil_list_remove(&ph->ph_in, func, arg);
@@ -295,8 +327,35 @@ pfil_remove_hook(int (*func)(void *, str
return (err);
}
+int
+pfil_get_cookie(int (*func)(void *, struct mbuf **, struct ifnet *, int,
+ struct inpcb *), void *arg, int flags, struct pfil_head *ph)
+{
+ pfil_list_t *list;
+ struct packet_filter_hook *pfh;
+ struct rm_priotracker tracker;
+ int cookie = 0;
+
+ PFIL_RLOCK(ph, &tracker);
+ if (flags & PFIL_IN)
+ list = &ph->ph_in;
+ else if (flags & PFIL_OUT)
+ list = &ph->ph_out;
+ else
+ goto out;
+
+ TAILQ_FOREACH(pfh, list, pfil_link)
+ if (pfh->pfil_func == func &&
+ pfh->pfil_arg == arg)
+ cookie = pfh->pfil_cookie;
+out:
+ PFIL_RUNLOCK(ph, &tracker);
+ return (cookie);
+}
+
static int
-pfil_list_add(pfil_list_t *list, struct packet_filter_hook *pfh1, int flags)
+pfil_list_add(pfil_list_t *list, struct packet_filter_hook *pfh1, int flags,
+ uint8_t order)
{
struct packet_filter_hook *pfh;
@@ -312,10 +371,24 @@ pfil_list_add(pfil_list_t *list, struct
* Insert the input list in reverse order of the output list so that
* the same path is followed in or out of the kernel.
*/
- if (flags & PFIL_IN)
- TAILQ_INSERT_HEAD(list, pfh1, pfil_link);
- else
- TAILQ_INSERT_TAIL(list, pfh1, pfil_link);
+ if (flags & PFIL_IN) {
+ TAILQ_FOREACH(pfh, list, pfil_link) {
+ if (pfh->pfil_order <= order)
+ break;
+ }
+ if (pfh == NULL)
+ TAILQ_INSERT_HEAD(list, pfh1, pfil_link);
+ else
+ TAILQ_INSERT_BEFORE(pfh, pfh1, pfil_link);
+ } else {
+ TAILQ_FOREACH_REVERSE(pfh, list, pfil_list, pfil_link)
+ if (pfh->pfil_order >= order)
+ break;
+ if (pfh == NULL)
+ TAILQ_INSERT_TAIL(list, pfh1, pfil_link);
+ else
+ TAILQ_INSERT_AFTER(list, pfh, pfh1, pfil_link);
+ }
return (0);
}
Modified: user/andre/tcp_workqueue/sys/net/pfil.h
==============================================================================
--- user/andre/tcp_workqueue/sys/net/pfil.h Tue Oct 23 19:20:50 2012 (r241965)
+++ user/andre/tcp_workqueue/sys/net/pfil.h Tue Oct 23 19:26:49 2012 (r241966)
@@ -52,8 +52,14 @@ struct packet_filter_hook {
int (*pfil_func)(void *, struct mbuf **, struct ifnet *, int,
struct inpcb *);
void *pfil_arg;
+ int pfil_cookie;
+ uint8_t pfil_order;
};
+#define PFIL_ORDER_FIRST 0
+#define PFIL_ORDER_DEFAULT 200
+#define PFIL_ORDER_LAST 255
+
#define PFIL_IN 0x00000001
#define PFIL_OUT 0x00000002
#define PFIL_WAITOK 0x00000004
@@ -89,10 +95,16 @@ struct pfil_head {
int pfil_add_hook(int (*func)(void *, struct mbuf **, struct ifnet *,
int, struct inpcb *), void *, int, struct pfil_head *);
+int pfil_add_hook_order(int (*func)(void *, struct mbuf **, struct ifnet *,
+ int, struct inpcb *), void *, int, uint8_t, struct pfil_head *);
+int pfil_get_cookie(int (*func)(void *, struct mbuf **, struct ifnet *,
+ int, struct inpcb *), void *, int, struct pfil_head *);
int pfil_remove_hook(int (*func)(void *, struct mbuf **, struct ifnet *,
int, struct inpcb *), void *, int, struct pfil_head *);
int pfil_run_hooks(struct pfil_head *, struct mbuf **, struct ifnet *,
int, struct inpcb *inp);
+int pfil_run_inject(struct pfil_head *, struct mbuf **, struct ifnet *,
+ int, struct inpcb *inp, int cookie);
struct rm_priotracker; /* Do not require including rmlock header */
int pfil_try_rlock(struct pfil_head *, struct rm_priotracker *);
More information about the svn-src-user
mailing list