svn commit: r243458 - in user/andre/tcp_workqueue/sys: net netinet
Andre Oppermann
andre at FreeBSD.org
Fri Nov 23 14:53:29 UTC 2012
Author: andre
Date: Fri Nov 23 14:53:28 2012
New Revision: 243458
URL: http://svnweb.freebsd.org/changeset/base/243458
Log:
Add sysctl support for pfil hook reporting and ordering.
pfil_head_register() takes an additional pointer to the parent sysctl
node pointer of the protocol family that is being registered here.
Two new branches are then attached named "pfil_in" and "pfil_out".
In each branch a list of the attached pfil hooks in the order of
their processing is provided in the "hooks" string sysctl.
In addition each attached pfil hook has its own node with a numeric
representation of is ordering rank (0-255). Writing a new ordering
rank changes the processing order. If two hooks have the same rank
the last installed or changed comes first.
Example output:
net.inet.pfil_in.hooks="pf,ipfw,ipfilter"
net.inet.pfil_in.pf=200
net.inet.pfil_in.ipfw=201
net.inet.pfil_in.ipfilter=202
net.inet.pfil_out.hooks="ipfilter,ipfw,pf"
net.inet.pfil_out.ipfilter=53
net.inet.pfil_out.ipfw=54
net.inet.pfil_out.pf=55
This may be further tweaked and refined.
Modified:
user/andre/tcp_workqueue/sys/net/if_ethersubr.c
user/andre/tcp_workqueue/sys/net/pfil.c
user/andre/tcp_workqueue/sys/net/pfil.h
user/andre/tcp_workqueue/sys/netinet/ip_input.c
Modified: user/andre/tcp_workqueue/sys/net/if_ethersubr.c
==============================================================================
--- user/andre/tcp_workqueue/sys/net/if_ethersubr.c Fri Nov 23 14:20:27 2012 (r243457)
+++ user/andre/tcp_workqueue/sys/net/if_ethersubr.c Fri Nov 23 14:53:28 2012 (r243458)
@@ -48,6 +48,7 @@
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
+#include <sys/types.h>
#include <net/if.h>
#include <net/if_arp.h>
@@ -686,7 +687,8 @@ vnet_ether_init(__unused void *arg)
/* Initialize packet filter hooks. */
V_link_pfil_hook.ph_type = PFIL_TYPE_AF;
V_link_pfil_hook.ph_af = AF_LINK;
- if ((i = pfil_head_register(&V_link_pfil_hook)) != 0)
+ if ((i = pfil_head_register(&V_link_pfil_hook,
+ SYSCTL_STATIC_CHILDREN(_net_link_ether))) != 0)
printf("%s: WARNING: unable to register pfil link hook, "
"error %d\n", __func__, i);
}
Modified: user/andre/tcp_workqueue/sys/net/pfil.c
==============================================================================
--- user/andre/tcp_workqueue/sys/net/pfil.c Fri Nov 23 14:20:27 2012 (r243457)
+++ user/andre/tcp_workqueue/sys/net/pfil.c Fri Nov 23 14:53:28 2012 (r243458)
@@ -37,12 +37,15 @@
#include <sys/rmlock.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
+#include <sys/sysctl.h>
#include <sys/systm.h>
+#include <sys/types.h>
#include <sys/condvar.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/queue.h>
+#include <sys/sbuf.h>
#include <net/if.h>
#include <net/pfil.h>
@@ -50,9 +53,10 @@
static struct mtx pfil_global_lock;
MTX_SYSINIT(pfil_global_lock, &pfil_global_lock, "pfil_head_list lock", MTX_DEF);
-static int pfil_chain_add(pfil_chain_t *, struct packet_filter_hook *,
- int, uint8_t);
+static int pfil_chain_add(pfil_chain_t *, struct packet_filter_hook *, int);
static int pfil_chain_remove(pfil_chain_t *, pfil_func_t, void *);
+static int pfil_chain_sysctl(SYSCTL_HANDLER_ARGS);
+static int pfil_hook_sysctl(SYSCTL_HANDLER_ARGS);
LIST_HEAD(pfilheadhead, pfil_head);
VNET_DEFINE(struct pfilheadhead, pfil_head_list);
@@ -178,7 +182,7 @@ pfil_wowned(struct pfil_head *ph)
* mechanism.
*/
int
-pfil_head_register(struct pfil_head *ph)
+pfil_head_register(struct pfil_head *ph, struct sysctl_oid_list *parent)
{
struct pfil_head *lph;
@@ -195,6 +199,18 @@ pfil_head_register(struct pfil_head *ph)
TAILQ_INIT(&ph->ph_in);
TAILQ_INIT(&ph->ph_out);
LIST_INSERT_HEAD(&V_pfil_head_list, ph, ph_list);
+ sysctl_ctx_init(ph->ph_sysctl_ctx);
+ ph->ph_sysctl_oid_in = SYSCTL_ADD_NODE(ph->ph_sysctl_ctx, parent,
+ OID_AUTO, "pfil_in", CTLFLAG_RD, NULL, "input packet filter hooks");
+ SYSCTL_ADD_PROC(ph->ph_sysctl_ctx, SYSCTL_CHILDREN(ph->ph_sysctl_oid_in),
+ OID_AUTO, "hooks", (CTLTYPE_STRING|CTLFLAG_RD), ph, (intptr_t)&ph->ph_in,
+ pfil_chain_sysctl, "S", "input chain list");
+ ph->ph_sysctl_oid_out = SYSCTL_ADD_NODE(ph->ph_sysctl_ctx, parent,
+ OID_AUTO, "pfil_out", CTLFLAG_RD, NULL, "output packet filter hooks");
+ SYSCTL_ADD_PROC(ph->ph_sysctl_ctx, SYSCTL_CHILDREN(ph->ph_sysctl_oid_out),
+ OID_AUTO, "hooks", (CTLTYPE_STRING|CTLFLAG_RD), ph, (intptr_t)&ph->ph_out,
+ pfil_chain_sysctl, "S", "output chain list");
+
PFIL_HEADLIST_UNLOCK();
return (0);
}
@@ -212,6 +228,7 @@ pfil_head_unregister(struct pfil_head *p
PFIL_HEADLIST_LOCK();
LIST_REMOVE(ph, ph_list);
PFIL_HEADLIST_UNLOCK();
+ sysctl_ctx_free(ph->ph_sysctl_ctx); /* Removes all children. */
TAILQ_FOREACH_SAFE(pfh, &ph->ph_in, pfil_chain, pfnext)
free(pfh, M_IFADDR);
TAILQ_FOREACH_SAFE(pfh, &ph->ph_out, pfil_chain, pfnext)
@@ -262,6 +279,11 @@ pfil_add_hook_order(pfil_func_t func, vo
struct packet_filter_hook *pfh2 = NULL;
int err;
+ KASSERT(func != NULL || arg != NULL || ph != NULL,
+ ("%s: func, arg or ph is NULL", __func__));
+ KASSERT(name != NULL || *name != '\0',
+ ("%s: name is NULL or empty", __func__));
+
if (flags & PFIL_IN) {
pfh1 = (struct packet_filter_hook *)malloc(sizeof(*pfh1),
M_IFADDR, (flags & PFIL_WAITOK) ? M_WAITOK : M_NOWAIT);
@@ -274,6 +296,7 @@ pfil_add_hook_order(pfil_func_t func, vo
pfh1->pfil_cookie = (int)random();
pfh1->pfil_order = order;
pfh1->pfil_name = name;
+ pfh1->pfil_head = ph;
}
if (flags & PFIL_OUT) {
pfh2 = (struct packet_filter_hook *)malloc(sizeof(*pfh1),
@@ -287,16 +310,17 @@ pfil_add_hook_order(pfil_func_t func, vo
pfh2->pfil_cookie = (int)random();
pfh2->pfil_order = order;
pfh2->pfil_name = name;
+ pfh2->pfil_head = ph;
}
PFIL_WLOCK(ph);
if (flags & PFIL_IN) {
- err = pfil_chain_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT, order);
+ err = pfil_chain_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT);
if (err)
goto locked_error;
ph->ph_nhooks++;
}
if (flags & PFIL_OUT) {
- err = pfil_chain_add(&ph->ph_out, pfh2, flags & ~PFIL_IN, order);
+ err = pfil_chain_add(&ph->ph_out, pfh2, flags & ~PFIL_IN);
if (err) {
if (flags & PFIL_IN)
pfil_chain_remove(&ph->ph_in, func, arg);
@@ -304,6 +328,22 @@ pfil_add_hook_order(pfil_func_t func, vo
}
ph->ph_nhooks++;
}
+
+ if (flags & PFIL_IN) {
+ pfh1->pfil_sysctl_oid = SYSCTL_ADD_PROC(ph->ph_sysctl_ctx,
+ SYSCTL_CHILDREN(ph->ph_sysctl_oid_in), OID_AUTO, name,
+ (CTLTYPE_INT|CTLFLAG_RW), pfh1,(intptr_t)&ph->ph_in,
+ pfil_hook_sysctl, "I",
+ "place in input chain of this packet filter hook");
+ }
+ if (flags & PFIL_OUT) {
+ pfh2->pfil_sysctl_oid = SYSCTL_ADD_PROC(ph->ph_sysctl_ctx,
+ SYSCTL_CHILDREN(ph->ph_sysctl_oid_out), OID_AUTO, name,
+ (CTLTYPE_INT|CTLFLAG_RW), pfh2, (intptr_t)&ph->ph_out,
+ pfil_hook_sysctl, "I",
+ "place in output chain of this packet filter hook");
+ }
+
PFIL_WUNLOCK(ph);
return (0);
locked_error:
@@ -369,8 +409,7 @@ out:
* Internal: Add a new pfil hook into a hook chain.
*/
static int
-pfil_chain_add(pfil_chain_t *chain, struct packet_filter_hook *pfh1, int flags,
- uint8_t order)
+pfil_chain_add(pfil_chain_t *chain, struct packet_filter_hook *pfh1, int flags)
{
struct packet_filter_hook *pfh;
@@ -388,7 +427,7 @@ pfil_chain_add(pfil_chain_t *chain, stru
*/
if (flags & PFIL_IN) {
TAILQ_FOREACH(pfh, chain, pfil_chain) {
- if (pfh->pfil_order <= order)
+ if (pfh->pfil_order <= pfh1->pfil_order)
break;
}
if (pfh == NULL)
@@ -397,7 +436,7 @@ pfil_chain_add(pfil_chain_t *chain, stru
TAILQ_INSERT_BEFORE(pfh, pfh1, pfil_chain);
} else {
TAILQ_FOREACH_REVERSE(pfh, chain, pfil_chain, pfil_chain)
- if (pfh->pfil_order >= order)
+ if (pfh->pfil_order >= pfh1->pfil_order)
break;
if (pfh == NULL)
TAILQ_INSERT_TAIL(chain, pfh1, pfil_chain);
@@ -409,6 +448,7 @@ pfil_chain_add(pfil_chain_t *chain, stru
/*
* Internal: Remove a pfil hook from a hook chain.
+ * NB: Frees the packet_filter_hook struct.
*/
static int
pfil_chain_remove(pfil_chain_t *chain, pfil_func_t func, void *arg)
@@ -418,6 +458,7 @@ pfil_chain_remove(pfil_chain_t *chain, p
TAILQ_FOREACH(pfh, chain, pfil_chain)
if (pfh->pfil_func == func && pfh->pfil_arg == arg) {
TAILQ_REMOVE(chain, pfh, pfil_chain);
+ sysctl_remove_oid(pfh->pfil_sysctl_oid, 1, 0);
free(pfh, M_IFADDR);
return (0);
}
@@ -425,6 +466,94 @@ pfil_chain_remove(pfil_chain_t *chain, p
}
/*
+ * Report an ordered list of pfil hook names.
+ */
+static int
+pfil_chain_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct rm_priotracker rmpt;
+ struct pfil_head *ph;
+ struct pfil_chain *chain;
+ struct packet_filter_hook *pfh;
+ struct sbuf *sb;
+ int error;
+
+ ph = arg1;
+ chain = (struct pfil_chain *)arg2;
+
+ sb = sbuf_new_auto();
+ PFIL_RLOCK(ph, &rmpt);
+ if (chain == &ph->ph_in) {
+ TAILQ_FOREACH(pfh, chain, pfil_chain) {
+ sbuf_cat(sb, pfh->pfil_name);
+ if (TAILQ_NEXT(pfh, pfil_chain) != NULL)
+ sbuf_cat(sb, ",");
+ }
+ } else {
+ TAILQ_FOREACH_REVERSE(pfh, chain, pfil_chain, pfil_chain) {
+ sbuf_cat(sb, pfh->pfil_name);
+ if (TAILQ_PREV(pfh, pfil_chain, pfil_chain) != NULL)
+ sbuf_cat(sb, ",");
+ }
+ }
+ PFIL_RUNLOCK(ph, &rmpt);
+ if ((error = sbuf_finish(sb)) != 0)
+ goto out;
+
+ error = sysctl_handle_string(oidp, sbuf_data(sb), sbuf_len(sb), req);
+out:
+ sbuf_delete(sb);
+ return (error);
+}
+
+/*
+ * Report the order rank of a pfil hook.
+ * Change the rank if a new value is provided.
+ */
+static int
+pfil_hook_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct rm_priotracker rmpt;
+ struct pfil_head *ph;
+ struct pfil_chain *chain;
+ struct packet_filter_hook *pfh;
+ int error, flags, order;
+
+ pfh = arg1;
+ chain = (pfil_chain_t *)arg2;
+
+ ph = pfh->pfil_head;
+ PFIL_RLOCK(ph, &rmpt);
+ order = pfh->pfil_order;
+ if (chain == &ph->ph_in)
+ order = pfh->pfil_order;
+ else
+ order = ~pfh->pfil_order;
+ PFIL_RUNLOCK(ph, &rmpt);
+
+ error = sysctl_handle_int(oidp, &order, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ goto out;
+
+ if (order < 255 && order >= 0) {
+ PFIL_WLOCK(ph);
+ pfh->pfil_order = order;
+ if (chain == &ph->ph_in)
+ flags = PFIL_IN;
+ else {
+ flags = PFIL_OUT;
+ pfh->pfil_order = ~pfh->pfil_order;
+ }
+ TAILQ_REMOVE(chain, pfh, pfil_chain);
+ pfil_chain_add(chain, pfh, flags);
+ PFIL_WUNLOCK(ph);
+ } else
+ error = EINVAL;
+out:
+ return (error);
+}
+
+/*
* Stuff that must be initialized for every instance (including the first of
* course).
*/
Modified: user/andre/tcp_workqueue/sys/net/pfil.h
==============================================================================
--- user/andre/tcp_workqueue/sys/net/pfil.h Fri Nov 23 14:20:27 2012 (r243457)
+++ user/andre/tcp_workqueue/sys/net/pfil.h Fri Nov 23 14:53:28 2012 (r243458)
@@ -38,6 +38,7 @@
#include <sys/_mutex.h>
#include <sys/lock.h>
#include <sys/rmlock.h>
+#include <sys/sysctl.h>
struct mbuf;
struct ifnet;
@@ -58,6 +59,8 @@ struct packet_filter_hook {
int pfil_cookie;
uint8_t pfil_order;
char *pfil_name;
+ struct sysctl_oid *pfil_sysctl_oid;
+ struct pfil_head *pfil_head;
};
#define PFIL_ORDER_FIRST 0
@@ -94,12 +97,15 @@ struct pfil_head {
} ph_un;
#define ph_af ph_un.phu_val
#define ph_ifnet ph_un.phu_ptr
+ struct sysctl_ctx_list *ph_sysctl_ctx;
+ struct sysctl_oid *ph_sysctl_oid_in;
+ struct sysctl_oid *ph_sysctl_oid_out;
LIST_ENTRY(pfil_head) ph_list;
};
/* Public functions for pfil head management by protocols. */
struct pfil_head *pfil_head_get(int, u_long);
-int pfil_head_register(struct pfil_head *);
+int pfil_head_register(struct pfil_head *, struct sysctl_oid_list *);
int pfil_head_unregister(struct pfil_head *);
/* Public functions for pfil hook management by protocols. */
Modified: user/andre/tcp_workqueue/sys/netinet/ip_input.c
==============================================================================
--- user/andre/tcp_workqueue/sys/netinet/ip_input.c Fri Nov 23 14:20:27 2012 (r243457)
+++ user/andre/tcp_workqueue/sys/netinet/ip_input.c Fri Nov 23 14:53:28 2012 (r243458)
@@ -298,7 +298,8 @@ ip_init(void)
/* Initialize packet filter hooks. */
V_inet_pfil_hook.ph_type = PFIL_TYPE_AF;
V_inet_pfil_hook.ph_af = AF_INET;
- if ((i = pfil_head_register(&V_inet_pfil_hook)) != 0)
+ if ((i = pfil_head_register(&V_inet_pfil_hook,
+ SYSCTL_STATIC_CHILDREN(_net_inet))) != 0)
printf("%s: WARNING: unable to register pfil hook, "
"error %d\n", __func__, i);
More information about the svn-src-user
mailing list