Author: melifaro
Date: Mon Oct 22 14:10:17 2012
New Revision: 241888
URL: http://svn.freebsd.org/changeset/base/241888

Log:
  Make PFIL use per-VNET lock instead of per-AF lock. Since most used packet
  filters (ipfw and PF) use the same ruleset with the same lock for both
  AF_INET and AF_INET6 there is no need in more fine-grade locking.
  However, it is possible to request personal lock by specifying
  PFIL_FLAG_PRIVATE_LOCK flag in pfil_head structure (see pfil.9 for
  more details).
  
  Export PFIL lock via rw_lock(9)/rm_lock(9)-like API permitting pfil consumers
  to use this lock instead of own lock. This help reducing locks on main
  traffic path.
  
  pfil_assert() is currently not implemented due to absense of rm_assert().
  Waiting for some kind of r234648 to be merged in HEAD.
  
  This change is part of bigger patch reducing routing locking.
  
  Sponsored by: Yandex LLC
  Reviewed by:  glebius, ae
  OK'd by:      silence on net@
  MFC after:    3 weeks

Modified:
  head/share/man/man9/pfil.9
  head/sys/net/pfil.c
  head/sys/net/pfil.h

Modified: head/share/man/man9/pfil.9
==============================================================================
--- head/share/man/man9/pfil.9  Mon Oct 22 13:21:11 2012        (r241887)
+++ head/share/man/man9/pfil.9  Mon Oct 22 14:10:17 2012        (r241888)
@@ -28,7 +28,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 6, 2012
+.Dd October 22, 2012
 .Dt PFIL 9
 .Os
 .Sh NAME
@@ -39,7 +39,11 @@
 .Nm pfil_hook_get ,
 .Nm pfil_add_hook ,
 .Nm pfil_remove_hook ,
-.Nm pfil_run_hooks
+.Nm pfil_run_hooks ,
+.Nm pfil_rlock ,
+.Nm pfil_runlock ,
+.Nm pfil_wlock ,
+.Nm pfil_wunlock
 .Nd packet filter interface
 .Sh SYNOPSIS
 .In sys/param.h
@@ -62,6 +66,14 @@
 .Fn (*func) "void *arg" "struct mbuf **mp" "struct ifnet *" "int dir" "struct 
inpcb *"
 .Ft int
 .Fn pfil_run_hooks "struct pfil_head *head" "struct mbuf **mp" "struct ifnet 
*" "int dir" "struct inpcb *"
+.Ft void
+.Fn pfil_rlock "struct pfil_head *" "struct rm_priotracker *"
+.Ft void
+.Fn pfil_runlock "struct pfil_head *" "struct rm_priotracker *"
+.Ft void
+.Fn pfil_wlock "struct pfil_head *"
+.Ft void
+.Fn pfil_wunlock "struct pfil_head *"
 .Sh DESCRIPTION
 The
 .Nm
@@ -86,6 +98,16 @@ The data link type is a
 .Xr bpf 4
 DLT constant indicating what kind of header is present on the packet
 at the filtering point.
+Each filtering point uses common per-VNET rmlock by default.
+This can be changed by specifying
+.Vt PFIL_FLAG_PRIVATE_LOCK
+as
+.Vt "flags"
+field in the
+.Vt pfil_head
+structure.
+Note that specifying private lock can break filters sharing the same
+ruleset and/or state between different data link types.
 Filtering points may be unregistered with the
 .Fn pfil_head_unregister
 function.
@@ -122,6 +144,31 @@ The filter returns an error (errno) if t
 if the processing is to continue.
 If the packet processing is to stop, it is the responsibility of the
 filter to free the packet.
+.Pp
+Every filter hook is called with
+.Nm
+read lock held.
+All heads uses the same lock within the same VNET instance.
+Packet filter can use this lock instead of own locking model to
+improve performance.
+Since
+.Nm
+uses
+.Xr rmlock 9
+.Fn pfil_rlock
+and
+.Fn pfil_runlock
+require
+.Va struct rm_priotracker
+to be passed as argument.
+Filter can acquire and release writer lock via
+.Fn pfil_wlock
+and
+.Fn pfil_wunlock
+functions.
+See
+.Xr rmlock 9
+for more details.
 .Sh FILTERING POINTS
 Currently, filtering points are implemented for the following link types:
 .Pp
