Merge branch 'master' of git://1984.lsi.us.es/net-next
authorDavid S. Miller <davem@davemloft.net>
Mon, 11 Jun 2012 19:56:14 +0000 (12:56 -0700)
committerDavid S. Miller <davem@davemloft.net>
Mon, 11 Jun 2012 19:56:14 +0000 (12:56 -0700)
34 files changed:
Documentation/feature-removal-schedule.txt
include/linux/netfilter.h
include/linux/netfilter/nfnetlink_queue.h
include/linux/netfilter/xt_connlimit.h
include/linux/netfilter/xt_recent.h
include/linux/netfilter_ipv4/Kbuild
include/linux/netfilter_ipv4/ipt_addrtype.h [deleted file]
include/net/netfilter/nf_conntrack_core.h
include/net/netfilter/nf_conntrack_l3proto.h
include/net/netfilter/nf_conntrack_l4proto.h
include/net/netns/conntrack.h
net/bridge/br_netfilter.c
net/decnet/netfilter/dn_rtmsg.c
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
net/ipv4/netfilter/nf_defrag_ipv4.c
net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
net/netfilter/ipvs/ip_vs_core.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_proto.c
net/netfilter/nf_conntrack_proto_dccp.c
net/netfilter/nf_conntrack_proto_generic.c
net/netfilter/nf_conntrack_proto_gre.c
net/netfilter/nf_conntrack_proto_sctp.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nf_conntrack_proto_udp.c
net/netfilter/nf_conntrack_proto_udplite.c
net/netfilter/nfnetlink_cttimeout.c
net/netfilter/nfnetlink_queue.c
net/netfilter/xt_NFQUEUE.c
net/netfilter/xt_connlimit.c
net/netfilter/xt_recent.c
security/selinux/hooks.c

index 56000b33340bbe33f0b141934c756470d32ecbbd..bc4b9c6eb80edd57c0ef8d2f6e5733a699accf04 100644 (file)
@@ -414,21 +414,6 @@ Who:       Jean Delvare <khali@linux-fr.org>
 
 ----------------------------
 
-What:  xt_connlimit rev 0
-When:  2012
-Who:   Jan Engelhardt <jengelh@medozas.de>
-Files: net/netfilter/xt_connlimit.c
-
-----------------------------
-
-What:  ipt_addrtype match include file
-When:  2012
-Why:   superseded by xt_addrtype
-Who:   Florian Westphal <fw@strlen.de>
-Files: include/linux/netfilter_ipv4/ipt_addrtype.h
-
-----------------------------
-
 What:  i2c_driver.attach_adapter
        i2c_driver.detach_adapter
 When:  September 2011
@@ -589,6 +574,13 @@ Why:       Remount currently allows changing bound subsystems and
 
 ----------------------------
 
+What:  xt_recent rev 0
+When:  2013
+Who:   Pablo Neira Ayuso <pablo@netfilter.org>
+Files: net/netfilter/xt_recent.c
+
+----------------------------
+
 What:  KVM debugfs statistics
 When:  2013
 Why:   KVM tracepoints provide mostly equivalent information in a much more
index ff9c84c29b28a5df3673e5618fc9df76bc0adb3e..4541f33dbfc3ab34d8251323f9953d778bb7e019 100644 (file)
@@ -94,6 +94,16 @@ static inline int nf_inet_addr_cmp(const union nf_inet_addr *a1,
               a1->all[3] == a2->all[3];
 }
 
+static inline void nf_inet_addr_mask(const union nf_inet_addr *a1,
+                                    union nf_inet_addr *result,
+                                    const union nf_inet_addr *mask)
+{
+       result->all[0] = a1->all[0] & mask->all[0];
+       result->all[1] = a1->all[1] & mask->all[1];
+       result->all[2] = a1->all[2] & mask->all[2];
+       result->all[3] = a1->all[3] & mask->all[3];
+}
+
 extern void netfilter_init(void);
 
 /* Largest hook number + 1 */
index 24b32e6c009e773f60a445228917740bd25f73b6..a6c1ddac05cc005dc2fff3d00c853193aa9bf3a5 100644 (file)
@@ -84,8 +84,13 @@ enum nfqnl_attr_config {
        NFQA_CFG_CMD,                   /* nfqnl_msg_config_cmd */
        NFQA_CFG_PARAMS,                /* nfqnl_msg_config_params */
        NFQA_CFG_QUEUE_MAXLEN,          /* __u32 */
+       NFQA_CFG_MASK,                  /* identify which flags to change */
+       NFQA_CFG_FLAGS,                 /* value of these flags (__u32) */
        __NFQA_CFG_MAX
 };
 #define NFQA_CFG_MAX (__NFQA_CFG_MAX-1)
 
+/* Flags for NFQA_CFG_FLAGS */
+#define NFQA_CFG_F_FAIL_OPEN                   (1 << 0)
+
 #endif /* _NFNETLINK_QUEUE_H */
index d1366f05d1b26076945e0a2cc791c6d0909347ad..f1656096121e045ff8dcd8ab4d140e7c9a312396 100644 (file)
@@ -22,13 +22,8 @@ struct xt_connlimit_info {
 #endif
        };
        unsigned int limit;
-       union {
-               /* revision 0 */
-               unsigned int inverse;
-
-               /* revision 1 */
-               __u32 flags;
-       };
+       /* revision 1 */
+       __u32 flags;
 
        /* Used internally by the kernel */
        struct xt_connlimit_data *data __attribute__((aligned(8)));
index 83318e01425e74494f5c48fb25f83d015e522d01..6ef36c113e89db5dc9b00811fd4036471ddd08d4 100644 (file)
@@ -32,4 +32,14 @@ struct xt_recent_mtinfo {
        __u8 side;
 };
 
+struct xt_recent_mtinfo_v1 {
+       __u32 seconds;
+       __u32 hit_count;
+       __u8 check_set;
+       __u8 invert;
+       char name[XT_RECENT_NAME_LEN];
+       __u8 side;
+       union nf_inet_addr mask;
+};
+
 #endif /* _LINUX_NETFILTER_XT_RECENT_H */
index c61b8fb1a9ef1b653329fa94df5eb42695155833..8ba0c5b72ea9f2e114399318f8a2ff2ff6078661 100644 (file)
@@ -5,7 +5,6 @@ header-y += ipt_LOG.h
 header-y += ipt_REJECT.h
 header-y += ipt_TTL.h
 header-y += ipt_ULOG.h
-header-y += ipt_addrtype.h
 header-y += ipt_ah.h
 header-y += ipt_ecn.h
 header-y += ipt_ttl.h
diff --git a/include/linux/netfilter_ipv4/ipt_addrtype.h b/include/linux/netfilter_ipv4/ipt_addrtype.h
deleted file mode 100644 (file)
index 0da4223..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _IPT_ADDRTYPE_H
-#define _IPT_ADDRTYPE_H
-
-#include <linux/types.h>
-
-enum {
-       IPT_ADDRTYPE_INVERT_SOURCE      = 0x0001,
-       IPT_ADDRTYPE_INVERT_DEST        = 0x0002,
-       IPT_ADDRTYPE_LIMIT_IFACE_IN     = 0x0004,
-       IPT_ADDRTYPE_LIMIT_IFACE_OUT    = 0x0008,
-};
-
-struct ipt_addrtype_info_v1 {
-       __u16   source;         /* source-type mask */
-       __u16   dest;           /* dest-type mask */
-       __u32   flags;
-};
-
-/* revision 0 */
-struct ipt_addrtype_info {
-       __u16   source;         /* source-type mask */
-       __u16   dest;           /* dest-type mask */
-       __u32   invert_source;
-       __u32   invert_dest;
-};
-
-#endif
index aced085132e7e52591f05ba1f1529dbba420465b..d8f5b9f5216939d2053c8c99ad54925fb5a0ce5c 100644 (file)
@@ -28,8 +28,8 @@ extern unsigned int nf_conntrack_in(struct net *net,
 extern int nf_conntrack_init(struct net *net);
 extern void nf_conntrack_cleanup(struct net *net);
 
-extern int nf_conntrack_proto_init(void);
-extern void nf_conntrack_proto_fini(void);
+extern int nf_conntrack_proto_init(struct net *net);
+extern void nf_conntrack_proto_fini(struct net *net);
 
 extern bool
 nf_ct_get_tuple(const struct sk_buff *skb,
index 9699c028b74b5731432726142687df4bd51aa450..6f7c13f4ac0329366ed32b9c5a27dc13253daff5 100644 (file)
@@ -64,11 +64,12 @@ struct nf_conntrack_l3proto {
        size_t nla_size;
 
 #ifdef CONFIG_SYSCTL
-       struct ctl_table_header *ctl_table_header;
        const char              *ctl_table_path;
-       struct ctl_table        *ctl_table;
 #endif /* CONFIG_SYSCTL */
 
+       /* Init l3proto pernet data */
+       int (*init_net)(struct net *net);
+
        /* Module (if any) which this is connected to. */
        struct module *me;
 };
@@ -76,8 +77,10 @@ struct nf_conntrack_l3proto {
 extern struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX];
 
 /* Protocol registration. */
-extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto);
-extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto);
+extern int nf_conntrack_l3proto_register(struct net *net,
+                                        struct nf_conntrack_l3proto *proto);
+extern void nf_conntrack_l3proto_unregister(struct net *net,
+                                           struct nf_conntrack_l3proto *proto);
 extern struct nf_conntrack_l3proto *nf_ct_l3proto_find_get(u_int16_t l3proto);
 extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p);
 
index 3b572bb20aa2bb1105cba9f04b28594108b63bc9..81c52b5205f2ea891aec766073af8edfcb527e3d 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/netlink.h>
 #include <net/netlink.h>
 #include <net/netfilter/nf_conntrack.h>
+#include <net/netns/generic.h>
 
 struct seq_file;
 
@@ -86,23 +87,18 @@ struct nf_conntrack_l4proto {
 #if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT)
        struct {
                size_t obj_size;
-               int (*nlattr_to_obj)(struct nlattr *tb[], void *data);
+               int (*nlattr_to_obj)(struct nlattr *tb[],
+                                    struct net *net, void *data);
                int (*obj_to_nlattr)(struct sk_buff *skb, const void *data);
 
                unsigned int nlattr_max;
                const struct nla_policy *nla_policy;
        } ctnl_timeout;
 #endif
+       int     *net_id;
+       /* Init l4proto pernet data */
+       int (*init_net)(struct net *net);
 
-#ifdef CONFIG_SYSCTL
-       struct ctl_table_header **ctl_table_header;
-       struct ctl_table        *ctl_table;
-       unsigned int            *ctl_table_users;
-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-       struct ctl_table_header *ctl_compat_table_header;
-       struct ctl_table        *ctl_compat_table;
-#endif
-#endif
        /* Protocol name */
        const char *name;
 
@@ -123,8 +119,10 @@ nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto);
 extern void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p);
 
 /* Protocol registration. */
-extern int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *proto);
-extern void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *proto);
+extern int nf_conntrack_l4proto_register(struct net *net,
+                                        struct nf_conntrack_l4proto *proto);
+extern void nf_conntrack_l4proto_unregister(struct net *net,
+                                           struct nf_conntrack_l4proto *proto);
 
 /* Generic netlink helpers */
 extern int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb,
index a053a19870cf9e0614be8c431a5337bf5e06b249..3aecdc7a84fb145255d6ae2c8457945d55a3c732 100644 (file)
@@ -4,10 +4,64 @@
 #include <linux/list.h>
 #include <linux/list_nulls.h>
 #include <linux/atomic.h>
+#include <linux/netfilter/nf_conntrack_tcp.h>
 
 struct ctl_table_header;
 struct nf_conntrack_ecache;
 
