Author: trociny
Date: Sun Sep  8 17:47:14 2013
New Revision: 255395
URL: http://svnweb.freebsd.org/changeset/base/255395

Log:
  MFC r254776:
  
  Make ipfw nat init/unint work correctly for VIMAGE:
  
  * Do per vnet instance cleanup (previously it was only for vnet0 on
    module unload, and led to libalias leaks and possible panics due to
    stale pointer dereferences).
  
  * Instead of protecting ipfw hooks registering/deregistering by only
    vnet0 lock (which does not prevent pointers access from another
    vnets), introduce per vnet ipfw_nat_loaded variable. The variable is
    set after hooks are registered and unset before they are deregistered.
  
  * Devirtualize ifaddr_event_tag as we run only one event handler for
    all vnets.
  
  * It is supposed that ifaddr_change event handler is called in the
    interface vnet context, so add an assertion.
  
  Reviewed by:  zec

Modified:
  stable/9/sys/netpfil/ipfw/ip_fw2.c
  stable/9/sys/netpfil/ipfw/ip_fw_nat.c
  stable/9/sys/netpfil/ipfw/ip_fw_private.h
Directory Properties:
  stable/9/sys/   (props changed)

Modified: stable/9/sys/netpfil/ipfw/ip_fw2.c
==============================================================================
--- stable/9/sys/netpfil/ipfw/ip_fw2.c  Sun Sep  8 17:28:11 2013        
(r255394)
+++ stable/9/sys/netpfil/ipfw/ip_fw2.c  Sun Sep  8 17:47:14 2013        
(r255395)
@@ -142,6 +142,8 @@ VNET_DEFINE(int, verbose_limit);
 /* layer3_chain contains the list of rules for layer 3 */
 VNET_DEFINE(struct ip_fw_chain, layer3_chain);
 
+VNET_DEFINE(int, ipfw_nat_ready) = 0;
+
 ipfw_nat_t *ipfw_nat_ptr = NULL;
 struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int);
 ipfw_nat_cfg_t *ipfw_nat_cfg_ptr;

Modified: stable/9/sys/netpfil/ipfw/ip_fw_nat.c
==============================================================================
--- stable/9/sys/netpfil/ipfw/ip_fw_nat.c       Sun Sep  8 17:28:11 2013        
(r255394)
+++ stable/9/sys/netpfil/ipfw/ip_fw_nat.c       Sun Sep  8 17:47:14 2013        
(r255395)
@@ -53,8 +53,7 @@ __FBSDID("$FreeBSD$");
 
 #include <machine/in_cksum.h>  /* XXX for in_cksum */
 
-static VNET_DEFINE(eventhandler_tag, ifaddr_event_tag);
-#define        V_ifaddr_event_tag      VNET(ifaddr_event_tag)
+static eventhandler_tag ifaddr_event_tag;
 
 static void
 ifaddr_change(void *arg __unused, struct ifnet *ifp)
@@ -63,6 +62,8 @@ ifaddr_change(void *arg __unused, struct
        struct ifaddr *ifa;
        struct ip_fw_chain *chain;
 
+       KASSERT(curvnet == ifp->if_vnet,
+           ("curvnet(%p) differs from iface vnet(%p)", curvnet, ifp->if_vnet));
        chain = &V_layer3_chain;
        IPFW_WLOCK(chain);
        /* Check every nat entry... */
@@ -590,11 +591,38 @@ ipfw_nat_get_log(struct sockopt *sopt)
        return(0);
 }
 
