Date: Fri, 23 Nov 2012 14:53:28 +0000 (UTC) From: Andre Oppermann <andre@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r243458 - in user/andre/tcp_workqueue/sys: net netinet Message-ID: <201211231453.qANErSKF034907@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201211231453.qANErSKF034907>