+struct nf_proto_net {
+#ifdef CONFIG_SYSCTL
+       struct ctl_table_header *ctl_table_header;
+       struct ctl_table        *ctl_table;
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+       struct ctl_table_header *ctl_compat_header;
+       struct ctl_table        *ctl_compat_table;
+#endif
+#endif
+       unsigned int            users;
+};
+
+struct nf_generic_net {
+       struct nf_proto_net pn;
+       unsigned int timeout;
+};
+
+struct nf_tcp_net {
+       struct nf_proto_net pn;
+       unsigned int timeouts[TCP_CONNTRACK_TIMEOUT_MAX];
+       unsigned int tcp_loose;
+       unsigned int tcp_be_liberal;
+       unsigned int tcp_max_retrans;
+};
+
+enum udp_conntrack {
+       UDP_CT_UNREPLIED,
+       UDP_CT_REPLIED,
+       UDP_CT_MAX
+};
+
+struct nf_udp_net {
+       struct nf_proto_net pn;
+       unsigned int timeouts[UDP_CT_MAX];
+};
+
+struct nf_icmp_net {
+       struct nf_proto_net pn;
+       unsigned int timeout;
+};
+
+struct nf_ip_net {
+       struct nf_generic_net   generic;
+       struct nf_tcp_net       tcp;
+       struct nf_udp_net       udp;
+       struct nf_icmp_net      icmp;
+       struct nf_icmp_net      icmpv6;
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
+       struct ctl_table_header *ctl_table_header;
+       struct ctl_table        *ctl_table;
+#endif
+};
+
 struct netns_ct {
        atomic_t                count;
        unsigned int            expect_count;
@@ -28,6 +82,7 @@ struct netns_ct {
        unsigned int            sysctl_log_invalid; /* Log invalid packets */
        int                     sysctl_auto_assign_helper;
        bool                    auto_assign_helper_warned;
+       struct nf_ip_net        nf_ct_proto;
 #ifdef CONFIG_SYSCTL
        struct ctl_table_header *sysctl_header;
        struct ctl_table_header *acct_sysctl_header;
index e41456bd3cc6bb6c374fff4ef76afe6326283732..20fa719889eea3bd86725c88b39bd1be5cad91aa 100644 (file)
@@ -764,9 +764,9 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
                return NF_DROP;
 
        if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
-               pf = PF_INET;
+               pf = NFPROTO_IPV4;
        else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
-               pf = PF_INET6;
+               pf = NFPROTO_IPV6;
        else
                return NF_ACCEPT;
 
@@ -778,13 +778,13 @@ static unsigned int br_nf_forward_ip(unsigned int hook, struct sk_buff *skb,
                nf_bridge->mask |= BRNF_PKT_TYPE;
        }
 
-       if (pf == PF_INET && br_parse_ip_options(skb))
+       if (pf == NFPROTO_IPV4 && br_parse_ip_options(skb))
                return NF_DROP;
 
        /* The physdev module checks on this */
        nf_bridge->mask |= BRNF_BRIDGED;
        nf_bridge->physoutdev = skb->dev;
-       if (pf == PF_INET)
+       if (pf == NFPROTO_IPV4)
                skb->protocol = htons(ETH_P_IP);
        else
                skb->protocol = htons(ETH_P_IPV6);
@@ -871,9 +871,9 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
                return NF_DROP;
 
        if (IS_IP(skb) || IS_VLAN_IP(skb) || IS_PPPOE_IP(skb))
-               pf = PF_INET;
+               pf = NFPROTO_IPV4;
        else if (IS_IPV6(skb) || IS_VLAN_IPV6(skb) || IS_PPPOE_IPV6(skb))
-               pf = PF_INET6;
+               pf = NFPROTO_IPV6;
        else
                return NF_ACCEPT;
 
@@ -886,7 +886,7 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
 
        nf_bridge_pull_encap_header(skb);
        nf_bridge_save_header(skb);
-       if (pf == PF_INET)
+       if (pf == NFPROTO_IPV4)
                skb->protocol = htons(ETH_P_IP);
        else
                skb->protocol = htons(ETH_P_IPV6);
@@ -919,49 +919,49 @@ static struct nf_hook_ops br_nf_ops[] __read_mostly = {
        {
                .hook = br_nf_pre_routing,
                .owner = THIS_MODULE,
-               .pf = PF_BRIDGE,
+               .pf = NFPROTO_BRIDGE,
                .hooknum = NF_BR_PRE_ROUTING,
                .priority = NF_BR_PRI_BRNF,
        },
        {
                .hook = br_nf_local_in,
                .owner = THIS_MODULE,
-               .pf = PF_BRIDGE,
+               .pf = NFPROTO_BRIDGE,
                .hooknum = NF_BR_LOCAL_IN,
                .priority = NF_BR_PRI_BRNF,
        },
        {
                .hook = br_nf_forward_ip,
                .owner = THIS_MODULE,
-               .pf = PF_BRIDGE,
+               .pf = NFPROTO_BRIDGE,
                .hooknum = NF_BR_FORWARD,
                .priority = NF_BR_PRI_BRNF - 1,
        },
        {
                .hook = br_nf_forward_arp,
                .owner = THIS_MODULE,
-               .pf = PF_BRIDGE,
+               .pf = NFPROTO_BRIDGE,
                .hooknum = NF_BR_FORWARD,
                .priority = NF_BR_PRI_BRNF,
        },
        {
                .hook = br_nf_post_routing,
                .owner = THIS_MODULE,
-               .pf = PF_BRIDGE,
+               .pf = NFPROTO_BRIDGE,
                .hooknum = NF_BR_POST_ROUTING,
                .priority = NF_BR_PRI_LAST,
        },
        {
                .hook = ip_sabotage_in,
                .owner = THIS_MODULE,
-               .pf = PF_INET,
+               .pf = NFPROTO_IPV4,
                .hooknum = NF_INET_PRE_ROUTING,
                .priority = NF_IP_PRI_FIRST,
        },
        {
                .hook = ip_sabotage_in,
                .owner = THIS_MODULE,
-               .pf = PF_INET6,
+               .pf = NFPROTO_IPV6,
                .hooknum = NF_INET_PRE_ROUTING,
                .priority = NF_IP6_PRI_FIRST,
        },
index 44b890936fc0e937dcdab69478ae6e94747a6822..e6f886255cde3427e77821436fc7de880ef458d7 100644 (file)
@@ -117,7 +117,7 @@ static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
 
 static struct nf_hook_ops dnrmg_ops __read_mostly = {
        .hook           = dnrmg_hook,
-       .pf             = PF_DECnet,
+       .pf             = NFPROTO_DECNET,
        .hooknum        = NF_DN_ROUTE,
        .priority       = NF_DN_PRI_DNRTMSG,
 };
index 91747d4ebc26e6b4f8319645aa2e55706b419cba..d79b961a8009b5d110489156fff920dfa89a26cb 100644 (file)
@@ -207,35 +207,30 @@ static int log_invalid_proto_max = 255;
 static ctl_table ip_ct_sysctl_table[] = {
        {
                .procname       = "ip_conntrack_max",
-               .data           = &nf_conntrack_max,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "ip_conntrack_count",
-               .data           = &init_net.ct.count,
                .maxlen         = sizeof(int),
                .mode           = 0444,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "ip_conntrack_buckets",
-               .data           = &init_net.ct.htable_size,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0444,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "ip_conntrack_checksum",
-               .data           = &init_net.ct.sysctl_checksum,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "ip_conntrack_log_invalid",
-               .data           = &init_net.ct.sysctl_log_invalid,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
@@ -351,6 +346,25 @@ static struct nf_sockopt_ops so_getorigdst = {
        .owner          = THIS_MODULE,
 };
 
+static int ipv4_init_net(struct net *net)
+{
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
+       struct nf_ip_net *in = &net->ct.nf_ct_proto;
+       in->ctl_table = kmemdup(ip_ct_sysctl_table,
+                               sizeof(ip_ct_sysctl_table),
+                               GFP_KERNEL);
+       if (!in->ctl_table)
+               return -ENOMEM;
+
+       in->ctl_table[0].data = &nf_conntrack_max;
+       in->ctl_table[1].data = &net->ct.count;
+       in->ctl_table[2].data = &net->ct.htable_size;
+       in->ctl_table[3].data = &net->ct.sysctl_checksum;
+       in->ctl_table[4].data = &net->ct.sysctl_log_invalid;
+#endif
+       return 0;
+}
+
 struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = {
        .l3proto         = PF_INET,
        .name            = "ipv4",
@@ -366,8 +380,8 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 __read_mostly = {
 #endif
 #if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
        .ctl_table_path  = "net/ipv4/netfilter",
-       .ctl_table       = ip_ct_sysctl_table,
 #endif
+       .init_net        = ipv4_init_net,
        .me              = THIS_MODULE,
 };
 
@@ -378,6 +392,65 @@ MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET));
 MODULE_ALIAS("ip_conntrack");
 MODULE_LICENSE("GPL");
 
+static int ipv4_net_init(struct net *net)
+{
+       int ret = 0;
+
+       ret = nf_conntrack_l4proto_register(net,
+                                           &nf_conntrack_l4proto_tcp4);
+       if (ret < 0) {
+               pr_err("nf_conntrack_l4proto_tcp4 :protocol register failed\n");
+               goto out_tcp;
+       }
+       ret = nf_conntrack_l4proto_register(net,
+                                           &nf_conntrack_l4proto_udp4);
+       if (ret < 0) {
+               pr_err("nf_conntrack_l4proto_udp4 :protocol register failed\n");
+               goto out_udp;
+       }
+       ret = nf_conntrack_l4proto_register(net,
+                                           &nf_conntrack_l4proto_icmp);
+       if (ret < 0) {
+               pr_err("nf_conntrack_l4proto_icmp4 :protocol register failed\n");
+               goto out_icmp;
+       }
+       ret = nf_conntrack_l3proto_register(net,
+                                           &nf_conntrack_l3proto_ipv4);
+       if (ret < 0) {
+               pr_err("nf_conntrack_l3proto_ipv4 :protocol register failed\n");
+               goto out_ipv4;
+       }
+       return 0;
+out_ipv4:
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_icmp);
+out_icmp:
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_udp4);
+out_udp:
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_tcp4);
+out_tcp:
+       return ret;
+}
+
+static void ipv4_net_exit(struct net *net)
+{
+       nf_conntrack_l3proto_unregister(net,
+                                       &nf_conntrack_l3proto_ipv4);
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_icmp);
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_udp4);
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_tcp4);
+}
+
+static struct pernet_operations ipv4_net_ops = {
+       .init = ipv4_net_init,
+       .exit = ipv4_net_exit,
+};
+
 static int __init nf_conntrack_l3proto_ipv4_init(void)
 {
        int ret = 0;
@@ -391,35 +464,17 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
                return ret;
        }
 
-       ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp4);
+       ret = register_pernet_subsys(&ipv4_net_ops);
        if (ret < 0) {
-               pr_err("nf_conntrack_ipv4: can't register tcp.\n");
+               pr_err("nf_conntrack_ipv4: can't register pernet ops\n");
                goto cleanup_sockopt;
        }
 
-       ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp4);
-       if (ret < 0) {
-               pr_err("nf_conntrack_ipv4: can't register udp.\n");
-               goto cleanup_tcp;
-       }
-
-       ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmp);
-       if (ret < 0) {
-               pr_err("nf_conntrack_ipv4: can't register icmp.\n");
-               goto cleanup_udp;
-       }
-
-       ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv4);
-       if (ret < 0) {
-               pr_err("nf_conntrack_ipv4: can't register ipv4\n");
-               goto cleanup_icmp;
-       }
-
        ret = nf_register_hooks(ipv4_conntrack_ops,
                                ARRAY_SIZE(ipv4_conntrack_ops));
        if (ret < 0) {
                pr_err("nf_conntrack_ipv4: can't register hooks.\n");
-               goto cleanup_ipv4;
+               goto cleanup_pernet;
        }
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
        ret = nf_conntrack_ipv4_compat_init();
@@ -431,14 +486,8 @@ static int __init nf_conntrack_l3proto_ipv4_init(void)
  cleanup_hooks:
        nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
 #endif
- cleanup_ipv4:
-       nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
- cleanup_icmp:
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp);
- cleanup_udp:
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp4);
- cleanup_tcp:
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp4);
+ cleanup_pernet:
+       unregister_pernet_subsys(&ipv4_net_ops);
  cleanup_sockopt:
        nf_unregister_sockopt(&so_getorigdst);
        return ret;
@@ -451,10 +500,7 @@ static void __exit nf_conntrack_l3proto_ipv4_fini(void)
        nf_conntrack_ipv4_compat_fini();
 #endif
        nf_unregister_hooks(ipv4_conntrack_ops, ARRAY_SIZE(ipv4_conntrack_ops));
-       nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv4);
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmp);
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp4);
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp4);
+       unregister_pernet_subsys(&ipv4_net_ops);
        nf_unregister_sockopt(&so_getorigdst);
 }
 
index 0847e373d33c4d1a1ae2291e8ddbf71e9b9cd906..041923cb67adce410f9d9ca896dd3641bf78baed 100644 (file)
 
 static unsigned int nf_ct_icmp_timeout __read_mostly = 30*HZ;
 
+static inline struct nf_icmp_net *icmp_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.icmp;
+}
+
 static bool icmp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
                              struct nf_conntrack_tuple *tuple)
 {
@@ -77,7 +82,7 @@ static int icmp_print_tuple(struct seq_file *s,
 
 static unsigned int *icmp_get_timeouts(struct net *net)
 {
-       return &nf_ct_icmp_timeout;
+       return &icmp_pernet(net)->timeout;
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
@@ -274,16 +279,18 @@ static int icmp_nlattr_tuple_size(void)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int icmp_timeout_nlattr_to_obj(struct nlattr *tb[],
+                                     struct net *net, void *data)
 {
        unsigned int *timeout = data;
+       struct nf_icmp_net *in = icmp_pernet(net);
 
        if (tb[CTA_TIMEOUT_ICMP_TIMEOUT]) {
                *timeout =
                        ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMP_TIMEOUT])) * HZ;
        } else {
                /* Set default ICMP timeout. */
-               *timeout = nf_ct_icmp_timeout;
+               *timeout = in->timeout;
        }
        return 0;
 }
@@ -308,11 +315,9 @@ icmp_timeout_nla_policy[CTA_TIMEOUT_ICMP_MAX+1] = {
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
 #ifdef CONFIG_SYSCTL
-static struct ctl_table_header *icmp_sysctl_header;
 static struct ctl_table icmp_sysctl_table[] = {
        {
                .procname       = "nf_conntrack_icmp_timeout",
-               .data           = &nf_ct_icmp_timeout,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -323,7 +328,6 @@ static struct ctl_table icmp_sysctl_table[] = {
 static struct ctl_table icmp_compat_sysctl_table[] = {
        {
                .procname       = "ip_conntrack_icmp_timeout",
-               .data           = &nf_ct_icmp_timeout,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -333,6 +337,34 @@ static struct ctl_table icmp_compat_sysctl_table[] = {
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
 
+static int icmp_init_net(struct net *net)
+{
+       struct nf_icmp_net *in = icmp_pernet(net);
+       struct nf_proto_net *pn = (struct nf_proto_net *)in;
+       in->timeout = nf_ct_icmp_timeout;
+
+#ifdef CONFIG_SYSCTL
+       pn->ctl_table = kmemdup(icmp_sysctl_table,
+                               sizeof(icmp_sysctl_table),
+                               GFP_KERNEL);
+       if (!pn->ctl_table)
+               return -ENOMEM;
+       pn->ctl_table[0].data = &in->timeout;
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+       pn->ctl_compat_table = kmemdup(icmp_compat_sysctl_table,
+                                      sizeof(icmp_compat_sysctl_table),
+                                      GFP_KERNEL);
+       if (!pn->ctl_compat_table) {
+               kfree(pn->ctl_table);
+               pn->ctl_table = NULL;
+               return -ENOMEM;
+       }
+       pn->ctl_compat_table[0].data = &in->timeout;
+#endif
+#endif
+       return 0;
+}
+
 struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
 {
        .l3proto                = PF_INET,
@@ -362,11 +394,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
                .nla_policy     = icmp_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-       .ctl_table_header       = &icmp_sysctl_header,
-       .ctl_table              = icmp_sysctl_table,
-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-       .ctl_compat_table       = icmp_compat_sysctl_table,
-#endif
-#endif
+       .init_net               = icmp_init_net,
 };
index 9bb1b8a37a22be1485466ff4b6097488a28e0974..742815518b0fd5ea78ec4205bfee76a8a804c88d 100644 (file)
@@ -94,14 +94,14 @@ static struct nf_hook_ops ipv4_defrag_ops[] = {
        {
                .hook           = ipv4_conntrack_defrag,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET,
+               .pf             = NFPROTO_IPV4,
                .hooknum        = NF_INET_PRE_ROUTING,
                .priority       = NF_IP_PRI_CONNTRACK_DEFRAG,
        },
        {
                .hook           = ipv4_conntrack_defrag,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET,
+               .pf             = NFPROTO_IPV4,
                .hooknum        = NF_INET_LOCAL_OUT,
                .priority       = NF_IP_PRI_CONNTRACK_DEFRAG,
        },
index 3224ef90a21a4b78bc500aeb4b0ef15c18ff4835..fca10da80ea796e0c90c5392bd7ed1cc05bd05d7 100644 (file)
@@ -333,37 +333,75 @@ MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
 
-static int __init nf_conntrack_l3proto_ipv6_init(void)
+static int ipv6_net_init(struct net *net)
 {
        int ret = 0;
 
-       need_conntrack();
-       nf_defrag_ipv6_enable();
-
-       ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_tcp6);
+       ret = nf_conntrack_l4proto_register(net,
+                                           &nf_conntrack_l4proto_tcp6);
        if (ret < 0) {
-               pr_err("nf_conntrack_ipv6: can't register tcp.\n");
-               return ret;
+               printk(KERN_ERR "nf_conntrack_l4proto_tcp6: protocol register failed\n");
+               goto out;
        }
-
-       ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udp6);
+       ret = nf_conntrack_l4proto_register(net,
+                                           &nf_conntrack_l4proto_udp6);
        if (ret < 0) {
-               pr_err("nf_conntrack_ipv6: can't register udp.\n");
-               goto cleanup_tcp;
+               printk(KERN_ERR "nf_conntrack_l4proto_udp6: protocol register failed\n");
+               goto cleanup_tcp6;
        }
-
-       ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_icmpv6);
+       ret = nf_conntrack_l4proto_register(net,
+                                           &nf_conntrack_l4proto_icmpv6);
        if (ret < 0) {
-               pr_err("nf_conntrack_ipv6: can't register icmpv6.\n");
-               goto cleanup_udp;
+               printk(KERN_ERR "nf_conntrack_l4proto_icmp6: protocol register failed\n");
+               goto cleanup_udp6;
        }
-
-       ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6);
+       ret = nf_conntrack_l3proto_register(net,
+                                           &nf_conntrack_l3proto_ipv6);
        if (ret < 0) {
-               pr_err("nf_conntrack_ipv6: can't register ipv6\n");
+               printk(KERN_ERR "nf_conntrack_l3proto_ipv6: protocol register failed\n");
                goto cleanup_icmpv6;
        }
+       return 0;
+ cleanup_icmpv6:
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_icmpv6);
+ cleanup_udp6:
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_udp6);
+ cleanup_tcp6:
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_tcp6);
+ out:
+       return ret;
+}
 
+static void ipv6_net_exit(struct net *net)
+{
+       nf_conntrack_l3proto_unregister(net,
+                                       &nf_conntrack_l3proto_ipv6);
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_icmpv6);
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_udp6);
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_tcp6);
+}
+
+static struct pernet_operations ipv6_net_ops = {
+       .init = ipv6_net_init,
+       .exit = ipv6_net_exit,
+};
+
+static int __init nf_conntrack_l3proto_ipv6_init(void)
+{
+       int ret = 0;
+
+       need_conntrack();
+       nf_defrag_ipv6_enable();
+
+       ret = register_pernet_subsys(&ipv6_net_ops);
+       if (ret < 0)
+               goto cleanup_pernet;
        ret = nf_register_hooks(ipv6_conntrack_ops,
                                ARRAY_SIZE(ipv6_conntrack_ops));
        if (ret < 0) {
@@ -374,13 +412,8 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
        return ret;
 
  cleanup_ipv6:
-       nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
- cleanup_icmpv6:
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6);
- cleanup_udp:
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6);
- cleanup_tcp:
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
+       unregister_pernet_subsys(&ipv6_net_ops);
+ cleanup_pernet:
        return ret;
 }
 