+static int
+vnet_ipfw_nat_init(const void *arg __unused)
+{
+
+       V_ipfw_nat_ready = 1;
+       return (0);
+}
+
+static int
+vnet_ipfw_nat_uninit(const void *arg __unused)
+{
+       struct cfg_nat *ptr, *ptr_temp;
+       struct ip_fw_chain *chain;
+
+       chain = &V_layer3_chain;
+       IPFW_WLOCK(chain);
+       LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) {
+               LIST_REMOVE(ptr, _next);
+               del_redir_spool_cfg(ptr, &ptr->redir_chain);
+               LibAliasUninit(ptr->lib);
+               free(ptr, M_IPFW);
+       }
+       flush_nat_ptrs(chain, -1 /* flush all */);
+       V_ipfw_nat_ready = 0;
+       IPFW_WUNLOCK(chain);
+       return (0);
+}
+
 static void
 ipfw_nat_init(void)
 {
 
-       IPFW_WLOCK(&V_layer3_chain);
        /* init ipfw hooks */
        ipfw_nat_ptr = ipfw_nat;
        lookup_nat_ptr = lookup_nat;
@@ -602,28 +630,16 @@ ipfw_nat_init(void)
        ipfw_nat_del_ptr = ipfw_nat_del;
        ipfw_nat_get_cfg_ptr = ipfw_nat_get_cfg;
        ipfw_nat_get_log_ptr = ipfw_nat_get_log;
-       IPFW_WUNLOCK(&V_layer3_chain);
-       V_ifaddr_event_tag = EVENTHANDLER_REGISTER(
-           ifaddr_event, ifaddr_change,
+
+       ifaddr_event_tag = EVENTHANDLER_REGISTER(ifaddr_event, ifaddr_change,
            NULL, EVENTHANDLER_PRI_ANY);
 }
 
 static void
 ipfw_nat_destroy(void)
 {
-       struct cfg_nat *ptr, *ptr_temp;
-       struct ip_fw_chain *chain;
 
-       chain = &V_layer3_chain;
-       IPFW_WLOCK(chain);
-       LIST_FOREACH_SAFE(ptr, &chain->nat, _next, ptr_temp) {
-               LIST_REMOVE(ptr, _next);
-               del_redir_spool_cfg(ptr, &ptr->redir_chain);
-               LibAliasUninit(ptr->lib);
-               free(ptr, M_IPFW);
-       }
-       EVENTHANDLER_DEREGISTER(ifaddr_event, V_ifaddr_event_tag);
-       flush_nat_ptrs(chain, -1 /* flush all */);
+       EVENTHANDLER_DEREGISTER(ifaddr_event, ifaddr_event_tag);
        /* deregister ipfw_nat */
        ipfw_nat_ptr = NULL;
        lookup_nat_ptr = NULL;
@@ -631,7 +647,6 @@ ipfw_nat_destroy(void)
        ipfw_nat_del_ptr = NULL;
        ipfw_nat_get_cfg_ptr = NULL;
        ipfw_nat_get_log_ptr = NULL;
-       IPFW_WUNLOCK(chain);
 }
 
 static int
@@ -641,11 +656,9 @@ ipfw_nat_modevent(module_t mod, int type
 
        switch (type) {
        case MOD_LOAD:
-               ipfw_nat_init();
                break;
 
        case MOD_UNLOAD:
-               ipfw_nat_destroy();
                break;
 
        default:
@@ -661,8 +674,25 @@ static moduledata_t ipfw_nat_mod = {
        0
 };
 
-DECLARE_MODULE(ipfw_nat, ipfw_nat_mod, SI_SUB_PROTO_IFATTACHDOMAIN, 
SI_ORDER_ANY);
+/* Define startup order. */
+#define        IPFW_NAT_SI_SUB_FIREWALL        SI_SUB_PROTO_IFATTACHDOMAIN
+#define        IPFW_NAT_MODEVENT_ORDER         (SI_ORDER_ANY - 255)
+#define        IPFW_NAT_MODULE_ORDER           (IPFW_NAT_MODEVENT_ORDER + 1)
+#define        IPFW_NAT_VNET_ORDER             (IPFW_NAT_MODEVENT_ORDER + 2)
+
+DECLARE_MODULE(ipfw_nat, ipfw_nat_mod, IPFW_NAT_SI_SUB_FIREWALL, SI_ORDER_ANY);
 MODULE_DEPEND(ipfw_nat, libalias, 1, 1, 1);
 MODULE_DEPEND(ipfw_nat, ipfw, 2, 2, 2);
 MODULE_VERSION(ipfw_nat, 1);
+
+SYSINIT(ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
+    ipfw_nat_init, NULL);
+VNET_SYSINIT(vnet_ipfw_nat_init, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_VNET_ORDER,
+    vnet_ipfw_nat_init, NULL);
+
+SYSUNINIT(ipfw_nat_destroy, IPFW_NAT_SI_SUB_FIREWALL, IPFW_NAT_MODULE_ORDER,
+    ipfw_nat_destroy, NULL);
+VNET_SYSUNINIT(vnet_ipfw_nat_uninit, IPFW_NAT_SI_SUB_FIREWALL,
+    IPFW_NAT_VNET_ORDER, vnet_ipfw_nat_uninit, NULL);
+
 /* end of file */

Modified: stable/9/sys/netpfil/ipfw/ip_fw_private.h
==============================================================================
--- stable/9/sys/netpfil/ipfw/ip_fw_private.h   Sun Sep  8 17:28:11 2013        
(r255394)
+++ stable/9/sys/netpfil/ipfw/ip_fw_private.h   Sun Sep  8 17:47:14 2013        
(r255395)
@@ -329,9 +329,11 @@ extern struct cfg_nat *(*lookup_nat_ptr)
 typedef int ipfw_nat_t(struct ip_fw_args *, struct cfg_nat *, struct mbuf *);
 typedef int ipfw_nat_cfg_t(struct sockopt *);
 
-extern ipfw_nat_t *ipfw_nat_ptr;
-#define IPFW_NAT_LOADED (ipfw_nat_ptr != NULL)
+VNET_DECLARE(int, ipfw_nat_ready);
+#define        V_ipfw_nat_ready        VNET(ipfw_nat_ready)
+#define        IPFW_NAT_LOADED (V_ipfw_nat_ready)
 
+extern ipfw_nat_t *ipfw_nat_ptr;
 extern ipfw_nat_cfg_t *ipfw_nat_cfg_ptr;
 extern ipfw_nat_cfg_t *ipfw_nat_del_ptr;
 extern ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr;
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to