From owner-svn-src-user@FreeBSD.ORG Fri Nov 23 14:53:29 2012 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 097F4AAE; Fri, 23 Nov 2012 14:53:29 +0000 (UTC) (envelope-from andre@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id D81568FC08; Fri, 23 Nov 2012 14:53:28 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id qANErS4l034911; Fri, 23 Nov 2012 14:53:28 GMT (envelope-from andre@svn.freebsd.org) Received: (from andre@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id qANErSKF034907; Fri, 23 Nov 2012 14:53:28 GMT (envelope-from andre@svn.freebsd.org) Message-Id: <201211231453.qANErSKF034907@svn.freebsd.org> From: Andre Oppermann Date: Fri, 23 Nov 2012 14:53:28 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r243458 - in user/andre/tcp_workqueue/sys: net netinet X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 23 Nov 2012 14:53:29 -0000 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 #include #include +#include #include #include @@ -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 #include #include +#include #include +#include #include #include #include #include #include +#include #include #include @@ -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 #include #include +#include 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);