@@ -388,10 +421,7 @@ static void __exit nf_conntrack_l3proto_ipv6_fini(void)
 {
        synchronize_net();
        nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
-       nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6);
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_icmpv6);
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udp6);
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_tcp6);
+       unregister_pernet_subsys(&ipv6_net_ops);
 }
 
 module_init(nf_conntrack_l3proto_ipv6_init);
index 3e81904fbbcdf09b13c2b830bd40f0b2b7ed313a..63ed0121836cffeaac2e6f98e43e4f3aa670fbdb 100644 (file)
 
 static unsigned int nf_ct_icmpv6_timeout __read_mostly = 30*HZ;
 
+static inline struct nf_icmp_net *icmpv6_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.icmpv6;
+}
+
 static bool icmpv6_pkt_to_tuple(const struct sk_buff *skb,
                                unsigned int dataoff,
                                struct nf_conntrack_tuple *tuple)
@@ -90,7 +95,7 @@ static int icmpv6_print_tuple(struct seq_file *s,
 
 static unsigned int *icmpv6_get_timeouts(struct net *net)
 {
-       return &nf_ct_icmpv6_timeout;
+       return &icmpv6_pernet(net)->timeout;
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
@@ -281,16 +286,18 @@ static int icmpv6_nlattr_tuple_size(void)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int icmpv6_timeout_nlattr_to_obj(struct nlattr *tb[],
+                                       struct net *net, void *data)
 {
        unsigned int *timeout = data;
+       struct nf_icmp_net *in = icmpv6_pernet(net);
 
        if (tb[CTA_TIMEOUT_ICMPV6_TIMEOUT]) {
                *timeout =
                    ntohl(nla_get_be32(tb[CTA_TIMEOUT_ICMPV6_TIMEOUT])) * HZ;
        } else {
                /* Set default ICMPv6 timeout. */
-               *timeout = nf_ct_icmpv6_timeout;
+               *timeout = in->timeout;
        }
        return 0;
 }
@@ -315,11 +322,9 @@ icmpv6_timeout_nla_policy[CTA_TIMEOUT_ICMPV6_MAX+1] = {
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
 #ifdef CONFIG_SYSCTL
-static struct ctl_table_header *icmpv6_sysctl_header;
 static struct ctl_table icmpv6_sysctl_table[] = {
        {
                .procname       = "nf_conntrack_icmpv6_timeout",
-               .data           = &nf_ct_icmpv6_timeout,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -328,6 +333,22 @@ static struct ctl_table icmpv6_sysctl_table[] = {
 };
 #endif /* CONFIG_SYSCTL */
 
+static int icmpv6_init_net(struct net *net)
+{
+       struct nf_icmp_net *in = icmpv6_pernet(net);
+       struct nf_proto_net *pn = (struct nf_proto_net *)in;
+       in->timeout = nf_ct_icmpv6_timeout;
+#ifdef CONFIG_SYSCTL
+       pn->ctl_table = kmemdup(icmpv6_sysctl_table,
+                               sizeof(icmpv6_sysctl_table),
+                               GFP_KERNEL);
+       if (!pn->ctl_table)
+               return -ENOMEM;
+       pn->ctl_table[0].data = &in->timeout;
+#endif
+       return 0;
+}
+
 struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
 {
        .l3proto                = PF_INET6,
@@ -355,8 +376,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
                .nla_policy     = icmpv6_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-       .ctl_table_header       = &icmpv6_sysctl_header,
-       .ctl_table              = icmpv6_sysctl_table,
-#endif
+       .init_net               = icmpv6_init_net,
 };
index a54b018c6eea72fc122aa47c6f66de76676c1fa1..b54eccef40b5cf7ecb74a1c7f1950f48d7823413 100644 (file)
@@ -1742,7 +1742,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
        {
                .hook           = ip_vs_reply4,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET,
+               .pf             = NFPROTO_IPV4,
                .hooknum        = NF_INET_LOCAL_IN,
                .priority       = NF_IP_PRI_NAT_SRC - 2,
        },
@@ -1752,7 +1752,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
        {
                .hook           = ip_vs_remote_request4,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET,
+               .pf             = NFPROTO_IPV4,
                .hooknum        = NF_INET_LOCAL_IN,
                .priority       = NF_IP_PRI_NAT_SRC - 1,
        },
@@ -1760,7 +1760,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
        {
                .hook           = ip_vs_local_reply4,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET,
+               .pf             = NFPROTO_IPV4,
                .hooknum        = NF_INET_LOCAL_OUT,
                .priority       = NF_IP_PRI_NAT_DST + 1,
        },
@@ -1768,7 +1768,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
        {
                .hook           = ip_vs_local_request4,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET,
+               .pf             = NFPROTO_IPV4,
                .hooknum        = NF_INET_LOCAL_OUT,
                .priority       = NF_IP_PRI_NAT_DST + 2,
        },
@@ -1777,7 +1777,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
        {
                .hook           = ip_vs_forward_icmp,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET,
+               .pf             = NFPROTO_IPV4,
                .hooknum        = NF_INET_FORWARD,
                .priority       = 99,
        },
@@ -1785,7 +1785,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
        {
                .hook           = ip_vs_reply4,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET,
+               .pf             = NFPROTO_IPV4,
                .hooknum        = NF_INET_FORWARD,
                .priority       = 100,
        },
@@ -1794,7 +1794,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
        {
                .hook           = ip_vs_reply6,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET6,
+               .pf             = NFPROTO_IPV6,
                .hooknum        = NF_INET_LOCAL_IN,
                .priority       = NF_IP6_PRI_NAT_SRC - 2,
        },
@@ -1804,7 +1804,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
        {
                .hook           = ip_vs_remote_request6,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET6,
+               .pf             = NFPROTO_IPV6,
                .hooknum        = NF_INET_LOCAL_IN,
                .priority       = NF_IP6_PRI_NAT_SRC - 1,
        },
@@ -1812,7 +1812,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
        {
                .hook           = ip_vs_local_reply6,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET,
+               .pf             = NFPROTO_IPV4,
                .hooknum        = NF_INET_LOCAL_OUT,
                .priority       = NF_IP6_PRI_NAT_DST + 1,
        },
@@ -1820,7 +1820,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
        {
                .hook           = ip_vs_local_request6,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET6,
+               .pf             = NFPROTO_IPV6,
                .hooknum        = NF_INET_LOCAL_OUT,
                .priority       = NF_IP6_PRI_NAT_DST + 2,
        },
@@ -1829,7 +1829,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
        {
                .hook           = ip_vs_forward_icmp_v6,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET6,
+               .pf             = NFPROTO_IPV6,
                .hooknum        = NF_INET_FORWARD,
                .priority       = 99,
        },
@@ -1837,7 +1837,7 @@ static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
        {
                .hook           = ip_vs_reply6,
                .owner          = THIS_MODULE,
-               .pf             = PF_INET6,
+               .pf             = NFPROTO_IPV6,
                .hooknum        = NF_INET_FORWARD,
                .priority       = 100,
        },
index 95976a593b981f25a7c653cbd2f34ddd1642bdfa..1ee2082b81b561a426ef6c3a43db815f7e991ddd 100644 (file)
@@ -1333,7 +1333,6 @@ static void nf_conntrack_cleanup_init_net(void)
        while (untrack_refs() > 0)
                schedule();
 
-       nf_conntrack_proto_fini();
 #ifdef CONFIG_NF_CONNTRACK_ZONES
        nf_ct_extend_unregister(&nf_ct_zone_extend);
 #endif
@@ -1372,7 +1371,7 @@ void nf_conntrack_cleanup(struct net *net)
           netfilter framework.  Roll on, two-stage module
           delete... */
        synchronize_net();
-
+       nf_conntrack_proto_fini(net);
        nf_conntrack_cleanup_net(net);
 
        if (net_eq(net, &init_net)) {
@@ -1496,11 +1495,6 @@ static int nf_conntrack_init_init_net(void)
        printk(KERN_INFO "nf_conntrack version %s (%u buckets, %d max)\n",
               NF_CONNTRACK_VERSION, nf_conntrack_htable_size,
               nf_conntrack_max);
-
-       ret = nf_conntrack_proto_init();
-       if (ret < 0)
-               goto err_proto;
-
 #ifdef CONFIG_NF_CONNTRACK_ZONES
        ret = nf_ct_extend_register(&nf_ct_zone_extend);
        if (ret < 0)
@@ -1518,9 +1512,7 @@ static int nf_conntrack_init_init_net(void)
 
 #ifdef CONFIG_NF_CONNTRACK_ZONES
 err_extend:
-       nf_conntrack_proto_fini();
 #endif
-err_proto:
        return ret;
 }
 
@@ -1583,9 +1575,7 @@ static int nf_conntrack_init_net(struct net *net)
        ret = nf_conntrack_helper_init(net);
        if (ret < 0)
                goto err_helper;
-
        return 0;
-
 err_helper:
        nf_conntrack_timeout_fini(net);
 err_timeout:
@@ -1622,6 +1612,9 @@ int nf_conntrack_init(struct net *net)
                if (ret < 0)
                        goto out_init_net;
        }
+       ret = nf_conntrack_proto_init(net);
+       if (ret < 0)
+               goto out_proto;
        ret = nf_conntrack_init_net(net);
        if (ret < 0)
                goto out_net;
@@ -1637,6 +1630,8 @@ int nf_conntrack_init(struct net *net)
        return 0;
 
 out_net:
+       nf_conntrack_proto_fini(net);
+out_proto:
        if (net_eq(net, &init_net))
                nf_conntrack_cleanup_init_net();
 out_init_net:
index 8b631b07a645878a865e2031e63dc23358acb2f5..1ea919450fc3b654ab9445cc7d6543adb79bb0fc 100644 (file)
@@ -36,28 +36,35 @@ static DEFINE_MUTEX(nf_ct_proto_mutex);
 
 #ifdef CONFIG_SYSCTL
 static int
-nf_ct_register_sysctl(struct ctl_table_header **header, const char *path,
-                     struct ctl_table *table, unsigned int *users)
+nf_ct_register_sysctl(struct net *net,
+                     struct ctl_table_header **header,
+                     const char *path,
+                     struct ctl_table *table,
+                     unsigned int *users)
 {
        if (*header == NULL) {
-               *header = register_net_sysctl(&init_net, path, table);
+               *header = register_net_sysctl(net, path, table);
                if (*header == NULL)
                        return -ENOMEM;
        }
        if (users != NULL)
                (*users)++;
+
        return 0;
 }
 
 static void
 nf_ct_unregister_sysctl(struct ctl_table_header **header,
-                       struct ctl_table *table, unsigned int *users)
+                       struct ctl_table **table,
+                       unsigned int *users)
 {
        if (users != NULL && --*users > 0)
                return;
 
        unregister_net_sysctl_table(*header);
+       kfree(*table);
        *header = NULL;
+       *table = NULL;
 }
 #endif
 
@@ -161,30 +168,57 @@ static int kill_l4proto(struct nf_conn *i, void *data)
               nf_ct_l3num(i) == l4proto->l3proto;
 }
 
-static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto)
+static struct nf_ip_net *nf_ct_l3proto_net(struct net *net,
+                                          struct nf_conntrack_l3proto *l3proto)
 {
-       int err = 0;
+       if (l3proto->l3proto == PF_INET)
+               return &net->ct.nf_ct_proto;
+       else
+               return NULL;
+}
 
-#ifdef CONFIG_SYSCTL
-       if (l3proto->ctl_table != NULL) {
-               err = nf_ct_register_sysctl(&l3proto->ctl_table_header,
+static int nf_ct_l3proto_register_sysctl(struct net *net,
+                                        struct nf_conntrack_l3proto *l3proto)
+{
+       int err = 0;
+       struct nf_ip_net *in = nf_ct_l3proto_net(net, l3proto);
+       /* nf_conntrack_l3proto_ipv6 doesn't support sysctl */
+       if (in == NULL)
+               return 0;
+
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
+       if (in->ctl_table != NULL) {
+               err = nf_ct_register_sysctl(net,
+                                           &in->ctl_table_header,
                                            l3proto->ctl_table_path,
-                                           l3proto->ctl_table, NULL);
+                                           in->ctl_table,
+                                           NULL);
+               if (err < 0) {
+                       kfree(in->ctl_table);
+                       in->ctl_table = NULL;
+               }
        }
 #endif
        return err;
 }
 
-static void nf_ct_l3proto_unregister_sysctl(struct nf_conntrack_l3proto *l3proto)
+static void nf_ct_l3proto_unregister_sysctl(struct net *net,
+                                           struct nf_conntrack_l3proto *l3proto)
 {
-#ifdef CONFIG_SYSCTL
-       if (l3proto->ctl_table_header != NULL)
-               nf_ct_unregister_sysctl(&l3proto->ctl_table_header,
-                                       l3proto->ctl_table, NULL);
+       struct nf_ip_net *in = nf_ct_l3proto_net(net, l3proto);
+
+       if (in == NULL)
+               return;
+#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT)
+       if (in->ctl_table_header != NULL)
+               nf_ct_unregister_sysctl(&in->ctl_table_header,
+                                       &in->ctl_table,
+                                       NULL);
 #endif
 }
 
-int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
+static int
+nf_conntrack_l3proto_register_net(struct nf_conntrack_l3proto *proto)
 {
        int ret = 0;
        struct nf_conntrack_l3proto *old;
@@ -203,10 +237,6 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
                goto out_unlock;
        }
 
-       ret = nf_ct_l3proto_register_sysctl(proto);
-       if (ret < 0)
-               goto out_unlock;
-
        if (proto->nlattr_tuple_size)
                proto->nla_size = 3 * proto->nlattr_tuple_size();
 
@@ -215,13 +245,32 @@ int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto)
 out_unlock:
        mutex_unlock(&nf_ct_proto_mutex);
        return ret;
+
 }
-EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register);
 
-void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
+int nf_conntrack_l3proto_register(struct net *net,
+                                 struct nf_conntrack_l3proto *proto)
 {
-       struct net *net;
+       int ret = 0;
 
+       if (net == &init_net)
+               ret = nf_conntrack_l3proto_register_net(proto);
+
+       if (ret < 0)
+               return ret;
+
+       if (proto->init_net) {
+               ret = proto->init_net(net);
+               if (ret < 0)
+                       return ret;
+       }
+       return nf_ct_l3proto_register_sysctl(net, proto);
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_register);
+
+static void
+nf_conntrack_l3proto_unregister_net(struct nf_conntrack_l3proto *proto)
+{
        BUG_ON(proto->l3proto >= AF_MAX);
 
        mutex_lock(&nf_ct_proto_mutex);
@@ -230,42 +279,88 @@ void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto)
                                         ) != proto);
        rcu_assign_pointer(nf_ct_l3protos[proto->l3proto],
                           &nf_conntrack_l3proto_generic);