@@ -157,6 +204,7 @@ might sleep!
 .Sh SEE ALSO
 .Xr bpf 4 ,
 .Xr if_bridge 4
+.Xr rmlock 4
 .Sh HISTORY
 The
 .Nm
@@ -192,6 +240,9 @@ as well as be less IP-centric.
 .Pp
 Fine-grained locking was added in
 .Fx 5.2 .
+.Nm
+lock export was added in
+.Fx 10.0 .
 .Sh BUGS
 The
 .Fn pfil_hook_get

Modified: head/sys/net/pfil.c
==============================================================================
--- head/sys/net/pfil.c Mon Oct 22 13:21:11 2012        (r241887)
+++ head/sys/net/pfil.c Mon Oct 22 14:10:17 2012        (r241888)
@@ -61,6 +61,8 @@ static int pfil_list_remove(pfil_list_t 
 LIST_HEAD(pfilheadhead, pfil_head);
 VNET_DEFINE(struct pfilheadhead, pfil_head_list);
 #define        V_pfil_head_list        VNET(pfil_head_list)
+VNET_DEFINE(struct rmlock, pfil_lock);
+#define        V_pfil_lock     VNET(pfil_lock)
 
 /*
  * pfil_run_hooks() runs the specified packet filter hooks.
@@ -91,6 +93,60 @@ pfil_run_hooks(struct pfil_head *ph, str
 }
 
 /*
+ * pfil_try_rlock() acquires rm reader lock for specified head
+ * if this is immediately possible,
+ */
+int
+pfil_try_rlock(struct pfil_head *ph, struct rm_priotracker *tracker)
+{
+       return PFIL_TRY_RLOCK(ph, tracker);
+}
+
+/*
+ * pfil_rlock() acquires rm reader lock for specified head.
+ */
+void
+pfil_rlock(struct pfil_head *ph, struct rm_priotracker *tracker)
+{
+       PFIL_RLOCK(ph, tracker);
+}
+
+/*
+ * pfil_runlock() releases reader lock for specified head.
+ */
+void
+pfil_runlock(struct pfil_head *ph, struct rm_priotracker *tracker)
+{
+       PFIL_RUNLOCK(ph, tracker);
+}
+
+/*
+ * pfil_wlock() acquires writer lock for specified head.
+ */
+void
+pfil_wlock(struct pfil_head *ph)
+{
+       PFIL_WLOCK(ph);
+}
+
+/*
+ * pfil_wunlock() releases writer lock for specified head.
+ */
+void
+pfil_wunlock(struct pfil_head *ph)
+{
+       PFIL_WUNLOCK(ph);
+}
+
+/*
+ * pfil_wowned() releases writer lock for specified head.
+ */
+int
+pfil_wowned(struct pfil_head *ph)
+{
+       return PFIL_WOWNED(ph);
+}
+/*
  * pfil_head_register() registers a pfil_head with the packet filter hook
  * mechanism.
  */
@@ -295,6 +351,7 @@ vnet_pfil_init(const void *unused)
 {
 
        LIST_INIT(&V_pfil_head_list);
+       PFIL_LOCK_INIT_REAL(&V_pfil_lock, "shared");
        return (0);
 }
 
@@ -306,6 +363,7 @@ vnet_pfil_uninit(const void *unused)
 {
 
        /*  XXX should panic if list is not empty */
+       PFIL_LOCK_DESTROY_REAL(&V_pfil_lock);
        return (0);
 }
 

Modified: head/sys/net/pfil.h
==============================================================================
--- head/sys/net/pfil.h Mon Oct 22 13:21:11 2012        (r241887)
+++ head/sys/net/pfil.h Mon Oct 22 14:10:17 2012        (r241888)
@@ -64,6 +64,8 @@ typedef       TAILQ_HEAD(pfil_list, packet_fil
 #define        PFIL_TYPE_AF            1       /* key is AF_* type */
 #define        PFIL_TYPE_IFNET         2       /* key is ifnet pointer */
 
+#define        PFIL_FLAG_PRIVATE_LOCK  0x01    /* Personal lock instead of 
global */
+
 struct pfil_head {
        pfil_list_t     ph_in;
        pfil_list_t     ph_out;
@@ -72,7 +74,9 @@ struct pfil_head {
 #if defined( __linux__ ) || defined( _WIN32 )
        rwlock_t        ph_mtx;
 #else
-       struct rmlock   ph_lock;
+       struct rmlock   *ph_plock;      /* Pointer to the used lock */
+       struct rmlock   ph_lock;        /* Private lock storage */
+       int             flags;
 #endif
        union {
                u_long          phu_val;
@@ -90,21 +94,43 @@ int pfil_remove_hook(int (*func)(void *,
 int    pfil_run_hooks(struct pfil_head *, struct mbuf **, struct ifnet *,
            int, struct inpcb *inp);
 
+struct rm_priotracker; /* Do not require including rmlock header */
+int pfil_try_rlock(struct pfil_head *, struct rm_priotracker *);
+void pfil_rlock(struct pfil_head *, struct rm_priotracker *);
+void pfil_runlock(struct pfil_head *, struct rm_priotracker *);
+void pfil_wlock(struct pfil_head *);
+void pfil_wunlock(struct pfil_head *);
+int pfil_wowned(struct pfil_head *ph);
+
 int    pfil_head_register(struct pfil_head *);
 int    pfil_head_unregister(struct pfil_head *);
 
 struct pfil_head *pfil_head_get(int, u_long);
 
 #define        PFIL_HOOKED(p) ((p)->ph_nhooks > 0)
-#define        PFIL_LOCK_INIT(p) \
-    rm_init_flags(&(p)->ph_lock, "PFil hook read/write mutex", RM_RECURSE)
-#define        PFIL_LOCK_DESTROY(p) rm_destroy(&(p)->ph_lock)
-#define PFIL_RLOCK(p, t) rm_rlock(&(p)->ph_lock, (t))
-#define PFIL_WLOCK(p) rm_wlock(&(p)->ph_lock)
-#define PFIL_RUNLOCK(p, t) rm_runlock(&(p)->ph_lock, (t))
-#define PFIL_WUNLOCK(p) rm_wunlock(&(p)->ph_lock)
-#define PFIL_LIST_LOCK() mtx_lock(&pfil_global_lock)
-#define PFIL_LIST_UNLOCK() mtx_unlock(&pfil_global_lock)
+#define        PFIL_LOCK_INIT_REAL(l, t)       \
+       rm_init_flags(l, "PFil " t " rmlock", RM_RECURSE)
+#define        PFIL_LOCK_DESTROY_REAL(l)       \
+       rm_destroy(l)
+#define        PFIL_LOCK_INIT(p)       do {                    \
+       if ((p)->flags & PFIL_FLAG_PRIVATE_LOCK) {      \
+               PFIL_LOCK_INIT_REAL(&(p)->ph_lock, "private");  \
+               (p)->ph_plock = &(p)->ph_lock;          \
+       } else                                          \
+               (p)->ph_plock = &V_pfil_lock;           \
+} while (0)
+#define        PFIL_LOCK_DESTROY(p)    do {                    \
+       if ((p)->flags & PFIL_FLAG_PRIVATE_LOCK)        \
+               PFIL_LOCK_DESTROY_REAL((p)->ph_plock);  \
+} while (0)
+#define PFIL_TRY_RLOCK(p, t)   rm_try_rlock((p)->ph_plock, (t))
+#define PFIL_RLOCK(p, t)       rm_rlock((p)->ph_plock, (t))
+#define PFIL_WLOCK(p)          rm_wlock((p)->ph_plock)
+#define PFIL_RUNLOCK(p, t)     rm_runlock((p)->ph_plock, (t))
+#define PFIL_WUNLOCK(p)                rm_wunlock((p)->ph_plock)
+#define PFIL_WOWNED(p)         rm_wowned((p)->ph_plock)
+#define PFIL_LIST_LOCK()       mtx_lock(&pfil_global_lock)
+#define PFIL_LIST_UNLOCK()     mtx_unlock(&pfil_global_lock)
 
 static __inline struct packet_filter_hook *
 pfil_hook_get(int dir, struct pfil_head *ph)
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to