initial import (Boeing r1752, NRL r878)

This commit is contained in:
ahrenholz 2013-08-29 14:21:13 +00:00
commit f8f46d28be
394 changed files with 99738 additions and 0 deletions

View file

@ -0,0 +1,62 @@
VERSION := 2.6.38
TARBALL := /usr/src/linux-source-$(VERSION).tar.bz2
SUBVERSION := -core
REVISION := 1.0
PATCHDIR := patches
PATCHES := $(sort $(wildcard $(PATCHDIR)/*.patch))
CONFIG := config.core
DEPDEBS := linux-source kernel-package po-debconf gettext
CONCURRENCY_LEVEL := 2
MAINTAINER ?= Tom Goff
EMAIL ?= thomas.goff@boeing.com
MAKEKPKGFLAGS := --initrd --rootcmd fakeroot --us --uc \
--append-to-version $(SUBVERSION) --revision $(REVISION)
.PHONY: build
build: debcheck defaultconfig patch
export CONCURRENCY_LEVEL="$(CONCURRENCY_LEVEL)" \
KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \
cd linux-source-$(VERSION) && \
if [ -f ../$(CONFIG) ]; then \
cat ../$(CONFIG) >> .config; \
fi && \
fakeroot make-kpkg $(MAKEKPKGFLAGS) binary-arch
.PHONY: debcheck
debcheck:
for d in $(DEPDEBS); do \
if ! dpkg-query -s $$d > /dev/null 2>&1; then \
echo ERROR: build dependency not installed: $$d >&2; \
exit 1; \
fi; \
done
.PHONY: defaultconfig
defaultconfig: linux-source-$(VERSION)
export KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \
cd linux-source-$(VERSION) && make-kpkg $(MAKEKPKGFLAGS) configure
.PHONY: patch
patch: linux-source-$(VERSION) patch-stamp
patch-stamp: $(PATCHES)
for p in $^; do \
if ! patch -d linux-source-$(VERSION) -p1 < $$p; then \
echo ERROR: applying patch failed: $$p >&2; \
exit 1; \
fi; \
done
touch patch-stamp
linux-source-$(VERSION): $(TARBALL)
tar -xjf $^
.PHONY: clean
clean:
rm -rf linux-source-$(VERSION) patch-stamp

View file

@ -0,0 +1,9 @@
Author: Tom Goff <thomas.goff@boeing.com>
The Makefile is basically a wrapper around the make-kpkg command that
simplifies building kernel packages. Running make will do some basic
dependency checks then build architecture appropriate kernel packages that
include changes from the patches directory. The nfnetlink patch is what
virtualizes the netfilter queue mechanism; the flow-cache patch allows using
IPsec between network namespaces; the ifindex patch virtualizes network
interface index numbers.

View file

@ -0,0 +1 @@
CONFIG_XFRM_STATISTICS=y

View file

@ -0,0 +1,31 @@
Only use the flow cache for the initial network namespace.
The flow cache is not per netns and its entries do not include what
namespace they are valid for. This causes problems when transformed
traffic is sent between namespaces.
---
net/core/flow.c | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
diff --git a/net/core/flow.c b/net/core/flow.c
index 127c8a7..890510f 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -24,6 +24,7 @@
#include <net/flow.h>
#include <asm/atomic.h>
#include <linux/security.h>
+#include <net/net_namespace.h>
struct flow_cache_entry {
union {
@@ -227,6 +228,9 @@ flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir,
if (!fcp->hash_table)
goto nocache;
+ if (!net_eq(net, &init_net))
+ goto nocache;
+
if (fcp->hash_rnd_recalc)
flow_new_hash_rnd(fc, fcp);

View file

@ -0,0 +1,52 @@
Make network device ifindex sequential per network namespace.
---
include/net/net_namespace.h | 2 ++
net/core/dev.c | 13 ++++++-------
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 1bf812b..6ee0db4 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -57,6 +57,8 @@ struct net {
struct sock *rtnl; /* rtnetlink socket */
struct sock *genl_sock;
+ int ifindex;
+
struct list_head dev_base_head;
struct hlist_head *dev_name_head;
struct hlist_head *dev_index_head;
diff --git a/net/core/dev.c b/net/core/dev.c
index 6561021..764a190 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4975,12 +4975,11 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
*/
static int dev_new_index(struct net *net)
{
- static int ifindex;
for (;;) {
- if (++ifindex <= 0)
- ifindex = 1;
- if (!__dev_get_by_index(net, ifindex))
- return ifindex;
+ if (++net->ifindex <= 0)
+ net->ifindex = 1;
+ if (!__dev_get_by_index(net, net->ifindex))
+ return net->ifindex;
}
}
@@ -5918,8 +5917,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
/* Actually switch the network namespace */
dev_net_set(dev, net);
- /* If there is an ifindex conflict assign a new one */
- if (__dev_get_by_index(net, dev->ifindex)) {
+ /* Assign a new ifindex */
+ {
int iflink = (dev->iflink == dev->ifindex);
dev->ifindex = dev_new_index(net);
if (iflink)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
VERSION := 3.0.0
TARBALL := /usr/src/linux-source-$(VERSION).tar.bz2
SUBVERSION := -core
REVISION := 1.0
PATCHDIR := patches
PATCHES := $(sort $(wildcard $(PATCHDIR)/*.patch))
CONFIG := config.core
DEPDEBS := linux-source kernel-package po-debconf gettext
CONCURRENCY_LEVEL := 8
MAINTAINER ?= Tom Goff
EMAIL ?= thomas.goff@boeing.com
MAKEKPKGFLAGS := --initrd --rootcmd fakeroot --us --uc \
--append-to-version $(SUBVERSION) --revision $(REVISION)
.PHONY: build
build: debcheck defaultconfig patch
export CONCURRENCY_LEVEL="$(CONCURRENCY_LEVEL)" \
KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \
cd linux-source-$(VERSION) && \
if [ -f ../$(CONFIG) ]; then \
cat ../$(CONFIG) >> .config; \
fi && \
fakeroot make-kpkg $(MAKEKPKGFLAGS) binary-arch
.PHONY: debcheck
debcheck:
for d in $(DEPDEBS); do \
if ! dpkg-query -s $$d > /dev/null 2>&1; then \
echo ERROR: build dependency not installed: $$d >&2; \
exit 1; \
fi; \
done
.PHONY: defaultconfig
defaultconfig: linux-source-$(VERSION)
export KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \
cd linux-source-$(VERSION) && make-kpkg $(MAKEKPKGFLAGS) configure
.PHONY: patch
patch: linux-source-$(VERSION) patch-stamp
patch-stamp: $(PATCHES)
for p in $^; do \
if ! patch -d linux-source-$(VERSION) -p1 < $$p; then \
echo ERROR: applying patch failed: $$p >&2; \
exit 1; \
fi; \
done
touch patch-stamp
linux-source-$(VERSION): $(TARBALL)
tar -xjf $^
.PHONY: clean
clean:
rm -rf linux-source-$(VERSION) patch-stamp

View file

@ -0,0 +1,9 @@
Author: Tom Goff <thomas.goff@boeing.com>
The Makefile is basically a wrapper around the make-kpkg command that
simplifies building kernel packages. Running make will do some basic
dependency checks then build architecture appropriate kernel packages that
include changes from the patches directory. The nfnetlink patch is what
virtualizes the netfilter queue mechanism; the flow-cache patch allows using
IPsec between network namespaces; the ifindex patch virtualizes network
interface index numbers.

View file

@ -0,0 +1 @@
CONFIG_XFRM_STATISTICS=y

View file

@ -0,0 +1,49 @@
commit 0542b69e2c57fc9668ce6a03155bea6e1f557901
Author: dpward <david.ward@ll.mit.edu>
Date: Wed Aug 31 06:05:27 2011 +0000
net: Make flow cache namespace-aware
flow_cache_lookup will return a cached object (or null pointer) that the
resolver (i.e. xfrm_policy_lookup) previously found for another namespace
using the same key/family/dir. Instead, make the namespace part of what
identifies entries in the cache.
As before, flow_entry_valid will return 0 for entries where the namespace
has been deleted, and they will be removed from the cache the next time
flow_cache_gc_task is run.
Reported-by: Andrew Dickinson <whydna@whydna.net>
Signed-off-by: David Ward <david.ward@ll.mit.edu>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/core/flow.c b/net/core/flow.c
index bf32c33..47b6d26 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -30,6 +30,7 @@ struct flow_cache_entry {
struct hlist_node hlist;
struct list_head gc_list;
} u;
+ struct net *net;
u16 family;
u8 dir;
u32 genid;
@@ -232,7 +233,8 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
hash = flow_hash_code(fc, fcp, key);
hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) {
- if (tfle->family == family &&
+ if (tfle->net == net &&
+ tfle->family == family &&
tfle->dir == dir &&
flow_key_compare(key, &tfle->key) == 0) {
fle = tfle;
@@ -246,6 +248,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir,
fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC);
if (fle) {
+ fle->net = net;
fle->family = family;
fle->dir = dir;
memcpy(&fle->key, key, sizeof(*key));

View file

@ -0,0 +1,51 @@
commit 7da7dfcb787d77929c15d5b7127c816ee16f1ede
Author: Tom Goff <thomas.goff@boeing.com>
Date: Fri Dec 16 17:39:00 2011 -0800
Make network device ifindex sequential per network namespace.
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 3bb6fa0..2fd53da 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -62,6 +62,8 @@ struct net {
struct sock *rtnl; /* rtnetlink socket */
struct sock *genl_sock;
+ int ifindex;
+
struct list_head dev_base_head;
struct hlist_head *dev_name_head;
struct hlist_head *dev_index_head;
diff --git a/net/core/dev.c b/net/core/dev.c
index 6ba50a1..ba95aa5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5260,12 +5260,11 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
*/
static int dev_new_index(struct net *net)
{
- static int ifindex;
for (;;) {
- if (++ifindex <= 0)
- ifindex = 1;
- if (!__dev_get_by_index(net, ifindex))
- return ifindex;
+ if (++net->ifindex <= 0)
+ net->ifindex = 1;
+ if (!__dev_get_by_index(net, net->ifindex))
+ return net->ifindex;
}
}
@@ -6277,8 +6276,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
/* Actually switch the network namespace */
dev_net_set(dev, net);
- /* If there is an ifindex conflict assign a new one */
- if (__dev_get_by_index(net, dev->ifindex)) {
+ /* Assign a new ifindex */
+ {
int iflink = (dev->iflink == dev->ifindex);
dev->ifindex = dev_new_index(net);
if (iflink)

View file

@ -0,0 +1,351 @@
From 4b819adab7892f61a96bab1e36e5d9a74018432b Mon Sep 17 00:00:00 2001
From: Tom Goff <thomas.goff@boeing.com>
Date: Tue, 3 Jan 2012 14:39:04 -0800
Subject: [PATCH 1/2] netfilter: Make the /proc/net/netfilter directory per
netns.
This allows subsystems to create per-netns entries.
Signed-off-by: Tom Goff <thomas.goff@boeing.com>
---
include/linux/netfilter.h | 5 ----
include/net/net_namespace.h | 3 ++
net/netfilter/core.c | 35 +++++++++++++++++++++++-------
net/netfilter/nf_log.c | 33 +++++++++++++++++++++++++---
net/netfilter/nf_queue.c | 31 +++++++++++++++++++++++---
net/netfilter/nfnetlink_log.c | 44 ++++++++++++++++++++++++++-----------
net/netfilter/nfnetlink_queue.c | 45 ++++++++++++++++++++++++++------------
7 files changed, 148 insertions(+), 48 deletions(-)
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 857f502..b4e02fb 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -340,11 +340,6 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
#endif
}
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-extern struct proc_dir_entry *proc_net_netfilter;
-#endif
-
#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 3bb6fa0..cf126ef 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -84,6 +84,9 @@ struct net {
struct netns_dccp dccp;
#endif
#ifdef CONFIG_NETFILTER
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc_net_netfilter;
+#endif
struct netns_xt xt;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct netns_ct ct;
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index afca6c7..9d9b103 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -255,25 +255,44 @@ void nf_conntrack_destroy(struct nf_conntrack *nfct)
EXPORT_SYMBOL(nf_conntrack_destroy);
#endif /* CONFIG_NF_CONNTRACK */
+static int __net_init netfilter_net_init(struct net *net)
+{
#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_net_netfilter;
-EXPORT_SYMBOL(proc_net_netfilter);
+ net->proc_net_netfilter = proc_net_mkdir(net, "netfilter",
+ net->proc_net);
+ if (!net->proc_net_netfilter) {
+ pr_err("%s: cannot create netfilter proc entry\n", __func__);
+ return -ENOMEM;
+ }
#endif
+ return 0;
+}
+
+static void __net_exit netfilter_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ proc_net_remove(net, "netfilter");
+#endif
+}
+
+static struct pernet_operations netfilter_net_ops = {
+ .init = netfilter_net_init,
+ .exit = netfilter_net_exit,
+};
+
void __init netfilter_init(void)
{
int i, h;
+
+ if (register_pernet_subsys(&netfilter_net_ops))
+ panic("%s: failed to register per netns operations", __func__);
+
for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) {
for (h = 0; h < NF_MAX_HOOKS; h++)
INIT_LIST_HEAD(&nf_hooks[i][h]);
}
-#ifdef CONFIG_PROC_FS
- proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net);
- if (!proc_net_netfilter)
- panic("cannot create netfilter proc entry");
-#endif
-
if (netfilter_queue_init() < 0)
panic("cannot initialize nf_queue");
if (netfilter_log_init() < 0)
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index ce0c406..ccc15d6 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -297,14 +297,39 @@ static __init int netfilter_log_sysctl_init(void)
}
#endif /* CONFIG_SYSCTL */
-int __init netfilter_log_init(void)
+static int __net_init netfilter_log_net_init(struct net *net)
{
- int i, r;
#ifdef CONFIG_PROC_FS
if (!proc_create("nf_log", S_IRUGO,
- proc_net_netfilter, &nflog_file_ops))
- return -1;
+ net->proc_net_netfilter, &nflog_file_ops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static void __net_exit netfilter_log_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nf_log", net->proc_net_netfilter);
#endif
+}
+
+static struct pernet_operations netfilter_log_net_ops = {
+ .init = netfilter_log_net_init,
+ .exit = netfilter_log_net_exit,
+};
+
+int __init netfilter_log_init(void)
+{
+ int i, r;
+
+ r = register_pernet_subsys(&netfilter_log_net_ops);
+ if (r) {
+ pr_err("%s: failed to register per netns operations\n",
+ __func__);
+ return r;
+ }
/* Errors will trigger panic, unroll on error is unnecessary. */
r = netfilter_log_sysctl_init();
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index 99ffd28..ecb84a3 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -383,14 +383,37 @@ static const struct file_operations nfqueue_file_ops = {
};
#endif /* PROC_FS */
-
-int __init netfilter_queue_init(void)
+static int __net_init netfilter_queue_net_init(struct net *net)
{
#ifdef CONFIG_PROC_FS
if (!proc_create("nf_queue", S_IRUGO,
- proc_net_netfilter, &nfqueue_file_ops))
- return -1;
+ net->proc_net_netfilter, &nfqueue_file_ops))
+ return -ENOMEM;
#endif
+
return 0;
}
+static void __net_exit netfilter_queue_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nf_queue", net->proc_net_netfilter);
+#endif
+}
+
+static struct pernet_operations netfilter_queue_net_ops = {
+ .init = netfilter_queue_net_init,
+ .exit = netfilter_queue_net_exit,
+};
+
+int __init netfilter_queue_init(void)
+{
+ int err;
+
+ err = register_pernet_subsys(&netfilter_queue_net_ops);
+ if (err)
+ pr_err("%s: cannot initialize per netns operations\n",
+ __func__);
+
+ return err;
+}
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 66b2c54..e4c3c1e 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -950,9 +950,39 @@ static const struct file_operations nful_file_ops = {
#endif /* PROC_FS */
+static int __net_init nfnetlink_log_net_init(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ if (!proc_create("nfnetlink_log", 0440,
+ net->proc_net_netfilter, &nful_file_ops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static void __net_exit nfnetlink_log_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nfnetlink_log", net->proc_net_netfilter);
+#endif
+}
+
+static struct pernet_operations nfnetlink_log_net_ops = {
+ .init = nfnetlink_log_net_init,
+ .exit = nfnetlink_log_net_exit,
+};
+
static int __init nfnetlink_log_init(void)
{
- int i, status = -ENOMEM;
+ int i, status;
+
+ status = register_pernet_subsys(&nfnetlink_log_net_ops);
+ if (status) {
+ pr_err("%s: failed to register per netns operations\n",
+ __func__);
+ return status;
+ }
for (i = 0; i < INSTANCE_BUCKETS; i++)
INIT_HLIST_HEAD(&instance_table[i]);
@@ -975,17 +1005,8 @@ static int __init nfnetlink_log_init(void)
goto cleanup_subsys;
}
-#ifdef CONFIG_PROC_FS
- if (!proc_create("nfnetlink_log", 0440,
- proc_net_netfilter, &nful_file_ops))
- goto cleanup_logger;
-#endif
return status;
-#ifdef CONFIG_PROC_FS
-cleanup_logger:
- nf_log_unregister(&nfulnl_logger);
-#endif
cleanup_subsys:
nfnetlink_subsys_unregister(&nfulnl_subsys);
cleanup_netlink_notifier:
@@ -996,9 +1017,6 @@ cleanup_netlink_notifier:
static void __exit nfnetlink_log_fini(void)
{
nf_log_unregister(&nfulnl_logger);
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("nfnetlink_log", proc_net_netfilter);
-#endif
nfnetlink_subsys_unregister(&nfulnl_subsys);
netlink_unregister_notifier(&nfulnl_rtnl_notifier);
}
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index a80b0cb..b615da5 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -974,9 +974,39 @@ static const struct file_operations nfqnl_file_ops = {
#endif /* PROC_FS */
+static int __net_init nfnetlink_queue_net_init(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ if (!proc_create("nfnetlink_queue", 0440,
+ net->proc_net_netfilter, &nfqnl_file_ops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static void __net_exit nfnetlink_queue_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nfnetlink_queue", net->proc_net_netfilter);
+#endif
+}
+
+static struct pernet_operations nfnetlink_queue_net_ops = {
+ .init = nfnetlink_queue_net_init,
+ .exit = nfnetlink_queue_net_exit,
+};
+
static int __init nfnetlink_queue_init(void)
{
- int i, status = -ENOMEM;
+ int i, status;
+
+ status = register_pernet_subsys(&nfnetlink_queue_net_ops);
+ if (status) {
+ pr_err("%s: failed to register per netns operations\n",
+ __func__);
+ return status;
+ }
for (i = 0; i < INSTANCE_BUCKETS; i++)
INIT_HLIST_HEAD(&instance_table[i]);
@@ -988,19 +1018,9 @@ static int __init nfnetlink_queue_init(void)
goto cleanup_netlink_notifier;
}
-#ifdef CONFIG_PROC_FS
- if (!proc_create("nfnetlink_queue", 0440,
- proc_net_netfilter, &nfqnl_file_ops))
- goto cleanup_subsys;
-#endif
-
register_netdevice_notifier(&nfqnl_dev_notifier);
return status;
-#ifdef CONFIG_PROC_FS
-cleanup_subsys:
- nfnetlink_subsys_unregister(&nfqnl_subsys);
-#endif
cleanup_netlink_notifier:
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
return status;
@@ -1010,9 +1030,6 @@ static void __exit nfnetlink_queue_fini(void)
{
nf_unregister_queue_handlers(&nfqh);
unregister_netdevice_notifier(&nfqnl_dev_notifier);
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("nfnetlink_queue", proc_net_netfilter);
-#endif
nfnetlink_subsys_unregister(&nfqnl_subsys);
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
--
1.7.5.4

View file

@ -0,0 +1,516 @@
From dd504f32d24e9f239d429204c43a5c500c9853c6 Mon Sep 17 00:00:00 2001
From: Tom Goff <thomas.goff@boeing.com>
Date: Tue, 3 Jan 2012 15:52:32 -0800
Subject: [PATCH 2/2] netfilter: nfnetlink_queue: Add netns support.
Make nfnetlink_queue network namespace aware including a per-netns
/proc/net/netfilter/nfnetlink_queue file.
Signed-off-by: Tom Goff <thomas.goff@boeing.com>
---
include/net/net_namespace.h | 6 ++
include/net/netfilter/nf_queue.h | 3 +-
include/net/netns/nfqnl.h | 14 ++++
net/ipv4/netfilter/ip_queue.c | 6 ++-
net/ipv6/netfilter/ip6_queue.c | 6 ++-
net/netfilter/nf_queue.c | 12 +++-
net/netfilter/nfnetlink_queue.c | 138 +++++++++++++++++++-------------------
7 files changed, 112 insertions(+), 73 deletions(-)
create mode 100644 include/net/netns/nfqnl.h
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index cf126ef..4b6f04a 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -21,6 +21,9 @@
#include <net/netns/conntrack.h>
#endif
#include <net/netns/xfrm.h>
+#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
+#include <net/netns/nfqnl.h>
+#endif
struct proc_dir_entry;
struct net_device;
@@ -93,6 +96,9 @@ struct net {
#endif
struct sock *nfnl;
struct sock *nfnl_stash;
+#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
+ struct netns_nfqnl nfqnl;
+#endif
#endif
#ifdef CONFIG_WEXT_CORE
struct sk_buff_head wext_nlevents;
diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h
index 252fd10..3e5bde8 100644
--- a/include/net/netfilter/nf_queue.h
+++ b/include/net/netfilter/nf_queue.h
@@ -19,7 +19,8 @@ struct nf_queue_entry {
/* Packet queuing */
struct nf_queue_handler {
- int (*outfn)(struct nf_queue_entry *entry,
+ int (*outfn)(struct net *net,
+ struct nf_queue_entry *entry,
unsigned int queuenum);
char *name;
};
diff --git a/include/net/netns/nfqnl.h b/include/net/netns/nfqnl.h
new file mode 100644
index 0000000..0fe7fbe
--- /dev/null
+++ b/include/net/netns/nfqnl.h
@@ -0,0 +1,14 @@
+#ifndef __NETNS_NFQNL_H
+#define __NETNS_NFQNL_H
+
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+#define NFQNL_INSTANCE_BUCKETS 16
+
+struct netns_nfqnl {
+ spinlock_t instances_lock;
+ struct hlist_head instance_table[NFQNL_INSTANCE_BUCKETS];
+};
+
+#endif /* __NETNS_NFQNL_H */
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index e59aabd..f3c43e5 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -225,7 +225,8 @@ nlmsg_failure:
}
static int
-ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
+ipq_enqueue_packet(struct net *net, struct nf_queue_entry *entry,
+ unsigned int queuenum)
{
int status = -EINVAL;
struct sk_buff *nskb;
@@ -239,6 +240,9 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
spin_lock_bh(&queue_lock);
+ if (!net_eq(net, &init_net))
+ goto err_out_free_nskb;
+
if (!peer_pid)
goto err_out_free_nskb;
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index e63c397..322c511 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -225,7 +225,8 @@ nlmsg_failure:
}
static int
-ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
+ipq_enqueue_packet(struct net *net, struct nf_queue_entry *entry,
+ unsigned int queuenum)
{
int status = -EINVAL;
struct sk_buff *nskb;
@@ -239,6 +240,9 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
spin_lock_bh(&queue_lock);
+ if (!net_eq(net, &init_net))
+ goto err_out_free_nskb;
+
if (!peer_pid)
goto err_out_free_nskb;
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index ecb84a3..9490bd5 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -133,6 +133,16 @@ static int __nf_queue(struct sk_buff *skb,
#endif
const struct nf_afinfo *afinfo;
const struct nf_queue_handler *qh;
+ struct net *net;
+
+ if (indev)
+ net = dev_net(indev);
+ else if (skb->sk)
+ net = sock_net(skb->sk);
+ else if (outdev)
+ net = dev_net(outdev);
+ else
+ return status;
/* QUEUE == DROP if no one is waiting, to be safe. */
rcu_read_lock();
@@ -185,7 +195,7 @@ static int __nf_queue(struct sk_buff *skb,
#endif
skb_dst_force(skb);
afinfo->saveroute(skb, entry);
- status = qh->outfn(entry, queuenum);
+ status = qh->outfn(net, entry, queuenum);
rcu_read_unlock();
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index b615da5..48ea6f4 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -64,24 +64,19 @@ struct nfqnl_instance {
typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long);
-static DEFINE_SPINLOCK(instances_lock);
-
-#define INSTANCE_BUCKETS 16
-static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly;
-
static inline u_int8_t instance_hashfn(u_int16_t queue_num)
{
- return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS;
+ return ((queue_num >> 8) | queue_num) % NFQNL_INSTANCE_BUCKETS;
}
static struct nfqnl_instance *
-instance_lookup(u_int16_t queue_num)
+instance_lookup(struct net *net, u_int16_t queue_num)
{
struct hlist_head *head;
struct hlist_node *pos;
struct nfqnl_instance *inst;
- head = &instance_table[instance_hashfn(queue_num)];
+ head = &net->nfqnl.instance_table[instance_hashfn(queue_num)];
hlist_for_each_entry_rcu(inst, pos, head, hlist) {
if (inst->queue_num == queue_num)
return inst;
@@ -90,14 +85,14 @@ instance_lookup(u_int16_t queue_num)
}
static struct nfqnl_instance *
-instance_create(u_int16_t queue_num, int pid)
+instance_create(struct net *net, u_int16_t queue_num, int pid)
{
struct nfqnl_instance *inst;
unsigned int h;
int err;
- spin_lock(&instances_lock);
- if (instance_lookup(queue_num)) {
+ spin_lock(&net->nfqnl.instances_lock);
+ if (instance_lookup(net, queue_num)) {
err = -EEXIST;
goto out_unlock;
}
@@ -122,16 +117,16 @@ instance_create(u_int16_t queue_num, int pid)
}
h = instance_hashfn(queue_num);
- hlist_add_head_rcu(&inst->hlist, &instance_table[h]);
+ hlist_add_head_rcu(&inst->hlist, &net->nfqnl.instance_table[h]);
- spin_unlock(&instances_lock);
+ spin_unlock(&net->nfqnl.instances_lock);
return inst;
out_free:
kfree(inst);
out_unlock:
- spin_unlock(&instances_lock);
+ spin_unlock(&net->nfqnl.instances_lock);
return ERR_PTR(err);
}
@@ -157,11 +152,11 @@ __instance_destroy(struct nfqnl_instance *inst)
}
static void
-instance_destroy(struct nfqnl_instance *inst)
+instance_destroy(struct net *net, struct nfqnl_instance *inst)
{
- spin_lock(&instances_lock);
+ spin_lock(&net->nfqnl.instances_lock);
__instance_destroy(inst);
- spin_unlock(&instances_lock);
+ spin_unlock(&net->nfqnl.instances_lock);
}
static inline void
@@ -390,7 +385,8 @@ nla_put_failure:
}
static int
-nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
+nfqnl_enqueue_packet(struct net *net, struct nf_queue_entry *entry,
+ unsigned int queuenum)
{
struct sk_buff *nskb;
struct nfqnl_instance *queue;
@@ -398,7 +394,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
__be32 *packet_id_ptr;
/* rcu_read_lock()ed by nf_hook_slow() */
- queue = instance_lookup(queuenum);
+ queue = instance_lookup(net, queuenum);
if (!queue) {
err = -ESRCH;
goto err_out;
@@ -432,7 +428,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
*packet_id_ptr = htonl(entry->id);
/* nfnetlink_unicast will either free the nskb or add it to a socket */
- err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT);
+ err = nfnetlink_unicast(nskb, net, queue->peer_pid, MSG_DONTWAIT);
if (err < 0) {
queue->queue_user_dropped++;
goto err_out_unlock;
@@ -541,16 +537,16 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
/* drop all packets with either indev or outdev == ifindex from all queue
* instances */
static void
-nfqnl_dev_drop(int ifindex)
+nfqnl_dev_drop(struct net *net, int ifindex)
{
int i;
rcu_read_lock();
- for (i = 0; i < INSTANCE_BUCKETS; i++) {
+ for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) {
struct hlist_node *tmp;
struct nfqnl_instance *inst;
- struct hlist_head *head = &instance_table[i];
+ struct hlist_head *head = &net->nfqnl.instance_table[i];
hlist_for_each_entry_rcu(inst, tmp, head, hlist)
nfqnl_flush(inst, dev_cmp, ifindex);
@@ -567,12 +563,9 @@ nfqnl_rcv_dev_event(struct notifier_block *this,
{
struct net_device *dev = ptr;
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
/* Drop any packets associated with the downed device */
if (event == NETDEV_DOWN)
- nfqnl_dev_drop(dev->ifindex);
+ nfqnl_dev_drop(dev_net(dev), dev->ifindex);
return NOTIFY_DONE;
}
@@ -590,19 +583,19 @@ nfqnl_rcv_nl_event(struct notifier_block *this,
int i;
/* destroy all instances for this pid */
- spin_lock(&instances_lock);
- for (i = 0; i < INSTANCE_BUCKETS; i++) {
+ spin_lock(&n->net->nfqnl.instances_lock);
+ for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) {
struct hlist_node *tmp, *t2;
struct nfqnl_instance *inst;
- struct hlist_head *head = &instance_table[i];
+ struct hlist_head *head =
+ &n->net->nfqnl.instance_table[i];
hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) {
- if ((n->net == &init_net) &&
- (n->pid == inst->peer_pid))
+ if (n->pid == inst->peer_pid)
__instance_destroy(inst);
}
}
- spin_unlock(&instances_lock);
+ spin_unlock(&n->net->nfqnl.instances_lock);
}
return NOTIFY_DONE;
}
@@ -715,9 +710,10 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
unsigned int verdict;
struct nf_queue_entry *entry;
int err;
+ struct net *net = sock_net(ctnl);
rcu_read_lock();
- queue = instance_lookup(queue_num);
+ queue = instance_lookup(net, queue_num);
if (!queue) {
err = -ENODEV;
goto err_out_unlock;
@@ -774,6 +770,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
struct nfqnl_instance *queue;
struct nfqnl_msg_config_cmd *cmd = NULL;
int ret = 0;
+ struct net *net = sock_net(ctnl);
if (nfqa[NFQA_CFG_CMD]) {
cmd = nla_data(nfqa[NFQA_CFG_CMD]);
@@ -790,7 +787,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
}
rcu_read_lock();
- queue = instance_lookup(queue_num);
+ queue = instance_lookup(net, queue_num);
if (queue && queue->peer_pid != NETLINK_CB(skb).pid) {
ret = -EPERM;
goto err_out_unlock;
@@ -803,7 +800,8 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
ret = -EBUSY;
goto err_out_unlock;
}
- queue = instance_create(queue_num, NETLINK_CB(skb).pid);
+ queue = instance_create(net, queue_num,
+ NETLINK_CB(skb).pid);
if (IS_ERR(queue)) {
ret = PTR_ERR(queue);
goto err_out_unlock;
@@ -814,7 +812,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
ret = -ENODEV;
goto err_out_unlock;
}
- instance_destroy(queue);
+ instance_destroy(net, queue);
break;
case NFQNL_CFG_CMD_PF_BIND:
case NFQNL_CFG_CMD_PF_UNBIND:
@@ -878,65 +876,64 @@ static const struct nfnetlink_subsystem nfqnl_subsys = {
#ifdef CONFIG_PROC_FS
struct iter_state {
+ struct seq_net_private p;
unsigned int bucket;
};
-static struct hlist_node *get_first(struct seq_file *seq)
+static struct hlist_node *get_first(struct net *net, struct iter_state *st)
{
- struct iter_state *st = seq->private;
-
if (!st)
return NULL;
- for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
- if (!hlist_empty(&instance_table[st->bucket]))
- return instance_table[st->bucket].first;
+ for (st->bucket = 0; st->bucket < NFQNL_INSTANCE_BUCKETS; st->bucket++) {
+ if (!hlist_empty(&net->nfqnl.instance_table[st->bucket]))
+ return net->nfqnl.instance_table[st->bucket].first;
}
return NULL;
}
-static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
+static struct hlist_node *get_next(struct net *net, struct iter_state *st,
+ struct hlist_node *h)
{
- struct iter_state *st = seq->private;
-
h = h->next;
while (!h) {
- if (++st->bucket >= INSTANCE_BUCKETS)
+ if (++st->bucket >= NFQNL_INSTANCE_BUCKETS)
return NULL;
- h = instance_table[st->bucket].first;
+ h = net->nfqnl.instance_table[st->bucket].first;
}
return h;
}
-static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
+static struct hlist_node *get_idx(struct net *net, struct iter_state *st,
+ loff_t pos)
{
struct hlist_node *head;
- head = get_first(seq);
+ head = get_first(net, st);
if (head)
- while (pos && (head = get_next(seq, head)))
+ while (pos && (head = get_next(net, st, head)))
pos--;
return pos ? NULL : head;
}
static void *seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(instances_lock)
{
- spin_lock(&instances_lock);
- return get_idx(seq, *pos);
+ struct net *net = seq_file_net(seq);
+ spin_lock(&net->nfqnl.instances_lock);
+ return get_idx(net, seq->private, *pos);
}
static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
{
(*pos)++;
- return get_next(s, v);
+ return get_next(seq_file_net(s), s->private, v);
}
static void seq_stop(struct seq_file *s, void *v)
- __releases(instances_lock)
{
- spin_unlock(&instances_lock);
+ struct net *net = seq_file_net(s);
+ spin_unlock(&net->nfqnl.instances_lock);
}
static int seq_show(struct seq_file *s, void *v)
@@ -960,8 +957,8 @@ static const struct seq_operations nfqnl_seq_ops = {
static int nfqnl_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &nfqnl_seq_ops,
- sizeof(struct iter_state));
+ return seq_open_net(inode, file, &nfqnl_seq_ops,
+ sizeof(struct iter_state));
}
static const struct file_operations nfqnl_file_ops = {
@@ -969,13 +966,19 @@ static const struct file_operations nfqnl_file_ops = {
.open = nfqnl_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
#endif /* PROC_FS */
static int __net_init nfnetlink_queue_net_init(struct net *net)
{
+ int i;
+
+ spin_lock_init(&net->nfqnl.instances_lock);
+ for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++)
+ INIT_HLIST_HEAD(&net->nfqnl.instance_table[i]);
+
#ifdef CONFIG_PROC_FS
if (!proc_create("nfnetlink_queue", 0440,
net->proc_net_netfilter, &nfqnl_file_ops))
@@ -999,7 +1002,7 @@ static struct pernet_operations nfnetlink_queue_net_ops = {
static int __init nfnetlink_queue_init(void)
{
- int i, status;
+ int status;
status = register_pernet_subsys(&nfnetlink_queue_net_ops);
if (status) {
@@ -1008,9 +1011,6 @@ static int __init nfnetlink_queue_init(void)
return status;
}
- for (i = 0; i < INSTANCE_BUCKETS; i++)
- INIT_HLIST_HEAD(&instance_table[i]);
-
netlink_register_notifier(&nfqnl_rtnl_notifier);
status = nfnetlink_subsys_register(&nfqnl_subsys);
if (status < 0) {
--
1.7.5.4

View file

@ -0,0 +1,62 @@
VERSION := 3.2.0
TARBALL := /usr/src/linux-source-$(VERSION).tar.bz2
SUBVERSION := -core
REVISION := 1.0
PATCHDIR := patches
PATCHES := $(sort $(wildcard $(PATCHDIR)/*.patch))
CONFIG := config.core
DEPDEBS := linux-source kernel-package po-debconf gettext
CONCURRENCY_LEVEL := 8
MAINTAINER ?= Tom Goff
EMAIL ?= thomas.goff@boeing.com
MAKEKPKGFLAGS := --initrd --rootcmd fakeroot --us --uc \
--append-to-version $(SUBVERSION) --revision $(REVISION)
.PHONY: build
build: debcheck defaultconfig patch
export CONCURRENCY_LEVEL="$(CONCURRENCY_LEVEL)" \
KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \
cd linux-source-$(VERSION) && \
if [ -f ../$(CONFIG) ]; then \
cat ../$(CONFIG) >> .config; \
fi && \
fakeroot make-kpkg $(MAKEKPKGFLAGS) binary-arch
.PHONY: debcheck
debcheck:
for d in $(DEPDEBS); do \
if ! dpkg-query -s $$d > /dev/null 2>&1; then \
echo ERROR: build dependency not installed: $$d >&2; \
exit 1; \
fi; \
done
.PHONY: defaultconfig
defaultconfig: linux-source-$(VERSION)
export KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \
cd linux-source-$(VERSION) && make-kpkg $(MAKEKPKGFLAGS) configure
.PHONY: patch
patch: linux-source-$(VERSION) patch-stamp
patch-stamp: $(PATCHES)
for p in $^; do \
if ! patch -d linux-source-$(VERSION) -p1 < $$p; then \
echo ERROR: applying patch failed: $$p >&2; \
exit 1; \
fi; \
done
touch patch-stamp
linux-source-$(VERSION): $(TARBALL)
tar -xjf $^
.PHONY: clean
clean:
rm -rf linux-source-$(VERSION) patch-stamp

View file

@ -0,0 +1,8 @@
Author: Tom Goff <thomas.goff@boeing.com>
The Makefile is basically a wrapper around the make-kpkg command that
simplifies building kernel packages. Running make will do some basic
dependency checks then build architecture appropriate kernel packages that
include changes from the patches directory. The nfnetlink patch is what
virtualizes the netfilter queue mechanism;
the ifindex patch virtualizes network interface index numbers.

View file

@ -0,0 +1 @@
CONFIG_XFRM_STATISTICS=y

View file

@ -0,0 +1,60 @@
From 918e253ebaa3d28c54ff64b596a0afc8779d106a Mon Sep 17 00:00:00 2001
From: Tom Goff <thomas.goff@boeing.com>
Date: Fri, 27 Jul 2012 00:02:50 -0700
Subject: [PATCH] Make network device ifindex sequential per network
namespace.
Signed-off-by: Tom Goff <thomas.goff@boeing.com>
---
include/net/net_namespace.h | 2 ++
net/core/dev.c | 13 ++++++-------
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 4b6f04a..266e747 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -65,6 +65,8 @@ struct net {
struct sock *rtnl; /* rtnetlink socket */
struct sock *genl_sock;
+ int ifindex;
+
struct list_head dev_base_head;
struct hlist_head *dev_name_head;
struct hlist_head *dev_index_head;
diff --git a/net/core/dev.c b/net/core/dev.c
index 1cbddc9..d7f5711 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5236,12 +5236,11 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
*/
static int dev_new_index(struct net *net)
{
- static int ifindex;
for (;;) {
- if (++ifindex <= 0)
- ifindex = 1;
- if (!__dev_get_by_index(net, ifindex))
- return ifindex;
+ if (++net->ifindex <= 0)
+ net->ifindex = 1;
+ if (!__dev_get_by_index(net, net->ifindex))
+ return net->ifindex;
}
}
@@ -6253,8 +6252,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
/* Actually switch the network namespace */
dev_net_set(dev, net);
- /* If there is an ifindex conflict assign a new one */
- if (__dev_get_by_index(net, dev->ifindex)) {
+ /* Assign a new ifindex */
+ {
int iflink = (dev->iflink == dev->ifindex);
dev->ifindex = dev_new_index(net);
if (iflink)
--
1.7.9.5

View file

@ -0,0 +1,351 @@
From 67765faf27ec646bcc008bd34d12e48a7466dcdd Mon Sep 17 00:00:00 2001
From: Tom Goff <thomas.goff@boeing.com>
Date: Thu, 26 Jul 2012 23:57:06 -0700
Subject: [PATCH 1/2] netfilter: Make the /proc/net/netfilter directory per
netns.
This allows subsystems to create per-netns entries.
Signed-off-by: Tom Goff <thomas.goff@boeing.com>
---
include/linux/netfilter.h | 5 -----
include/net/net_namespace.h | 3 +++
net/netfilter/core.c | 35 +++++++++++++++++++++++-------
net/netfilter/nf_log.c | 33 ++++++++++++++++++++++++----
net/netfilter/nf_queue.c | 31 +++++++++++++++++++++++----
net/netfilter/nfnetlink_log.c | 44 +++++++++++++++++++++++++++-----------
net/netfilter/nfnetlink_queue.c | 45 +++++++++++++++++++++++++++------------
7 files changed, 148 insertions(+), 48 deletions(-)
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 857f502..b4e02fb 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -340,11 +340,6 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
#endif
}
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-extern struct proc_dir_entry *proc_net_netfilter;
-#endif
-
#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 3bb6fa0..cf126ef 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -84,6 +84,9 @@ struct net {
struct netns_dccp dccp;
#endif
#ifdef CONFIG_NETFILTER
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc_net_netfilter;
+#endif
struct netns_xt xt;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct netns_ct ct;
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index afca6c7..9d9b103 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -255,25 +255,44 @@ void nf_conntrack_destroy(struct nf_conntrack *nfct)
EXPORT_SYMBOL(nf_conntrack_destroy);
#endif /* CONFIG_NF_CONNTRACK */
+static int __net_init netfilter_net_init(struct net *net)
+{
#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_net_netfilter;
-EXPORT_SYMBOL(proc_net_netfilter);
+ net->proc_net_netfilter = proc_net_mkdir(net, "netfilter",
+ net->proc_net);
+ if (!net->proc_net_netfilter) {
+ pr_err("%s: cannot create netfilter proc entry\n", __func__);
+ return -ENOMEM;
+ }
#endif
+ return 0;
+}
+
+static void __net_exit netfilter_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ proc_net_remove(net, "netfilter");
+#endif
+}
+
+static struct pernet_operations netfilter_net_ops = {
+ .init = netfilter_net_init,
+ .exit = netfilter_net_exit,
+};
+
void __init netfilter_init(void)
{
int i, h;
+
+ if (register_pernet_subsys(&netfilter_net_ops))
+ panic("%s: failed to register per netns operations", __func__);
+
for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) {
for (h = 0; h < NF_MAX_HOOKS; h++)
INIT_LIST_HEAD(&nf_hooks[i][h]);
}
-#ifdef CONFIG_PROC_FS
- proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net);
- if (!proc_net_netfilter)
- panic("cannot create netfilter proc entry");
-#endif
-
if (netfilter_queue_init() < 0)
panic("cannot initialize nf_queue");
if (netfilter_log_init() < 0)
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index 957374a..c546ad7 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -297,14 +297,39 @@ static __init int netfilter_log_sysctl_init(void)
}
#endif /* CONFIG_SYSCTL */
-int __init netfilter_log_init(void)
+static int __net_init netfilter_log_net_init(struct net *net)
{
- int i, r;
#ifdef CONFIG_PROC_FS
if (!proc_create("nf_log", S_IRUGO,
- proc_net_netfilter, &nflog_file_ops))
- return -1;
+ net->proc_net_netfilter, &nflog_file_ops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static void __net_exit netfilter_log_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nf_log", net->proc_net_netfilter);
#endif
+}
+
+static struct pernet_operations netfilter_log_net_ops = {
+ .init = netfilter_log_net_init,
+ .exit = netfilter_log_net_exit,
+};
+
+int __init netfilter_log_init(void)
+{
+ int i, r;
+
+ r = register_pernet_subsys(&netfilter_log_net_ops);
+ if (r) {
+ pr_err("%s: failed to register per netns operations\n",
+ __func__);
+ return r;
+ }
/* Errors will trigger panic, unroll on error is unnecessary. */
r = netfilter_log_sysctl_init();
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index b3a7db6..470ec3a 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -383,14 +383,37 @@ static const struct file_operations nfqueue_file_ops = {
};
#endif /* PROC_FS */
-
-int __init netfilter_queue_init(void)
+static int __net_init netfilter_queue_net_init(struct net *net)
{
#ifdef CONFIG_PROC_FS
if (!proc_create("nf_queue", S_IRUGO,
- proc_net_netfilter, &nfqueue_file_ops))
- return -1;
+ net->proc_net_netfilter, &nfqueue_file_ops))
+ return -ENOMEM;
#endif
+
return 0;
}
+static void __net_exit netfilter_queue_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nf_queue", net->proc_net_netfilter);
+#endif
+}
+
+static struct pernet_operations netfilter_queue_net_ops = {
+ .init = netfilter_queue_net_init,
+ .exit = netfilter_queue_net_exit,
+};
+
+int __init netfilter_queue_init(void)
+{
+ int err;
+
+ err = register_pernet_subsys(&netfilter_queue_net_ops);
+ if (err)
+ pr_err("%s: cannot initialize per netns operations\n",
+ __func__);
+
+ return err;
+}
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 66b2c54..e4c3c1e 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -950,9 +950,39 @@ static const struct file_operations nful_file_ops = {
#endif /* PROC_FS */
+static int __net_init nfnetlink_log_net_init(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ if (!proc_create("nfnetlink_log", 0440,
+ net->proc_net_netfilter, &nful_file_ops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static void __net_exit nfnetlink_log_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nfnetlink_log", net->proc_net_netfilter);
+#endif
+}
+
+static struct pernet_operations nfnetlink_log_net_ops = {
+ .init = nfnetlink_log_net_init,
+ .exit = nfnetlink_log_net_exit,
+};
+
static int __init nfnetlink_log_init(void)
{
- int i, status = -ENOMEM;
+ int i, status;
+
+ status = register_pernet_subsys(&nfnetlink_log_net_ops);
+ if (status) {
+ pr_err("%s: failed to register per netns operations\n",
+ __func__);
+ return status;
+ }
for (i = 0; i < INSTANCE_BUCKETS; i++)
INIT_HLIST_HEAD(&instance_table[i]);
@@ -975,17 +1005,8 @@ static int __init nfnetlink_log_init(void)
goto cleanup_subsys;
}
-#ifdef CONFIG_PROC_FS
- if (!proc_create("nfnetlink_log", 0440,
- proc_net_netfilter, &nful_file_ops))
- goto cleanup_logger;
-#endif
return status;
-#ifdef CONFIG_PROC_FS
-cleanup_logger:
- nf_log_unregister(&nfulnl_logger);
-#endif
cleanup_subsys:
nfnetlink_subsys_unregister(&nfulnl_subsys);
cleanup_netlink_notifier:
@@ -996,9 +1017,6 @@ cleanup_netlink_notifier:
static void __exit nfnetlink_log_fini(void)
{
nf_log_unregister(&nfulnl_logger);
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("nfnetlink_log", proc_net_netfilter);
-#endif
nfnetlink_subsys_unregister(&nfulnl_subsys);
netlink_unregister_notifier(&nfulnl_rtnl_notifier);
}
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index a80b0cb..b615da5 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -974,9 +974,39 @@ static const struct file_operations nfqnl_file_ops = {
#endif /* PROC_FS */
+static int __net_init nfnetlink_queue_net_init(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ if (!proc_create("nfnetlink_queue", 0440,
+ net->proc_net_netfilter, &nfqnl_file_ops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static void __net_exit nfnetlink_queue_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nfnetlink_queue", net->proc_net_netfilter);
+#endif
+}
+
+static struct pernet_operations nfnetlink_queue_net_ops = {
+ .init = nfnetlink_queue_net_init,
+ .exit = nfnetlink_queue_net_exit,
+};
+
static int __init nfnetlink_queue_init(void)
{
- int i, status = -ENOMEM;
+ int i, status;
+
+ status = register_pernet_subsys(&nfnetlink_queue_net_ops);
+ if (status) {
+ pr_err("%s: failed to register per netns operations\n",
+ __func__);
+ return status;
+ }
for (i = 0; i < INSTANCE_BUCKETS; i++)
INIT_HLIST_HEAD(&instance_table[i]);
@@ -988,19 +1018,9 @@ static int __init nfnetlink_queue_init(void)
goto cleanup_netlink_notifier;
}
-#ifdef CONFIG_PROC_FS
- if (!proc_create("nfnetlink_queue", 0440,
- proc_net_netfilter, &nfqnl_file_ops))
- goto cleanup_subsys;
-#endif
-
register_netdevice_notifier(&nfqnl_dev_notifier);
return status;
-#ifdef CONFIG_PROC_FS
-cleanup_subsys:
- nfnetlink_subsys_unregister(&nfqnl_subsys);
-#endif
cleanup_netlink_notifier:
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
return status;
@@ -1010,9 +1030,6 @@ static void __exit nfnetlink_queue_fini(void)
{
nf_unregister_queue_handlers(&nfqh);
unregister_netdevice_notifier(&nfqnl_dev_notifier);
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("nfnetlink_queue", proc_net_netfilter);
-#endif
nfnetlink_subsys_unregister(&nfqnl_subsys);
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
--
1.7.9.5

View file

@ -0,0 +1,544 @@
From f8179877a37f37631d831de6381f22fd643b4ea0 Mon Sep 17 00:00:00 2001
From: Tom Goff <thomas.goff@boeing.com>
Date: Thu, 26 Jul 2012 23:58:38 -0700
Subject: [PATCH 2/2] netfilter: nfnetlink_queue: Add netns support.
Make nfnetlink_queue network namespace aware including a per-netns
/proc/net/netfilter/nfnetlink_queue file.
Signed-off-by: Tom Goff <thomas.goff@boeing.com>
---
include/net/net_namespace.h | 6 ++
include/net/netfilter/nf_queue.h | 3 +-
include/net/netns/nfqnl.h | 14 ++++
net/ipv4/netfilter/ip_queue.c | 6 +-
net/ipv6/netfilter/ip6_queue.c | 6 +-
net/netfilter/nf_queue.c | 12 +++-
net/netfilter/nfnetlink_queue.c | 136 +++++++++++++++++++-------------------
7 files changed, 111 insertions(+), 72 deletions(-)
create mode 100644 include/net/netns/nfqnl.h
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index cf126ef..4b6f04a 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -21,6 +21,9 @@
#include <net/netns/conntrack.h>
#endif
#include <net/netns/xfrm.h>
+#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
+#include <net/netns/nfqnl.h>
+#endif
struct proc_dir_entry;
struct net_device;
@@ -93,6 +96,9 @@ struct net {
#endif
struct sock *nfnl;
struct sock *nfnl_stash;
+#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
+ struct netns_nfqnl nfqnl;
+#endif
#endif
#ifdef CONFIG_WEXT_CORE
struct sk_buff_head wext_nlevents;
diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h
index 252fd10..3e5bde8 100644
--- a/include/net/netfilter/nf_queue.h
+++ b/include/net/netfilter/nf_queue.h
@@ -19,7 +19,8 @@ struct nf_queue_entry {
/* Packet queuing */
struct nf_queue_handler {
- int (*outfn)(struct nf_queue_entry *entry,
+ int (*outfn)(struct net *net,
+ struct nf_queue_entry *entry,
unsigned int queuenum);
char *name;
};
diff --git a/include/net/netns/nfqnl.h b/include/net/netns/nfqnl.h
new file mode 100644
index 0000000..0fe7fbe
--- /dev/null
+++ b/include/net/netns/nfqnl.h
@@ -0,0 +1,14 @@
+#ifndef __NETNS_NFQNL_H
+#define __NETNS_NFQNL_H
+
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+#define NFQNL_INSTANCE_BUCKETS 16
+
+struct netns_nfqnl {
+ spinlock_t instances_lock;
+ struct hlist_head instance_table[NFQNL_INSTANCE_BUCKETS];
+};
+
+#endif /* __NETNS_NFQNL_H */
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index e59aabd..f3c43e5 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -225,7 +225,8 @@ nlmsg_failure:
}
static int
-ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
+ipq_enqueue_packet(struct net *net, struct nf_queue_entry *entry,
+ unsigned int queuenum)
{
int status = -EINVAL;
struct sk_buff *nskb;
@@ -239,6 +240,9 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
spin_lock_bh(&queue_lock);
+ if (!net_eq(net, &init_net))
+ goto err_out_free_nskb;
+
if (!peer_pid)
goto err_out_free_nskb;
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index e63c397..322c511 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -225,7 +225,8 @@ nlmsg_failure:
}
static int
-ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
+ipq_enqueue_packet(struct net *net, struct nf_queue_entry *entry,
+ unsigned int queuenum)
{
int status = -EINVAL;
struct sk_buff *nskb;
@@ -239,6 +240,9 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
spin_lock_bh(&queue_lock);
+ if (!net_eq(net, &init_net))
+ goto err_out_free_nskb;
+
if (!peer_pid)
goto err_out_free_nskb;
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index 470ec3a..6894ecc 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -133,6 +133,16 @@ static int __nf_queue(struct sk_buff *skb,
#endif
const struct nf_afinfo *afinfo;
const struct nf_queue_handler *qh;
+ struct net *net;
+
+ if (indev)
+ net = dev_net(indev);
+ else if (skb->sk)
+ net = sock_net(skb->sk);
+ else if (outdev)
+ net = dev_net(outdev);
+ else
+ return status;
/* QUEUE == DROP if no one is waiting, to be safe. */
rcu_read_lock();
@@ -185,7 +195,7 @@ static int __nf_queue(struct sk_buff *skb,
#endif
skb_dst_force(skb);
afinfo->saveroute(skb, entry);
- status = qh->outfn(entry, queuenum);
+ status = qh->outfn(net, entry, queuenum);
rcu_read_unlock();
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index b615da5..11725a0 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -64,24 +64,19 @@ struct nfqnl_instance {
typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long);
-static DEFINE_SPINLOCK(instances_lock);
-
-#define INSTANCE_BUCKETS 16
-static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly;
-
static inline u_int8_t instance_hashfn(u_int16_t queue_num)
{
- return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS;
+ return ((queue_num >> 8) | queue_num) % NFQNL_INSTANCE_BUCKETS;
}
static struct nfqnl_instance *
-instance_lookup(u_int16_t queue_num)
+instance_lookup(struct net *net, u_int16_t queue_num)
{
struct hlist_head *head;
struct hlist_node *pos;
struct nfqnl_instance *inst;
- head = &instance_table[instance_hashfn(queue_num)];
+ head = &net->nfqnl.instance_table[instance_hashfn(queue_num)];
hlist_for_each_entry_rcu(inst, pos, head, hlist) {
if (inst->queue_num == queue_num)
return inst;
@@ -90,14 +85,14 @@ instance_lookup(u_int16_t queue_num)
}
static struct nfqnl_instance *
-instance_create(u_int16_t queue_num, int pid)
+instance_create(struct net *net, u_int16_t queue_num, int pid)
{
struct nfqnl_instance *inst;
unsigned int h;
int err;
- spin_lock(&instances_lock);
- if (instance_lookup(queue_num)) {
+ spin_lock(&net->nfqnl.instances_lock);
+ if (instance_lookup(net, queue_num)) {
err = -EEXIST;
goto out_unlock;
}
@@ -122,16 +117,16 @@ instance_create(u_int16_t queue_num, int pid)
}
h = instance_hashfn(queue_num);
- hlist_add_head_rcu(&inst->hlist, &instance_table[h]);
+ hlist_add_head_rcu(&inst->hlist, &net->nfqnl.instance_table[h]);
- spin_unlock(&instances_lock);
+ spin_unlock(&net->nfqnl.instances_lock);
return inst;
out_free:
kfree(inst);
out_unlock:
- spin_unlock(&instances_lock);
+ spin_unlock(&net->nfqnl.instances_lock);
return ERR_PTR(err);
}
@@ -157,11 +152,11 @@ __instance_destroy(struct nfqnl_instance *inst)
}
static void
-instance_destroy(struct nfqnl_instance *inst)
+instance_destroy(struct net *net, struct nfqnl_instance *inst)
{
- spin_lock(&instances_lock);
+ spin_lock(&net->nfqnl.instances_lock);
__instance_destroy(inst);
- spin_unlock(&instances_lock);
+ spin_unlock(&net->nfqnl.instances_lock);
}
static inline void
@@ -390,7 +385,8 @@ nla_put_failure:
}
static int
-nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
+nfqnl_enqueue_packet(struct net *net, struct nf_queue_entry *entry,
+ unsigned int queuenum)
{
struct sk_buff *nskb;
struct nfqnl_instance *queue;
@@ -398,7 +394,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
__be32 *packet_id_ptr;
/* rcu_read_lock()ed by nf_hook_slow() */
- queue = instance_lookup(queuenum);
+ queue = instance_lookup(net, queuenum);
if (!queue) {
err = -ESRCH;
goto err_out;
@@ -432,7 +428,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
*packet_id_ptr = htonl(entry->id);
/* nfnetlink_unicast will either free the nskb or add it to a socket */
- err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT);
+ err = nfnetlink_unicast(nskb, net, queue->peer_pid, MSG_DONTWAIT);
if (err < 0) {
queue->queue_user_dropped++;
goto err_out_unlock;
@@ -541,16 +537,16 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
/* drop all packets with either indev or outdev == ifindex from all queue
* instances */
static void
-nfqnl_dev_drop(int ifindex)
+nfqnl_dev_drop(struct net *net, int ifindex)
{
int i;
rcu_read_lock();
- for (i = 0; i < INSTANCE_BUCKETS; i++) {
+ for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) {
struct hlist_node *tmp;
struct nfqnl_instance *inst;
- struct hlist_head *head = &instance_table[i];
+ struct hlist_head *head = &net->nfqnl.instance_table[i];
hlist_for_each_entry_rcu(inst, tmp, head, hlist)
nfqnl_flush(inst, dev_cmp, ifindex);
@@ -567,12 +563,9 @@ nfqnl_rcv_dev_event(struct notifier_block *this,
{
struct net_device *dev = ptr;
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
/* Drop any packets associated with the downed device */
if (event == NETDEV_DOWN)
- nfqnl_dev_drop(dev->ifindex);
+ nfqnl_dev_drop(dev_net(dev), dev->ifindex);
return NOTIFY_DONE;
}
@@ -590,19 +583,19 @@ nfqnl_rcv_nl_event(struct notifier_block *this,
int i;
/* destroy all instances for this pid */
- spin_lock(&instances_lock);
- for (i = 0; i < INSTANCE_BUCKETS; i++) {
+ spin_lock(&n->net->nfqnl.instances_lock);
+ for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) {
struct hlist_node *tmp, *t2;
struct nfqnl_instance *inst;
- struct hlist_head *head = &instance_table[i];
+ struct hlist_head *head =
+ &n->net->nfqnl.instance_table[i];
hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) {
- if ((n->net == &init_net) &&
- (n->pid == inst->peer_pid))
+ if (n->pid == inst->peer_pid)
__instance_destroy(inst);
}
}
- spin_unlock(&instances_lock);
+ spin_unlock(&n->net->nfqnl.instances_lock);
}
return NOTIFY_DONE;
}
@@ -622,11 +615,12 @@ static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = {
[NFQA_MARK] = { .type = NLA_U32 },
};
-static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlpid)
+static struct nfqnl_instance *verdict_instance_lookup(struct net *net,
+ u16 queue_num, int nlpid)
{
struct nfqnl_instance *queue;
- queue = instance_lookup(queue_num);
+ queue = instance_lookup(net, queue_num);
if (!queue)
return ERR_PTR(-ENODEV);
@@ -670,7 +664,8 @@ nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
LIST_HEAD(batch_list);
u16 queue_num = ntohs(nfmsg->res_id);
- queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid);
+ queue = verdict_instance_lookup(sock_net(ctnl), queue_num,
+ NETLINK_CB(skb).pid);
if (IS_ERR(queue))
return PTR_ERR(queue);
@@ -715,11 +710,12 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
struct nfqnl_instance *queue;
unsigned int verdict;
struct nf_queue_entry *entry;
+ struct net *net = sock_net(ctnl);
- queue = instance_lookup(queue_num);
+ queue = instance_lookup(net, queue_num);
if (!queue)
- queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid);
+ queue = verdict_instance_lookup(net, queue_num, NETLINK_CB(skb).pid);
if (IS_ERR(queue))
return PTR_ERR(queue);
@@ -774,6 +770,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
struct nfqnl_instance *queue;
struct nfqnl_msg_config_cmd *cmd = NULL;
int ret = 0;
+ struct net *net = sock_net(ctnl);
if (nfqa[NFQA_CFG_CMD]) {
cmd = nla_data(nfqa[NFQA_CFG_CMD]);
@@ -790,7 +787,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
}
rcu_read_lock();
- queue = instance_lookup(queue_num);
+ queue = instance_lookup(net, queue_num);
if (queue && queue->peer_pid != NETLINK_CB(skb).pid) {
ret = -EPERM;
goto err_out_unlock;
@@ -803,7 +800,8 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
ret = -EBUSY;
goto err_out_unlock;
}
- queue = instance_create(queue_num, NETLINK_CB(skb).pid);
+ queue = instance_create(net, queue_num,
+ NETLINK_CB(skb).pid);
if (IS_ERR(queue)) {
ret = PTR_ERR(queue);
goto err_out_unlock;
@@ -814,7 +812,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
ret = -ENODEV;
goto err_out_unlock;
}
- instance_destroy(queue);
+ instance_destroy(net, queue);
break;
case NFQNL_CFG_CMD_PF_BIND:
case NFQNL_CFG_CMD_PF_UNBIND:
@@ -878,65 +876,64 @@ static const struct nfnetlink_subsystem nfqnl_subsys = {
#ifdef CONFIG_PROC_FS
struct iter_state {
+ struct seq_net_private p;
unsigned int bucket;
};
-static struct hlist_node *get_first(struct seq_file *seq)
+static struct hlist_node *get_first(struct net *net, struct iter_state *st)
{
- struct iter_state *st = seq->private;
-
if (!st)
return NULL;
- for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
- if (!hlist_empty(&instance_table[st->bucket]))
- return instance_table[st->bucket].first;
+ for (st->bucket = 0; st->bucket < NFQNL_INSTANCE_BUCKETS; st->bucket++) {
+ if (!hlist_empty(&net->nfqnl.instance_table[st->bucket]))
+ return net->nfqnl.instance_table[st->bucket].first;
}
return NULL;
}
-static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
+static struct hlist_node *get_next(struct net *net, struct iter_state *st,
+ struct hlist_node *h)
{
- struct iter_state *st = seq->private;
-
h = h->next;
while (!h) {
- if (++st->bucket >= INSTANCE_BUCKETS)
+ if (++st->bucket >= NFQNL_INSTANCE_BUCKETS)
return NULL;
- h = instance_table[st->bucket].first;
+ h = net->nfqnl.instance_table[st->bucket].first;
}
return h;
}
-static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
+static struct hlist_node *get_idx(struct net *net, struct iter_state *st,
+ loff_t pos)
{
struct hlist_node *head;
- head = get_first(seq);
+ head = get_first(net, st);
if (head)
- while (pos && (head = get_next(seq, head)))
+ while (pos && (head = get_next(net, st, head)))
pos--;
return pos ? NULL : head;
}
static void *seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(instances_lock)
{
- spin_lock(&instances_lock);
- return get_idx(seq, *pos);
+ struct net *net = seq_file_net(seq);
+ spin_lock(&net->nfqnl.instances_lock);
+ return get_idx(net, seq->private, *pos);
}
static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
{
(*pos)++;
- return get_next(s, v);
+ return get_next(seq_file_net(s), s->private, v);
}
static void seq_stop(struct seq_file *s, void *v)
- __releases(instances_lock)
{
- spin_unlock(&instances_lock);
+ struct net *net = seq_file_net(s);
+ spin_unlock(&net->nfqnl.instances_lock);
}
static int seq_show(struct seq_file *s, void *v)
@@ -960,8 +957,8 @@ static const struct seq_operations nfqnl_seq_ops = {
static int nfqnl_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &nfqnl_seq_ops,
- sizeof(struct iter_state));
+ return seq_open_net(inode, file, &nfqnl_seq_ops,
+ sizeof(struct iter_state));
}
static const struct file_operations nfqnl_file_ops = {
@@ -969,13 +966,19 @@ static const struct file_operations nfqnl_file_ops = {
.open = nfqnl_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
#endif /* PROC_FS */
static int __net_init nfnetlink_queue_net_init(struct net *net)
{
+ int i;
+
+ spin_lock_init(&net->nfqnl.instances_lock);
+ for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++)
+ INIT_HLIST_HEAD(&net->nfqnl.instance_table[i]);
+
#ifdef CONFIG_PROC_FS
if (!proc_create("nfnetlink_queue", 0440,
net->proc_net_netfilter, &nfqnl_file_ops))
@@ -999,7 +1002,7 @@ static struct pernet_operations nfnetlink_queue_net_ops = {
static int __init nfnetlink_queue_init(void)
{
- int i, status;
+ int status;
status = register_pernet_subsys(&nfnetlink_queue_net_ops);
if (status) {
@@ -1008,9 +1011,6 @@ static int __init nfnetlink_queue_init(void)
return status;
}
- for (i = 0; i < INSTANCE_BUCKETS; i++)
- INIT_HLIST_HEAD(&instance_table[i]);
-
netlink_register_notifier(&nfqnl_rtnl_notifier);
status = nfnetlink_subsys_register(&nfqnl_subsys);
if (status < 0) {
--
1.7.9.5

View file

@ -0,0 +1,70 @@
VERSION := $(shell dpkg -l linux-source 2> /dev/null | \
awk '/^i/ {print gensub("([0-9]+[.][0-9]+[.][0-9]+)[.0-9]*", "\\1", "1", $$3)}')
TARBALL := /usr/src/linux-source-$(VERSION).tar.bz2
SUBVERSION := -core
REVISION := 1.0
PATCHDIR := patches
PATCHES := $(sort $(wildcard $(PATCHDIR)/*.patch))
CONFIG := config.core
DEPDEBS := linux-source kernel-package po-debconf gettext
CONCURRENCY_LEVEL := $(shell lscpu 2> /dev/null | \
awk '/^CPU\(s\)/ {print $$2}')
ifeq ($(strip $(CONCURRENCY_LEVEL)),)
CONCURRENCY_LEVEL := 1
endif
MAINTAINER ?= $(shell id -nu)
EMAIL ?= $(MAINTAINER)@$(shell hostname -f)
MAKEKPKGFLAGS := --initrd --rootcmd fakeroot --us --uc \
--append-to-version $(SUBVERSION) --revision $(REVISION)
.PHONY: build
build: debcheck defaultconfig patch
export CONCURRENCY_LEVEL="$(CONCURRENCY_LEVEL)" \
KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \
cd linux-source-$(VERSION) && \
if [ -f ../$(CONFIG) ]; then \
cat ../$(CONFIG) >> .config; \
fi && \
fakeroot make-kpkg $(MAKEKPKGFLAGS) binary-arch
.PHONY: debcheck
debcheck:
for d in $(DEPDEBS); do \
if ! dpkg-query -s $$d > /dev/null 2>&1; then \
echo ERROR: build dependency not installed: $$d >&2; \
exit 1; \
fi; \
done
.PHONY: defaultconfig
defaultconfig: linux-source-$(VERSION)
export KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \
cd linux-source-$(VERSION) && make-kpkg $(MAKEKPKGFLAGS) configure
.PHONY: patch
patch: linux-source-$(VERSION) patch-stamp
patch-stamp: $(PATCHES)
for p in $^; do \
if ! patch -d linux-source-$(VERSION) -p1 < $$p; then \
echo ERROR: applying patch failed: $$p >&2; \
exit 1; \
fi; \
done
touch patch-stamp
.PHONY: source
source: linux-source-$(VERSION)
linux-source-$(VERSION): $(TARBALL)
tar -xjf $^
.PHONY: clean
clean:
rm -rf linux-source-$(VERSION) patch-stamp

View file

@ -0,0 +1 @@
CONFIG_XFRM_STATISTICS=y

View file

@ -0,0 +1,60 @@
From e98f08306dd0dc854d93339730a8603638173e23 Mon Sep 17 00:00:00 2001
From: Tom Goff <thomas.goff@boeing.com>
Date: Fri, 27 Jul 2012 00:02:50 -0700
Subject: [PATCH] Make network device ifindex sequential per network
namespace.
Signed-off-by: Tom Goff <thomas.goff@boeing.com>
---
include/net/net_namespace.h | 2 ++
net/core/dev.c | 13 ++++++-------
2 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index ac9195e..1b9c99a 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -62,6 +62,8 @@ struct net {
struct sock *rtnl; /* rtnetlink socket */
struct sock *genl_sock;
+ int ifindex;
+
struct list_head dev_base_head;
struct hlist_head *dev_name_head;
struct hlist_head *dev_index_head;
diff --git a/net/core/dev.c b/net/core/dev.c
index 3ad746b..7bec156 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5168,12 +5168,11 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
*/
static int dev_new_index(struct net *net)
{
- static int ifindex;
for (;;) {
- if (++ifindex <= 0)
- ifindex = 1;
- if (!__dev_get_by_index(net, ifindex))
- return ifindex;
+ if (++net->ifindex <= 0)
+ net->ifindex = 1;
+ if (!__dev_get_by_index(net, net->ifindex))
+ return net->ifindex;
}
}
@@ -6182,8 +6181,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
/* Actually switch the network namespace */
dev_net_set(dev, net);
- /* If there is an ifindex conflict assign a new one */
- if (__dev_get_by_index(net, dev->ifindex)) {
+ /* Assign a new ifindex */
+ {
int iflink = (dev->iflink == dev->ifindex);
dev->ifindex = dev_new_index(net);
if (iflink)
--
1.7.10.4

View file

@ -0,0 +1,351 @@
From 5af499895ded68e1d42510df30be2004b4b778bf Mon Sep 17 00:00:00 2001
From: Tom Goff <thomas.goff@boeing.com>
Date: Thu, 26 Jul 2012 23:57:06 -0700
Subject: [PATCH 1/2] netfilter: Make the /proc/net/netfilter directory per
netns.
This allows subsystems to create per-netns entries.
Signed-off-by: Tom Goff <thomas.goff@boeing.com>
---
include/linux/netfilter.h | 5 -----
include/net/net_namespace.h | 3 +++
net/netfilter/core.c | 35 +++++++++++++++++++++++-------
net/netfilter/nf_log.c | 33 ++++++++++++++++++++++++----
net/netfilter/nf_queue.c | 31 +++++++++++++++++++++++----
net/netfilter/nfnetlink_log.c | 44 +++++++++++++++++++++++++++-----------
net/netfilter/nfnetlink_queue.c | 45 +++++++++++++++++++++++++++------------
7 files changed, 148 insertions(+), 48 deletions(-)
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index ff9c84c..e28a566 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -350,11 +350,6 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
#endif
}
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-extern struct proc_dir_entry *proc_net_netfilter;
-#endif
-
#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 1b9c99a..449fc8e 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -86,6 +86,9 @@ struct net {
struct netns_dccp dccp;
#endif
#ifdef CONFIG_NETFILTER
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc_net_netfilter;
+#endif
struct netns_xt xt;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct netns_ct ct;
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index e19f365..c7c9f39 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -266,25 +266,44 @@ void nf_conntrack_destroy(struct nf_conntrack *nfct)
EXPORT_SYMBOL(nf_conntrack_destroy);
#endif /* CONFIG_NF_CONNTRACK */
+static int __net_init netfilter_net_init(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ net->proc_net_netfilter = proc_net_mkdir(net, "netfilter",
+ net->proc_net);
+ if (!net->proc_net_netfilter) {
+ pr_err("%s: cannot create netfilter proc entry\n", __func__);
+ return -ENOMEM;
+ }
+#endif
+
+ return 0;
+}
+
+static void __net_exit netfilter_net_exit(struct net *net)
+{
#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_net_netfilter;
-EXPORT_SYMBOL(proc_net_netfilter);
+ proc_net_remove(net, "netfilter");
#endif
+}
+
+static struct pernet_operations netfilter_net_ops = {
+ .init = netfilter_net_init,
+ .exit = netfilter_net_exit,
+};
void __init netfilter_init(void)
{
int i, h;
+
+ if (register_pernet_subsys(&netfilter_net_ops))
+ panic("%s: failed to register per netns operations", __func__);
+
for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) {
for (h = 0; h < NF_MAX_HOOKS; h++)
INIT_LIST_HEAD(&nf_hooks[i][h]);
}
-#ifdef CONFIG_PROC_FS
- proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net);
- if (!proc_net_netfilter)
- panic("cannot create netfilter proc entry");
-#endif
-
if (netfilter_queue_init() < 0)
panic("cannot initialize nf_queue");
if (netfilter_log_init() < 0)
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index 703fb26..4507932 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -290,14 +290,39 @@ static __init int netfilter_log_sysctl_init(void)
}
#endif /* CONFIG_SYSCTL */
-int __init netfilter_log_init(void)
+static int __net_init netfilter_log_net_init(struct net *net)
{
- int i, r;
#ifdef CONFIG_PROC_FS
if (!proc_create("nf_log", S_IRUGO,
- proc_net_netfilter, &nflog_file_ops))
- return -1;
+ net->proc_net_netfilter, &nflog_file_ops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static void __net_exit netfilter_log_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nf_log", net->proc_net_netfilter);
#endif
+}
+
+static struct pernet_operations netfilter_log_net_ops = {
+ .init = netfilter_log_net_init,
+ .exit = netfilter_log_net_exit,
+};
+
+int __init netfilter_log_init(void)
+{
+ int i, r;
+
+ r = register_pernet_subsys(&netfilter_log_net_ops);
+ if (r) {
+ pr_err("%s: failed to register per netns operations\n",
+ __func__);
+ return r;
+ }
/* Errors will trigger panic, unroll on error is unnecessary. */
r = netfilter_log_sysctl_init();
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index ce60cf0..288c6f5 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -407,14 +407,37 @@ static const struct file_operations nfqueue_file_ops = {
};
#endif /* PROC_FS */
-
-int __init netfilter_queue_init(void)
+static int __net_init netfilter_queue_net_init(struct net *net)
{
#ifdef CONFIG_PROC_FS
if (!proc_create("nf_queue", S_IRUGO,
- proc_net_netfilter, &nfqueue_file_ops))
- return -1;
+ net->proc_net_netfilter, &nfqueue_file_ops))
+ return -ENOMEM;
#endif
+
return 0;
}
+static void __net_exit netfilter_queue_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nf_queue", net->proc_net_netfilter);
+#endif
+}
+
+static struct pernet_operations netfilter_queue_net_ops = {
+ .init = netfilter_queue_net_init,
+ .exit = netfilter_queue_net_exit,
+};
+
+int __init netfilter_queue_init(void)
+{
+ int err;
+
+ err = register_pernet_subsys(&netfilter_queue_net_ops);
+ if (err)
+ pr_err("%s: cannot initialize per netns operations\n",
+ __func__);
+
+ return err;
+}
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index bbc1d91..e5c1731 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -966,9 +966,39 @@ static const struct file_operations nful_file_ops = {
#endif /* PROC_FS */
+static int __net_init nfnetlink_log_net_init(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ if (!proc_create("nfnetlink_log", 0440,
+ net->proc_net_netfilter, &nful_file_ops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static void __net_exit nfnetlink_log_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nfnetlink_log", net->proc_net_netfilter);
+#endif
+}
+
+static struct pernet_operations nfnetlink_log_net_ops = {
+ .init = nfnetlink_log_net_init,
+ .exit = nfnetlink_log_net_exit,
+};
+
static int __init nfnetlink_log_init(void)
{
- int i, status = -ENOMEM;
+ int i, status;
+
+ status = register_pernet_subsys(&nfnetlink_log_net_ops);
+ if (status) {
+ pr_err("%s: failed to register per netns operations\n",
+ __func__);
+ return status;
+ }
for (i = 0; i < INSTANCE_BUCKETS; i++)
INIT_HLIST_HEAD(&instance_table[i]);
@@ -991,17 +1021,8 @@ static int __init nfnetlink_log_init(void)
goto cleanup_subsys;
}
-#ifdef CONFIG_PROC_FS
- if (!proc_create("nfnetlink_log", 0440,
- proc_net_netfilter, &nful_file_ops))
- goto cleanup_logger;
-#endif
return status;
-#ifdef CONFIG_PROC_FS
-cleanup_logger:
- nf_log_unregister(&nfulnl_logger);
-#endif
cleanup_subsys:
nfnetlink_subsys_unregister(&nfulnl_subsys);
cleanup_netlink_notifier:
@@ -1012,9 +1033,6 @@ cleanup_netlink_notifier:
static void __exit nfnetlink_log_fini(void)
{
nf_log_unregister(&nfulnl_logger);
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("nfnetlink_log", proc_net_netfilter);
-#endif
nfnetlink_subsys_unregister(&nfulnl_subsys);
netlink_unregister_notifier(&nfulnl_rtnl_notifier);
}
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 4162437..add33dc 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -982,9 +982,39 @@ static const struct file_operations nfqnl_file_ops = {
#endif /* PROC_FS */
+static int __net_init nfnetlink_queue_net_init(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ if (!proc_create("nfnetlink_queue", 0440,
+ net->proc_net_netfilter, &nfqnl_file_ops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static void __net_exit nfnetlink_queue_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nfnetlink_queue", net->proc_net_netfilter);
+#endif
+}
+
+static struct pernet_operations nfnetlink_queue_net_ops = {
+ .init = nfnetlink_queue_net_init,
+ .exit = nfnetlink_queue_net_exit,
+};
+
static int __init nfnetlink_queue_init(void)
{
- int i, status = -ENOMEM;
+ int i, status;
+
+ status = register_pernet_subsys(&nfnetlink_queue_net_ops);
+ if (status) {
+ pr_err("%s: failed to register per netns operations\n",
+ __func__);
+ return status;
+ }
for (i = 0; i < INSTANCE_BUCKETS; i++)
INIT_HLIST_HEAD(&instance_table[i]);
@@ -996,19 +1026,9 @@ static int __init nfnetlink_queue_init(void)
goto cleanup_netlink_notifier;
}
-#ifdef CONFIG_PROC_FS
- if (!proc_create("nfnetlink_queue", 0440,
- proc_net_netfilter, &nfqnl_file_ops))
- goto cleanup_subsys;
-#endif
-
register_netdevice_notifier(&nfqnl_dev_notifier);
return status;
-#ifdef CONFIG_PROC_FS
-cleanup_subsys:
- nfnetlink_subsys_unregister(&nfqnl_subsys);
-#endif
cleanup_netlink_notifier:
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
return status;
@@ -1018,9 +1038,6 @@ static void __exit nfnetlink_queue_fini(void)
{
nf_unregister_queue_handlers(&nfqh);
unregister_netdevice_notifier(&nfqnl_dev_notifier);
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("nfnetlink_queue", proc_net_netfilter);
-#endif
nfnetlink_subsys_unregister(&nfqnl_subsys);
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
--
1.7.10.4

View file

@ -0,0 +1,494 @@
From 1ede1963c84e15359d4b5bf7fb01587d90bcf1d4 Mon Sep 17 00:00:00 2001
From: Tom Goff <thomas.goff@boeing.com>
Date: Thu, 26 Jul 2012 23:58:38 -0700
Subject: [PATCH 2/2] netfilter: nfnetlink_queue: Add netns support.
Make nfnetlink_queue network namespace aware including a per-netns
/proc/net/netfilter/nfnetlink_queue file.
Signed-off-by: Tom Goff <thomas.goff@boeing.com>
---
include/net/net_namespace.h | 6 ++
include/net/netfilter/nf_queue.h | 3 +-
include/net/netns/nfqnl.h | 14 ++++
net/netfilter/nf_queue.c | 12 +++-
net/netfilter/nfnetlink_queue.c | 136 +++++++++++++++++++-------------------
5 files changed, 101 insertions(+), 70 deletions(-)
create mode 100644 include/net/netns/nfqnl.h
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 449fc8e..c4229f1 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -21,6 +21,9 @@
#include <net/netns/conntrack.h>
#endif
#include <net/netns/xfrm.h>
+#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
+#include <net/netns/nfqnl.h>
+#endif
struct proc_dir_entry;
struct net_device;
@@ -95,6 +98,9 @@ struct net {
#endif
struct sock *nfnl;
struct sock *nfnl_stash;
+#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
+ struct netns_nfqnl nfqnl;
+#endif
#endif
#ifdef CONFIG_WEXT_CORE
struct sk_buff_head wext_nlevents;
diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h
index 252fd10..3e5bde8 100644
--- a/include/net/netfilter/nf_queue.h
+++ b/include/net/netfilter/nf_queue.h
@@ -19,7 +19,8 @@ struct nf_queue_entry {
/* Packet queuing */
struct nf_queue_handler {
- int (*outfn)(struct nf_queue_entry *entry,
+ int (*outfn)(struct net *net,
+ struct nf_queue_entry *entry,
unsigned int queuenum);
char *name;
};
diff --git a/include/net/netns/nfqnl.h b/include/net/netns/nfqnl.h
new file mode 100644
index 0000000..0fe7fbe
--- /dev/null
+++ b/include/net/netns/nfqnl.h
@@ -0,0 +1,14 @@
+#ifndef __NETNS_NFQNL_H
+#define __NETNS_NFQNL_H
+
+#include <linux/spinlock.h>
+#include <linux/list.h>
+
+#define NFQNL_INSTANCE_BUCKETS 16
+
+struct netns_nfqnl {
+ spinlock_t instances_lock;
+ struct hlist_head instance_table[NFQNL_INSTANCE_BUCKETS];
+};
+
+#endif /* __NETNS_NFQNL_H */
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index 288c6f5..3cb8733 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -133,6 +133,16 @@ static int __nf_queue(struct sk_buff *skb,
#endif
const struct nf_afinfo *afinfo;
const struct nf_queue_handler *qh;
+ struct net *net;
+
+ if (indev)
+ net = dev_net(indev);
+ else if (skb->sk)
+ net = sock_net(skb->sk);
+ else if (outdev)
+ net = dev_net(outdev);
+ else
+ return status;
/* QUEUE == DROP if no one is waiting, to be safe. */
rcu_read_lock();
@@ -185,7 +195,7 @@ static int __nf_queue(struct sk_buff *skb,
#endif
skb_dst_force(skb);
afinfo->saveroute(skb, entry);
- status = qh->outfn(entry, queuenum);
+ status = qh->outfn(net, entry, queuenum);
rcu_read_unlock();
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index add33dc..43c50bb 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -64,24 +64,19 @@ struct nfqnl_instance {
typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long);
-static DEFINE_SPINLOCK(instances_lock);
-
-#define INSTANCE_BUCKETS 16
-static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly;
-
static inline u_int8_t instance_hashfn(u_int16_t queue_num)
{
- return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS;
+ return ((queue_num >> 8) | queue_num) % NFQNL_INSTANCE_BUCKETS;
}
static struct nfqnl_instance *
-instance_lookup(u_int16_t queue_num)
+instance_lookup(struct net *net, u_int16_t queue_num)
{
struct hlist_head *head;
struct hlist_node *pos;
struct nfqnl_instance *inst;
- head = &instance_table[instance_hashfn(queue_num)];
+ head = &net->nfqnl.instance_table[instance_hashfn(queue_num)];
hlist_for_each_entry_rcu(inst, pos, head, hlist) {
if (inst->queue_num == queue_num)
return inst;
@@ -90,14 +85,14 @@ instance_lookup(u_int16_t queue_num)
}
static struct nfqnl_instance *
-instance_create(u_int16_t queue_num, int pid)
+instance_create(struct net *net, u_int16_t queue_num, int pid)
{
struct nfqnl_instance *inst;
unsigned int h;
int err;
- spin_lock(&instances_lock);
- if (instance_lookup(queue_num)) {
+ spin_lock(&net->nfqnl.instances_lock);
+ if (instance_lookup(net, queue_num)) {
err = -EEXIST;
goto out_unlock;
}
@@ -122,16 +117,16 @@ instance_create(u_int16_t queue_num, int pid)
}
h = instance_hashfn(queue_num);
- hlist_add_head_rcu(&inst->hlist, &instance_table[h]);
+ hlist_add_head_rcu(&inst->hlist, &net->nfqnl.instance_table[h]);
- spin_unlock(&instances_lock);
+ spin_unlock(&net->nfqnl.instances_lock);
return inst;
out_free:
kfree(inst);
out_unlock:
- spin_unlock(&instances_lock);
+ spin_unlock(&net->nfqnl.instances_lock);
return ERR_PTR(err);
}
@@ -157,11 +152,11 @@ __instance_destroy(struct nfqnl_instance *inst)
}
static void
-instance_destroy(struct nfqnl_instance *inst)
+instance_destroy(struct net *net, struct nfqnl_instance *inst)
{
- spin_lock(&instances_lock);
+ spin_lock(&net->nfqnl.instances_lock);
__instance_destroy(inst);
- spin_unlock(&instances_lock);
+ spin_unlock(&net->nfqnl.instances_lock);
}
static inline void
@@ -400,7 +395,8 @@ nla_put_failure:
}
static int
-nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
+nfqnl_enqueue_packet(struct net *net, struct nf_queue_entry *entry,
+ unsigned int queuenum)
{
struct sk_buff *nskb;
struct nfqnl_instance *queue;
@@ -408,7 +404,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
__be32 *packet_id_ptr;
/* rcu_read_lock()ed by nf_hook_slow() */
- queue = instance_lookup(queuenum);
+ queue = instance_lookup(net, queuenum);
if (!queue) {
err = -ESRCH;
goto err_out;
@@ -440,7 +436,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
*packet_id_ptr = htonl(entry->id);
/* nfnetlink_unicast will either free the nskb or add it to a socket */
- err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT);
+ err = nfnetlink_unicast(nskb, net, queue->peer_pid, MSG_DONTWAIT);
if (err < 0) {
queue->queue_user_dropped++;
goto err_out_unlock;
@@ -549,16 +545,16 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
/* drop all packets with either indev or outdev == ifindex from all queue
* instances */
static void
-nfqnl_dev_drop(int ifindex)
+nfqnl_dev_drop(struct net *net, int ifindex)
{
int i;
rcu_read_lock();
- for (i = 0; i < INSTANCE_BUCKETS; i++) {
+ for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) {
struct hlist_node *tmp;
struct nfqnl_instance *inst;
- struct hlist_head *head = &instance_table[i];
+ struct hlist_head *head = &net->nfqnl.instance_table[i];
hlist_for_each_entry_rcu(inst, tmp, head, hlist)
nfqnl_flush(inst, dev_cmp, ifindex);
@@ -575,12 +571,9 @@ nfqnl_rcv_dev_event(struct notifier_block *this,
{
struct net_device *dev = ptr;
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
/* Drop any packets associated with the downed device */
if (event == NETDEV_DOWN)
- nfqnl_dev_drop(dev->ifindex);
+ nfqnl_dev_drop(dev_net(dev), dev->ifindex);
return NOTIFY_DONE;
}
@@ -598,19 +591,19 @@ nfqnl_rcv_nl_event(struct notifier_block *this,
int i;
/* destroy all instances for this pid */
- spin_lock(&instances_lock);
- for (i = 0; i < INSTANCE_BUCKETS; i++) {
+ spin_lock(&n->net->nfqnl.instances_lock);
+ for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) {
struct hlist_node *tmp, *t2;
struct nfqnl_instance *inst;
- struct hlist_head *head = &instance_table[i];
+ struct hlist_head *head =
+ &n->net->nfqnl.instance_table[i];
hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) {
- if ((n->net == &init_net) &&
- (n->pid == inst->peer_pid))
+ if (n->pid == inst->peer_pid)
__instance_destroy(inst);
}
}
- spin_unlock(&instances_lock);
+ spin_unlock(&n->net->nfqnl.instances_lock);
}
return NOTIFY_DONE;
}
@@ -630,11 +623,12 @@ static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = {
[NFQA_MARK] = { .type = NLA_U32 },
};
-static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlpid)
+static struct nfqnl_instance *verdict_instance_lookup(struct net *net,
+ u16 queue_num, int nlpid)
{
struct nfqnl_instance *queue;
- queue = instance_lookup(queue_num);
+ queue = instance_lookup(net, queue_num);
if (!queue)
return ERR_PTR(-ENODEV);
@@ -678,7 +672,8 @@ nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
LIST_HEAD(batch_list);
u16 queue_num = ntohs(nfmsg->res_id);
- queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid);
+ queue = verdict_instance_lookup(sock_net(ctnl), queue_num,
+ NETLINK_CB(skb).pid);
if (IS_ERR(queue))
return PTR_ERR(queue);
@@ -723,11 +718,12 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
struct nfqnl_instance *queue;
unsigned int verdict;
struct nf_queue_entry *entry;
+ struct net *net = sock_net(ctnl);
- queue = instance_lookup(queue_num);
+ queue = instance_lookup(net, queue_num);
if (!queue)
- queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid);
+ queue = verdict_instance_lookup(net, queue_num, NETLINK_CB(skb).pid);
if (IS_ERR(queue))
return PTR_ERR(queue);
@@ -782,6 +778,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
struct nfqnl_instance *queue;
struct nfqnl_msg_config_cmd *cmd = NULL;
int ret = 0;
+ struct net *net = sock_net(ctnl);
if (nfqa[NFQA_CFG_CMD]) {
cmd = nla_data(nfqa[NFQA_CFG_CMD]);
@@ -798,7 +795,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
}
rcu_read_lock();
- queue = instance_lookup(queue_num);
+ queue = instance_lookup(net, queue_num);
if (queue && queue->peer_pid != NETLINK_CB(skb).pid) {
ret = -EPERM;
goto err_out_unlock;
@@ -811,7 +808,8 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
ret = -EBUSY;
goto err_out_unlock;
}
- queue = instance_create(queue_num, NETLINK_CB(skb).pid);
+ queue = instance_create(net, queue_num,
+ NETLINK_CB(skb).pid);
if (IS_ERR(queue)) {
ret = PTR_ERR(queue);
goto err_out_unlock;
@@ -822,7 +820,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
ret = -ENODEV;
goto err_out_unlock;
}
- instance_destroy(queue);
+ instance_destroy(net, queue);
break;
case NFQNL_CFG_CMD_PF_BIND:
case NFQNL_CFG_CMD_PF_UNBIND:
@@ -886,65 +884,64 @@ static const struct nfnetlink_subsystem nfqnl_subsys = {
#ifdef CONFIG_PROC_FS
struct iter_state {
+ struct seq_net_private p;
unsigned int bucket;
};
-static struct hlist_node *get_first(struct seq_file *seq)
+static struct hlist_node *get_first(struct net *net, struct iter_state *st)
{
- struct iter_state *st = seq->private;
-
if (!st)
return NULL;
- for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
- if (!hlist_empty(&instance_table[st->bucket]))
- return instance_table[st->bucket].first;
+ for (st->bucket = 0; st->bucket < NFQNL_INSTANCE_BUCKETS; st->bucket++) {
+ if (!hlist_empty(&net->nfqnl.instance_table[st->bucket]))
+ return net->nfqnl.instance_table[st->bucket].first;
}
return NULL;
}
-static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
+static struct hlist_node *get_next(struct net *net, struct iter_state *st,
+ struct hlist_node *h)
{
- struct iter_state *st = seq->private;
-
h = h->next;
while (!h) {
- if (++st->bucket >= INSTANCE_BUCKETS)
+ if (++st->bucket >= NFQNL_INSTANCE_BUCKETS)
return NULL;
- h = instance_table[st->bucket].first;
+ h = net->nfqnl.instance_table[st->bucket].first;
}
return h;
}
-static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
+static struct hlist_node *get_idx(struct net *net, struct iter_state *st,
+ loff_t pos)
{
struct hlist_node *head;
- head = get_first(seq);
+ head = get_first(net, st);
if (head)
- while (pos && (head = get_next(seq, head)))
+ while (pos && (head = get_next(net, st, head)))
pos--;
return pos ? NULL : head;
}
static void *seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(instances_lock)
{
- spin_lock(&instances_lock);
- return get_idx(seq, *pos);
+ struct net *net = seq_file_net(seq);
+ spin_lock(&net->nfqnl.instances_lock);
+ return get_idx(net, seq->private, *pos);
}
static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
{
(*pos)++;
- return get_next(s, v);
+ return get_next(seq_file_net(s), s->private, v);
}
static void seq_stop(struct seq_file *s, void *v)
- __releases(instances_lock)
{
- spin_unlock(&instances_lock);
+ struct net *net = seq_file_net(s);
+ spin_unlock(&net->nfqnl.instances_lock);
}
static int seq_show(struct seq_file *s, void *v)
@@ -968,8 +965,8 @@ static const struct seq_operations nfqnl_seq_ops = {
static int nfqnl_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &nfqnl_seq_ops,
- sizeof(struct iter_state));
+ return seq_open_net(inode, file, &nfqnl_seq_ops,
+ sizeof(struct iter_state));
}
static const struct file_operations nfqnl_file_ops = {
@@ -977,13 +974,19 @@ static const struct file_operations nfqnl_file_ops = {
.open = nfqnl_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
#endif /* PROC_FS */
static int __net_init nfnetlink_queue_net_init(struct net *net)
{
+ int i;
+
+ spin_lock_init(&net->nfqnl.instances_lock);
+ for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++)
+ INIT_HLIST_HEAD(&net->nfqnl.instance_table[i]);
+
#ifdef CONFIG_PROC_FS
if (!proc_create("nfnetlink_queue", 0440,
net->proc_net_netfilter, &nfqnl_file_ops))
@@ -1007,7 +1010,7 @@ static struct pernet_operations nfnetlink_queue_net_ops = {
static int __init nfnetlink_queue_init(void)
{
- int i, status;
+ int status;
status = register_pernet_subsys(&nfnetlink_queue_net_ops);
if (status) {
@@ -1016,9 +1019,6 @@ static int __init nfnetlink_queue_init(void)
return status;
}
- for (i = 0; i < INSTANCE_BUCKETS; i++)
- INIT_HLIST_HEAD(&instance_table[i]);
-
netlink_register_notifier(&nfqnl_rtnl_notifier);
status = nfnetlink_subsys_register(&nfqnl_subsys);
if (status < 0) {
--
1.7.10.4

View file

@ -0,0 +1,70 @@
VERSION := $(shell dpkg -l linux-source 2> /dev/null | \
awk '/^i/ {print gensub("([0-9]+[.][0-9]+[.][0-9]+)[.0-9]*", "\\1", "1", $$3)}')
TARBALL := /usr/src/linux-source-$(VERSION).tar.bz2
SUBVERSION := -core
REVISION := 1.0
PATCHDIR := patches
PATCHES := $(sort $(wildcard $(PATCHDIR)/*.patch))
CONFIG := config.core
DEPDEBS := linux-source kernel-package po-debconf gettext
CONCURRENCY_LEVEL := $(shell lscpu 2> /dev/null | \
awk '/^CPU\(s\)/ {print $$2}')
ifeq ($(strip $(CONCURRENCY_LEVEL)),)
CONCURRENCY_LEVEL := 1
endif
MAINTAINER ?= $(shell id -nu)
EMAIL ?= $(MAINTAINER)@$(shell hostname -f)
MAKEKPKGFLAGS := --initrd --rootcmd fakeroot --us --uc \
--append-to-version $(SUBVERSION) --revision $(REVISION)
.PHONY: build
build: debcheck defaultconfig patch
export CONCURRENCY_LEVEL="$(CONCURRENCY_LEVEL)" \
KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \
cd linux-source-$(VERSION) && \
if [ -f ../$(CONFIG) ]; then \
cat ../$(CONFIG) >> .config; \
fi && \
fakeroot make-kpkg $(MAKEKPKGFLAGS) binary-arch
.PHONY: debcheck
debcheck:
for d in $(DEPDEBS); do \
if ! dpkg-query -s $$d > /dev/null 2>&1; then \
echo ERROR: build dependency not installed: $$d >&2; \
exit 1; \
fi; \
done
.PHONY: defaultconfig
defaultconfig: linux-source-$(VERSION)
export KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \
cd linux-source-$(VERSION) && make-kpkg $(MAKEKPKGFLAGS) configure
.PHONY: patch
patch: linux-source-$(VERSION) patch-stamp
patch-stamp: $(PATCHES)
for p in $^; do \
if ! patch -d linux-source-$(VERSION) -p1 < $$p; then \
echo ERROR: applying patch failed: $$p >&2; \
exit 1; \
fi; \
done
touch patch-stamp
.PHONY: source
source: linux-source-$(VERSION)
linux-source-$(VERSION): $(TARBALL)
tar -xjf $^
.PHONY: clean
clean:
rm -rf linux-source-$(VERSION) patch-stamp

View file

@ -0,0 +1 @@
CONFIG_XFRM_STATISTICS=y

View file

@ -0,0 +1,29 @@
From 1d992600b0f1962d0478df2083b76b1ceba50517 Mon Sep 17 00:00:00 2001
From: Tom Goff <thomas.goff@boeing.com>
Date: Mon, 3 Jun 2013 18:29:42 -0700
Subject: [PATCH 1/3] Make network device ifindex sequential per network
namespace.
Signed-off-by: Tom Goff <thomas.goff@boeing.com>
---
net/core/dev.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index d592214..4b8da6e 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -6455,8 +6455,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char
/* Actually switch the network namespace */
dev_net_set(dev, net);
- /* If there is an ifindex conflict assign a new one */
- if (__dev_get_by_index(net, dev->ifindex)) {
+ /* Assign a new ifindex */
+ {
int iflink = (dev->iflink == dev->ifindex);
dev->ifindex = dev_new_index(net);
if (iflink)
--
1.8.1.2

View file

@ -0,0 +1,307 @@
From 433bc9e01b6a50db276c0b0d9dcd8bfcc2bc42f8 Mon Sep 17 00:00:00 2001
From: Tom Goff <thomas.goff@boeing.com>
Date: Mon, 3 Jun 2013 18:30:31 -0700
Subject: [PATCH 2/3] netfilter: Make the /proc/net/netfilter directory per
netns.
This allows subsystems to create per-netns entries.
Signed-off-by: Tom Goff <thomas.goff@boeing.com>
---
include/linux/netfilter.h | 5 ----
include/net/net_namespace.h | 3 +++
net/netfilter/core.c | 35 ++++++++++++++++++++-------
net/netfilter/nf_log.c | 33 ++++++++++++++++++++++----
net/netfilter/nfnetlink_log.c | 46 ++++++++++++++++++++++++------------
net/netfilter/nfnetlink_queue_core.c | 45 ++++++++++++++++++++++++-----------
6 files changed, 121 insertions(+), 46 deletions(-)
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index ee14284..0060fde 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -289,11 +289,6 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family)
#endif
}
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-extern struct proc_dir_entry *proc_net_netfilter;
-#endif
-
#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index de644bc..96b2242 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -94,6 +94,9 @@ struct net {
struct netns_dccp dccp;
#endif
#ifdef CONFIG_NETFILTER
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *proc_net_netfilter;
+#endif
struct netns_xt xt;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
struct netns_ct ct;
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
index a9c488b..00e356d 100644
--- a/net/netfilter/core.c
+++ b/net/netfilter/core.c
@@ -276,25 +276,44 @@ void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *);
EXPORT_SYMBOL(nf_nat_decode_session_hook);
#endif
+static int __net_init netfilter_net_init(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ net->proc_net_netfilter = proc_net_mkdir(net, "netfilter",
+ net->proc_net);
+ if (!net->proc_net_netfilter) {
+ pr_err("%s: cannot create netfilter proc entry\n", __func__);
+ return -ENOMEM;
+ }
+#endif
+
+ return 0;
+}
+
+static void __net_exit netfilter_net_exit(struct net *net)
+{
#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_net_netfilter;
-EXPORT_SYMBOL(proc_net_netfilter);
+ proc_net_remove(net, "netfilter");
#endif
+}
+
+static struct pernet_operations netfilter_net_ops = {
+ .init = netfilter_net_init,
+ .exit = netfilter_net_exit,
+};
void __init netfilter_init(void)
{
int i, h;
+
+ if (register_pernet_subsys(&netfilter_net_ops))
+ panic("%s: failed to register per netns operations", __func__);
+
for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) {
for (h = 0; h < NF_MAX_HOOKS; h++)
INIT_LIST_HEAD(&nf_hooks[i][h]);
}
-#ifdef CONFIG_PROC_FS
- proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net);
- if (!proc_net_netfilter)
- panic("cannot create netfilter proc entry");
-#endif
-
if (netfilter_log_init() < 0)
panic("cannot initialize nf_log");
}
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index 9e31269..5f33072 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -290,14 +290,39 @@ static __init int netfilter_log_sysctl_init(void)
}
#endif /* CONFIG_SYSCTL */
-int __init netfilter_log_init(void)
+static int __net_init netfilter_log_net_init(struct net *net)
{
- int i, r;
#ifdef CONFIG_PROC_FS
if (!proc_create("nf_log", S_IRUGO,
- proc_net_netfilter, &nflog_file_ops))
- return -1;
+ net->proc_net_netfilter, &nflog_file_ops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static void __net_exit netfilter_log_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nf_log", net->proc_net_netfilter);
#endif
+}
+
+static struct pernet_operations netfilter_log_net_ops = {
+ .init = netfilter_log_net_init,
+ .exit = netfilter_log_net_exit,
+};
+
+int __init netfilter_log_init(void)
+{
+ int i, r;
+
+ r = register_pernet_subsys(&netfilter_log_net_ops);
+ if (r) {
+ pr_err("%s: failed to register per netns operations\n",
+ __func__);
+ return r;
+ }
/* Errors will trigger panic, unroll on error is unnecessary. */
r = netfilter_log_sysctl_init();
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 92fd8ec..9571c43 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -986,9 +986,39 @@ static const struct file_operations nful_file_ops = {
#endif /* PROC_FS */
+static int __net_init nfnetlink_log_net_init(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ if (!proc_create("nfnetlink_log", 0440,
+ net->proc_net_netfilter, &nful_file_ops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static void __net_exit nfnetlink_log_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nfnetlink_log", net->proc_net_netfilter);
+#endif
+}
+
+static struct pernet_operations nfnetlink_log_net_ops = {
+ .init = nfnetlink_log_net_init,
+ .exit = nfnetlink_log_net_exit,
+};
+
static int __init nfnetlink_log_init(void)
{
- int i, status = -ENOMEM;
+ int i, status;
+
+ status = register_pernet_subsys(&nfnetlink_log_net_ops);
+ if (status) {
+ pr_err("%s: failed to register per netns operations\n",
+ __func__);
+ return status;
+ }
for (i = 0; i < INSTANCE_BUCKETS; i++)
INIT_HLIST_HEAD(&instance_table[i]);
@@ -1011,19 +1041,8 @@ static int __init nfnetlink_log_init(void)
goto cleanup_subsys;
}
-#ifdef CONFIG_PROC_FS
- if (!proc_create("nfnetlink_log", 0440,
- proc_net_netfilter, &nful_file_ops)) {
- status = -ENOMEM;
- goto cleanup_logger;
- }
-#endif
return status;
-#ifdef CONFIG_PROC_FS
-cleanup_logger:
- nf_log_unregister(&nfulnl_logger);
-#endif
cleanup_subsys:
nfnetlink_subsys_unregister(&nfulnl_subsys);
cleanup_netlink_notifier:
@@ -1034,9 +1053,6 @@ cleanup_netlink_notifier:
static void __exit nfnetlink_log_fini(void)
{
nf_log_unregister(&nfulnl_logger);
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("nfnetlink_log", proc_net_netfilter);
-#endif
nfnetlink_subsys_unregister(&nfulnl_subsys);
netlink_unregister_notifier(&nfulnl_rtnl_notifier);
}
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
index 3158d87..8f2d9bb 100644
--- a/net/netfilter/nfnetlink_queue_core.c
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -1048,9 +1048,39 @@ static const struct file_operations nfqnl_file_ops = {
#endif /* PROC_FS */
+static int __net_init nfnetlink_queue_net_init(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ if (!proc_create("nfnetlink_queue", 0440,
+ net->proc_net_netfilter, &nfqnl_file_ops))
+ return -ENOMEM;
+#endif
+
+ return 0;
+}
+
+static void __net_exit nfnetlink_queue_net_exit(struct net *net)
+{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("nfnetlink_queue", net->proc_net_netfilter);
+#endif
+}
+
+static struct pernet_operations nfnetlink_queue_net_ops = {
+ .init = nfnetlink_queue_net_init,
+ .exit = nfnetlink_queue_net_exit,
+};
+
static int __init nfnetlink_queue_init(void)
{
- int i, status = -ENOMEM;
+ int i, status;
+
+ status = register_pernet_subsys(&nfnetlink_queue_net_ops);
+ if (status) {
+ pr_err("%s: failed to register per netns operations\n",
+ __func__);
+ return status;
+ }
for (i = 0; i < INSTANCE_BUCKETS; i++)
INIT_HLIST_HEAD(&instance_table[i]);
@@ -1062,20 +1092,10 @@ static int __init nfnetlink_queue_init(void)
goto cleanup_netlink_notifier;
}
-#ifdef CONFIG_PROC_FS
- if (!proc_create("nfnetlink_queue", 0440,
- proc_net_netfilter, &nfqnl_file_ops))
- goto cleanup_subsys;
-#endif
-
register_netdevice_notifier(&nfqnl_dev_notifier);
nf_register_queue_handler(&nfqh);
return status;
-#ifdef CONFIG_PROC_FS
-cleanup_subsys:
- nfnetlink_subsys_unregister(&nfqnl_subsys);
-#endif
cleanup_netlink_notifier:
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
return status;
@@ -1085,9 +1105,6 @@ static void __exit nfnetlink_queue_fini(void)
{
nf_unregister_queue_handler();
unregister_netdevice_notifier(&nfqnl_dev_notifier);
-#ifdef CONFIG_PROC_FS
- remove_proc_entry("nfnetlink_queue", proc_net_netfilter);
-#endif
nfnetlink_subsys_unregister(&nfqnl_subsys);
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
--
1.8.1.2

View file

@ -0,0 +1,475 @@
From 3d1c0bfef9d6ca43050e7a9077b46e0139ee1e1f Mon Sep 17 00:00:00 2001
From: Tom Goff <thomas.goff@boeing.com>
Date: Mon, 3 Jun 2013 18:31:29 -0700
Subject: [PATCH 3/3] netfilter: nfnetlink_queue: Add netns support.
Make nfnetlink_queue network namespace aware including a per-netns
/proc/net/netfilter/nfnetlink_queue file.
Signed-off-by: Tom Goff <thomas.goff@boeing.com>
---
include/net/net_namespace.h | 6 ++
include/net/netfilter/nf_queue.h | 3 +-
net/netfilter/nf_queue.c | 12 ++-
net/netfilter/nfnetlink_queue_core.c | 137 ++++++++++++++++++-----------------
4 files changed, 88 insertions(+), 70 deletions(-)
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index 96b2242..1af155b 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -22,6 +22,9 @@
#include <net/netns/conntrack.h>
#endif
#include <net/netns/xfrm.h>
+#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
+#include <net/netns/nfqnl.h>
+#endif
struct user_namespace;
struct proc_dir_entry;
@@ -106,6 +109,9 @@ struct net {
#endif
struct sock *nfnl;
struct sock *nfnl_stash;
+#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE)
+ struct netns_nfqnl nfqnl;
+#endif
#endif
#ifdef CONFIG_WEXT_CORE
struct sk_buff_head wext_nlevents;
diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h
index fb1c0be..484453d 100644
--- a/include/net/netfilter/nf_queue.h
+++ b/include/net/netfilter/nf_queue.h
@@ -19,7 +19,8 @@ struct nf_queue_entry {
/* Packet queuing */
struct nf_queue_handler {
- int (*outfn)(struct nf_queue_entry *entry,
+ int (*outfn)(struct net *net,
+ struct nf_queue_entry *entry,
unsigned int queuenum);
};
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index d812c12..0d69be9 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -81,6 +81,16 @@ static int __nf_queue(struct sk_buff *skb,
#endif
const struct nf_afinfo *afinfo;
const struct nf_queue_handler *qh;
+ struct net *net;
+
+ if (indev)
+ net = dev_net(indev);
+ else if (skb->sk)
+ net = sock_net(skb->sk);
+ else if (outdev)
+ net = dev_net(outdev);
+ else
+ return status;
/* QUEUE == DROP if no one is waiting, to be safe. */
rcu_read_lock();
@@ -133,7 +143,7 @@ static int __nf_queue(struct sk_buff *skb,
#endif
skb_dst_force(skb);
afinfo->saveroute(skb, entry);
- status = qh->outfn(entry, queuenum);
+ status = qh->outfn(net, entry, queuenum);
rcu_read_unlock();
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
index 8f2d9bb..1e0a830 100644
--- a/net/netfilter/nfnetlink_queue_core.c
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -66,24 +66,19 @@ struct nfqnl_instance {
typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long);
-static DEFINE_SPINLOCK(instances_lock);
-
-#define INSTANCE_BUCKETS 16
-static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly;
-
static inline u_int8_t instance_hashfn(u_int16_t queue_num)
{
- return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS;
+ return ((queue_num >> 8) | queue_num) % NFQNL_INSTANCE_BUCKETS;
}
static struct nfqnl_instance *
-instance_lookup(u_int16_t queue_num)
+instance_lookup(struct net *net, u_int16_t queue_num)
{
struct hlist_head *head;
struct hlist_node *pos;
struct nfqnl_instance *inst;
- head = &instance_table[instance_hashfn(queue_num)];
+ head = &net->nfqnl.instance_table[instance_hashfn(queue_num)];
hlist_for_each_entry_rcu(inst, pos, head, hlist) {
if (inst->queue_num == queue_num)
return inst;
@@ -92,14 +87,14 @@ instance_lookup(u_int16_t queue_num)
}
static struct nfqnl_instance *
-instance_create(u_int16_t queue_num, int portid)
+instance_create(struct net *net, u_int16_t queue_num, int portid)
{
struct nfqnl_instance *inst;
unsigned int h;
int err;
- spin_lock(&instances_lock);
- if (instance_lookup(queue_num)) {
+ spin_lock(&net->nfqnl.instances_lock);
+ if (instance_lookup(net, queue_num)) {
err = -EEXIST;
goto out_unlock;
}
@@ -124,16 +119,16 @@ instance_create(u_int16_t queue_num, int portid)
}
h = instance_hashfn(queue_num);
- hlist_add_head_rcu(&inst->hlist, &instance_table[h]);
+ hlist_add_head_rcu(&inst->hlist, &net->nfqnl.instance_table[h]);
- spin_unlock(&instances_lock);
+ spin_unlock(&net->nfqnl.instances_lock);
return inst;
out_free:
kfree(inst);
out_unlock:
- spin_unlock(&instances_lock);
+ spin_unlock(&net->nfqnl.instances_lock);
return ERR_PTR(err);
}
@@ -159,11 +154,11 @@ __instance_destroy(struct nfqnl_instance *inst)
}
static void
-instance_destroy(struct nfqnl_instance *inst)
+instance_destroy(struct net *net, struct nfqnl_instance *inst)
{
- spin_lock(&instances_lock);
+ spin_lock(&net->nfqnl.instances_lock);
__instance_destroy(inst);
- spin_unlock(&instances_lock);
+ spin_unlock(&net->nfqnl.instances_lock);
}
static inline void
@@ -417,7 +412,8 @@ nla_put_failure:
}
static int
-nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
+nfqnl_enqueue_packet(struct net *net, struct nf_queue_entry *entry,
+ unsigned int queuenum)
{
struct sk_buff *nskb;
struct nfqnl_instance *queue;
@@ -426,7 +422,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
int failopen = 0;
/* rcu_read_lock()ed by nf_hook_slow() */
- queue = instance_lookup(queuenum);
+ queue = instance_lookup(net, queuenum);
if (!queue) {
err = -ESRCH;
goto err_out;
@@ -463,7 +459,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum)
*packet_id_ptr = htonl(entry->id);
/* nfnetlink_unicast will either free the nskb or add it to a socket */
- err = nfnetlink_unicast(nskb, &init_net, queue->peer_portid, MSG_DONTWAIT);
+ err = nfnetlink_unicast(nskb, net, queue->peer_portid, MSG_DONTWAIT);
if (err < 0) {
queue->queue_user_dropped++;
goto err_out_unlock;
@@ -576,16 +572,16 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)
/* drop all packets with either indev or outdev == ifindex from all queue
* instances */
static void
-nfqnl_dev_drop(int ifindex)
+nfqnl_dev_drop(struct net *net, int ifindex)
{
int i;
rcu_read_lock();
- for (i = 0; i < INSTANCE_BUCKETS; i++) {
+ for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) {
struct hlist_node *tmp;
struct nfqnl_instance *inst;
- struct hlist_head *head = &instance_table[i];
+ struct hlist_head *head = &net->nfqnl.instance_table[i];
hlist_for_each_entry_rcu(inst, tmp, head, hlist)
nfqnl_flush(inst, dev_cmp, ifindex);
@@ -602,12 +598,9 @@ nfqnl_rcv_dev_event(struct notifier_block *this,
{
struct net_device *dev = ptr;
- if (!net_eq(dev_net(dev), &init_net))
- return NOTIFY_DONE;
-
/* Drop any packets associated with the downed device */
if (event == NETDEV_DOWN)
- nfqnl_dev_drop(dev->ifindex);
+ nfqnl_dev_drop(dev_net(dev), dev->ifindex);
return NOTIFY_DONE;
}
@@ -625,19 +618,19 @@ nfqnl_rcv_nl_event(struct notifier_block *this,
int i;
/* destroy all instances for this portid */
- spin_lock(&instances_lock);
- for (i = 0; i < INSTANCE_BUCKETS; i++) {
+ spin_lock(&n->net->nfqnl.instances_lock);
+ for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) {
struct hlist_node *tmp, *t2;
struct nfqnl_instance *inst;
- struct hlist_head *head = &instance_table[i];
+ struct hlist_head *head =
+ &n->net->nfqnl.instance_table[i];
hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) {
- if ((n->net == &init_net) &&
- (n->portid == inst->peer_portid))
+ if (n->portid == inst->peer_portid)
__instance_destroy(inst);
}
}
- spin_unlock(&instances_lock);
+ spin_unlock(&n->net->nfqnl.instances_lock);
}
return NOTIFY_DONE;
}
@@ -658,11 +651,13 @@ static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = {
[NFQA_MARK] = { .type = NLA_U32 },
};
-static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlportid)
+static struct nfqnl_instance *verdict_instance_lookup(struct net *net,
+ u16 queue_num,
+ int nlportid)
{
struct nfqnl_instance *queue;
- queue = instance_lookup(queue_num);
+ queue = instance_lookup(net, queue_num);
if (!queue)
return ERR_PTR(-ENODEV);
@@ -706,7 +701,8 @@ nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb,
LIST_HEAD(batch_list);
u16 queue_num = ntohs(nfmsg->res_id);
- queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).portid);
+ queue = verdict_instance_lookup(sock_net(ctnl), queue_num,
+ NETLINK_CB(skb).portid);
if (IS_ERR(queue))
return PTR_ERR(queue);
@@ -751,13 +747,14 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
struct nfqnl_instance *queue;
unsigned int verdict;
struct nf_queue_entry *entry;
+ struct net *net = sock_net(ctnl);
enum ip_conntrack_info uninitialized_var(ctinfo);
struct nf_conn *ct = NULL;
- queue = instance_lookup(queue_num);
+ queue = instance_lookup(net, queue_num);
if (!queue)
- queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).portid);
+ queue = verdict_instance_lookup(net, queue_num, NETLINK_CB(skb).portid);
if (IS_ERR(queue))
return PTR_ERR(queue);
@@ -822,6 +819,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
struct nfqnl_instance *queue;
struct nfqnl_msg_config_cmd *cmd = NULL;
int ret = 0;
+ struct net *net = sock_net(ctnl);
if (nfqa[NFQA_CFG_CMD]) {
cmd = nla_data(nfqa[NFQA_CFG_CMD]);
@@ -834,7 +832,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
}
rcu_read_lock();
- queue = instance_lookup(queue_num);
+ queue = instance_lookup(net, queue_num);
if (queue && queue->peer_portid != NETLINK_CB(skb).portid) {
ret = -EPERM;
goto err_out_unlock;
@@ -847,7 +845,8 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
ret = -EBUSY;
goto err_out_unlock;
}
- queue = instance_create(queue_num, NETLINK_CB(skb).portid);
+ queue = instance_create(net, queue_num,
+ NETLINK_CB(skb).portid);
if (IS_ERR(queue)) {
ret = PTR_ERR(queue);
goto err_out_unlock;
@@ -858,7 +857,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
ret = -ENODEV;
goto err_out_unlock;
}
- instance_destroy(queue);
+ instance_destroy(net, queue);
break;
case NFQNL_CFG_CMD_PF_BIND:
case NFQNL_CFG_CMD_PF_UNBIND:
@@ -952,65 +951,64 @@ static const struct nfnetlink_subsystem nfqnl_subsys = {
#ifdef CONFIG_PROC_FS
struct iter_state {
+ struct seq_net_private p;
unsigned int bucket;
};
-static struct hlist_node *get_first(struct seq_file *seq)
+static struct hlist_node *get_first(struct net *net, struct iter_state *st)
{
- struct iter_state *st = seq->private;
-
if (!st)
return NULL;
- for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
- if (!hlist_empty(&instance_table[st->bucket]))
- return instance_table[st->bucket].first;
+ for (st->bucket = 0; st->bucket < NFQNL_INSTANCE_BUCKETS; st->bucket++) {
+ if (!hlist_empty(&net->nfqnl.instance_table[st->bucket]))
+ return net->nfqnl.instance_table[st->bucket].first;
}
return NULL;
}
-static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
+static struct hlist_node *get_next(struct net *net, struct iter_state *st,
+ struct hlist_node *h)
{
- struct iter_state *st = seq->private;
-
h = h->next;
while (!h) {
- if (++st->bucket >= INSTANCE_BUCKETS)
+ if (++st->bucket >= NFQNL_INSTANCE_BUCKETS)
return NULL;
- h = instance_table[st->bucket].first;
+ h = net->nfqnl.instance_table[st->bucket].first;
}
return h;
}
-static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
+static struct hlist_node *get_idx(struct net *net, struct iter_state *st,
+ loff_t pos)
{
struct hlist_node *head;
- head = get_first(seq);
+ head = get_first(net, st);
if (head)
- while (pos && (head = get_next(seq, head)))
+ while (pos && (head = get_next(net, st, head)))
pos--;
return pos ? NULL : head;
}
static void *seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(instances_lock)
{
- spin_lock(&instances_lock);
- return get_idx(seq, *pos);
+ struct net *net = seq_file_net(seq);
+ spin_lock(&net->nfqnl.instances_lock);
+ return get_idx(net, seq->private, *pos);
}
static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
{
(*pos)++;
- return get_next(s, v);
+ return get_next(seq_file_net(s), s->private, v);
}
static void seq_stop(struct seq_file *s, void *v)
- __releases(instances_lock)
{
- spin_unlock(&instances_lock);
+ struct net *net = seq_file_net(s);
+ spin_unlock(&net->nfqnl.instances_lock);
}
static int seq_show(struct seq_file *s, void *v)
@@ -1034,8 +1032,8 @@ static const struct seq_operations nfqnl_seq_ops = {
static int nfqnl_open(struct inode *inode, struct file *file)
{
- return seq_open_private(file, &nfqnl_seq_ops,
- sizeof(struct iter_state));
+ return seq_open_net(inode, file, &nfqnl_seq_ops,
+ sizeof(struct iter_state));
}
static const struct file_operations nfqnl_file_ops = {
@@ -1043,13 +1041,19 @@ static const struct file_operations nfqnl_file_ops = {
.open = nfqnl_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release_private,
+ .release = seq_release_net,
};
#endif /* PROC_FS */
static int __net_init nfnetlink_queue_net_init(struct net *net)
{
+ int i;
+
+ spin_lock_init(&net->nfqnl.instances_lock);
+ for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++)
+ INIT_HLIST_HEAD(&net->nfqnl.instance_table[i]);
+
#ifdef CONFIG_PROC_FS
if (!proc_create("nfnetlink_queue", 0440,
net->proc_net_netfilter, &nfqnl_file_ops))
@@ -1073,7 +1077,7 @@ static struct pernet_operations nfnetlink_queue_net_ops = {
static int __init nfnetlink_queue_init(void)
{
- int i, status;
+ int status;
status = register_pernet_subsys(&nfnetlink_queue_net_ops);
if (status) {
@@ -1082,9 +1086,6 @@ static int __init nfnetlink_queue_init(void)
return status;
}
- for (i = 0; i < INSTANCE_BUCKETS; i++)
- INIT_HLIST_HEAD(&instance_table[i]);
-
netlink_register_notifier(&nfqnl_rtnl_notifier);
status = nfnetlink_subsys_register(&nfqnl_subsys);
if (status < 0) {
--
1.8.1.2

File diff suppressed because it is too large Load diff

24
kernel/freebsd/README.txt Normal file
View file

@ -0,0 +1,24 @@
CORE kernel patches
For information on the kernel modules ng_pipe and ng_wlan, see the README files in their respective directories. You should run the make && make install from
the module directories for CORE to work properly.
FreeBSD 8.x requires the small patches to allow per-node directories.
The FreeBSD 7.x version of CORE does not require the patch included here.
Instead you should download the latest vimage_7 kernel from:
http://imunes.net/virtnet/
The FreeBSD 4.11 version of CORE requires the included patch to work. See the
CORE manual for patching details.
ng_pipe module you should install with FreeBSD 4.11 or 7.x
ng_wlan module you should install with FreeBSD 4.11 or 7.x
4.11-R-CORE.diff patch you should use with FreeBSD 4.11
freebsd7-config-CORE config that you may use with vimage_7 kernels
freebsd7-config-COREDEBUG debugging config for use with vimage_7 kernels
vimage_7-CORE.diff patch to add multicast routing to vimage_7_20081015
imunes-8.0-RELEASE.diff per-node directories, persistent hub/switch, and
traffic snopping for wireshark for FreeBSD 8.0
symlinks-8.1-RELEASE.diff per-node directories for FreeBSD 8.1

View file

@ -0,0 +1,20 @@
#
# VIMAGE - sample kernel configuration file with a virtualized network stack
# configure.
#
# $FreeBSD$
#
include GENERIC
ident CORE
options IPSEC
device crypto
options VIMAGE
options IPFIREWALL
options IPFIREWALL_DEFAULT_TO_ACCEPT #allow everything by default
#
# Some kernel subsystems and functions don't yet compile with VIMAGE. Remove
# from the configuration for now.
#
nooptions SCTP

View file

@ -0,0 +1,22 @@
#
# VIMAGE - sample kernel configuration file with a virtualized network stack
# configure.
#
# $FreeBSD$
#
include GENERIC
ident COREDEBUG
device crypto
options IPSEC
options VIMAGE
options DDB
options GDB
options KDB
options KDB_TRACE
#
# Some kernel subsystems and functions don't yet compile with VIMAGE. Remove
# from the configuration for now.
#
nooptions SCTP

View file

@ -0,0 +1,11 @@
# this is the FreeBSD 8.x kernel configuration file for CORE
include GENERIC
ident CORE
options VIMAGE
nooptions SCTP
options IPSEC
device crypto
options IPFIREWALL
options IPFIREWALL_DEFAULT_TO_ACCEPT

View file

@ -0,0 +1,372 @@
# This patch is from http://imunes.net/imunes-8.0-RC3.diff
#
# This patch enables per-node directories, persistent hub/switch nodes, traffic
# snooping for wireshark, and disallows vlan interfaces within a jail.
diff -drup src-org/sys/kern/vfs_lookup.c src/sys/kern/vfs_lookup.c
--- src-org/sys/kern/vfs_lookup.c 2009-10-25 01:10:29.000000000 +0000
+++ src/sys/kern/vfs_lookup.c 2009-11-11 12:46:02.000000000 +0000
@@ -59,6 +59,8 @@ __FBSDID("$FreeBSD: src/sys/kern/vfs_loo
#include <sys/ktrace.h>
#endif
+#include <net/vnet.h>
+
#include <security/audit/audit.h>
#include <security/mac/mac_framework.h>
@@ -72,6 +74,19 @@ SDT_PROBE_DEFINE3(vfs, namei, lookup, en
"unsigned long");
SDT_PROBE_DEFINE2(vfs, namei, lookup, return, "int", "struct vnode *");
+#ifdef VIMAGE
+#define IMUNES_SYMLINK_HACK
+#endif
+
+#ifdef IMUNES_SYMLINK_HACK
+static VNET_DEFINE(int, morphing_symlinks);
+#define V_morphing_symlinks VNET(morphing_symlinks)
+
+SYSCTL_VNET_INT(_vfs, OID_AUTO, morphing_symlinks, CTLFLAG_RW,
+ &VNET_NAME(morphing_symlinks), 0,
+ "Resolve @ to vimage name in symlinks");
+#endif
+
/*
* Allocation zone for namei
*/
@@ -333,6 +348,44 @@ namei(struct nameidata *ndp)
error = ENOENT;
break;
}
+#ifdef IMUNES_SYMLINK_HACK
+ /*
+ * If the symbolic link includes a special character '@',
+ * and V_morphing_symlinks is set, substitute the first
+ * occurence of '@' with full path to jail / vimage name.
+ * If the full path includes subhierarchies, s/./\// when
+ * expanding '@' to jail / vimage name.
+ *
+ * XXX revisit buffer length checking.
+ */
+ CURVNET_SET_QUIET(TD_TO_VNET(curthread));
+ if (V_morphing_symlinks) {
+ char *sp = strchr(cp, '@');
+
+ if (sp) {
+ char *vname = td->td_ucred->cr_prison->pr_name;
+ int vnamelen = strlen(vname);
+ int i;
+
+ if (vnamelen >= auio.uio_resid) {
+ if (ndp->ni_pathlen > 1)
+ uma_zfree(namei_zone, cp);
+ error = ENAMETOOLONG;
+ CURVNET_RESTORE();
+ break;
+ }
+ bcopy(sp + 1, sp + vnamelen,
+ linklen - (sp - cp));
+ bcopy(td->td_ucred->cr_prison->pr_name,
+ sp, vnamelen);
+ linklen += (vnamelen - 1);
+ for (i = 0; i < vnamelen; i++)
+ if (sp[i] == '.')
+ sp[i] = '/';
+ }
+ }
+ CURVNET_RESTORE();
+#endif
if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
if (ndp->ni_pathlen > 1)
uma_zfree(namei_zone, cp);
diff -drup src-org/sys/net/bpf.c src/sys/net/bpf.c
--- src-org/sys/net/bpf.c 2009-10-25 01:10:29.000000000 +0000
+++ src/sys/net/bpf.c 2009-11-11 12:46:02.000000000 +0000
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD: src/sys/net/bpf.c,v
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
+#include <sys/ctype.h>
#include <sys/fcntl.h>
#include <sys/jail.h>
#include <sys/malloc.h>
@@ -1435,9 +1436,34 @@ bpf_setif(struct bpf_d *d, struct ifreq
struct bpf_if *bp;
struct ifnet *theywant;
+#define XVNET_BPF_SNOOPING
+#if defined(VIMAGE) && defined(XVNET_BPF_SNOOPING)
+ struct vnet *target_vnet = curvnet;
+ char *c;
+
+ /* Attempt to attach to an ifnet in a foreign vnet, specified as @ */
+ c = rindex(ifr->ifr_name, '@');
+ if ( c != NULL ) {
+ struct prison *target_pr;
+
+ *c++ = 0;
+ if (!isascii(*c) && !isdigit(*c))
+ return ENXIO;
+ target_pr = prison_find_name(curthread->td_ucred->cr_prison, c);
+ if (target_pr == NULL)
+ return ENXIO;
+ target_vnet = target_pr->pr_vnet;
+ }
+ CURVNET_SET_QUIET(target_vnet);
+#endif
+
theywant = ifunit(ifr->ifr_name);
- if (theywant == NULL || theywant->if_bpf == NULL)
+ if (theywant == NULL || theywant->if_bpf == NULL) {
+#if defined(VIMAGE) && defined(XVNET_BPF_SNOOPING)
+ CURVNET_RESTORE();
+#endif
return (ENXIO);
+ }
bp = theywant->if_bpf;
@@ -1477,6 +1503,9 @@ bpf_setif(struct bpf_d *d, struct ifreq
BPFD_LOCK(d);
reset_d(d);
BPFD_UNLOCK(d);
+#if defined(VIMAGE) && defined(XVNET_BPF_SNOOPING)
+ CURVNET_RESTORE();
+#endif
return (0);
}
diff -drup src-org/sys/net/if.c src/sys/net/if.c
--- src-org/sys/net/if.c 2009-10-25 01:10:29.000000000 +0000
+++ src/sys/net/if.c 2009-11-11 12:46:02.000000000 +0000
@@ -813,6 +813,14 @@ if_detach_internal(struct ifnet *ifp, in
struct ifnet *iter;
int found = 0;
+ /*
+ * Detach from any vlan, bridge or lagg ifnets linked to us.
+ * A small though unlikely window for a race from here to ifp
+ * unlinking from ifnet list is possible, hence we repeat the
+ * procedure once again further bellow. XXX.
+ */
+ EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
+
IFNET_WLOCK();
TAILQ_FOREACH(iter, &V_ifnet, if_link)
if (iter == ifp) {
diff -drup src-org/sys/net/if_llatbl.c src/sys/net/if_llatbl.c
--- src-org/sys/net/if_llatbl.c 2009-10-25 01:10:29.000000000 +0000
+++ src/sys/net/if_llatbl.c 2009-11-11 12:53:49.000000000 +0000
@@ -57,11 +57,14 @@ __FBSDID("$FreeBSD: src/sys/net/if_llatb
MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables");
-static SLIST_HEAD(, lltable) lltables = SLIST_HEAD_INITIALIZER(lltables);
+static VNET_DEFINE(SLIST_HEAD(, lltable), lltables);
+#define V_lltables VNET(lltables)
extern void arprequest(struct ifnet *, struct in_addr *, struct in_addr *,
u_char *);
+static void vnet_lltable_init(void);
+
struct rwlock lltable_rwlock;
RW_SYSINIT(lltable_rwlock, &lltable_rwlock, "lltable_rwlock");
@@ -75,7 +78,7 @@ lltable_sysctl_dumparp(int af, struct sy
int error = 0;
LLTABLE_RLOCK();
- SLIST_FOREACH(llt, &lltables, llt_link) {
+ SLIST_FOREACH(llt, &V_lltables, llt_link) {
if (llt->llt_af == af) {
error = llt->llt_dump(llt, wr);
if (error != 0)
@@ -157,7 +160,7 @@ lltable_free(struct lltable *llt)
KASSERT(llt != NULL, ("%s: llt is NULL", __func__));
LLTABLE_WLOCK();
- SLIST_REMOVE(&lltables, llt, lltable, llt_link);
+ SLIST_REMOVE(&V_lltables, llt, lltable, llt_link);
LLTABLE_WUNLOCK();
for (i=0; i < LLTBL_HASHTBL_SIZE; i++) {
@@ -180,7 +183,7 @@ lltable_drain(int af)
register int i;
LLTABLE_RLOCK();
- SLIST_FOREACH(llt, &lltables, llt_link) {
+ SLIST_FOREACH(llt, &V_lltables, llt_link) {
if (llt->llt_af != af)
continue;
@@ -202,7 +205,7 @@ lltable_prefix_free(int af, struct socka
struct lltable *llt;
LLTABLE_RLOCK();
- SLIST_FOREACH(llt, &lltables, llt_link) {
+ SLIST_FOREACH(llt, &V_lltables, llt_link) {
if (llt->llt_af != af)
continue;
@@ -232,7 +235,7 @@ lltable_init(struct ifnet *ifp, int af)
LIST_INIT(&llt->lle_head[i]);
LLTABLE_WLOCK();
- SLIST_INSERT_HEAD(&lltables, llt, llt_link);
+ SLIST_INSERT_HEAD(&V_lltables, llt, llt_link);
LLTABLE_WUNLOCK();
return (llt);
@@ -302,7 +305,7 @@ lla_rt_output(struct rt_msghdr *rtm, str
/* XXX linked list may be too expensive */
LLTABLE_RLOCK();
- SLIST_FOREACH(llt, &lltables, llt_link) {
+ SLIST_FOREACH(llt, &V_lltables, llt_link) {
if (llt->llt_af == dst->sa_family &&
llt->llt_ifp == ifp)
break;
@@ -367,3 +370,12 @@ lla_rt_output(struct rt_msghdr *rtm, str
return (error);
}
+
+static void
+vnet_lltable_init()
+{
+
+ SLIST_INIT(&V_lltables);
+}
+VNET_SYSINIT(vnet_lltable_init, SI_SUB_PSEUDO, SI_ORDER_FIRST, vnet_lltable_init, NULL);
+
diff -drup src-org/sys/net/if_vlan.c src/sys/net/if_vlan.c
--- src-org/sys/net/if_vlan.c 2009-10-25 01:10:29.000000000 +0000
+++ src/sys/net/if_vlan.c 2009-11-11 12:46:02.000000000 +0000
@@ -1359,6 +1359,12 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd
error = copyin(ifr->ifr_data, &vlr, sizeof(vlr));
if (error)
break;
+#ifdef VIMAGE
+ if (ifp->if_home_vnet != ifp->if_vnet) {
+ error = EPERM;
+ break;
+ }
+#endif
if (vlr.vlr_parent[0] == '\0') {
vlan_unconfig(ifp);
break;
@@ -1386,6 +1392,12 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd
case SIOCGETVLAN:
bzero(&vlr, sizeof(vlr));
+#ifdef VIMAGE
+ if (ifp->if_home_vnet != ifp->if_vnet) {
+ error = EPERM;
+ break;
+ }
+#endif
VLAN_LOCK();
if (TRUNK(ifv) != NULL) {
strlcpy(vlr.vlr_parent, PARENT(ifv)->if_xname,
diff -drup src-org/sys/netgraph/ng_bridge.c src/sys/netgraph/ng_bridge.c
--- src-org/sys/netgraph/ng_bridge.c 2009-10-25 01:10:29.000000000 +0000
+++ src/sys/netgraph/ng_bridge.c 2009-11-11 12:46:02.000000000 +0000
@@ -105,6 +105,7 @@ struct ng_bridge_private {
u_int numBuckets; /* num buckets in table */
u_int hashMask; /* numBuckets - 1 */
int numLinks; /* num connected links */
+ int persistent; /* can exist w/o any hooks */
struct callout timer; /* one second periodic timer */
};
typedef struct ng_bridge_private *priv_p;
@@ -345,13 +346,13 @@ static int
ng_bridge_newhook(node_p node, hook_p hook, const char *name)
{
const priv_p priv = NG_NODE_PRIVATE(node);
+ int linkNum = -1;
/* Check for a link hook */
if (strncmp(name, NG_BRIDGE_HOOK_LINK_PREFIX,
strlen(NG_BRIDGE_HOOK_LINK_PREFIX)) == 0) {
const char *cp;
char *eptr;
- u_long linkNum;
cp = name + strlen(NG_BRIDGE_HOOK_LINK_PREFIX);
if (!isdigit(*cp) || (cp[0] == '0' && cp[1] != '\0'))
@@ -359,6 +360,12 @@ ng_bridge_newhook(node_p node, hook_p ho
linkNum = strtoul(cp, &eptr, 10);
if (*eptr != '\0' || linkNum >= NG_BRIDGE_MAX_LINKS)
return (EINVAL);
+ } else if (strcmp(name, "anchor") == 0) {
+ linkNum = 0;
+ priv->persistent = 1;
+ }
+
+ if (linkNum >= 0 ) {
if (priv->links[linkNum] != NULL)
return (EISCONN);
priv->links[linkNum] = malloc(sizeof(*priv->links[linkNum]),
@@ -366,7 +373,7 @@ ng_bridge_newhook(node_p node, hook_p ho
if (priv->links[linkNum] == NULL)
return (ENOMEM);
priv->links[linkNum]->hook = hook;
- NG_HOOK_SET_PRIVATE(hook, (void *)linkNum);
+ NG_HOOK_SET_PRIVATE(hook, (void *)(intptr_t)linkNum);
priv->numLinks++;
return (0);
}
@@ -799,7 +806,8 @@ ng_bridge_disconnect(hook_p hook)
/* If no more hooks, go away */
if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
- && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) {
+ && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))
+ && !priv->persistent) {
ng_rmnode_self(NG_HOOK_NODE(hook));
}
return (0);
diff -drup src-org/sys/netgraph/ng_hub.c src/sys/netgraph/ng_hub.c
--- src-org/sys/netgraph/ng_hub.c 2009-10-25 01:10:29.000000000 +0000
+++ src/sys/netgraph/ng_hub.c 2009-11-11 12:46:02.000000000 +0000
@@ -37,6 +37,7 @@
#include <netgraph/netgraph.h>
static ng_constructor_t ng_hub_constructor;
+static ng_newhook_t ng_hub_newhook;
static ng_rcvdata_t ng_hub_rcvdata;
static ng_disconnect_t ng_hub_disconnect;
@@ -44,6 +45,7 @@ static struct ng_type ng_hub_typestruct
.version = NG_ABI_VERSION,
.name = NG_HUB_NODE_TYPE,
.constructor = ng_hub_constructor,
+ .newhook = ng_hub_newhook,
.rcvdata = ng_hub_rcvdata,
.disconnect = ng_hub_disconnect,
};
@@ -57,6 +59,14 @@ ng_hub_constructor(node_p node)
return (0);
}
+static int
+ng_hub_newhook(node_p node, hook_p hook, const char *name)
+{
+ if (strcmp(name, "anchor") == 0)
+ node->nd_private = (void *) 1;
+ return (0);
+}
+
static int
ng_hub_rcvdata(hook_p hook, item_p item)
{
@@ -94,7 +104,7 @@ ng_hub_disconnect(hook_p hook)
{
if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 &&
- NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))
+ NG_NODE_IS_VALID(NG_HOOK_NODE(hook)) && !hook->hk_node->nd_private)
ng_rmnode_self(NG_HOOK_NODE(hook));
return (0);
}

View file

@ -0,0 +1,27 @@
#
# (c)2008 the Boeing Company
#
# modified ng_pipe node
#
.if !defined(PLATFORM)
#PLATFORM=i386
PLATFORM=amd64
.endif
CFLAGS=-DBOEING_WLAN -I/usr/src/sys/${PLATFORM}/compile/CORE
KMOD= ng_pipe
SRCS= ng_pipe.c
#MAN= ng_pipe.4
# FreeBSD 4.11 is "FreeBSD" and 7.0 is "freebsd7.0"
#.if defined(OSTYPE)
#.if (${OSTYPE} == "FreeBSD")
#CFLAGS+=-DFREEBSD411
#SRCS= ng_pipe_freebsd4.c
#.endif
#.endif
.include <bsd.kmod.mk>

View file

@ -0,0 +1,21 @@
ng_pipe FreeBSD kernel module
See the copyright statement at the top of the source file.
Copyright (c) 2004, 2005, 2007 University of Zagreb
Copyright (c) 2007 FreeBSD Foundation
(c) 2008 the Boeing Company
modifications: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
More complete documentation is available in the ng_pipe(4) man page.
This version of ng_pipe has been modified as follows:
- added burst rate (or burstiness) which is the probability that the next packet
will be dropped given an error with the current packet, 0 to 100
- added jitter effect, which randomizes the delay an additional amount from
0 to jitter microseconds
- ng_wlan support added, to remove and read mbuf tags containing wlan link
effect information
- bugfix: random number generation improved from defective modulo algorithm
- bugfix: fixed mbuf dangling pointer reference when ng_pipe has both duplicates
and errors configured

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,171 @@
/*
* Copyright (c) 2004, 2007 University of Zagreb
* Copyright (c) 2007 FreeBSD Foundation
*
* This software was developed by the University of Zagreb and the
* FreeBSD Foundation under sponsorship by the Stichting NLnet and the
* FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _NETGRAPH_PIPE_H_
#define _NETGRAPH_PIPE_H_
/* Node type name and magic cookie */
#define NG_PIPE_NODE_TYPE "pipe"
#define NGM_PIPE_COOKIE 200708191
/* Hook names */
#define NG_PIPE_HOOK_UPPER "upper"
#define NG_PIPE_HOOK_LOWER "lower"
#define MAX_FSIZE 16384 /* Largest supported frame size, in bytes, for BER */
#define MAX_OHSIZE 256 /* Largest supported dummy-framing size, in bytes */
/* Statistics structure for one hook */
struct ng_pipe_hookstat {
u_int64_t fwd_octets;
u_int64_t fwd_frames;
u_int64_t in_disc_octets;
u_int64_t in_disc_frames;
u_int64_t out_disc_octets;
u_int64_t out_disc_frames;
};
/* Keep this in sync with the above structure definition */
#define NG_PIPE_HOOKSTAT_INFO { \
{ "FwdOctets", &ng_parse_uint64_type }, \
{ "FwdFrames", &ng_parse_uint64_type }, \
{ "queueDropOctets", &ng_parse_uint64_type }, \
{ "queueDropFrames", &ng_parse_uint64_type }, \
{ "delayDropOctets", &ng_parse_uint64_type }, \
{ "delayDropFrames", &ng_parse_uint64_type }, \
{ NULL }, \
}
/* Statistics structure returned by NGM_PIPE_GET_STATS */
struct ng_pipe_stats {
struct ng_pipe_hookstat downstream;
struct ng_pipe_hookstat upstream;
};
/* Keep this in sync with the above structure definition */
#define NG_PIPE_STATS_INFO(hstype) { \
{ "downstream", (hstype) }, \
{ "upstream", (hstype) }, \
{ NULL }, \
}
/* Runtime structure for one hook */
struct ng_pipe_hookrun {
u_int32_t fifo_queues;
u_int32_t qin_octets;
u_int32_t qin_frames;
u_int32_t qout_octets;
u_int32_t qout_frames;
};
/* Keep this in sync with the above structure definition */
#define NG_PIPE_HOOKRUN_INFO { \
{ "queues", &ng_parse_uint32_type }, \
{ "queuedOctets", &ng_parse_uint32_type }, \
{ "queuedFrames", &ng_parse_uint32_type }, \
{ "delayedOctets", &ng_parse_uint32_type }, \
{ "delayedFrames", &ng_parse_uint32_type }, \
{ NULL }, \
}
/* Runtime structure returned by NGM_PIPE_GET_RUN */
struct ng_pipe_run {
struct ng_pipe_hookrun downstream;
struct ng_pipe_hookrun upstream;
};
/* Keep this in sync with the above structure definition */
#define NG_PIPE_RUN_INFO(hstype) { \
{ "downstream", (hstype) }, \
{ "upstream", (hstype) }, \
{ NULL }, \
}
/* Config structure for one hook */
struct ng_pipe_hookcfg {
u_int64_t bandwidth;
u_int64_t ber;
u_int32_t qin_size_limit;
u_int32_t qout_size_limit;
u_int32_t duplicate;
u_int32_t fifo;
u_int32_t drr;
u_int32_t wfq;
u_int32_t droptail;
u_int32_t drophead;
};
/* Keep this in sync with the above structure definition */
#define NG_PIPE_HOOKCFG_INFO { \
{ "bandwidth", &ng_parse_uint64_type }, \
{ "BER", &ng_parse_uint64_type }, \
{ "queuelen", &ng_parse_uint32_type }, \
{ "delaylen", &ng_parse_uint32_type }, \
{ "duplicate", &ng_parse_uint32_type }, \
{ "fifo", &ng_parse_uint32_type }, \
{ "drr", &ng_parse_uint32_type }, \
{ "wfq", &ng_parse_uint32_type }, \
{ "droptail", &ng_parse_uint32_type }, \
{ "drophead", &ng_parse_uint32_type }, \
{ NULL }, \
}
/* Config structure returned by NGM_PIPE_GET_CFG */
struct ng_pipe_cfg {
u_int64_t bandwidth;
u_int64_t delay;
u_int32_t header_offset;
u_int32_t overhead;
struct ng_pipe_hookcfg downstream;
struct ng_pipe_hookcfg upstream;
};
/* Keep this in sync with the above structure definition */
#define NG_PIPE_CFG_INFO(hstype) { \
{ "bandwidth", &ng_parse_uint64_type }, \
{ "delay", &ng_parse_uint64_type }, \
{ "header_offset", &ng_parse_uint32_type }, \
{ "overhead", &ng_parse_uint32_type }, \
{ "downstream", (hstype) }, \
{ "upstream", (hstype) }, \
{ NULL }, \
}
/* Netgraph commands */
enum {
NGM_PIPE_GET_STATS=1, /* get stats */
NGM_PIPE_CLR_STATS, /* clear stats */
NGM_PIPE_GETCLR_STATS, /* atomically get and clear stats */
NGM_PIPE_GET_RUN, /* get current runtime status */
NGM_PIPE_GET_CFG, /* get configurable parameters */
NGM_PIPE_SET_CFG, /* set configurable parameters */
};
#endif /* _NETGRAPH_PIPE_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,27 @@
#
# (c)2006-2011 the Boeing Company
#
# ng_wlan
#
.if !defined(PLATFORM)
#PLATFORM=i386
PLATFORM=amd64
.endif
CFLAGS+=-I/usr/src/sys/${PLATFORM}/compile/CORE -DMULTICAST_LOOKUPS
# FreeBSD 4.11 is "FreeBSD" and 7.0 is "freebsd7.0"
#.if defined(OSTYPE)
#.if (${OSTYPE} == "FreeBSD")
#CFLAGS+=-DFREEBSD411
#.endif
#.endif
KMOD= ng_wlan
SRCS= ng_wlan.c
#MAN= ng_wlan.4
.include <bsd.kmod.mk>

View file

@ -0,0 +1,50 @@
ng_wlan FreeBSD kernel module
(c) 2006-2011 the Boeing Company
author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
The ng_wlan modules implements a netgraph node that models wireless
LAN connectivity. ng_wlan extends the ng_hub node, only instead of sending
packets to each connected peer, maintains a hash table of node connectivity,
and sends packets between two nodes only when they are linked. By default all
nodes are unlinked. Nodes can be linked and unlinked using "link" and
"unlink" messages:
ngctl msg e0_n2: link { node1=0x23 node2=0x0c }
The node IDs of the two nodes are the parameters, as depicted above.
Link effects between can also be specified for each node pair. If two nodes
are linked and parameters are specified, an mbuf tag will be added to each data
packet mbuf that specifies the effects. For FreeBSD 4.11, the metadata parameter
is used instead of mbuf tags. Delay (microseconds), bandwidth
(bits per second), PER (% packet errors), duplicates (%), jitter
(microseconds), and burst (% burst errors) are supported. This tag is then
removed by the ng_pipe node and the appropriate effects are applied. Link
effects are specified with "set" and "unset" messages:
ngctl msg e0_n2: set { node1=0x23 node2=0x0c delay=50000 bandwidth=54000000 per=0 duplicate=0 jitter=5000 burst=30 }
ngctl msg e0_n2: unset { node1=0x23 node2=0x0c }
Note that a special ng_pipe module is needed (the default one does not support
the mbuf tags and some effects.)
A separate error rate and burst rate affecting all multicast packets may be
defined. Use the "mer" message:
ngctl msg e0_n2: mer { mer=20 mburst=35 }
The above example sets the multicast error rate to drop 20% of all multicast
packets, with 35% burst errors.
When MULTICAST_LOOKUPS is defined, a second lookup table is defined for each
WLAN where multicast group, source, and node pair tuples can be linked or
unlinked. This causes different forwarding behavior for multicast packets,
where non-local groups are only forwarded if the node pair has been linked
together for that group (and the normal node pair has been linked).
Usage:
ngctl msg e0_n2: mcastset { node1=0x23 node2=0x0c group=0xEF020364 source=0x0a000002 }
ngctl msg e0_n2: mcastset { node1=0x23 node2=0x0c group=0xEF020364 source=0}
ngctl msg e0_n2: mcastunset { node1=0x23 node2=0x0c group=0xEF020364 source=0 }
Once the first mcastset/mcastunset message is received, that ng_wlan will drop
all non-local multicast packets that do not have a matching source, group,
node pair entry. The source address of zero matches any IP source.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,109 @@
/*
* Copyright (c) 2006-2011 the Boeing Company
* ng_wlan is based on ng_hub, which is:
* Copyright (c) 2004 Ruslan Ermilov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#ifndef _NETGRAPH_NG_WLAN_H_
#define _NETGRAPH_NG_WLAN_H_
/* Node type name and magic cookie. */
#define NG_WLAN_NODE_TYPE "wlan"
#define NGM_WLAN_COOKIE 1146673193
/* Control message parse info */
struct ng_wlan_config {
u_int32_t node1;
u_int32_t node2;
};
#define NG_WLAN_CONFIG_TYPE_INFO { \
{ "node1", &ng_parse_uint32_type }, \
{ "node2", &ng_parse_uint32_type }, \
{ NULL } \
}
struct ng_wlan_set_data {
u_int32_t node1;
u_int32_t node2;
u_int64_t delay; /* keep these aligned with struct ng_wlan_tag */
u_int64_t bandwidth;
u_int16_t per;
u_int16_t duplicate;
u_int32_t jitter;
u_int16_t burst;
};
#define NG_WLAN_SET_DATA_TYPE_INFO { \
{ "node1", &ng_parse_uint32_type }, \
{ "node2", &ng_parse_uint32_type }, \
{ "delay", &ng_parse_uint64_type }, \
{ "bandwidth", &ng_parse_uint64_type }, \
{ "per", &ng_parse_uint16_type }, \
{ "duplicate", &ng_parse_uint16_type }, \
{ "jitter", &ng_parse_uint32_type }, \
{ "burst", &ng_parse_uint16_type }, \
{ NULL } \
}
struct ng_wlan_mer {
uint16_t mer;
uint16_t mburst;
};
#define NG_WLAN_MER_TYPE_INFO { \
{ "mer", &ng_parse_uint16_type }, \
{ "mburst", &ng_parse_uint16_type }, \
{ NULL } \
}
#ifdef MULTICAST_LOOKUPS
struct ng_wlan_multicast_set_data {
u_int32_t node1;
u_int32_t node2;
u_int32_t group;
u_int32_t source;
};
#define NG_WLAN_MULTICAST_SET_DATA_TYPE_INFO { \
{ "node1", &ng_parse_uint32_type }, \
{ "node2", &ng_parse_uint32_type }, \
{ "group", &ng_parse_uint32_type }, \
{ "source", &ng_parse_uint32_type }, \
{ NULL } \
}
#endif /* MULTICAST_LOOKUPS */
/* List of supported Netgraph control messages */
enum {
NGM_WLAN_LINK_NODES = 1,
NGM_WLAN_UNLINK_NODES,
NGM_WLAN_NODES_SET,
NGM_WLAN_NODES_UNSET,
NGM_WLAN_NODES_GET,
NGM_WLAN_MER, /* MULTICAST_ERR */
NGM_WLAN_MULTICAST_SET, /* MULTICAST_LOOKUPS */
NGM_WLAN_MULTICAST_UNSET, /* MULTICAST_LOOKUPS */
NGM_WLAN_MULTICAST_GET, /* MULTICAST_LOOKUPS */
};
#endif /* _NETGRAPH_NG_WLAN_H_ */

View file

@ -0,0 +1,60 @@
/*
* Copyright (c) 2006-2011 the Boeing Company
* All rights reserved.
*
* author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
*/
#define NG_TAG_WLAN 0x01
#ifdef FREEBSD411
#define WLAN_META_SIZE (sizeof(struct ng_meta))+(sizeof(struct ng_wlan_tag))
#define WLAN_META_PRIORITY 0x01
#define TAGSIZE (sizeof(struct ng_wlan_tag) - sizeof(struct meta_field_header))
#else
#define TAGSIZE (sizeof(struct ng_wlan_tag) - sizeof(struct m_tag))
#endif
#define NG_WLAN_MAX_DELAY 2000000 /* 2,000,000us = 2s */
#define NG_WLAN_MAX_BW 1000000000 /* 1,000,000,000bps = 1000M */
#define NG_WLAN_MAX_PER 100 /* 100% */
#define NG_WLAN_MAX_DUP 50 /* 50% */
#define NG_WLAN_MAX_JITTER NG_WLAN_MAX_DELAY
#define NG_WLAN_MAX_BURST NG_WLAN_MAX_PER
/* Tag data that is prepended to packets passing through the WLAN node.
*/
struct ng_wlan_tag {
#ifdef FREEBSD411
struct meta_field_header meta_hdr;
#else
struct m_tag tag;
#endif
u_int64_t delay;
u_int64_t bandwidth;
u_int16_t per;
u_int16_t duplicate;
u_int32_t jitter;
u_int16_t burst;
};
#define TAG_HAS_DATA(t) (t->delay || t->bandwidth || t->per || t->duplicate \
|| t->jitter || t->burst )
#define WLAN_TAG_ZERO(t) do { \
t->delay = 0; \
t->bandwidth = 0; \
t->per = 0; \
t->duplicate = 0; \
t->jitter = 0; \
t->burst = 0; \
} while(0);
#define WLAN_TAG_COPY(a, b) do { \
a->delay = ((struct ng_wlan_tag*)b)->delay; \
a->bandwidth = ((struct ng_wlan_tag*)b)->bandwidth; \
a->per = ((struct ng_wlan_tag*)b)->per; \
a->duplicate = ((struct ng_wlan_tag*)b)->duplicate; \
a->jitter = ((struct ng_wlan_tag*)b)->jitter; \
a->burst = ((struct ng_wlan_tag*)b)->burst; \
} while(0);

View file

@ -0,0 +1,78 @@
Index: sys/kern/vfs_lookup.c
===========================================================================
--- sys/kern/vfs_lookup.c 2010/06/17 19:18:00 #3
+++ sys/kern/vfs_lookup.c 2010/06/17 19:18:00
@@ -59,6 +59,8 @@
#include <sys/ktrace.h>
#endif
+#include <net/vnet.h>
+
#include <security/audit/audit.h>
#include <security/mac/mac_framework.h>
@@ -72,6 +74,19 @@
"unsigned long");
SDT_PROBE_DEFINE2(vfs, namei, lookup, return, "int", "struct vnode *");
+#ifdef VIMAGE
+#define IMUNES_SYMLINK_HACK
+#endif
+
+#ifdef IMUNES_SYMLINK_HACK
+static VNET_DEFINE(int, morphing_symlinks);
+#define V_morphing_symlinks VNET(morphing_symlinks)
+
+SYSCTL_VNET_INT(_vfs, OID_AUTO, morphing_symlinks, CTLFLAG_RW,
+ &VNET_NAME(morphing_symlinks), 0,
+ "Resolve @ to vimage name in symlinks");
+#endif
+
/*
* Allocation zone for namei
*/
@@ -333,6 +348,44 @@
error = ENOENT;
break;
}
+#ifdef IMUNES_SYMLINK_HACK
+ /*
+ * If the symbolic link includes a special character '@',
+ * and V_morphing_symlinks is set, substitute the first
+ * occurence of '@' with full path to jail / vimage name.
+ * If the full path includes subhierarchies, s/./\// when
+ * expanding '@' to jail / vimage name.
+ *
+ * XXX revisit buffer length checking.
+ */
+ CURVNET_SET_QUIET(TD_TO_VNET(curthread));
+ if (V_morphing_symlinks) {
+ char *sp = strchr(cp, '@');
+
+ if (sp) {
+ char *vname = td->td_ucred->cr_prison->pr_name;
+ int vnamelen = strlen(vname);
+ int i;
+
+ if (vnamelen >= auio.uio_resid) {
+ if (ndp->ni_pathlen > 1)
+ uma_zfree(namei_zone, cp);
+ error = ENAMETOOLONG;
+ CURVNET_RESTORE();
+ break;
+ }
+ bcopy(sp + 1, sp + vnamelen,
+ linklen - (sp - cp));
+ bcopy(td->td_ucred->cr_prison->pr_name,
+ sp, vnamelen);
+ linklen += (vnamelen - 1);
+ for (i = 0; i < vnamelen; i++)
+ if (sp[i] == '.')
+ sp[i] = '/';
+ }
+ }
+ CURVNET_RESTORE();
+#endif
if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
if (ndp->ni_pathlen > 1)
uma_zfree(namei_zone, cp);

View file

@ -0,0 +1,14 @@
# $FreeBSD$
PROG= vimage
LDADD= -ljail
DPADD= ${LIBJAIL}
WARNS?= 2
CFLAGS+= -I../../../sys
MAN= vimage.8
BINDIR?= /usr/sbin
.include <bsd.prog.mk>

View file

@ -0,0 +1,195 @@
.\" Copyright (c) 2002, 2003 Marko Zec <zec@fer.hr>
.\" Copyright (c) 2009 University of Zagreb
.\" Copyright (c) 2009 FreeBSD Foundation
.\"
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd August 25, 2009
.Dt VIMAGE 8
.Os
.Sh NAME
.Nm vimage
.Nd manage virtual network stacks
.Sh SYNOPSIS
.Nm
.Op Fl c | m
.Ar vname
.Op Ar param=value ...
.Nm
.Fl d
.Ar vname
.Nm
.Fl l
.Op Fl rvj
.Op Ar vname
.Nm
.Fl i
.Ar vname ifname
.Op Ar newifname
.Nm
.Ar vi_name
.Op command ...
.Sh DESCRIPTION
The
.Nm
utility is an alternative user interface for controlling virtual network
stacks in FreeBSD, aimed primarily at supporting legacy applications
which are not yet converted to using
.Xr jail 8 ,
.Xr jexec 8 ,
and
.Xr jls 8 .
.
.Ss Overview
A virtual image or vimage is a jail with its own independent network
stack instance. Every process, socket and network interface present
in the system is always attached to one, and only one, virtual network
stack instance (vnet).
During system bootup sequence a default vnet
is created to which all the configured interfaces and user processes
are initially attached.
Assuming that enough system resources are
are available, a user with sufficient privileges can create and manage
a hierarchy of subordinated virtual images.
The
.Nm
command allows for creation, deletion and monitoring of virtual images,
as well as for execution of arbitrary processes in a targeted virtual
image.
.Ss Invocation
If invoked with no modifiers, the
.Nm
command spawns a new interactive shell in virtual image
.Ar vname .
If optional additional arguments following
.Ar vname
are provided, the first of those will be executed in place of the
interactive shell, and the rest of the arguments will be passed as
arguments to the executed command.
.Pp
The following modifiers are available:
.Bl -tag -width indent
.It Fl c
Create a new virtual image named
.Ar vname .
Additional arguments, if provided, may be used to specify operating
parameters different from defaults, in format
.Ar param=value .
See
.Xr jail 8
for an extensive list of available parameters.
.It Fl m
Modify the parameters of a virtual image named
.Ar vname ,
using the same syntax as with the -c form of the command.
.It Fl d
Delete the virtual image
.Ar vname .
No processes and/or sockets should exist in the target virtual image
in order for the delete request to succeed. Non-loopback interfaces
residing in the target virtual image will be reassigned to the virtual
image's parent.
.It Fl l
List the properties and statistics for virtual images one level
below the current one in the hierarchy. If an optional argument
.Ar vname
is provided, only the information regarding the target virtual image
.Ar vname
is displayed.
With the optional
.Op Ar -r
switch enabled the list will include all virtual images below the
current level in the vimage hierarchy.
Enabling the optional
.Op Ar -v
or
.Op Ar -j
switches results in a more detailed output.
.It Fl i
Move interface
.Ar ifname
to the target virtual image
.Ar vname .
Interfaces will be automatically renamed to
.So
ethXX
.Sc ,
unless an optional argument specifying the desired interface name
.Op Ar newifname
is provided.
.El
.Sh EXAMPLES
Create a new virtual image named
.So v1
.Sc ,
which is allowed to create and manage an own subhierarchy of vimages:
.Pp
.Dl vimage -c v1 children.max=100
.Pp
Execute the
.So ifconfig
.Sc command in the virtual image
.So v1
.Sc :
.Pp
.Dl vimage v1 ifconfig
.Pp
Move the interface
.So vlan0
.Sc to the virtual image
.So v1
.Sc while renaming the interface as
.So
ve0
.Sc :
.Pp
.Dl vimage -i v1 vlan0 ve0
.Pp
Show the status information for virtual image
.So v1
.Sc :
.Pp
.Dl vimage -lv v1
.Sh DIAGNOSTICS
The
.Nm
command exits 0 on success, and >0 if an error occurs.
.Sh SEE ALSO
.Xr jail 8
.Xr jexec 8
.Xr jls 8
.Sh HISTORY
Network stack virtualization framework first appeared as a patchset
against the FreeBSD 4.7 kernel in 2002, and was maintained outside
of the main FreeBSD tree.
As a result of a project sponsored by the FreeBSD Foundation and
Stiching NLNet, integrated virtualized network stack first appeared
in FreeBSD 8.0.
.Sh BUGS
Deletion of vimages / vnets is known to leak kernel memory and fail at
stopping various timers, hence may lead to system crashes.
.Sh AUTHOR
.An "Marko Zec" Aq zec@fer.hr

View file

@ -0,0 +1,390 @@
/*
* Copyright (c) 2002-2004 Marko Zec <zec@fer.hr>
* Copyright (c) 2009 University of Zagreb
* Copyright (c) 2009 FreeBSD Foundation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/jail.h>
#include <sys/socket.h>
#include <net/if.h>
#include <ctype.h>
#include <jail.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
typedef enum {
VI_SWITCHTO,
VI_CREATE,
VI_MODIFY,
VI_DESTROY,
VI_IFMOVE,
VI_GET
} vi_cmd_t;
typedef struct vimage_status {
char name[MAXPATHLEN]; /* Must be first field for strcmp(). */
char path[MAXPATHLEN];
char hostname[MAXPATHLEN];
char domainname[MAXPATHLEN];
int jid;
int parentjid;
int vnet;
int childcnt;
int childmax;
int cpuset;
int rawsock;
int socket_af;
int mount;
} vstat_t;
#define VST_SIZE_STEP 1024
#define MAXPARAMS 32
static int getjail(vstat_t *, int, int);
static char *invocname;
static void
usage(void)
{
fprintf(stderr,
"usage: %s [-c | -m] vname [param=value ...]\n"
" %s -d vname\n"
" %s -l[rvj] [vname]\n"
" %s -i vname ifname [newifname]\n"
" %s vname [command ...]\n",
invocname, invocname, invocname, invocname, invocname);
exit(1);
}
int
main(int argc, char **argv)
{
struct jailparam params[MAXPARAMS];
char ifname[IFNAMSIZ];
struct ifreq ifreq;
vi_cmd_t newcmd, cmd;
int recurse = 0;
int verbose = 0;
int jid, i, s, namelen;
int vst_size, vst_last;
vstat_t *vst;
char *str;
char ch;
invocname = argv[0];
newcmd = cmd = VI_SWITCHTO; /* Default if no modifiers specified. */
while ((ch = getopt(argc, argv, "cdijlmrv")) != -1) {
switch (ch) {
case 'c':
newcmd = VI_CREATE;
break;
case 'm':
newcmd = VI_MODIFY;
break;
case 'd':
newcmd = VI_DESTROY;
break;
case 'l':
newcmd = VI_GET;
break;
case 'i':
newcmd = VI_IFMOVE;
break;
case 'r':
recurse = 1;
break;
case 'v':
verbose++;
break;
case 'j':
verbose = 2;
break;
default:
usage();
}
if (cmd == VI_SWITCHTO || cmd == newcmd)
cmd = newcmd;
else
usage();
}
argc -= optind;
argv += optind;
if ((cmd != VI_GET && (argc == 0 || recurse != 0 || verbose != 0)) ||
(cmd == VI_IFMOVE && (argc < 2 || argc > 3)) ||
(cmd == VI_MODIFY && argc < 2) || argc >= MAXPARAMS)
usage();
switch (cmd) {
case VI_GET:
vst_last = 0;
vst_size = VST_SIZE_STEP;
if ((vst = malloc(vst_size * sizeof(*vst))) == NULL)
break;
if (argc == 1)
namelen = strlen(argv[0]);
else
namelen = 0;
jid = 0;
while ((jid = getjail(&vst[vst_last], jid, verbose)) > 0) {
/* Skip jails which do not own vnets. */
if (vst[vst_last].vnet != 1)
continue;
/* Skip non-matching vnames / hierarchies. */
if (namelen &&
((strlen(vst[vst_last].name) < namelen ||
strncmp(vst[vst_last].name, argv[0], namelen) != 0)
|| (strlen(vst[vst_last].name) > namelen &&
vst[vst_last].name[namelen] != '.')))
continue;
/* Skip any sub-trees if -r not requested. */
if (!recurse &&
(strlen(vst[vst_last].name) < namelen ||
strchr(&vst[vst_last].name[namelen], '.') != NULL))
continue;
/* Grow vst table if necessary. */
if (++vst_last == vst_size) {
vst_size += VST_SIZE_STEP;
vst = realloc(vst, vst_size * sizeof(*vst));
if (vst == NULL)
break;
}
}
if (vst == NULL)
break;
/* Sort: the key is the 1st field in *vst, i.e. vimage name. */
qsort(vst, vst_last, sizeof(*vst), (void *) strcmp);
for (i = 0; i < vst_last; i++) {
if (!verbose) {
printf("%s\n", vst[i].name);
continue;
}
printf("%s:\n", vst[i].name);
printf(" Path: %s\n", vst[i].path);
printf(" Hostname: %s\n", vst[i].hostname);
printf(" Domainname: %s\n", vst[i].domainname);
printf(" Children: %d\n", vst[i].childcnt);
if (verbose < 2)
continue;
printf(" Children limit: %d\n", vst[i].childmax);
printf(" CPUsetID: %d\n", vst[i].cpuset);
printf(" JID: %d\n", vst[i].jid);
printf(" PJID: %d\n", vst[i].parentjid);
printf(" Raw sockets allowed: %d\n", vst[i].rawsock);
printf(" All AF allowed: %d\n", vst[i].socket_af);
printf(" Mount allowed: %d\n", vst[i].mount);
}
free(vst);
exit(0);
case VI_IFMOVE:
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
break;
if ((jid = jail_getid(argv[0])) < 0)
break;
ifreq.ifr_jid = jid;
strncpy(ifreq.ifr_name, argv[1], sizeof(ifreq.ifr_name));
if (ioctl(s, SIOCSIFVNET, (caddr_t)&ifreq) < 0)
break;
close(s);
if (argc == 3)
snprintf(ifname, sizeof(ifname), "%s", argv[2]);
else
snprintf(ifname, sizeof(ifname), "eth0");
ifreq.ifr_data = ifname;
/* Do we need to rename the ifnet? */
if (strcmp(ifreq.ifr_name, ifname) != 0) {
/* Switch to the context of the target vimage. */
if (jail_attach(jid) < 0)
break;
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
break;
for (namelen = 0; isalpha(ifname[namelen]); namelen++);
i = 0;
/* Search for a free ifunit in target vnet. Unsafe. */
while (ioctl(s, SIOCSIFNAME, (caddr_t)&ifreq) < 0) {
snprintf(&ifname[namelen],
sizeof(ifname) - namelen, "%d", i);
/* Emergency brake. */
if (i++ == IF_MAXUNIT)
break;
}
}
if (i < IF_MAXUNIT)
printf("%s@%s\n", ifname, argv[0]);
else
printf("%s@%s\n", ifreq.ifr_name, argv[0]);
exit(0);
case VI_CREATE:
if (jail_setv(JAIL_CREATE,
"name", argv[0],
"vnet", NULL,
"host", NULL,
"persist", NULL,
"allow.raw_sockets", "true",
"allow.socket_af", "true",
"allow.mount", "true",
NULL) < 0)
break;
if (argc == 1)
exit(0);
/* Not done yet, proceed to apply non-default parameters. */
case VI_MODIFY:
jailparam_init(&params[0], "name");
jailparam_import(&params[0], argv[0]);
for (i = 1; i < argc; i++) {
for (str = argv[i]; *str != '=' && *str != 0; str++) {
/* Do nothing - search for '=' delimeter. */
}
if (*str == 0)
break;
*str++ = 0;
if (*str == 0)
break;
jailparam_init(&params[i], argv[i]);
jailparam_import(&params[i], str);
}
if (i != argc)
break;
if (jailparam_set(params, i, JAIL_UPDATE) < 0)
break;
exit(0);
case VI_DESTROY:
if ((jid = jail_getid(argv[0])) < 0)
break;
if (jail_remove(jid) < 0)
break;
exit(0);
case VI_SWITCHTO:
if ((jid = jail_getid(argv[0])) < 0)
break;
if (jail_attach(jid) < 0)
break;
if (argc == 1) {
printf("Switched to vimage %s\n", argv[0]);
if ((str = getenv("SHELL")) == NULL)
execlp("/bin/sh", invocname, NULL);
else
execlp(str, invocname, NULL);
} else
execvp(argv[1], &argv[1]);
break;
default:
/* Should be unreachable. */
break;
}
if (jail_errmsg[0])
fprintf(stderr, "Error: %s\n", jail_errmsg);
else
perror("Error");
exit(1);
}
static int
getjail(vstat_t *vs, int lastjid, int verbose)
{
struct jailparam params[32]; /* Must be > max(psize). */
int psize = 0;
bzero(params, sizeof(params));
bzero(vs, sizeof(*vs));
jailparam_init(&params[psize], "lastjid");
jailparam_import_raw(&params[psize++], &lastjid, sizeof lastjid);
jailparam_init(&params[psize], "vnet");
jailparam_import_raw(&params[psize++], &vs->vnet, sizeof(vs->vnet));
jailparam_init(&params[psize], "name");
jailparam_import_raw(&params[psize++], &vs->name, sizeof(vs->name));
if (verbose == 0)
goto done;
jailparam_init(&params[psize], "path");
jailparam_import_raw(&params[psize++], &vs->path, sizeof(vs->path));
jailparam_init(&params[psize], "host.hostname");
jailparam_import_raw(&params[psize++], &vs->hostname,
sizeof(vs->hostname));
jailparam_init(&params[psize], "host.domainname");
jailparam_import_raw(&params[psize++], &vs->domainname,
sizeof(vs->domainname));
jailparam_init(&params[psize], "children.cur");
jailparam_import_raw(&params[psize++], &vs->childcnt,
sizeof(vs->childcnt));
if (verbose == 1)
goto done;
jailparam_init(&params[psize], "children.max");
jailparam_import_raw(&params[psize++], &vs->childmax,
sizeof(vs->childmax));
jailparam_init(&params[psize], "cpuset.id");
jailparam_import_raw(&params[psize++], &vs->cpuset,
sizeof(vs->cpuset));
jailparam_init(&params[psize], "parent");
jailparam_import_raw(&params[psize++], &vs->parentjid,
sizeof(vs->parentjid));
jailparam_init(&params[psize], "allow.raw_sockets");
jailparam_import_raw(&params[psize++], &vs->rawsock,
sizeof(vs->rawsock));
jailparam_init(&params[psize], "allow.socket_af");
jailparam_import_raw(&params[psize++], &vs->socket_af,
sizeof(vs->socket_af));
jailparam_init(&params[psize], "allow.mount");
jailparam_import_raw(&params[psize++], &vs->mount, sizeof(vs->mount));
done:
vs->jid = jailparam_get(params, psize, 0);
jailparam_free(params, psize);
return (vs->jid);
}

File diff suppressed because it is too large Load diff