-       nf_ct_l3proto_unregister_sysctl(proto);
        mutex_unlock(&nf_ct_proto_mutex);
 
        synchronize_rcu();
+}
+
+void nf_conntrack_l3proto_unregister(struct net *net,
+                                    struct nf_conntrack_l3proto *proto)
+{
+       if (net == &init_net)
+               nf_conntrack_l3proto_unregister_net(proto);
+
+       nf_ct_l3proto_unregister_sysctl(net, proto);
 
        /* Remove all contrack entries for this protocol */
        rtnl_lock();
-       for_each_net(net)
-               nf_ct_iterate_cleanup(net, kill_l3proto, proto);
+       nf_ct_iterate_cleanup(net, kill_l3proto, proto);
        rtnl_unlock();
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l3proto_unregister);
 
-static int nf_ct_l4proto_register_sysctl(struct nf_conntrack_l4proto *l4proto)
+static struct nf_proto_net *nf_ct_l4proto_net(struct net *net,
+                                             struct nf_conntrack_l4proto *l4proto)
+{
+       switch (l4proto->l4proto) {
+       case IPPROTO_TCP:
+               return (struct nf_proto_net *)&net->ct.nf_ct_proto.tcp;
+       case IPPROTO_UDP:
+               return (struct nf_proto_net *)&net->ct.nf_ct_proto.udp;
+       case IPPROTO_ICMP:
+               return (struct nf_proto_net *)&net->ct.nf_ct_proto.icmp;
+       case IPPROTO_ICMPV6:
+               return (struct nf_proto_net *)&net->ct.nf_ct_proto.icmpv6;
+       case 255: /* l4proto_generic */
+               return (struct nf_proto_net *)&net->ct.nf_ct_proto.generic;
+       default:
+               if (l4proto->net_id)
+                       return net_generic(net, *l4proto->net_id);
+               else
+                       return NULL;
+       }
+       return NULL;
+}
+
+static
+int nf_ct_l4proto_register_sysctl(struct net *net,
+                                 struct nf_conntrack_l4proto *l4proto)
 {
        int err = 0;
+       struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto);
+       if (pn == NULL)
+               return 0;
 
 #ifdef CONFIG_SYSCTL
-       if (l4proto->ctl_table != NULL) {
-               err = nf_ct_register_sysctl(l4proto->ctl_table_header,
+       if (pn->ctl_table != NULL) {
+               err = nf_ct_register_sysctl(net,
+                                           &pn->ctl_table_header,
                                            "net/netfilter",
-                                           l4proto->ctl_table,
-                                           l4proto->ctl_table_users);
-               if (err < 0)
+                                           pn->ctl_table,
+                                           &pn->users);
+               if (err < 0) {
+                       if (!pn->users) {
+                               kfree(pn->ctl_table);
+                               pn->ctl_table = NULL;
+                       }
                        goto out;
+               }
        }
 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-       if (l4proto->ctl_compat_table != NULL) {
-               err = nf_ct_register_sysctl(&l4proto->ctl_compat_table_header,
+       if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_table != NULL) {
+               err = nf_ct_register_sysctl(net,
+                                           &pn->ctl_compat_header,
                                            "net/ipv4/netfilter",
-                                           l4proto->ctl_compat_table, NULL);
+                                           pn->ctl_compat_table,
+                                           NULL);
                if (err == 0)
                        goto out;
-               nf_ct_unregister_sysctl(l4proto->ctl_table_header,
-                                       l4proto->ctl_table,
-                                       l4proto->ctl_table_users);
+
+               kfree(pn->ctl_compat_table);
+               pn->ctl_compat_table = NULL;
+               nf_ct_unregister_sysctl(&pn->ctl_table_header,
+                                       &pn->ctl_table,
+                                       &pn->users);
        }
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 out:
@@ -273,25 +368,34 @@ out:
        return err;
 }
 
-static void nf_ct_l4proto_unregister_sysctl(struct nf_conntrack_l4proto *l4proto)
+static
+void nf_ct_l4proto_unregister_sysctl(struct net *net,
+                                    struct nf_conntrack_l4proto *l4proto)
 {
+       struct nf_proto_net *pn = nf_ct_l4proto_net(net, l4proto);
+       if (pn == NULL)
+               return;
 #ifdef CONFIG_SYSCTL
-       if (l4proto->ctl_table_header != NULL &&
-           *l4proto->ctl_table_header != NULL)
-               nf_ct_unregister_sysctl(l4proto->ctl_table_header,
-                                       l4proto->ctl_table,
-                                       l4proto->ctl_table_users);
+       if (pn->ctl_table_header != NULL)
+               nf_ct_unregister_sysctl(&pn->ctl_table_header,
+                                       &pn->ctl_table,
+                                       &pn->users);
+
 #ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-       if (l4proto->ctl_compat_table_header != NULL)
-               nf_ct_unregister_sysctl(&l4proto->ctl_compat_table_header,
-                                       l4proto->ctl_compat_table, NULL);
+       if (l4proto->l3proto != AF_INET6 && pn->ctl_compat_header != NULL)
+               nf_ct_unregister_sysctl(&pn->ctl_compat_header,
+                                       &pn->ctl_compat_table,
+                                       NULL);
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
+#else
+       pn->users--;
 #endif /* CONFIG_SYSCTL */
 }
 
 /* FIXME: Allow NULL functions and sub in pointers to generic for
    them. --RR */
-int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
+static int
+nf_conntrack_l4proto_register_net(struct nf_conntrack_l4proto *l4proto)
 {
        int ret = 0;
 
@@ -333,10 +437,6 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
                goto out_unlock;
        }
 
-       ret = nf_ct_l4proto_register_sysctl(l4proto);
-       if (ret < 0)
-               goto out_unlock;
-
        l4proto->nla_size = 0;
        if (l4proto->nlattr_size)
                l4proto->nla_size += l4proto->nlattr_size();
@@ -345,17 +445,34 @@ int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *l4proto)
 
        rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
                           l4proto);
-
 out_unlock:
        mutex_unlock(&nf_ct_proto_mutex);
        return ret;
 }
-EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register);
 
-void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
+int nf_conntrack_l4proto_register(struct net *net,
+                                 struct nf_conntrack_l4proto *l4proto)
 {
-       struct net *net;
+       int ret = 0;
+       if (net == &init_net)
+               ret = nf_conntrack_l4proto_register_net(l4proto);
+
+       if (ret < 0)
+               return ret;
+
+       if (l4proto->init_net)
+               ret = l4proto->init_net(net);
+
+       if (ret < 0)
+               return ret;
+
+       return nf_ct_l4proto_register_sysctl(net, l4proto);
+}
+EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_register);
 
+static void
+nf_conntrack_l4proto_unregister_net(struct nf_conntrack_l4proto *l4proto)
+{
        BUG_ON(l4proto->l3proto >= PF_MAX);
 
        mutex_lock(&nf_ct_proto_mutex);
@@ -365,41 +482,53 @@ void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *l4proto)
                        ) != l4proto);
        rcu_assign_pointer(nf_ct_protos[l4proto->l3proto][l4proto->l4proto],
                           &nf_conntrack_l4proto_generic);
-       nf_ct_l4proto_unregister_sysctl(l4proto);
        mutex_unlock(&nf_ct_proto_mutex);
 
        synchronize_rcu();
+}
+
+void nf_conntrack_l4proto_unregister(struct net *net,
+                                    struct nf_conntrack_l4proto *l4proto)
+{
+       if (net == &init_net)
+               nf_conntrack_l4proto_unregister_net(l4proto);
 
+       nf_ct_l4proto_unregister_sysctl(net, l4proto);
        /* Remove all contrack entries for this protocol */
        rtnl_lock();
-       for_each_net(net)
-               nf_ct_iterate_cleanup(net, kill_l4proto, l4proto);
+       nf_ct_iterate_cleanup(net, kill_l4proto, l4proto);
        rtnl_unlock();
 }
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_unregister);
 
-int nf_conntrack_proto_init(void)
+int nf_conntrack_proto_init(struct net *net)
 {
        unsigned int i;
        int err;
-
-       err = nf_ct_l4proto_register_sysctl(&nf_conntrack_l4proto_generic);
+       err = nf_conntrack_l4proto_generic.init_net(net);
+       if (err < 0)
+               return err;
+       err = nf_ct_l4proto_register_sysctl(net,
+                                           &nf_conntrack_l4proto_generic);
        if (err < 0)
                return err;
 
-       for (i = 0; i < AF_MAX; i++)
-               rcu_assign_pointer(nf_ct_l3protos[i],
-                                  &nf_conntrack_l3proto_generic);
+       if (net == &init_net) {
+               for (i = 0; i < AF_MAX; i++)
+                       rcu_assign_pointer(nf_ct_l3protos[i],
+                                          &nf_conntrack_l3proto_generic);
+       }
        return 0;
 }
 
-void nf_conntrack_proto_fini(void)
+void nf_conntrack_proto_fini(struct net *net)
 {
        unsigned int i;
-
-       nf_ct_l4proto_unregister_sysctl(&nf_conntrack_l4proto_generic);
-
-       /* free l3proto protocol tables */
-       for (i = 0; i < PF_MAX; i++)
-               kfree(nf_ct_protos[i]);
+       nf_ct_l4proto_unregister_sysctl(net,
+                                       &nf_conntrack_l4proto_generic);
+       if (net == &init_net) {
+               /* free l3proto protocol tables */
+               for (i = 0; i < PF_MAX; i++)
+                       kfree(nf_ct_protos[i]);
+       }
 }
index ef706a485be11d79f84df30b253af5b477542127..c33f76af913ffc39d063e708d0bb47f119f0f3df 100644 (file)
@@ -387,12 +387,9 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] =
 /* this module per-net specifics */
 static int dccp_net_id __read_mostly;
 struct dccp_net {
+       struct nf_proto_net np;
        int dccp_loose;
        unsigned int dccp_timeout[CT_DCCP_MAX + 1];
-#ifdef CONFIG_SYSCTL
-       struct ctl_table_header *sysctl_header;
-       struct ctl_table *sysctl_table;
-#endif
 };
 
 static inline struct dccp_net *dccp_pernet(struct net *net)
@@ -715,9 +712,10 @@ static int dccp_nlattr_size(void)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int dccp_timeout_nlattr_to_obj(struct nlattr *tb[],
+                                     struct net *net, void *data)
 {
-       struct dccp_net *dn = dccp_pernet(&init_net);
+       struct dccp_net *dn = dccp_pernet(net);
        unsigned int *timeouts = data;
        int i;
 
@@ -817,6 +815,45 @@ static struct ctl_table dccp_sysctl_table[] = {
 };
 #endif /* CONFIG_SYSCTL */
 
+static int dccp_init_net(struct net *net)
+{
+       struct dccp_net *dn = dccp_pernet(net);
+       struct nf_proto_net *pn = (struct nf_proto_net *)dn;
+
+#ifdef CONFIG_SYSCTL
+       if (!pn->ctl_table) {
+#else
+       if (!pn->users++) {
+#endif
+               /* default values */
+               dn->dccp_loose = 1;
+               dn->dccp_timeout[CT_DCCP_REQUEST]       = 2 * DCCP_MSL;
+               dn->dccp_timeout[CT_DCCP_RESPOND]       = 4 * DCCP_MSL;
+               dn->dccp_timeout[CT_DCCP_PARTOPEN]      = 4 * DCCP_MSL;
+               dn->dccp_timeout[CT_DCCP_OPEN]          = 12 * 3600 * HZ;
+               dn->dccp_timeout[CT_DCCP_CLOSEREQ]      = 64 * HZ;
+               dn->dccp_timeout[CT_DCCP_CLOSING]       = 64 * HZ;
+               dn->dccp_timeout[CT_DCCP_TIMEWAIT]      = 2 * DCCP_MSL;
+#ifdef CONFIG_SYSCTL
+               pn->ctl_table = kmemdup(dccp_sysctl_table,
+                                       sizeof(dccp_sysctl_table),
+                                       GFP_KERNEL);
+               if (!pn->ctl_table)
+                       return -ENOMEM;
+
+               pn->ctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
+               pn->ctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
+               pn->ctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
+               pn->ctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
+               pn->ctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
+               pn->ctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
+               pn->ctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
+               pn->ctl_table[7].data = &dn->dccp_loose;
+#endif
+       }
+       return 0;
+}
+
 static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
        .l3proto                = AF_INET,
        .l4proto                = IPPROTO_DCCP,
@@ -847,6 +884,8 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
                .nla_policy     = dccp_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+       .net_id                 = &dccp_net_id,
+       .init_net               = dccp_init_net,
 };
 
 static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
@@ -879,55 +918,39 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
                .nla_policy     = dccp_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+       .net_id                 = &dccp_net_id,
+       .init_net               = dccp_init_net,
 };
 
 static __net_init int dccp_net_init(struct net *net)
 {
-       struct dccp_net *dn = dccp_pernet(net);
-
-       /* default values */
-       dn->dccp_loose = 1;
-       dn->dccp_timeout[CT_DCCP_REQUEST]       = 2 * DCCP_MSL;
-       dn->dccp_timeout[CT_DCCP_RESPOND]       = 4 * DCCP_MSL;
-       dn->dccp_timeout[CT_DCCP_PARTOPEN]      = 4 * DCCP_MSL;
-       dn->dccp_timeout[CT_DCCP_OPEN]          = 12 * 3600 * HZ;
-       dn->dccp_timeout[CT_DCCP_CLOSEREQ]      = 64 * HZ;
-       dn->dccp_timeout[CT_DCCP_CLOSING]       = 64 * HZ;
-       dn->dccp_timeout[CT_DCCP_TIMEWAIT]      = 2 * DCCP_MSL;
-
-#ifdef CONFIG_SYSCTL
-       dn->sysctl_table = kmemdup(dccp_sysctl_table,
-                       sizeof(dccp_sysctl_table), GFP_KERNEL);
-       if (!dn->sysctl_table)
-               return -ENOMEM;
-
-       dn->sysctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST];
-       dn->sysctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND];
-       dn->sysctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN];
-       dn->sysctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN];
-       dn->sysctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ];
-       dn->sysctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING];
-       dn->sysctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT];
-       dn->sysctl_table[7].data = &dn->dccp_loose;
-
-       dn->sysctl_header = register_net_sysctl(net, "net/netfilter",
-                                               dn->sysctl_table);
-       if (!dn->sysctl_header) {
-               kfree(dn->sysctl_table);
-               return -ENOMEM;
+       int ret = 0;
+       ret = nf_conntrack_l4proto_register(net,
+                                           &dccp_proto4);
+       if (ret < 0) {
+               pr_err("nf_conntrack_l4proto_dccp4 :protocol register failed.\n");
+               goto out;
+       }
+       ret = nf_conntrack_l4proto_register(net,
+                                           &dccp_proto6);
+       if (ret < 0) {
+               pr_err("nf_conntrack_l4proto_dccp6 :protocol register failed.\n");
+               goto cleanup_dccp4;
        }
-#endif
-
        return 0;
+cleanup_dccp4:
+       nf_conntrack_l4proto_unregister(net,
+                                       &dccp_proto4);
+out:
+       return ret;
 }
 
 static __net_exit void dccp_net_exit(struct net *net)
 {
-       struct dccp_net *dn = dccp_pernet(net);
-#ifdef CONFIG_SYSCTL
-       unregister_net_sysctl_table(dn->sysctl_header);
-       kfree(dn->sysctl_table);
-#endif
+       nf_conntrack_l4proto_unregister(net,
+                                       &dccp_proto6);
+       nf_conntrack_l4proto_unregister(net,
+                                       &dccp_proto4);
 }
 
 static struct pernet_operations dccp_net_ops = {
@@ -939,34 +962,12 @@ static struct pernet_operations dccp_net_ops = {
 
 static int __init nf_conntrack_proto_dccp_init(void)
 {
-       int err;
-
-       err = register_pernet_subsys(&dccp_net_ops);
-       if (err < 0)
-               goto err1;
-
-       err = nf_conntrack_l4proto_register(&dccp_proto4);
-       if (err < 0)
-               goto err2;
-
-       err = nf_conntrack_l4proto_register(&dccp_proto6);
-       if (err < 0)
-               goto err3;
-       return 0;
-
-err3:
-       nf_conntrack_l4proto_unregister(&dccp_proto4);
-err2:
-       unregister_pernet_subsys(&dccp_net_ops);
-err1:
-       return err;
+       return register_pernet_subsys(&dccp_net_ops);
 }
 
 static void __exit nf_conntrack_proto_dccp_fini(void)
 {
        unregister_pernet_subsys(&dccp_net_ops);
-       nf_conntrack_l4proto_unregister(&dccp_proto6);
-       nf_conntrack_l4proto_unregister(&dccp_proto4);
 }
 
 module_init(nf_conntrack_proto_dccp_init);
index d8923d54b3585bf579c66eaba82dc4ec7d464236..bb0e74fe0fae5df05c3114286c49a47cd7437a33 100644 (file)
 
 static unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ;
 
+static inline struct nf_generic_net *generic_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.generic;
+}
+
 static bool generic_pkt_to_tuple(const struct sk_buff *skb,
                                 unsigned int dataoff,
                                 struct nf_conntrack_tuple *tuple)
@@ -42,7 +47,7 @@ static int generic_print_tuple(struct seq_file *s,
 
 static unsigned int *generic_get_timeouts(struct net *net)
 {
-       return &nf_ct_generic_timeout;
+       return &(generic_pernet(net)->timeout);
 }
 
 /* Returns verdict for packet, or -1 for invalid. */
@@ -70,16 +75,18 @@ static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb,
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int generic_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int generic_timeout_nlattr_to_obj(struct nlattr *tb[],
+                                        struct net *net, void *data)
 {
        unsigned int *timeout = data;
+       struct nf_generic_net *gn = generic_pernet(net);
 
        if (tb[CTA_TIMEOUT_GENERIC_TIMEOUT])
                *timeout =
                    ntohl(nla_get_be32(tb[CTA_TIMEOUT_GENERIC_TIMEOUT])) * HZ;
        else {
                /* Set default generic timeout. */
-               *timeout = nf_ct_generic_timeout;
+               *timeout = gn->timeout;
        }
 
        return 0;
@@ -106,11 +113,9 @@ generic_timeout_nla_policy[CTA_TIMEOUT_GENERIC_MAX+1] = {
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
 #ifdef CONFIG_SYSCTL
-static struct ctl_table_header *generic_sysctl_header;
 static struct ctl_table generic_sysctl_table[] = {
        {
                .procname       = "nf_conntrack_generic_timeout",
-               .data           = &nf_ct_generic_timeout,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -121,7 +126,6 @@ static struct ctl_table generic_sysctl_table[] = {
 static struct ctl_table generic_compat_sysctl_table[] = {
        {
                .procname       = "ip_conntrack_generic_timeout",
-               .data           = &nf_ct_generic_timeout,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -131,6 +135,34 @@ static struct ctl_table generic_compat_sysctl_table[] = {
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
 
+static int generic_init_net(struct net *net)
+{
+       struct nf_generic_net *gn = generic_pernet(net);
+       struct nf_proto_net *pn = (struct nf_proto_net *)gn;
+       gn->timeout = nf_ct_generic_timeout;
+#ifdef CONFIG_SYSCTL
+       pn->ctl_table = kmemdup(generic_sysctl_table,
+                               sizeof(generic_sysctl_table),
+                               GFP_KERNEL);
+       if (!pn->ctl_table)
+               return -ENOMEM;
+       pn->ctl_table[0].data = &gn->timeout;
+
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+       pn->ctl_compat_table = kmemdup(generic_compat_sysctl_table,
+                                      sizeof(generic_compat_sysctl_table),
+                                      GFP_KERNEL);
+       if (!pn->ctl_compat_table) {
+               kfree(pn->ctl_table);
+               pn->ctl_table = NULL;
+               return -ENOMEM;
+       }
+       pn->ctl_compat_table[0].data = &gn->timeout;
+#endif
+#endif
+       return 0;
+}
+
 struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
 {
        .l3proto                = PF_UNSPEC,
@@ -151,11 +183,5 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
                .nla_policy     = generic_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-       .ctl_table_header       = &generic_sysctl_header,
-       .ctl_table              = generic_sysctl_table,
-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-       .ctl_compat_table       = generic_compat_sysctl_table,
-#endif
-#endif
+       .init_net               = generic_init_net,
 };
index 4bf6b4e4b7763197c5698db8993e5362c5ef0911..25ba5a2f5edcac559cbe658e9ce72ffcd4cfa182 100644 (file)
@@ -54,13 +54,20 @@ static unsigned int gre_timeouts[GRE_CT_MAX] = {
 
 static int proto_gre_net_id __read_mostly;
 struct netns_proto_gre {
+       struct nf_proto_net     nf;
        rwlock_t                keymap_lock;
        struct list_head        keymap_list;
+       unsigned int            gre_timeouts[GRE_CT_MAX];
 };
 
+static inline struct netns_proto_gre *gre_pernet(struct net *net)
+{
+       return net_generic(net, proto_gre_net_id);
+}
+
 void nf_ct_gre_keymap_flush(struct net *net)
 {
-       struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
+       struct netns_proto_gre *net_gre = gre_pernet(net);
        struct nf_ct_gre_keymap *km, *tmp;
 
        write_lock_bh(&net_gre->keymap_lock);
@@ -85,7 +92,7 @@ static inline int gre_key_cmpfn(const struct nf_ct_gre_keymap *km,
 /* look up the source key for a given tuple */
 static __be16 gre_keymap_lookup(struct net *net, struct nf_conntrack_tuple *t)
 {
-       struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
+       struct netns_proto_gre *net_gre = gre_pernet(net);
        struct nf_ct_gre_keymap *km;
        __be16 key = 0;
 
@@ -109,7 +116,7 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
                         struct nf_conntrack_tuple *t)
 {
        struct net *net = nf_ct_net(ct);
-       struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
+       struct netns_proto_gre *net_gre = gre_pernet(net);
        struct nf_conn_help *help = nfct_help(ct);
        struct nf_ct_gre_keymap **kmp, *km;
 
@@ -150,7 +157,7 @@ EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_add);
 void nf_ct_gre_keymap_destroy(struct nf_conn *ct)
 {
        struct net *net = nf_ct_net(ct);
-       struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
+       struct netns_proto_gre *net_gre = gre_pernet(net);
        struct nf_conn_help *help = nfct_help(ct);
        enum ip_conntrack_dir dir;
 
@@ -237,7 +244,7 @@ static int gre_print_conntrack(struct seq_file *s, struct nf_conn *ct)
 
 static unsigned int *gre_get_timeouts(struct net *net)
 {
-       return gre_timeouts;
+       return gre_pernet(net)->gre_timeouts;
 }
 
 /* Returns verdict for packet, and may modify conntrack */
@@ -297,13 +304,15 @@ static void gre_destroy(struct nf_conn *ct)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int gre_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int gre_timeout_nlattr_to_obj(struct nlattr *tb[],
+                                    struct net *net, void *data)
 {
        unsigned int *timeouts = data;
+       struct netns_proto_gre *net_gre = gre_pernet(net);
 
        /* set default timeouts for GRE. */
-       timeouts[GRE_CT_UNREPLIED] = gre_timeouts[GRE_CT_UNREPLIED];
-       timeouts[GRE_CT_REPLIED] = gre_timeouts[GRE_CT_REPLIED];
+       timeouts[GRE_CT_UNREPLIED] = net_gre->gre_timeouts[GRE_CT_UNREPLIED];
+       timeouts[GRE_CT_REPLIED] = net_gre->gre_timeouts[GRE_CT_REPLIED];
 
        if (tb[CTA_TIMEOUT_GRE_UNREPLIED]) {
                timeouts[GRE_CT_UNREPLIED] =
@@ -339,6 +348,19 @@ gre_timeout_nla_policy[CTA_TIMEOUT_GRE_MAX+1] = {
 };
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
+static int gre_init_net(struct net *net)
+{
+       struct netns_proto_gre *net_gre = gre_pernet(net);
+       int i;
+
+       rwlock_init(&net_gre->keymap_lock);
+       INIT_LIST_HEAD(&net_gre->keymap_list);
+       for (i = 0; i < GRE_CT_MAX; i++)
+               net_gre->gre_timeouts[i] = gre_timeouts[i];
+
+       return 0;
+}
+
 /* protocol helper struct */
 static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
        .l3proto         = AF_INET,
@@ -368,20 +390,22 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
                .nla_policy     = gre_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
+       .net_id         = &proto_gre_net_id,
+       .init_net       = gre_init_net,
 };
 
 static int proto_gre_net_init(struct net *net)
 {
-       struct netns_proto_gre *net_gre = net_generic(net, proto_gre_net_id);
-
-       rwlock_init(&net_gre->keymap_lock);
-       INIT_LIST_HEAD(&net_gre->keymap_list);
-
-       return 0;
+       int ret = 0;
+       ret = nf_conntrack_l4proto_register(net, &nf_conntrack_l4proto_gre4);
+       if (ret < 0)
+               pr_err("nf_conntrack_l4proto_gre4 :protocol register failed.\n");
+       return ret;
 }
 
 static void proto_gre_net_exit(struct net *net)
 {
+       nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_gre4);
        nf_ct_gre_keymap_flush(net);
 }
 
@@ -394,20 +418,11 @@ static struct pernet_operations proto_gre_net_ops = {
 
 static int __init nf_ct_proto_gre_init(void)
 {
-       int rv;
-
-       rv = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_gre4);
-       if (rv < 0)
-               return rv;
-       rv = register_pernet_subsys(&proto_gre_net_ops);
-       if (rv < 0)
-               nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4);
-       return rv;
+       return register_pernet_subsys(&proto_gre_net_ops);
 }
 
 static void __exit nf_ct_proto_gre_fini(void)
 {
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4);
        unregister_pernet_subsys(&proto_gre_net_ops);
 }
 
index 996db2fa21f7621cacf70fea4b371fafb8c1bae6..8fb0582ad39758708cadd040974539eef8cf4f58 100644 (file)
@@ -127,6 +127,17 @@ static const u8 sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = {
        }
 };
 
+static int sctp_net_id __read_mostly;
+struct sctp_net {
+       struct nf_proto_net pn;
+       unsigned int timeouts[SCTP_CONNTRACK_MAX];
+};
+
+static inline struct sctp_net *sctp_pernet(struct net *net)
+{
+       return net_generic(net, sctp_net_id);
+}
+
 static bool sctp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
                              struct nf_conntrack_tuple *tuple)
 {
@@ -281,7 +292,7 @@ static int sctp_new_state(enum ip_conntrack_dir dir,
 
 static unsigned int *sctp_get_timeouts(struct net *net)
 {
-       return sctp_timeouts;
+       return sctp_pernet(net)->timeouts;
 }
 
 /* Returns verdict for packet, or -NF_ACCEPT for invalid. */
@@ -551,14 +562,16 @@ static int sctp_nlattr_size(void)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int sctp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int sctp_timeout_nlattr_to_obj(struct nlattr *tb[],
+                                     struct net *net, void *data)
 {
        unsigned int *timeouts = data;
+       struct sctp_net *sn = sctp_pernet(net);
        int i;
 
        /* set default SCTP timeouts. */
        for (i=0; i<SCTP_CONNTRACK_MAX; i++)
-               timeouts[i] = sctp_timeouts[i];
+               timeouts[i] = sn->timeouts[i];
 
        /* there's a 1:1 mapping between attributes and protocol states. */
        for (i=CTA_TIMEOUT_SCTP_UNSPEC+1; i<CTA_TIMEOUT_SCTP_MAX+1; i++) {
@@ -599,54 +612,45 @@ sctp_timeout_nla_policy[CTA_TIMEOUT_SCTP_MAX+1] = {
 
 
 #ifdef CONFIG_SYSCTL
-static unsigned int sctp_sysctl_table_users;
-static struct ctl_table_header *sctp_sysctl_header;
 static struct ctl_table sctp_sysctl_table[] = {
        {
                .procname       = "nf_conntrack_sctp_timeout_closed",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_CLOSED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_sctp_timeout_cookie_wait",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_COOKIE_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_sctp_timeout_cookie_echoed",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_COOKIE_ECHOED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_sctp_timeout_established",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_ESTABLISHED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_sctp_timeout_shutdown_sent",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_sctp_timeout_shutdown_recd",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_sctp_timeout_shutdown_ack_sent",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -658,49 +662,42 @@ static struct ctl_table sctp_sysctl_table[] = {
 static struct ctl_table sctp_compat_sysctl_table[] = {
        {
                .procname       = "ip_conntrack_sctp_timeout_closed",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_CLOSED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_sctp_timeout_cookie_wait",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_COOKIE_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_sctp_timeout_cookie_echoed",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_COOKIE_ECHOED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_sctp_timeout_established",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_ESTABLISHED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_sctp_timeout_shutdown_sent",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_sctp_timeout_shutdown_recd",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_sctp_timeout_shutdown_ack_sent",
-               .data           = &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -710,6 +707,101 @@ static struct ctl_table sctp_compat_sysctl_table[] = {
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif
 
+static void sctp_init_net_data(struct sctp_net *sn)
+{
+       int i;
+#ifdef CONFIG_SYSCTL
+       if (!sn->pn.ctl_table) {
+#else
+       if (!sn->pn.users++) {
+#endif
+               for (i = 0; i < SCTP_CONNTRACK_MAX; i++)
+                       sn->timeouts[i] = sctp_timeouts[i];
+       }
+}
+
+static int sctp_kmemdup_sysctl_table(struct nf_proto_net *pn)
+{
+#ifdef CONFIG_SYSCTL
+       struct sctp_net *sn = (struct sctp_net *)pn;
+       if (pn->ctl_table)
+               return 0;
+
+       pn->ctl_table = kmemdup(sctp_sysctl_table,
+                               sizeof(sctp_sysctl_table),
+                               GFP_KERNEL);
+       if (!pn->ctl_table)
+               return -ENOMEM;
+
+       pn->ctl_table[0].data = &sn->timeouts[SCTP_CONNTRACK_CLOSED];
+       pn->ctl_table[1].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_WAIT];
+       pn->ctl_table[2].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_ECHOED];
+       pn->ctl_table[3].data = &sn->timeouts[SCTP_CONNTRACK_ESTABLISHED];
+       pn->ctl_table[4].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT];
+       pn->ctl_table[5].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD];
+       pn->ctl_table[6].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT];
+#endif
+       return 0;
+}
+
+static int sctp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
+{
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+       struct sctp_net *sn = (struct sctp_net *)pn;
+       pn->ctl_compat_table = kmemdup(sctp_compat_sysctl_table,
+                                      sizeof(sctp_compat_sysctl_table),
+                                      GFP_KERNEL);
+       if (!pn->ctl_compat_table)
+               return -ENOMEM;
+
+       pn->ctl_compat_table[0].data = &sn->timeouts[SCTP_CONNTRACK_CLOSED];
+       pn->ctl_compat_table[1].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_WAIT];
+       pn->ctl_compat_table[2].data = &sn->timeouts[SCTP_CONNTRACK_COOKIE_ECHOED];
+       pn->ctl_compat_table[3].data = &sn->timeouts[SCTP_CONNTRACK_ESTABLISHED];
+       pn->ctl_compat_table[4].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT];
+       pn->ctl_compat_table[5].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD];
+       pn->ctl_compat_table[6].data = &sn->timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT];
+#endif
+#endif
+       return 0;
+}
+
+static int sctpv4_init_net(struct net *net)
+{
+       int ret;
+       struct sctp_net *sn = sctp_pernet(net);
+       struct nf_proto_net *pn = (struct nf_proto_net *)sn;
+
+       sctp_init_net_data(sn);
+
+       ret = sctp_kmemdup_compat_sysctl_table(pn);
+       if (ret < 0)
+               return ret;
+
+       ret = sctp_kmemdup_sysctl_table(pn);
+
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+       if (ret < 0) {
+
+               kfree(pn->ctl_compat_table);
+               pn->ctl_compat_table = NULL;
+       }
+#endif
+#endif
+       return ret;
+}
+
+static int sctpv6_init_net(struct net *net)
+{
+       struct sctp_net *sn = sctp_pernet(net);
+       struct nf_proto_net *pn = (struct nf_proto_net *)sn;
+
+       sctp_init_net_data(sn);
+       return sctp_kmemdup_sysctl_table(pn);
+}
+
 static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
        .l3proto                = PF_INET,
        .l4proto                = IPPROTO_SCTP,
@@ -740,14 +832,8 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
                .nla_policy     = sctp_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-       .ctl_table_users        = &sctp_sysctl_table_users,
-       .ctl_table_header       = &sctp_sysctl_header,
-       .ctl_table              = sctp_sysctl_table,
-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-       .ctl_compat_table       = sctp_compat_sysctl_table,
-#endif
-#endif
+       .net_id                 = &sctp_net_id,
+       .init_net               = sctpv4_init_net,
 };
 
 static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
@@ -780,40 +866,58 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 #endif
-#ifdef CONFIG_SYSCTL
-       .ctl_table_users        = &sctp_sysctl_table_users,
-       .ctl_table_header       = &sctp_sysctl_header,
-       .ctl_table              = sctp_sysctl_table,
-#endif
+       .net_id                 = &sctp_net_id,
+       .init_net               = sctpv6_init_net,
 };
 
-static int __init nf_conntrack_proto_sctp_init(void)
+static int sctp_net_init(struct net *net)
 {
-       int ret;
+       int ret = 0;
 
-       ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_sctp4);
-       if (ret) {
-               pr_err("nf_conntrack_l4proto_sctp4: protocol register failed\n");
+       ret = nf_conntrack_l4proto_register(net,
+                                           &nf_conntrack_l4proto_sctp4);
+       if (ret < 0) {
+               pr_err("nf_conntrack_l4proto_sctp4 :protocol register failed.\n");
                goto out;
        }
-       ret = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_sctp6);
-       if (ret) {
-               pr_err("nf_conntrack_l4proto_sctp6: protocol register failed\n");
+       ret = nf_conntrack_l4proto_register(net,
+                                           &nf_conntrack_l4proto_sctp6);
+       if (ret < 0) {
+               pr_err("nf_conntrack_l4proto_sctp6 :protocol register failed.\n");
                goto cleanup_sctp4;
        }
+       return 0;
 
+cleanup_sctp4:
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_sctp4);
+out:
        return ret;
+}
 
- cleanup_sctp4:
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_sctp4);
- out:
-       return ret;
+static void sctp_net_exit(struct net *net)
+{
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_sctp6);
+       nf_conntrack_l4proto_unregister(net,
+                                       &nf_conntrack_l4proto_sctp4);
+}
+
+static struct pernet_operations sctp_net_ops = {
+       .init = sctp_net_init,
+       .exit = sctp_net_exit,
+       .id   = &sctp_net_id,
+       .size = sizeof(struct sctp_net),
+};
+
+static int __init nf_conntrack_proto_sctp_init(void)
+{
+       return register_pernet_subsys(&sctp_net_ops);
 }
 
 static void __exit nf_conntrack_proto_sctp_fini(void)
 {
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_sctp6);
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_sctp4);
+       unregister_pernet_subsys(&sctp_net_ops);
 }
 
 module_init(nf_conntrack_proto_sctp_init);
index 21ff1a99f5341c1fe475c10a0170a1b62fc9a5f5..1cff854ccb888abfa6c1afd83cd613e3c9314635 100644 (file)
@@ -270,6 +270,11 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = {
        }
 };
 
+static inline struct nf_tcp_net *tcp_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.tcp;
+}
+
 static bool tcp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
                             struct nf_conntrack_tuple *tuple)
 {
@@ -516,6 +521,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
                          u_int8_t pf)
 {
        struct net *net = nf_ct_net(ct);
+       struct nf_tcp_net *tn = tcp_pernet(net);
        struct ip_ct_tcp_state *sender = &state->seen[dir];
        struct ip_ct_tcp_state *receiver = &state->seen[!dir];
        const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple;
@@ -720,7 +726,7 @@ static bool tcp_in_window(const struct nf_conn *ct,
        } else {
                res = false;
                if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL ||
-                   nf_ct_tcp_be_liberal)
+                   tn->tcp_be_liberal)
                        res = true;
                if (!res && LOG_INVALID(net, IPPROTO_TCP))
                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
@@ -828,6 +834,7 @@ static int tcp_packet(struct nf_conn *ct,
                      unsigned int *timeouts)
 {
        struct net *net = nf_ct_net(ct);
+       struct nf_tcp_net *tn = tcp_pernet(net);
        struct nf_conntrack_tuple *tuple;
        enum tcp_conntrack new_state, old_state;
        enum ip_conntrack_dir dir;
@@ -1020,7 +1027,7 @@ static int tcp_packet(struct nf_conn *ct,
            && new_state == TCP_CONNTRACK_FIN_WAIT)
                ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
 
-       if (ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans &&
+       if (ct->proto.tcp.retrans >= tn->tcp_max_retrans &&
            timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS])
                timeout = timeouts[TCP_CONNTRACK_RETRANS];
        else if ((ct->proto.tcp.seen[0].flags | ct->proto.tcp.seen[1].flags) &
@@ -1065,6 +1072,8 @@ static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb,
        enum tcp_conntrack new_state;
        const struct tcphdr *th;
        struct tcphdr _tcph;
+       struct net *net = nf_ct_net(ct);
+       struct nf_tcp_net *tn = tcp_pernet(net);
        const struct ip_ct_tcp_state *sender = &ct->proto.tcp.seen[0];
        const struct ip_ct_tcp_state *receiver = &ct->proto.tcp.seen[1];
 
@@ -1093,7 +1102,7 @@ static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb,
                        ct->proto.tcp.seen[0].td_end;
 
                tcp_options(skb, dataoff, th, &ct->proto.tcp.seen[0]);
-       } else if (nf_ct_tcp_loose == 0) {
+       } else if (tn->tcp_loose == 0) {
                /* Don't try to pick up connections. */
                return false;
        } else {
@@ -1251,14 +1260,16 @@ static int tcp_nlattr_tuple_size(void)
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int tcp_timeout_nlattr_to_obj(struct nlattr *tb[],
+                                    struct net *net, void *data)
 {
        unsigned int *timeouts = data;
+       struct nf_tcp_net *tn = tcp_pernet(net);
        int i;
 
        /* set default TCP timeouts. */
        for (i=0; i<TCP_CONNTRACK_TIMEOUT_MAX; i++)
-               timeouts[i] = tcp_timeouts[i];
+               timeouts[i] = tn->timeouts[i];
 
        if (tb[CTA_TIMEOUT_TCP_SYN_SENT]) {
                timeouts[TCP_CONNTRACK_SYN_SENT] =
@@ -1355,96 +1366,81 @@ static const struct nla_policy tcp_timeout_nla_policy[CTA_TIMEOUT_TCP_MAX+1] = {
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
 #ifdef CONFIG_SYSCTL
-static unsigned int tcp_sysctl_table_users;
-static struct ctl_table_header *tcp_sysctl_header;
 static struct ctl_table tcp_sysctl_table[] = {
        {
                .procname       = "nf_conntrack_tcp_timeout_syn_sent",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_SYN_SENT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_syn_recv",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_SYN_RECV],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_established",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_ESTABLISHED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_fin_wait",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_FIN_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_close_wait",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_CLOSE_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_last_ack",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_LAST_ACK],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_time_wait",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_TIME_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_close",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_CLOSE],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_max_retrans",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_RETRANS],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_timeout_unacknowledged",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_UNACK],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_tcp_loose",
-               .data           = &nf_ct_tcp_loose,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "nf_conntrack_tcp_be_liberal",
-               .data           = &nf_ct_tcp_be_liberal,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "nf_conntrack_tcp_max_retrans",
-               .data           = &nf_ct_tcp_max_retrans,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
@@ -1456,91 +1452,78 @@ static struct ctl_table tcp_sysctl_table[] = {
 static struct ctl_table tcp_compat_sysctl_table[] = {
        {
                .procname       = "ip_conntrack_tcp_timeout_syn_sent",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_SYN_SENT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_syn_sent2",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_SYN_SENT2],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_syn_recv",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_SYN_RECV],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_established",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_ESTABLISHED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_fin_wait",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_FIN_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_close_wait",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_CLOSE_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_last_ack",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_LAST_ACK],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_time_wait",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_TIME_WAIT],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_close",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_CLOSE],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_timeout_max_retrans",
-               .data           = &tcp_timeouts[TCP_CONNTRACK_RETRANS],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_tcp_loose",
-               .data           = &nf_ct_tcp_loose,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "ip_conntrack_tcp_be_liberal",
-               .data           = &nf_ct_tcp_be_liberal,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "ip_conntrack_tcp_max_retrans",
-               .data           = &nf_ct_tcp_max_retrans,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
@@ -1550,6 +1533,125 @@ static struct ctl_table tcp_compat_sysctl_table[] = {
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
 
+static int tcp_kmemdup_sysctl_table(struct nf_proto_net *pn)
+{
+#ifdef CONFIG_SYSCTL
+       struct nf_tcp_net *tn = (struct nf_tcp_net *)pn;
+
+       if (pn->ctl_table)
+               return 0;
+
+       pn->ctl_table = kmemdup(tcp_sysctl_table,
+                               sizeof(tcp_sysctl_table),
+                               GFP_KERNEL);
+       if (!pn->ctl_table)
+               return -ENOMEM;
+
+       pn->ctl_table[0].data = &tn->timeouts[TCP_CONNTRACK_SYN_SENT];
+       pn->ctl_table[1].data = &tn->timeouts[TCP_CONNTRACK_SYN_RECV];
+       pn->ctl_table[2].data = &tn->timeouts[TCP_CONNTRACK_ESTABLISHED];
+       pn->ctl_table[3].data = &tn->timeouts[TCP_CONNTRACK_FIN_WAIT];
+       pn->ctl_table[4].data = &tn->timeouts[TCP_CONNTRACK_CLOSE_WAIT];
+       pn->ctl_table[5].data = &tn->timeouts[TCP_CONNTRACK_LAST_ACK];
+       pn->ctl_table[6].data = &tn->timeouts[TCP_CONNTRACK_TIME_WAIT];
+       pn->ctl_table[7].data = &tn->timeouts[TCP_CONNTRACK_CLOSE];
+       pn->ctl_table[8].data = &tn->timeouts[TCP_CONNTRACK_RETRANS];
+       pn->ctl_table[9].data = &tn->timeouts[TCP_CONNTRACK_UNACK];
+       pn->ctl_table[10].data = &tn->tcp_loose;
+       pn->ctl_table[11].data = &tn->tcp_be_liberal;
+       pn->ctl_table[12].data = &tn->tcp_max_retrans;
+#endif
+       return 0;
+}
+
+static int tcp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
+{
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+       struct nf_tcp_net *tn = (struct nf_tcp_net *)pn;
+       pn->ctl_compat_table = kmemdup(tcp_compat_sysctl_table,
+                                      sizeof(tcp_compat_sysctl_table),
+                                      GFP_KERNEL);
+       if (!pn->ctl_compat_table)
+               return -ENOMEM;
+
+       pn->ctl_compat_table[0].data = &tn->timeouts[TCP_CONNTRACK_SYN_SENT];
+       pn->ctl_compat_table[1].data = &tn->timeouts[TCP_CONNTRACK_SYN_SENT2];
+       pn->ctl_compat_table[2].data = &tn->timeouts[TCP_CONNTRACK_SYN_RECV];
+       pn->ctl_compat_table[3].data = &tn->timeouts[TCP_CONNTRACK_ESTABLISHED];
+       pn->ctl_compat_table[4].data = &tn->timeouts[TCP_CONNTRACK_FIN_WAIT];
+       pn->ctl_compat_table[5].data = &tn->timeouts[TCP_CONNTRACK_CLOSE_WAIT];
+       pn->ctl_compat_table[6].data = &tn->timeouts[TCP_CONNTRACK_LAST_ACK];
+       pn->ctl_compat_table[7].data = &tn->timeouts[TCP_CONNTRACK_TIME_WAIT];
+       pn->ctl_compat_table[8].data = &tn->timeouts[TCP_CONNTRACK_CLOSE];
+       pn->ctl_compat_table[9].data = &tn->timeouts[TCP_CONNTRACK_RETRANS];
+       pn->ctl_compat_table[10].data = &tn->tcp_loose;
+       pn->ctl_compat_table[11].data = &tn->tcp_be_liberal;
+       pn->ctl_compat_table[12].data = &tn->tcp_max_retrans;
+#endif
+#endif
+       return 0;
+}
+
+static int tcpv4_init_net(struct net *net)
+{
+       int i;
+       int ret = 0;
+       struct nf_tcp_net *tn = tcp_pernet(net);
+       struct nf_proto_net *pn = (struct nf_proto_net *)tn;
+
+#ifdef CONFIG_SYSCTL
+       if (!pn->ctl_table) {
+#else
+       if (!pn->user++) {
+#endif
+               for (i = 0; i < TCP_CONNTRACK_TIMEOUT_MAX; i++)
+                       tn->timeouts[i] = tcp_timeouts[i];
+
+               tn->tcp_loose = nf_ct_tcp_loose;
+               tn->tcp_be_liberal = nf_ct_tcp_be_liberal;
+               tn->tcp_max_retrans = nf_ct_tcp_max_retrans;
+       }
+
+       ret = tcp_kmemdup_compat_sysctl_table(pn);
+
+       if (ret < 0)
+               return ret;
+
+       ret = tcp_kmemdup_sysctl_table(pn);
+
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+       if (ret < 0) {
+               kfree(pn->ctl_compat_table);
+               pn->ctl_compat_table = NULL;
+       }
+#endif
+#endif
+       return ret;
+}
+
+static int tcpv6_init_net(struct net *net)
+{
+       int i;
+       struct nf_tcp_net *tn = tcp_pernet(net);
+       struct nf_proto_net *pn = (struct nf_proto_net *)tn;
+
+#ifdef CONFIG_SYSCTL
+       if (!pn->ctl_table) {
+#else
+       if (!pn->user++) {
+#endif
+               for (i = 0; i < TCP_CONNTRACK_TIMEOUT_MAX; i++)
+                       tn->timeouts[i] = tcp_timeouts[i];
+               tn->tcp_loose = nf_ct_tcp_loose;
+               tn->tcp_be_liberal = nf_ct_tcp_be_liberal;
+               tn->tcp_max_retrans = nf_ct_tcp_max_retrans;
+       }
+
+       return tcp_kmemdup_sysctl_table(pn);
+}
+
 struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
 {
        .l3proto                = PF_INET,
@@ -1582,14 +1684,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4 __read_mostly =
                .nla_policy     = tcp_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-       .ctl_table_users        = &tcp_sysctl_table_users,
-       .ctl_table_header       = &tcp_sysctl_header,
-       .ctl_table              = tcp_sysctl_table,
-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-       .ctl_compat_table       = tcp_compat_sysctl_table,
-#endif
-#endif
+       .init_net               = tcpv4_init_net,
 };
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp4);
 
@@ -1625,10 +1720,6 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6 __read_mostly =
                .nla_policy     = tcp_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-       .ctl_table_users        = &tcp_sysctl_table_users,
-       .ctl_table_header       = &tcp_sysctl_header,
-       .ctl_table              = tcp_sysctl_table,
-#endif
+       .init_net               = tcpv6_init_net,
 };
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_tcp6);
index 7259a6bdeb491f4057d5527d1f68ff63a097311b..360565a95de4e92006f84d407548776c3245c700 100644 (file)
 #include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
 #include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
 
-enum udp_conntrack {
-       UDP_CT_UNREPLIED,
-       UDP_CT_REPLIED,
-       UDP_CT_MAX
-};
-
 static unsigned int udp_timeouts[UDP_CT_MAX] = {
        [UDP_CT_UNREPLIED]      = 30*HZ,
        [UDP_CT_REPLIED]        = 180*HZ,
 };
 
+static inline struct nf_udp_net *udp_pernet(struct net *net)
+{
+       return &net->ct.nf_ct_proto.udp;
+}
+
 static bool udp_pkt_to_tuple(const struct sk_buff *skb,
                             unsigned int dataoff,
                             struct nf_conntrack_tuple *tuple)
@@ -73,7 +72,7 @@ static int udp_print_tuple(struct seq_file *s,
 
 static unsigned int *udp_get_timeouts(struct net *net)
 {
-       return udp_timeouts;
+       return udp_pernet(net)->timeouts;
 }
 
 /* Returns verdict for packet, and may modify conntracktype */
@@ -157,13 +156,15 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int udp_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int udp_timeout_nlattr_to_obj(struct nlattr *tb[],
+                                    struct net *net, void *data)
 {
        unsigned int *timeouts = data;
+       struct nf_udp_net *un = udp_pernet(net);
 
        /* set default timeouts for UDP. */
-       timeouts[UDP_CT_UNREPLIED] = udp_timeouts[UDP_CT_UNREPLIED];
-       timeouts[UDP_CT_REPLIED] = udp_timeouts[UDP_CT_REPLIED];
+       timeouts[UDP_CT_UNREPLIED] = un->timeouts[UDP_CT_UNREPLIED];
+       timeouts[UDP_CT_REPLIED] = un->timeouts[UDP_CT_REPLIED];
 
        if (tb[CTA_TIMEOUT_UDP_UNREPLIED]) {
                timeouts[UDP_CT_UNREPLIED] =
@@ -200,19 +201,15 @@ udp_timeout_nla_policy[CTA_TIMEOUT_UDP_MAX+1] = {
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
 #ifdef CONFIG_SYSCTL
-static unsigned int udp_sysctl_table_users;
-static struct ctl_table_header *udp_sysctl_header;
 static struct ctl_table udp_sysctl_table[] = {
        {
                .procname       = "nf_conntrack_udp_timeout",
-               .data           = &udp_timeouts[UDP_CT_UNREPLIED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_udp_timeout_stream",
-               .data           = &udp_timeouts[UDP_CT_REPLIED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -223,14 +220,12 @@ static struct ctl_table udp_sysctl_table[] = {
 static struct ctl_table udp_compat_sysctl_table[] = {
        {
                .procname       = "ip_conntrack_udp_timeout",
-               .data           = &udp_timeouts[UDP_CT_UNREPLIED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "ip_conntrack_udp_timeout_stream",
-               .data           = &udp_timeouts[UDP_CT_REPLIED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -240,6 +235,87 @@ static struct ctl_table udp_compat_sysctl_table[] = {
 #endif /* CONFIG_NF_CONNTRACK_PROC_COMPAT */
 #endif /* CONFIG_SYSCTL */
 
+static int udp_kmemdup_sysctl_table(struct nf_proto_net *pn)
+{
+#ifdef CONFIG_SYSCTL
+       struct nf_udp_net *un = (struct nf_udp_net *)pn;
+       if (pn->ctl_table)
+               return 0;
+       pn->ctl_table = kmemdup(udp_sysctl_table,
+                               sizeof(udp_sysctl_table),
+                               GFP_KERNEL);
+       if (!pn->ctl_table)
+               return -ENOMEM;
+       pn->ctl_table[0].data = &un->timeouts[UDP_CT_UNREPLIED];
+       pn->ctl_table[1].data = &un->timeouts[UDP_CT_REPLIED];
+#endif
+       return 0;
+}
+
+static int udp_kmemdup_compat_sysctl_table(struct nf_proto_net *pn)
+{
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+       struct nf_udp_net *un = (struct nf_udp_net *)pn;
+       pn->ctl_compat_table = kmemdup(udp_compat_sysctl_table,
+                                      sizeof(udp_compat_sysctl_table),
+                                      GFP_KERNEL);
+       if (!pn->ctl_compat_table)
+               return -ENOMEM;
+
+       pn->ctl_compat_table[0].data = &un->timeouts[UDP_CT_UNREPLIED];
+       pn->ctl_compat_table[1].data = &un->timeouts[UDP_CT_REPLIED];
+#endif
+#endif
+       return 0;
+}
+
+static void udp_init_net_data(struct nf_udp_net *un)
+{
+       int i;
+#ifdef CONFIG_SYSCTL
+       if (!un->pn.ctl_table) {
+#else
+       if (!un->pn.user++) {
+#endif
+               for (i = 0; i < UDP_CT_MAX; i++)
+                       un->timeouts[i] = udp_timeouts[i];
+       }
+}
+
+static int udpv4_init_net(struct net *net)
+{
+       int ret;
+       struct nf_udp_net *un = udp_pernet(net);
+       struct nf_proto_net *pn = (struct nf_proto_net *)un;
+
+       udp_init_net_data(un);
+
+       ret = udp_kmemdup_compat_sysctl_table(pn);
+       if (ret < 0)
+               return ret;
+
+       ret = udp_kmemdup_sysctl_table(pn);
+#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
+       if (ret < 0) {
+               kfree(pn->ctl_compat_table);
+               pn->ctl_compat_table = NULL;
+       }
+#endif
+#endif
+       return ret;
+}
+
+static int udpv6_init_net(struct net *net)
+{
+       struct nf_udp_net *un = udp_pernet(net);
+       struct nf_proto_net *pn = (struct nf_proto_net *)un;
+
+       udp_init_net_data(un);
+       return udp_kmemdup_sysctl_table(pn);
+}
+
 struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
 {
        .l3proto                = PF_INET,
@@ -267,14 +343,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4 __read_mostly =
                .nla_policy     = udp_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-       .ctl_table_users        = &udp_sysctl_table_users,
-       .ctl_table_header       = &udp_sysctl_header,
-       .ctl_table              = udp_sysctl_table,
-#ifdef CONFIG_NF_CONNTRACK_PROC_COMPAT
-       .ctl_compat_table       = udp_compat_sysctl_table,
-#endif
-#endif
+       .init_net               = udpv4_init_net,
 };
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp4);
 
@@ -305,10 +374,6 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6 __read_mostly =
                .nla_policy     = udp_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-       .ctl_table_users        = &udp_sysctl_table_users,
-       .ctl_table_header       = &udp_sysctl_header,
-       .ctl_table              = udp_sysctl_table,
-#endif
+       .init_net               = udpv6_init_net,
 };
 EXPORT_SYMBOL_GPL(nf_conntrack_l4proto_udp6);
index 4d60a5376aa6d418d6cf10f889e6a12f348dd9d2..b32e700f8dde7a50672d55f312d8b56dbc78b4fd 100644 (file)
@@ -35,6 +35,17 @@ static unsigned int udplite_timeouts[UDPLITE_CT_MAX] = {
        [UDPLITE_CT_REPLIED]    = 180*HZ,
 };
 
+static int udplite_net_id __read_mostly;
+struct udplite_net {
+       struct nf_proto_net pn;
+       unsigned int timeouts[UDPLITE_CT_MAX];
+};
+
+static inline struct udplite_net *udplite_pernet(struct net *net)
+{
+       return net_generic(net, udplite_net_id);
+}
+
 static bool udplite_pkt_to_tuple(const struct sk_buff *skb,
                                 unsigned int dataoff,
                                 struct nf_conntrack_tuple *tuple)
@@ -70,7 +81,7 @@ static int udplite_print_tuple(struct seq_file *s,
 
 static unsigned int *udplite_get_timeouts(struct net *net)
 {
-       return udplite_timeouts;
+       return udplite_pernet(net)->timeouts;
 }
 
 /* Returns verdict for packet, and may modify conntracktype */
@@ -161,13 +172,15 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl,
 #include <linux/netfilter/nfnetlink.h>
 #include <linux/netfilter/nfnetlink_cttimeout.h>
 
-static int udplite_timeout_nlattr_to_obj(struct nlattr *tb[], void *data)
+static int udplite_timeout_nlattr_to_obj(struct nlattr *tb[],
+                                        struct net *net, void *data)
 {
        unsigned int *timeouts = data;
+       struct udplite_net *un = udplite_pernet(net);
 
        /* set default timeouts for UDPlite. */
-       timeouts[UDPLITE_CT_UNREPLIED] = udplite_timeouts[UDPLITE_CT_UNREPLIED];
-       timeouts[UDPLITE_CT_REPLIED] = udplite_timeouts[UDPLITE_CT_REPLIED];
+       timeouts[UDPLITE_CT_UNREPLIED] = un->timeouts[UDPLITE_CT_UNREPLIED];
+       timeouts[UDPLITE_CT_REPLIED] = un->timeouts[UDPLITE_CT_REPLIED];
 
        if (tb[CTA_TIMEOUT_UDPLITE_UNREPLIED]) {
                timeouts[UDPLITE_CT_UNREPLIED] =
@@ -204,19 +217,15 @@ udplite_timeout_nla_policy[CTA_TIMEOUT_UDPLITE_MAX+1] = {
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
 
 #ifdef CONFIG_SYSCTL
-static unsigned int udplite_sysctl_table_users;
-static struct ctl_table_header *udplite_sysctl_header;
 static struct ctl_table udplite_sysctl_table[] = {
        {
                .procname       = "nf_conntrack_udplite_timeout",
-               .data           = &udplite_timeouts[UDPLITE_CT_UNREPLIED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
        {
                .procname       = "nf_conntrack_udplite_timeout_stream",
-               .data           = &udplite_timeouts[UDPLITE_CT_REPLIED],
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
@@ -225,6 +234,31 @@ static struct ctl_table udplite_sysctl_table[] = {
 };
 #endif /* CONFIG_SYSCTL */
 
+static int udplite_init_net(struct net *net)
+{
+       int i;
+       struct udplite_net *un = udplite_pernet(net);
+       struct nf_proto_net *pn = (struct nf_proto_net *)un;
+#ifdef CONFIG_SYSCTL
+       if (!pn->ctl_table) {
+#else
+       if (!pn->users++) {
+#endif
+               for (i = 0 ; i < UDPLITE_CT_MAX; i++)
+                       un->timeouts[i] = udplite_timeouts[i];
+#ifdef CONFIG_SYSCTL
+               pn->ctl_table = kmemdup(udplite_sysctl_table,
+                                       sizeof(udplite_sysctl_table),
+                                       GFP_KERNEL);
+               if (!pn->ctl_table)
+                       return -ENOMEM;
+               pn->ctl_table[0].data = &un->timeouts[UDPLITE_CT_UNREPLIED];
+               pn->ctl_table[1].data = &un->timeouts[UDPLITE_CT_REPLIED];
+#endif
+       }
+       return 0;
+}
+
 static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
 {
        .l3proto                = PF_INET,
@@ -253,11 +287,8 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite4 __read_mostly =
                .nla_policy     = udplite_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-       .ctl_table_users        = &udplite_sysctl_table_users,
-       .ctl_table_header       = &udplite_sysctl_header,
-       .ctl_table              = udplite_sysctl_table,
-#endif
+       .net_id                 = &udplite_net_id,
+       .init_net               = udplite_init_net,
 };
 
 static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
@@ -288,34 +319,55 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
                .nla_policy     = udplite_timeout_nla_policy,
        },
 #endif /* CONFIG_NF_CT_NETLINK_TIMEOUT */
-#ifdef CONFIG_SYSCTL
-       .ctl_table_users        = &udplite_sysctl_table_users,
-       .ctl_table_header       = &udplite_sysctl_header,
-       .ctl_table              = udplite_sysctl_table,
-#endif
+       .net_id                 = &udplite_net_id,
+       .init_net               = udplite_init_net,
 };
 
-static int __init nf_conntrack_proto_udplite_init(void)
+static int udplite_net_init(struct net *net)
 {
-       int err;
-
-       err = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udplite4);
-       if (err < 0)
-               goto err1;
-       err = nf_conntrack_l4proto_register(&nf_conntrack_l4proto_udplite6);
-       if (err < 0)
-               goto err2;
+       int ret = 0;
+
+       ret = nf_conntrack_l4proto_register(net,
+                                           &nf_conntrack_l4proto_udplite4);
+       if (ret < 0) {
+               pr_err("nf_conntrack_l4proto_udplite4 :protocol register failed.\n");
+               goto out;
+       }
+       ret = nf_conntrack_l4proto_register(net,
+                                           &nf_conntrack_l4proto_udplite6);
+       if (ret < 0) {
+               pr_err("nf_conntrack_l4proto_udplite4 :protocol register failed.\n");
+               goto cleanup_udplite4;
+       }
        return 0;
-err2:
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
-err1:
-       return err;
+
+cleanup_udplite4:
+       nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite4);
+out:
+       return ret;
+}
+
+static void udplite_net_exit(struct net *net)
+{
+       nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite6);
+       nf_conntrack_l4proto_unregister(net, &nf_conntrack_l4proto_udplite4);
+}
+
+static struct pernet_operations udplite_net_ops = {
+       .init = udplite_net_init,
+       .exit = udplite_net_exit,
+       .id   = &udplite_net_id,
+       .size = sizeof(struct udplite_net),
+};
+
+static int __init nf_conntrack_proto_udplite_init(void)
+{
+       return register_pernet_subsys(&udplite_net_ops);
 }
 
 static void __exit nf_conntrack_proto_udplite_exit(void)
 {
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite6);
-       nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_udplite4);
+       unregister_pernet_subsys(&udplite_net_ops);
 }
 
 module_init(nf_conntrack_proto_udplite_init);
index 3e655288d1d6163b23504154b1e11b15c65937e3..cdecbc8fe965e9ed66216e1702fd1b43fe569091 100644 (file)
@@ -49,8 +49,9 @@ static const struct nla_policy cttimeout_nla_policy[CTA_TIMEOUT_MAX+1] = {
 
 static int
 ctnl_timeout_parse_policy(struct ctnl_timeout *timeout,
-                              struct nf_conntrack_l4proto *l4proto,
-                              const struct nlattr *attr)
+                         struct nf_conntrack_l4proto *l4proto,
+                         struct net *net,
+                         const struct nlattr *attr)
 {
        int ret = 0;
 
@@ -60,7 +61,8 @@ ctnl_timeout_parse_policy(struct ctnl_timeout *timeout,
                nla_parse_nested(tb, l4proto->ctnl_timeout.nlattr_max,
                                 attr, l4proto->ctnl_timeout.nla_policy);
 
-               ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, &timeout->data);
+               ret = l4proto->ctnl_timeout.nlattr_to_obj(tb, net,
+                                                         &timeout->data);
        }
        return ret;
 }
@@ -74,6 +76,7 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
        __u8 l4num;
        struct nf_conntrack_l4proto *l4proto;
        struct ctnl_timeout *timeout, *matching = NULL;
+       struct net *net = sock_net(skb->sk);
        char *name;
        int ret;
 
@@ -117,7 +120,7 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
                                goto err_proto_put;
                        }
 
-                       ret = ctnl_timeout_parse_policy(matching, l4proto,
+                       ret = ctnl_timeout_parse_policy(matching, l4proto, net,
                                                        cda[CTA_TIMEOUT_DATA]);
                        return ret;
                }
@@ -132,7 +135,7 @@ cttimeout_new_timeout(struct sock *ctnl, struct sk_buff *skb,
                goto err_proto_put;
        }
 
-       ret = ctnl_timeout_parse_policy(timeout, l4proto,
+       ret = ctnl_timeout_parse_policy(timeout, l4proto, net,
                                        cda[CTA_TIMEOUT_DATA]);
        if (ret < 0)
                goto err;
index 4162437b83614e380a70d5f4fe2a94e76a4d0a0d..630da3d2c62a5473894c03d52896a27bc35b49ea 100644 (file)
@@ -52,6 +52,7 @@ struct nfqnl_instance {
 
        u_int16_t queue_num;                    /* number of this queue */
        u_int8_t copy_mode;
+       u_int32_t flags;                        /* Set using NFQA_CFG_FLAGS */
 /*
  * Following fields are dirtied for each queued packet,
  * keep them in same cache line if possible.
@@ -406,6 +407,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
        struct nfqnl_instance *queue;
        int err = -ENOBUFS;
        __be32 *packet_id_ptr;
+       int failopen = 0;
 
        /* rcu_read_lock()ed by nf_hook_slow() */
        queue = instance_lookup(queuenum);
@@ -431,9 +433,14 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
                goto err_out_free_nskb;
        }
        if (queue->queue_total >= queue->queue_maxlen) {
-               queue->queue_dropped++;
-               net_warn_ratelimited("nf_queue: full at %d entries, dropping packets(s)\n",
-                                    queue->queue_total);
+               if (queue->flags & NFQA_CFG_F_FAIL_OPEN) {
+                       failopen = 1;
+                       err = 0;
+               } else {
+                       queue->queue_dropped++;
+                       net_warn_ratelimited("nf_queue: full at %d entries, dropping packets(s)\n",
+                                            queue->queue_total);
+               }
                goto err_out_free_nskb;
        }
        entry->id = ++queue->id_sequence;
@@ -455,6 +462,8 @@ err_out_free_nskb:
        kfree_skb(nskb);
 err_out_unlock:
        spin_unlock_bh(&queue->lock);
+       if (failopen)
+               nf_reinject(entry, NF_ACCEPT);
 err_out:
        return err;
 }
@@ -858,6 +867,31 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
                spin_unlock_bh(&queue->lock);
        }
 
+       if (nfqa[NFQA_CFG_FLAGS]) {
+               __u32 flags, mask;
+
+               if (!queue) {
+                       ret = -ENODEV;
+                       goto err_out_unlock;
+               }
+
+               if (!nfqa[NFQA_CFG_MASK]) {
+                       /* A mask is needed to specify which flags are being
+                        * changed.
+                        */
+                       ret = -EINVAL;
+                       goto err_out_unlock;
+               }
+
+               flags = ntohl(nla_get_be32(nfqa[NFQA_CFG_FLAGS]));
+               mask = ntohl(nla_get_be32(nfqa[NFQA_CFG_MASK]));
+
+               spin_lock_bh(&queue->lock);
+               queue->flags &= ~mask;
+               queue->flags |= flags & mask;
+               spin_unlock_bh(&queue->lock);
+       }
+
 err_out_unlock:
        rcu_read_unlock();
        return ret;
index 95237c89607a7ee330273abf693c77af607d108a..7babe7d687169d6231fa17149bfd10cb52ee7ebe 100644 (file)
@@ -41,26 +41,36 @@ nfqueue_tg(struct sk_buff *skb, const struct xt_action_param *par)
 static u32 hash_v4(const struct sk_buff *skb)
 {
        const struct iphdr *iph = ip_hdr(skb);
-       __be32 ipaddr;
 
        /* packets in either direction go into same queue */
-       ipaddr = iph->saddr ^ iph->daddr;
+       if (iph->saddr < iph->daddr)
+               return jhash_3words((__force u32)iph->saddr,
+                       (__force u32)iph->daddr, iph->protocol, jhash_initval);
 
-       return jhash_2words((__force u32)ipaddr, iph->protocol, jhash_initval);
+       return jhash_3words((__force u32)iph->daddr,
+                       (__force u32)iph->saddr, iph->protocol, jhash_initval);
 }
 
 #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
 static u32 hash_v6(const struct sk_buff *skb)
 {
        const struct ipv6hdr *ip6h = ipv6_hdr(skb);
-       __be32 addr[4];
+       u32 a, b, c;
+
+       if (ip6h->saddr.s6_addr32[3] < ip6h->daddr.s6_addr32[3]) {
+               a = (__force u32) ip6h->saddr.s6_addr32[3];
+               b = (__force u32) ip6h->daddr.s6_addr32[3];
+       } else {
+               b = (__force u32) ip6h->saddr.s6_addr32[3];
+               a = (__force u32) ip6h->daddr.s6_addr32[3];
+       }
 
-       addr[0] = ip6h->saddr.s6_addr32[0] ^ ip6h->daddr.s6_addr32[0];
-       addr[1] = ip6h->saddr.s6_addr32[1] ^ ip6h->daddr.s6_addr32[1];
-       addr[2] = ip6h->saddr.s6_addr32[2] ^ ip6h->daddr.s6_addr32[2];
-       addr[3] = ip6h->saddr.s6_addr32[3] ^ ip6h->daddr.s6_addr32[3];
+       if (ip6h->saddr.s6_addr32[1] < ip6h->daddr.s6_addr32[1])
+               c = (__force u32) ip6h->saddr.s6_addr32[1];
+       else
+               c = (__force u32) ip6h->daddr.s6_addr32[1];
 
-       return jhash2((__force u32 *)addr, ARRAY_SIZE(addr), jhash_initval);
+       return jhash_3words(a, b, c, jhash_initval);
 }
 #endif
 
index c6d5a83450c9b414462c91ab6fb4bf08f48402af..70b5591a2586877d82b67022ee731bb2246c93eb 100644 (file)
@@ -274,38 +274,25 @@ static void connlimit_mt_destroy(const struct xt_mtdtor_param *par)
        kfree(info->data);
 }
 
-static struct xt_match connlimit_mt_reg[] __read_mostly = {
-       {
-               .name       = "connlimit",
-               .revision   = 0,
-               .family     = NFPROTO_UNSPEC,
-               .checkentry = connlimit_mt_check,
-               .match      = connlimit_mt,
-               .matchsize  = sizeof(struct xt_connlimit_info),
-               .destroy    = connlimit_mt_destroy,
-               .me         = THIS_MODULE,
-       },
-       {
-               .name       = "connlimit",
-               .revision   = 1,
-               .family     = NFPROTO_UNSPEC,
-               .checkentry = connlimit_mt_check,
-               .match      = connlimit_mt,
-               .matchsize  = sizeof(struct xt_connlimit_info),
-               .destroy    = connlimit_mt_destroy,
-               .me         = THIS_MODULE,
-       },
+static struct xt_match connlimit_mt_reg __read_mostly = {
+       .name       = "connlimit",
+       .revision   = 1,
+       .family     = NFPROTO_UNSPEC,
+       .checkentry = connlimit_mt_check,
+       .match      = connlimit_mt,
+       .matchsize  = sizeof(struct xt_connlimit_info),
+       .destroy    = connlimit_mt_destroy,
+       .me         = THIS_MODULE,
 };
 
 static int __init connlimit_mt_init(void)
 {
-       return xt_register_matches(connlimit_mt_reg,
-              ARRAY_SIZE(connlimit_mt_reg));
+       return xt_register_match(&connlimit_mt_reg);
 }
 
 static void __exit connlimit_mt_exit(void)
 {
-       xt_unregister_matches(connlimit_mt_reg, ARRAY_SIZE(connlimit_mt_reg));
+       xt_unregister_match(&connlimit_mt_reg);
 }
 
 module_init(connlimit_mt_init);
index fc0d6dbe5d17253014b4ee76217dc0cdebc5ce5c..ae2ad1eec8d0ccc03fa862cb9a752701c5cd9493 100644 (file)
@@ -75,6 +75,7 @@ struct recent_entry {
 struct recent_table {
        struct list_head        list;
        char                    name[XT_RECENT_NAME_LEN];
+       union nf_inet_addr      mask;
        unsigned int            refcnt;
        unsigned int            entries;
        struct list_head        lru_list;
@@ -228,10 +229,10 @@ recent_mt(const struct sk_buff *skb, struct xt_action_param *par)
 {
        struct net *net = dev_net(par->in ? par->in : par->out);
        struct recent_net *recent_net = recent_pernet(net);
-       const struct xt_recent_mtinfo *info = par->matchinfo;
+       const struct xt_recent_mtinfo_v1 *info = par->matchinfo;
        struct recent_table *t;
        struct recent_entry *e;
-       union nf_inet_addr addr = {};
+       union nf_inet_addr addr = {}, addr_mask;
        u_int8_t ttl;
        bool ret = info->invert;
 
@@ -261,12 +262,15 @@ recent_mt(const struct sk_buff *skb, struct xt_action_param *par)
 
        spin_lock_bh(&recent_lock);
        t = recent_table_lookup(recent_net, info->name);
-       e = recent_entry_lookup(t, &addr, par->family,
+
+       nf_inet_addr_mask(&addr, &addr_mask, &t->mask);
+
+       e = recent_entry_lookup(t, &addr_mask, par->family,
                                (info->check_set & XT_RECENT_TTL) ? ttl : 0);
        if (e == NULL) {
                if (!(info->check_set & XT_RECENT_SET))
                        goto out;
-               e = recent_entry_init(t, &addr, par->family, ttl);
+               e = recent_entry_init(t, &addr_mask, par->family, ttl);
                if (e == NULL)
                        par->hotdrop = true;
                ret = !ret;
@@ -306,10 +310,10 @@ out:
        return ret;
 }
 
-static int recent_mt_check(const struct xt_mtchk_param *par)
+static int recent_mt_check(const struct xt_mtchk_param *par,
+                          const struct xt_recent_mtinfo_v1 *info)
 {
        struct recent_net *recent_net = recent_pernet(par->net);
-       const struct xt_recent_mtinfo *info = par->matchinfo;
        struct recent_table *t;
 #ifdef CONFIG_PROC_FS
        struct proc_dir_entry *pde;
@@ -361,6 +365,8 @@ static int recent_mt_check(const struct xt_mtchk_param *par)
                goto out;
        }
        t->refcnt = 1;
+
+       memcpy(&t->mask, &info->mask, sizeof(t->mask));
        strcpy(t->name, info->name);
        INIT_LIST_HEAD(&t->lru_list);
        for (i = 0; i < ip_list_hash_size; i++)
@@ -385,10 +391,28 @@ out:
        return ret;
 }
 
+static int recent_mt_check_v0(const struct xt_mtchk_param *par)
+{
+       const struct xt_recent_mtinfo_v0 *info_v0 = par->matchinfo;
+       struct xt_recent_mtinfo_v1 info_v1;
+
+       /* Copy revision 0 structure to revision 1 */
+       memcpy(&info_v1, info_v0, sizeof(struct xt_recent_mtinfo));
+       /* Set default mask to ensure backward compatible behaviour */
+       memset(info_v1.mask.all, 0xFF, sizeof(info_v1.mask.all));
+
+       return recent_mt_check(par, &info_v1);
+}
+
+static int recent_mt_check_v1(const struct xt_mtchk_param *par)
+{
+       return recent_mt_check(par, par->matchinfo);
+}
+
 static void recent_mt_destroy(const struct xt_mtdtor_param *par)
 {
        struct recent_net *recent_net = recent_pernet(par->net);
-       const struct xt_recent_mtinfo *info = par->matchinfo;
+       const struct xt_recent_mtinfo_v1 *info = par->matchinfo;
        struct recent_table *t;
 
        mutex_lock(&recent_mutex);
@@ -625,7 +649,7 @@ static struct xt_match recent_mt_reg[] __read_mostly = {
                .family     = NFPROTO_IPV4,
                .match      = recent_mt,
                .matchsize  = sizeof(struct xt_recent_mtinfo),
-               .checkentry = recent_mt_check,
+               .checkentry = recent_mt_check_v0,
                .destroy    = recent_mt_destroy,
                .me         = THIS_MODULE,
        },
@@ -635,10 +659,30 @@ static struct xt_match recent_mt_reg[] __read_mostly = {
                .family     = NFPROTO_IPV6,
                .match      = recent_mt,
                .matchsize  = sizeof(struct xt_recent_mtinfo),
-               .checkentry = recent_mt_check,
+               .checkentry = recent_mt_check_v0,
+               .destroy    = recent_mt_destroy,
+               .me         = THIS_MODULE,
+       },
+       {
+               .name       = "recent",
+               .revision   = 1,
+               .family     = NFPROTO_IPV4,
+               .match      = recent_mt,
+               .matchsize  = sizeof(struct xt_recent_mtinfo_v1),
+               .checkentry = recent_mt_check_v1,
                .destroy    = recent_mt_destroy,
                .me         = THIS_MODULE,
        },
+       {
+               .name       = "recent",
+               .revision   = 1,
+               .family     = NFPROTO_IPV6,
+               .match      = recent_mt,
+               .matchsize  = sizeof(struct xt_recent_mtinfo_v1),
+               .checkentry = recent_mt_check_v1,
+               .destroy    = recent_mt_destroy,
+               .me         = THIS_MODULE,
+       }
 };
 
 static int __init recent_mt_init(void)
index 372ec6502aa8752dca83c3c507e2d0ce9cac84d1..4ee6f23700167f8e921ff6b8e5f8d9e3707f0806 100644 (file)
@@ -5763,21 +5763,21 @@ static struct nf_hook_ops selinux_ipv4_ops[] = {
        {
                .hook =         selinux_ipv4_postroute,
                .owner =        THIS_MODULE,
-               .pf =           PF_INET,
+               .pf =           NFPROTO_IPV4,
                .hooknum =      NF_INET_POST_ROUTING,
                .priority =     NF_IP_PRI_SELINUX_LAST,
        },
        {
                .hook =         selinux_ipv4_forward,
                .owner =        THIS_MODULE,
-               .pf =           PF_INET,
+               .pf =           NFPROTO_IPV4,
                .hooknum =      NF_INET_FORWARD,
                .priority =     NF_IP_PRI_SELINUX_FIRST,
        },
        {
                .hook =         selinux_ipv4_output,
                .owner =        THIS_MODULE,
-               .pf =           PF_INET,
+               .pf =           NFPROTO_IPV4,
                .hooknum =      NF_INET_LOCAL_OUT,
                .priority =     NF_IP_PRI_SELINUX_FIRST,
        }
@@ -5789,14 +5789,14 @@ static struct nf_hook_ops selinux_ipv6_ops[] = {
        {
                .hook =         selinux_ipv6_postroute,
                .owner =        THIS_MODULE,
-               .pf =           PF_INET6,
+               .pf =           NFPROTO_IPV6,
                .hooknum =      NF_INET_POST_ROUTING,
                .priority =     NF_IP6_PRI_SELINUX_LAST,
        },
        {
                .hook =         selinux_ipv6_forward,
                .owner =        THIS_MODULE,
-               .pf =           PF_INET6,
+               .pf =           NFPROTO_IPV6,
                .hooknum =      NF_INET_FORWARD,
                .priority =     NF_IP6_PRI_SELINUX_FIRST,
        }