* [PATCH 4/5] Add loopback checkpoint support
From: Dan Smith @ 2010-02-16 16:03 UTC (permalink / raw)
To: containers, netdev
In-Reply-To: <1266336187-19105-1-git-send-email-danms@us.ibm.com>
Adds a small ndo_checkpoint() handler for loopback devices to write the
name and addresses like other interfaces.
Signed-off-by: Dan Smith <danms@us.ibm.com>
---
drivers/net/loopback.c | 41 ++++++++++++++++++++++++++++++++++++++---
1 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index b9fcc98..816a527 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -57,6 +57,8 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/percpu.h>
+#include <linux/checkpoint.h>
+#include <linux/checkpoint_hdr.h>
#include <net/net_namespace.h>
struct pcpu_lstats {
@@ -153,10 +155,43 @@ static void loopback_dev_free(struct net_device *dev)
free_netdev(dev);
}
+static int loopback_checkpoint(struct ckpt_ctx *ctx, struct net_device *dev)
+{
+ struct ckpt_hdr_netdev *h;
+ struct ckpt_netdev_addr *addrs;
+ int ret;
+
+ h = ckpt_netdev_base(ctx, dev, &addrs);
+ if (IS_ERR(h))
+ return PTR_ERR(h);
+
+ h->type = CKPT_NETDEV_LO;
+
+ ret = ckpt_write_obj(ctx, (struct ckpt_hdr *)h);
+ if (ret < 0)
+ goto out;
+
+ ret = ckpt_write_buffer(ctx, dev->name, IFNAMSIZ);
+ if (ret < 0)
+ goto out;
+
+ if (h->inet_addrs > 0) {
+ int len = (sizeof(struct ckpt_netdev_addr) * h->inet_addrs);
+ ret = ckpt_write_buffer(ctx, addrs, len);
+ }
+
+ out:
+ ckpt_hdr_put(ctx, h);
+ kfree(addrs);
+
+ return ret;
+}
+
static const struct net_device_ops loopback_ops = {
- .ndo_init = loopback_dev_init,
- .ndo_start_xmit= loopback_xmit,
- .ndo_get_stats = loopback_get_stats,
+ .ndo_init = loopback_dev_init,
+ .ndo_start_xmit = loopback_xmit,
+ .ndo_get_stats = loopback_get_stats,
+ .ndo_checkpoint = loopback_checkpoint,
};
/*
--
1.6.2.5
^ permalink raw reply related
* Network device and namespace checkpoint/restart (v3)
From: Dan Smith @ 2010-02-16 16:03 UTC (permalink / raw)
To: containers, netdev
This patch set adds checkpoint/restart support for network namespaces,
as well as the network devices within. Currently supports veth and loopback
device types.
Minor changes this time around, based on feedback from the previous
posting. Changes are detailed per-patch, and a new one at the end
adds a checkpoint handler for SIT devices (which does the bare minimum
so that we can fail when a device has no support).
^ permalink raw reply
* [PATCH 2/5] C/R: Basic support for network namespaces and devices (v4)
From: Dan Smith @ 2010-02-16 16:03 UTC (permalink / raw)
To: containers, netdev
In-Reply-To: <1266336187-19105-1-git-send-email-danms@us.ibm.com>
When checkpointing a task tree with network namespaces, we hook into
do_checkpoint_ns() along with the others. Any devices in a given namespace
are checkpointed (including their peer, in the case of veth) sequentially.
Each network device stores a list of protocol addresses, as well as other
information, such as hardware address.
This patch supports veth pairs, as well as the loopback adapter. The
loopback support is there to make sure that any additional addresses and
state (such as up/down) is copied to the loopback adapter that we are
given in the new network namespace.
On restart, we instantiate new network namespaces and veth pairs as
necessary. Any device we encounter that isn't in a network namespace
that was checkpointed as part of a task is left in the namespace of the
restarting process. This will be the case for a veth half that exists
in the init netns to provide network access to a container.
Still to do are:
1. Routes
2. Netfilter rules
3. IPv6 addresses
4. Other virtual device types (e.g. bridges)
5. Multicast
6. Device config info (ipv4_devconf)
7. Additional ipv4 address attributes
Changes in v4:
- Fix allocation under lock in ckpt_netdev_inet_addrs()
- Add comment for case where there is no netns info in checkpoint image
- Fix inner structure alignment in netdev_addr header
- Fix instances of kfree(skb)
- Remove init_netns_ref from container header and checkpoint context
- Add 'extern' to checkpoint.h prototypes
- Swizzle do_restore_netns() to handle netns more like the others
- Return E2BIG for failure case when collecting inet addrs
- Report case where device doesn't support checkpoint
- Remove nested netns check from may_checkpoint_task()
- Move veth-specific netdev attributes into unioned struct to set an
example for specific attributes of additional device types
- Add 'sit' device restore path that doesn't really do anything
- Fail instead of skip when encountering a device with no checkpoint
support
Changes in v3:
- Use dev->checkpoint() for per-device checkpoint operation
- Use RTNL for veth pair creation on restart
- Export some of the functions that will be needed by dev->ndo_checkpoint()
Changes in v2:
- Add CONFIG_CHECKPOINT_NETNS that is dependent on NET, NET_NS, and
CHECKPOINT. Conditionally compile the checkpoint_dev code based on it.
- Updated comment on should_checkpoint_netdev()
- Updated checkpoint_netdev() to explicitly check for "veth" in name
- Changed checkpoint_netns() to use BUG() for impossible condition
- Fixed a bug on restart with all devices in the init netns
- Lock the dev_base_lock while traversing interface addresses
- Collect all addresses for an interface before writing out in one
single pass
Signed-off-by: Dan Smith <danms@us.ibm.com>
Cc: netdev@vger.kernel.org
---
checkpoint/checkpoint.c | 18 +-
checkpoint/objhash.c | 48 +++
include/linux/checkpoint.h | 23 ++
include/linux/checkpoint_hdr.h | 54 +++
include/linux/checkpoint_types.h | 1 +
kernel/nsproxy.c | 24 ++-
net/Kconfig | 4 +
net/Makefile | 1 +
net/checkpoint_dev.c | 703 ++++++++++++++++++++++++++++++++++++++
9 files changed, 864 insertions(+), 12 deletions(-)
create mode 100644 net/checkpoint_dev.c
diff --git a/checkpoint/checkpoint.c b/checkpoint/checkpoint.c
index b4e0021..119f093 100644
--- a/checkpoint/checkpoint.c
+++ b/checkpoint/checkpoint.c
@@ -185,11 +185,10 @@ static int checkpoint_container(struct ckpt_ctx *ctx)
h = ckpt_hdr_get_type(ctx, sizeof(*h), CKPT_HDR_CONTAINER);
if (!h)
return -ENOMEM;
- ret = ckpt_write_obj(ctx, &h->h);
- ckpt_hdr_put(ctx, h);
+ ret = ckpt_write_obj(ctx, &h->h);
if (ret < 0)
- return ret;
+ goto out;
memset(ctx->lsm_name, 0, CHECKPOINT_LSM_NAME_MAX + 1);
strlcpy(ctx->lsm_name, security_get_lsm_name(),
@@ -197,9 +196,13 @@ static int checkpoint_container(struct ckpt_ctx *ctx)
ret = ckpt_write_buffer(ctx, ctx->lsm_name,
CHECKPOINT_LSM_NAME_MAX + 1);
if (ret < 0)
- return ret;
+ goto out;
- return security_checkpoint_header(ctx);
+ ret = security_checkpoint_header(ctx);
+ out:
+ ckpt_hdr_put(ctx, h);
+
+ return ret;
}
/* write the checkpoint trailer */
@@ -285,11 +288,6 @@ static int may_checkpoint_task(struct ckpt_ctx *ctx, struct task_struct *t)
_ckpt_err(ctx, -EPERM, "%(T)Nested mnt_ns unsupported\n");
ret = -EPERM;
}
- /* no support for >1 private netns */
- if (nsproxy->net_ns != ctx->root_nsproxy->net_ns) {
- _ckpt_err(ctx, -EPERM, "%(T)Nested net_ns unsupported\n");
- ret = -EPERM;
- }
/* no support for >1 private pidns */
if (nsproxy->pid_ns != ctx->root_nsproxy->pid_ns) {
_ckpt_err(ctx, -EPERM, "%(T)Nested pid_ns unsupported\n");
diff --git a/checkpoint/objhash.c b/checkpoint/objhash.c
index 4ca7799..729fbe5 100644
--- a/checkpoint/objhash.c
+++ b/checkpoint/objhash.c
@@ -348,6 +348,36 @@ static void lsm_string_drop(void *ptr, int lastref)
kref_put(&s->kref, lsm_string_free);
}
+static int netns_grab(void *ptr)
+{
+ struct net *net = ptr;
+
+ get_net(net);
+ return 0;
+}
+
+static void netns_drop(void *ptr, int lastref)
+{
+ struct net *net = ptr;
+
+ put_net(net);
+}
+
+static int netdev_grab(void *ptr)
+{
+ struct net_device *dev = ptr;
+
+ dev_hold(dev);
+ return 0;
+}
+
+static void netdev_drop(void *ptr, int lastref)
+{
+ struct net_device *dev = ptr;
+
+ dev_put(dev);
+}
+
/* security context strings */
static int checkpoint_lsm_string(struct ckpt_ctx *ctx, void *ptr);
static struct ckpt_lsm_string *restore_lsm_string(struct ckpt_ctx *ctx);
@@ -550,6 +580,24 @@ static struct ckpt_obj_ops ckpt_obj_ops[] = {
.checkpoint = checkpoint_lsm_string,
.restore = restore_lsm_string_wrap,
},
+ /* Network Namespace Object */
+ {
+ .obj_name = "NET_NS",
+ .obj_type = CKPT_OBJ_NET_NS,
+ .ref_grab = netns_grab,
+ .ref_drop = netns_drop,
+ .checkpoint = checkpoint_netns,
+ .restore = restore_netns,
+ },
+ /* Network Device Object */
+ {
+ .obj_name = "NET_DEV",
+ .obj_type = CKPT_OBJ_NETDEV,
+ .ref_grab = netdev_grab,
+ .ref_drop = netdev_drop,
+ .checkpoint = checkpoint_netdev,
+ .restore = restore_netdev,
+ },
};
diff --git a/include/linux/checkpoint.h b/include/linux/checkpoint.h
index 7101d6f..a25bac1 100644
--- a/include/linux/checkpoint.h
+++ b/include/linux/checkpoint.h
@@ -35,6 +35,7 @@
#include <linux/checkpoint_types.h>
#include <linux/checkpoint_hdr.h>
#include <linux/err.h>
+#include <linux/inetdevice.h>
#include <net/sock.h>
/* sycall helpers */
@@ -119,6 +120,28 @@ extern int ckpt_sock_getnames(struct ckpt_ctx *ctx,
extern struct sk_buff *sock_restore_skb(struct ckpt_ctx *ctx, struct sock *sk);
extern void sock_listening_list_free(struct list_head *head);
+#ifdef CONFIG_CHECKPOINT_NETNS
+extern int checkpoint_netns(struct ckpt_ctx *ctx, void *ptr);
+extern void *restore_netns(struct ckpt_ctx *ctx);
+extern int checkpoint_netdev(struct ckpt_ctx *ctx, void *ptr);
+extern void *restore_netdev(struct ckpt_ctx *ctx);
+
+extern int ckpt_netdev_in_init_netns(struct ckpt_ctx *ctx,
+ struct net_device *dev);
+extern int ckpt_netdev_inet_addrs(struct in_device *indev,
+ struct ckpt_netdev_addr *list[]);
+extern int ckpt_netdev_hwaddr(struct net_device *dev,
+ struct ckpt_hdr_netdev *h);
+extern struct ckpt_hdr_netdev *ckpt_netdev_base(struct ckpt_ctx *ctx,
+ struct net_device *dev,
+ struct ckpt_netdev_addr *addrs[]);
+#else
+# define checkpoint_netns NULL
+# define restore_netns NULL
+# define checkpoint_netdev NULL
+# define restore_netdev NULL
+#endif
+
/* ckpt kflags */
#define ckpt_set_ctx_kflag(__ctx, __kflag) \
set_bit(__kflag##_BIT, &(__ctx)->kflags)
diff --git a/include/linux/checkpoint_hdr.h b/include/linux/checkpoint_hdr.h
index e591fd1..1fa0482 100644
--- a/include/linux/checkpoint_hdr.h
+++ b/include/linux/checkpoint_hdr.h
@@ -181,6 +181,12 @@ enum {
#define CKPT_HDR_SOCKET_UNIX CKPT_HDR_SOCKET_UNIX
CKPT_HDR_SOCKET_INET,
#define CKPT_HDR_SOCKET_INET CKPT_HDR_SOCKET_INET
+ CKPT_HDR_NET_NS,
+#define CKPT_HDR_NET_NS CKPT_HDR_NET_NS
+ CKPT_HDR_NETDEV,
+#define CKPT_HDR_NETDEV CKPT_HDR_NETDEV
+ CKPT_HDR_NETDEV_ADDR,
+#define CKPT_HDR_NETDEV_ADDR CKPT_HDR_NETDEV_ADDR
CKPT_HDR_TAIL = 9001,
#define CKPT_HDR_TAIL CKPT_HDR_TAIL
@@ -253,6 +259,10 @@ enum obj_type {
#define CKPT_OBJ_SECURITY_PTR CKPT_OBJ_SECURITY_PTR
CKPT_OBJ_SECURITY,
#define CKPT_OBJ_SECURITY CKPT_OBJ_SECURITY
+ CKPT_OBJ_NET_NS,
+#define CKPT_OBJ_NET_NS CKPT_OBJ_NET_NS
+ CKPT_OBJ_NETDEV,
+#define CKPT_OBJ_NETDEV CKPT_OBJ_NETDEV
CKPT_OBJ_MAX
#define CKPT_OBJ_MAX CKPT_OBJ_MAX
};
@@ -313,6 +323,7 @@ struct ckpt_hdr_tail {
/* container configuration section header */
struct ckpt_hdr_container {
struct ckpt_hdr h;
+ __s32 init_netns_ref;
/*
* the header is followed by the string:
* char lsm_name[SECURITY_NAME_MAX + 1]
@@ -434,6 +445,7 @@ struct ckpt_hdr_ns {
struct ckpt_hdr h;
__s32 uts_objref;
__s32 ipc_objref;
+ __s32 net_objref;
} __attribute__((aligned(8)));
/* cannot include <linux/tty.h> from userspace, so define: */
@@ -758,6 +770,48 @@ struct ckpt_hdr_file_socket {
__s32 sock_objref;
} __attribute__((aligned(8)));
+struct ckpt_hdr_netns {
+ struct ckpt_hdr h;
+ __s32 this_ref;
+} __attribute__((aligned(8)));
+
+enum ckpt_netdev_types {
+ CKPT_NETDEV_LO,
+ CKPT_NETDEV_VETH,
+ CKPT_NETDEV_SIT,
+};
+
+struct ckpt_hdr_netdev {
+ struct ckpt_hdr h;
+ __s32 netns_ref;
+ union {
+ struct {
+ __s32 this_ref;
+ __s32 peer_ref;
+ } veth;
+ };
+ __u32 inet_addrs;
+ __u16 type;
+ __u16 flags;
+ __u8 hwaddr[6];
+} __attribute__((aligned(8)));
+
+enum ckpt_netdev_addr_types {
+ CKPT_NETDEV_ADDR_IPV4,
+};
+
+struct ckpt_netdev_addr {
+ __u16 type;
+ union {
+ struct {
+ __u32 inet4_local;
+ __u32 inet4_address;
+ __u32 inet4_mask;
+ __u32 inet4_broadcast;
+ };
+ } __attribute__((aligned(8)));
+} __attribute__((aligned(8)));
+
struct ckpt_hdr_eventpoll_items {
struct ckpt_hdr h;
__s32 epfile_objref;
diff --git a/include/linux/checkpoint_types.h b/include/linux/checkpoint_types.h
index 51efd5a..e646ec6 100644
--- a/include/linux/checkpoint_types.h
+++ b/include/linux/checkpoint_types.h
@@ -86,6 +86,7 @@ struct ckpt_ctx {
wait_queue_head_t ghostq; /* waitqueue for ghost tasks */
struct cred *realcred, *ecred; /* tmp storage for cred at restart */
struct list_head listen_sockets;/* listening parent sockets */
+ int init_netns_ref; /* Objref of root net namespace */
struct ckpt_stats stats; /* statistics */
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index b0e71f2..e6c84cd 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -248,6 +248,11 @@ int ckpt_collect_ns(struct ckpt_ctx *ctx, struct task_struct *t)
ret = ckpt_obj_collect(ctx, nsproxy->uts_ns, CKPT_OBJ_UTS_NS);
if (ret < 0)
goto out;
+#ifdef CONFIG_CHECKPOINT_NETNS
+ ret = ckpt_obj_collect(ctx, nsproxy->net_ns, CKPT_OBJ_NET_NS);
+ if (ret < 0)
+ goto out;
+#endif
ret = ckpt_obj_collect(ctx, nsproxy->ipc_ns, CKPT_OBJ_IPC_NS);
if (ret < 0)
goto out;
@@ -288,6 +293,12 @@ static int do_checkpoint_ns(struct ckpt_ctx *ctx, struct nsproxy *nsproxy)
if (ret < 0)
goto out;
h->ipc_objref = ret;
+#ifdef CONFIG_CHECKPOINT_NETNS
+ ret = checkpoint_obj(ctx, nsproxy->net_ns, CKPT_OBJ_NET_NS);
+ if (ret < 0)
+ goto out;
+ h->net_objref = ret;
+#endif
/* FIXME: for now, only marked visited to pacify leaks */
ret = ckpt_obj_visit(ctx, nsproxy->mnt_ns, CKPT_OBJ_MNT_NS);
@@ -312,6 +323,7 @@ static struct nsproxy *do_restore_ns(struct ckpt_ctx *ctx)
struct nsproxy *nsproxy = NULL;
struct uts_namespace *uts_ns;
struct ipc_namespace *ipc_ns;
+ struct net *net_ns;
int ret;
h = ckpt_read_obj_type(ctx, sizeof(*h), CKPT_HDR_NS);
@@ -333,6 +345,14 @@ static struct nsproxy *do_restore_ns(struct ckpt_ctx *ctx)
ret = PTR_ERR(ipc_ns);
goto out;
}
+ if (h->net_objref == 0)
+ net_ns = current->nsproxy->net_ns;
+ else
+ net_ns = ckpt_obj_fetch(ctx, h->net_objref, CKPT_OBJ_NET_NS);
+ if (IS_ERR(net_ns)) {
+ ret = PTR_ERR(net_ns);
+ goto out;
+ }
#if defined(COFNIG_UTS_NS) || defined(CONFIG_IPC_NS)
ret = -ENOMEM;
@@ -344,13 +364,13 @@ static struct nsproxy *do_restore_ns(struct ckpt_ctx *ctx)
nsproxy->uts_ns = uts_ns;
get_ipc_ns(ipc_ns);
nsproxy->ipc_ns = ipc_ns;
+ get_net(net_ns);
+ nsproxy->net_ns = net_ns;
get_pid_ns(current->nsproxy->pid_ns);
nsproxy->pid_ns = current->nsproxy->pid_ns;
get_mnt_ns(current->nsproxy->mnt_ns);
nsproxy->mnt_ns = current->nsproxy->mnt_ns;
- get_net(current->nsproxy->net_ns);
- nsproxy->net_ns = current->nsproxy->net_ns;
#else
nsproxy = current->nsproxy;
get_nsproxy(nsproxy);
diff --git a/net/Kconfig b/net/Kconfig
index 041c35e..64dd3cd 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -276,4 +276,8 @@ source "net/wimax/Kconfig"
source "net/rfkill/Kconfig"
source "net/9p/Kconfig"
+config CHECKPOINT_NETNS
+ bool
+ default y if NET && NET_NS && CHECKPOINT
+
endif # if NET
diff --git a/net/Makefile b/net/Makefile
index 74b038f..570ee98 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -67,3 +67,4 @@ endif
obj-$(CONFIG_WIMAX) += wimax/
obj-$(CONFIG_CHECKPOINT) += checkpoint.o
+obj-$(CONFIG_CHECKPOINT_NETNS) += checkpoint_dev.o
diff --git a/net/checkpoint_dev.c b/net/checkpoint_dev.c
new file mode 100644
index 0000000..3515560
--- /dev/null
+++ b/net/checkpoint_dev.c
@@ -0,0 +1,703 @@
+/*
+ * Copyright 2010 IBM Corporation
+ *
+ * Author(s): Dan Smith <danms@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2 of the
+ * License.
+ */
+
+#include <linux/sched.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/inetdevice.h>
+#include <linux/veth.h>
+#include <linux/checkpoint.h>
+#include <linux/checkpoint_hdr.h>
+#include <linux/deferqueue.h>
+
+#include <net/net_namespace.h>
+#include <net/sch_generic.h>
+
+struct dq_netdev {
+ struct net_device *dev;
+ struct ckpt_ctx *ctx;
+};
+
+static int __kern_devinet_ioctl(struct net *net, unsigned int cmd, void *arg)
+{
+ mm_segment_t fs;
+ int ret;
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = devinet_ioctl(net, cmd, arg);
+ set_fs(fs);
+
+ return ret;
+}
+
+static int __kern_dev_ioctl(struct net *net, unsigned int cmd, void *arg)
+{
+ mm_segment_t fs;
+ int ret;
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = dev_ioctl(net, cmd, arg);
+ set_fs(fs);
+
+ return ret;
+}
+
+static struct socket *rtnl_open(void)
+{
+ struct socket *sock;
+ int ret;
+
+ ret = sock_create(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, &sock);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ return sock;
+}
+
+static int rtnl_close(struct socket *rtnl)
+{
+ if (rtnl)
+ return kernel_sock_shutdown(rtnl, SHUT_RDWR);
+ else
+ return 0;
+}
+
+static struct nlmsghdr *rtnl_get_response(struct socket *rtnl,
+ struct sk_buff **skb)
+{
+ int ret;
+ long timeo = MAX_SCHEDULE_TIMEOUT;
+ struct nlmsghdr *nlh;
+
+ ret = sk_wait_data(rtnl->sk, &timeo);
+ if (!ret)
+ return ERR_PTR(-EPIPE);
+
+ *skb = skb_dequeue(&rtnl->sk->sk_receive_queue);
+ if (!*skb)
+ return ERR_PTR(-EPIPE);
+
+ ret = -EINVAL;
+ nlh = nlmsg_hdr(*skb);
+ if (!nlh)
+ goto err;
+
+ if (nlh->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *errmsg = nlmsg_data(nlh);
+ ret = errmsg->error;
+ goto err;
+ }
+
+ return nlh;
+ err:
+ kfree_skb(*skb);
+ *skb = NULL;
+
+ return ERR_PTR(ret);
+}
+
+int ckpt_netdev_in_init_netns(struct ckpt_ctx *ctx, struct net_device *dev)
+{
+ return dev->nd_net == current->nsproxy->net_ns;
+}
+
+int ckpt_netdev_hwaddr(struct net_device *dev, struct ckpt_hdr_netdev *h)
+{
+ struct net *net = dev->nd_net;
+ struct ifreq req;
+ int ret;
+
+ memcpy(req.ifr_name, dev->name, IFNAMSIZ);
+ ret = __kern_dev_ioctl(net, SIOCGIFFLAGS, &req);
+ h->flags = req.ifr_flags;
+ if (ret < 0)
+ return ret;
+
+ ret = __kern_dev_ioctl(net, SIOCGIFHWADDR, &req);
+ if (ret < 0)
+ return ret;
+
+ memcpy(h->hwaddr, req.ifr_hwaddr.sa_data, sizeof(h->hwaddr));
+
+ return 0;
+}
+
+int ckpt_netdev_inet_addrs(struct in_device *indev,
+ struct ckpt_netdev_addr *_abuf[])
+{
+ struct ckpt_netdev_addr *abuf = NULL;
+ struct in_ifaddr *addr = indev->ifa_list;
+ int pages = 0;
+ int addrs = 0;
+ int max;
+
+ retry:
+ if (++pages > 4) {
+ addrs = -E2BIG;
+ goto out;
+ }
+
+ *_abuf = krealloc(abuf, PAGE_SIZE * pages, GFP_KERNEL);
+ if (*_abuf == NULL) {
+ addrs = -ENOMEM;
+ goto out;
+ }
+ abuf = *_abuf;
+
+ read_lock(&dev_base_lock);
+
+ max = (pages * PAGE_SIZE) / sizeof(*abuf);
+ while (addr) {
+ abuf[addrs].type = CKPT_NETDEV_ADDR_IPV4; /* Only IPv4 now */
+ abuf[addrs].inet4_local = addr->ifa_local;
+ abuf[addrs].inet4_address = addr->ifa_address;
+ abuf[addrs].inet4_mask = addr->ifa_mask;
+ abuf[addrs].inet4_broadcast = addr->ifa_broadcast;
+
+ addr = addr->ifa_next;
+ if (++addrs >= max) {
+ read_unlock(&dev_base_lock);
+ goto retry;
+ }
+ }
+
+ read_unlock(&dev_base_lock);
+ out:
+ if (addrs < 0) {
+ kfree(abuf);
+ *_abuf = NULL;
+ }
+
+ return addrs;
+}
+
+struct ckpt_hdr_netdev *ckpt_netdev_base(struct ckpt_ctx *ctx,
+ struct net_device *dev,
+ struct ckpt_netdev_addr *addrs[])
+{
+ struct ckpt_hdr_netdev *h;
+ int ret;
+
+ h = ckpt_hdr_get_type(ctx, sizeof(*h), CKPT_HDR_NETDEV);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
+
+ ret = ckpt_netdev_hwaddr(dev, h);
+ if (ret < 0)
+ goto out;
+
+ *addrs = NULL;
+ ret = h->inet_addrs = ckpt_netdev_inet_addrs(dev->ip_ptr, addrs);
+ if (ret < 0) {
+ if (ret == -E2BIG)
+ ckpt_err(ctx, ret,
+ "Too many inet addresses on interface %s\n",
+ dev->name);
+ goto out;
+ }
+
+ if (ckpt_netdev_in_init_netns(ctx, dev))
+ ret = h->netns_ref = 0;
+ else
+ ret = h->netns_ref = checkpoint_obj(ctx, dev->nd_net,
+ CKPT_OBJ_NET_NS);
+ out:
+ if (ret < 0) {
+ ckpt_hdr_put(ctx, h);
+ h = ERR_PTR(ret);
+ if (*addrs)
+ kfree(*addrs);
+ }
+
+ return h;
+}
+
+int checkpoint_netdev(struct ckpt_ctx *ctx, void *ptr)
+{
+ struct net_device *dev = (struct net_device *)ptr;
+
+ if (!dev->netdev_ops->ndo_checkpoint) {
+ ckpt_err(ctx, -ENOSYS,
+ "Device %s does not support checkpoint\n", dev->name);
+ return -ENOSYS;
+ }
+
+ ckpt_debug("checkpointing netdev %s\n", dev->name);
+
+ return dev->netdev_ops->ndo_checkpoint(ctx, dev);
+}
+
+int checkpoint_netns(struct ckpt_ctx *ctx, void *ptr)
+{
+ struct net *net = ptr;
+ struct net_device *dev;
+ struct ckpt_hdr_netns *h;
+ int ret;
+
+ h = ckpt_hdr_get_type(ctx, sizeof(*h), CKPT_HDR_NET_NS);
+ if (!h)
+ return -ENOMEM;
+
+ h->this_ref = ckpt_obj_lookup(ctx, net, CKPT_OBJ_NET_NS);
+ BUG_ON(h->this_ref == 0);
+
+ ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) h);
+ if (ret < 0)
+ goto out;
+
+ for_each_netdev(net, dev) {
+ if (!dev->netdev_ops->ndo_checkpoint) {
+ ckpt_debug("Device %s does not support checkpoint\n",
+ dev->name);
+ ret = -ENOSYS;
+ break;
+ }
+
+ ret = checkpoint_obj(ctx, dev, CKPT_OBJ_NETDEV);
+ if (ret < 0)
+ break;
+ }
+ out:
+ ckpt_hdr_put(ctx, h);
+
+ return ret;
+}
+
+static int restore_in_addrs(struct ckpt_ctx *ctx,
+ __u32 naddrs,
+ struct net *net,
+ struct net_device *dev)
+{
+ __u32 i;
+ int ret = 0;
+ int len = naddrs * sizeof(struct ckpt_netdev_addr);
+ struct ckpt_netdev_addr *addrs = NULL;
+
+ addrs = kmalloc(len, GFP_KERNEL);
+ if (!addrs)
+ return -ENOMEM;
+
+ ret = _ckpt_read_buffer(ctx, addrs, len);
+ if (ret < 0)
+ goto out;
+
+ for (i = 0; i < naddrs; i++) {
+ struct ckpt_netdev_addr *addr = &addrs[i];
+ struct ifreq req;
+ struct sockaddr_in *inaddr;
+
+ if (addr->type != CKPT_NETDEV_ADDR_IPV4) {
+ ret = -EINVAL;
+ ckpt_err(ctx, ret, "Unsupported netdev addr type %i\n",
+ addr->type);
+ break;
+ }
+
+ ckpt_debug("restoring %s: %x/%x/%x\n", dev->name,
+ addr->inet4_address,
+ addr->inet4_mask,
+ addr->inet4_broadcast);
+
+ memcpy(req.ifr_name, dev->name, IFNAMSIZ);
+
+ inaddr = (struct sockaddr_in *)&req.ifr_addr;
+ inaddr->sin_addr.s_addr = addr->inet4_address;
+ inaddr->sin_family = AF_INET;
+ ret = __kern_devinet_ioctl(net, SIOCSIFADDR, &req);
+ if (ret < 0) {
+ ckpt_err(ctx, ret, "Failed to set address\n");
+ break;
+ }
+
+ inaddr = (struct sockaddr_in *)&req.ifr_addr;
+ inaddr->sin_addr.s_addr = addr->inet4_mask;
+ inaddr->sin_family = AF_INET;
+ ret = __kern_devinet_ioctl(net, SIOCSIFNETMASK, &req);
+ if (ret < 0) {
+ ckpt_err(ctx, ret, "Failed to set netmask\n");
+ break;
+ }
+
+ inaddr = (struct sockaddr_in *)&req.ifr_addr;
+ inaddr->sin_addr.s_addr = addr->inet4_broadcast;
+ inaddr->sin_family = AF_INET;
+ ret = __kern_devinet_ioctl(net, SIOCSIFBRDADDR, &req);
+ if (ret < 0) {
+ ckpt_err(ctx, ret, "Failed to set broadcast\n");
+ break;
+ }
+ }
+
+ out:
+ kfree(addrs);
+
+ return ret;
+}
+
+static int veth_peer_data(struct sk_buff *skb, char *peer_name)
+{
+ struct nlattr *linkdata;
+ struct ifinfomsg ifm;
+
+ linkdata = nla_nest_start(skb, IFLA_INFO_DATA);
+ if (!linkdata)
+ return -ENOMEM;
+
+ nla_put(skb, VETH_INFO_PEER, sizeof(ifm), &ifm);
+ nla_put_string(skb, IFLA_IFNAME, peer_name);
+
+ nla_nest_end(skb, linkdata);
+
+ return 0;
+}
+
+static struct sk_buff *new_link_message(char *this_name, char *peer_name)
+{
+ int ret = -ENOMEM;
+ int flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
+ struct nlmsghdr *nlh;
+ struct sk_buff *skb;
+ struct ifinfomsg *ifm;
+ struct nlattr *linkinfo;
+
+ skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!skb)
+ goto out;
+
+ nlh = nlmsg_put(skb, 0, 0, RTM_NEWLINK, sizeof(*ifm), flags);
+ if (!nlh)
+ goto out;
+
+ ifm = nlmsg_data(nlh);
+ memset(ifm, 0, sizeof(*ifm));
+
+ ret = nla_put_string(skb, IFLA_IFNAME, this_name);
+ if (ret)
+ goto out;
+
+ ret = -ENOMEM;
+
+ linkinfo = nla_nest_start(skb, IFLA_LINKINFO);
+ if (!linkinfo)
+ goto out;
+
+ if (nla_put_string(skb, IFLA_INFO_KIND, "veth") < 0)
+ goto out;
+
+ ret = veth_peer_data(skb, peer_name);
+ if (ret < 0)
+ goto out;
+
+ nla_nest_end(skb, linkinfo);
+ nlmsg_end(skb, nlh);
+
+ out:
+ if (ret < 0) {
+ kfree_skb(skb);
+ skb = ERR_PTR(ret);
+ }
+
+ return skb;
+}
+
+static struct net_device *new_veth_pair(char *this_name, char *peer_name)
+{
+ int ret = -ENOMEM;
+ struct socket *rtnl = NULL;
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nlh;
+ struct msghdr msg;
+ struct kvec kvec;
+
+ skb = new_link_message(this_name, peer_name);
+ if (IS_ERR(skb)) {
+ ret = PTR_ERR(skb);
+ ckpt_debug("failed to create new link message: %i\n", ret);
+ skb = NULL;
+ goto out;
+ }
+
+ memset(&msg, 0, sizeof(msg));
+ kvec.iov_len = skb->len;
+ kvec.iov_base = skb->head;
+
+ rtnl = rtnl_open();
+ if (IS_ERR(rtnl)) {
+ ret = PTR_ERR(rtnl);
+ ckpt_debug("Unable to open rtnetlink socket: %i\n", ret);
+ goto out_noclose;
+ }
+
+ ret = kernel_sendmsg(rtnl, &msg, &kvec, 1, kvec.iov_len);
+ if (ret < 0)
+ goto out;
+ else if (ret != skb->len) {
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Free the send skb to make room for the receive skb */
+ kfree_skb(skb);
+
+ nlh = rtnl_get_response(rtnl, &skb);
+ if (IS_ERR(nlh)) {
+ ret = PTR_ERR(nlh);
+ ckpt_debug("RTNETLINK said: %i\n", ret);
+ }
+ out:
+ rtnl_close(rtnl);
+ out_noclose:
+ kfree_skb(skb);
+
+ if (ret < 0)
+ return ERR_PTR(ret);
+ else
+ return dev_get_by_name(current->nsproxy->net_ns, this_name);
+}
+
+static int netdev_noop(void *data)
+{
+ return 0;
+}
+
+static int netdev_cleanup(void *data)
+{
+ struct dq_netdev *dq = data;
+
+ dev_put(dq->dev);
+
+ if (dq->ctx->errno) {
+ ckpt_debug("Unregistering netdev %s\n", dq->dev->name);
+ unregister_netdev(dq->dev);
+ }
+
+ return 0;
+}
+
+static struct net_device *restore_veth(struct ckpt_ctx *ctx,
+ struct ckpt_hdr_netdev *h,
+ struct net *net)
+{
+ int ret;
+ char this_name[IFNAMSIZ];
+ char peer_name[IFNAMSIZ];
+ struct net_device *dev;
+ struct net_device *peer;
+ int didreg = 0;
+ struct ifreq req;
+ struct dq_netdev dq;
+
+ dq.ctx = ctx;
+
+ ret = _ckpt_read_buffer(ctx, this_name, IFNAMSIZ);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ ret = _ckpt_read_buffer(ctx, peer_name, IFNAMSIZ);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ ckpt_debug("restored veth netdev %s:%s\n", this_name, peer_name);
+
+ peer = ckpt_obj_try_fetch(ctx, h->veth.peer_ref, CKPT_OBJ_NETDEV);
+ if (IS_ERR(peer)) {
+ /* We're first: allocate the veth pair */
+ didreg = 1;
+ dev = new_veth_pair(this_name, peer_name);
+ if (IS_ERR(dev))
+ return dev;
+
+ peer = dev_get_by_name(current->nsproxy->net_ns, peer_name);
+ if (!peer) {
+ ret = -EINVAL;
+ goto err_dev;
+ }
+
+ dq.dev = peer;
+ ret = deferqueue_add(ctx->deferqueue, &dq, sizeof(dq),
+ netdev_noop, netdev_cleanup);
+ if (ret)
+ goto err_peer;
+
+ ret = ckpt_obj_insert(ctx, peer, h->veth.peer_ref,
+ CKPT_OBJ_NETDEV);
+ if (ret < 0)
+ /* Can't recall peer dq, so let it cleanup peer */
+ goto err_dev;
+ dev_put(peer);
+
+ dq.dev = dev;
+ ret = deferqueue_add(ctx->deferqueue, &dq, sizeof(dq),
+ netdev_noop, netdev_cleanup);
+ if (ret)
+ /* Can't recall peer dq, so let it cleanup peer */
+ goto err_dev;
+
+ } else {
+ /* We're second: get our dev from the hash */
+ dev = ckpt_obj_fetch(ctx, h->veth.this_ref, CKPT_OBJ_NETDEV);
+ if (IS_ERR(dev))
+ return dev;
+ }
+
+ /* Move to our new netns */
+ rtnl_lock();
+ ret = dev_change_net_namespace(dev, net, dev->name);
+ rtnl_unlock();
+ if (ret < 0)
+ goto out;
+
+ /* Restore MAC address */
+ memcpy(req.ifr_name, dev->name, IFNAMSIZ);
+ memcpy(req.ifr_hwaddr.sa_data, h->hwaddr, sizeof(h->hwaddr));
+ req.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+ ret = __kern_dev_ioctl(net, SIOCSIFHWADDR, &req);
+ out:
+ if (ret)
+ dev = ERR_PTR(ret);
+
+ return dev;
+
+ err_peer:
+ dev_put(peer);
+ unregister_netdev(peer);
+ err_dev:
+ dev_put(dev);
+ unregister_netdev(dev);
+
+ return ERR_PTR(ret);
+}
+
+static struct net_device *restore_lo(struct ckpt_ctx *ctx,
+ struct ckpt_hdr_netdev *h,
+ struct net *net)
+{
+ struct net_device *dev;
+ char name[IFNAMSIZ+1];
+ int ret;
+
+ dev = dev_get_by_name(net, "lo");
+ if (!dev)
+ return ERR_PTR(-EINVAL);
+
+ ret = _ckpt_read_buffer(ctx, name, IFNAMSIZ);
+ if (ret < 0)
+ goto err;
+
+ if (strncmp(dev->name, name, IFNAMSIZ) != 0) {
+ ret = dev_change_name(dev, name);
+ if (ret < 0)
+ goto err;
+ }
+
+ return dev;
+ err:
+ dev_put(dev);
+
+ return ERR_PTR(ret);
+}
+
+static struct net_device *restore_sit(struct ckpt_ctx *ctx,
+ struct ckpt_hdr_netdev *h,
+ struct net *net)
+{
+ /* Don't actually do anything for SIT devices yet */
+ return dev_get_by_name(net, "sit0");
+}
+
+void *restore_netdev(struct ckpt_ctx *ctx)
+{
+ struct ckpt_hdr_netdev *h;
+ struct net_device *dev = NULL;
+ struct ifreq req;
+ struct net *net;
+ int ret;
+
+ h = ckpt_read_obj_type(ctx, sizeof(*h), CKPT_HDR_NETDEV);
+ if (IS_ERR(h)) {
+ ckpt_err(ctx, PTR_ERR(h), "failed to read netdev\n");
+ return h;
+ }
+
+ if (h->netns_ref != 0) {
+ net = ckpt_obj_try_fetch(ctx, h->netns_ref, CKPT_OBJ_NET_NS);
+ if (IS_ERR(net)) {
+ ckpt_debug("failed to get net for %i\n", h->netns_ref);
+ ret = PTR_ERR(net);
+ net = current->nsproxy->net_ns;
+ goto out;
+ }
+ } else
+ net = current->nsproxy->net_ns;
+
+ if (h->type == CKPT_NETDEV_VETH)
+ dev = restore_veth(ctx, h, net);
+ else if (h->type == CKPT_NETDEV_LO)
+ dev = restore_lo(ctx, h, net);
+ else if (h->type == CKPT_NETDEV_SIT)
+ dev = restore_sit(ctx, h, net);
+ else
+ dev = ERR_PTR(-EINVAL);
+
+ if (IS_ERR(dev)) {
+ ret = PTR_ERR(dev);
+ ckpt_err(ctx, ret, "Netdev type %i not supported\n", h->type);
+ goto out;
+ }
+
+ /* Restore flags (which will likely bring the interface up) */
+ memcpy(req.ifr_name, dev->name, IFNAMSIZ);
+ req.ifr_flags = h->flags;
+ ret = __kern_dev_ioctl(net, SIOCSIFFLAGS, &req);
+ if (ret < 0)
+ goto out;
+
+ if (h->inet_addrs > 0)
+ ret = restore_in_addrs(ctx, h->inet_addrs, net, dev);
+ out:
+ if (ret) {
+ ckpt_err(ctx, ret, "Failed to restore netdevice\n");
+ if ((h->type == CKPT_NETDEV_VETH) && !IS_ERR(dev)) {
+ dev_put(dev);
+ }
+ dev = ERR_PTR(ret);
+ } else
+ ckpt_debug("restored netdev %s\n", dev->name);
+
+ ckpt_hdr_put(ctx, h);
+
+ return dev;
+}
+
+void *restore_netns(struct ckpt_ctx *ctx)
+{
+ struct ckpt_hdr_netns *h;
+ struct net *net;
+
+ h = ckpt_read_obj_type(ctx, sizeof(*h), CKPT_HDR_NET_NS);
+ if (IS_ERR(h)) {
+ ckpt_err(ctx, PTR_ERR(h), "failed to read netns\n");
+ return h;
+ }
+
+ if (h->this_ref != 0) {
+ net = copy_net_ns(CLONE_NEWNET, current->nsproxy->net_ns);
+ if (IS_ERR(net))
+ goto out;
+ } else
+ net = current->nsproxy->net_ns;
+ out:
+ ckpt_hdr_put(ctx, h);
+
+ return net;
+}
--
1.6.2.5
^ permalink raw reply related
* [PATCH 3/5] Add checkpoint support for veth devices (v2)
From: Dan Smith @ 2010-02-16 16:03 UTC (permalink / raw)
To: containers, netdev
In-Reply-To: <1266336187-19105-1-git-send-email-danms@us.ibm.com>
Adds an ndo_checkpoint() handler for veth devices to checkpoint themselves.
Writes out the pairing information, addresses, and initiates a checkpoint
on the peer if the peer won't be reached from another netns. Throws an
error of our peer's netns isn't already in the hash (i.e., a tree leak).
Changes in v2:
- Fix check detecting if peer is in the init netns
Signed-off-by: Dan Smith <danms@us.ibm.com>
---
drivers/net/veth.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 76 insertions(+), 0 deletions(-)
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 3a15de5..db92de8 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -16,6 +16,9 @@
#include <net/xfrm.h>
#include <linux/veth.h>
+#include <linux/checkpoint.h>
+#include <linux/checkpoint_hdr.h>
+
#define DRV_NAME "veth"
#define DRV_VERSION "1.0"
@@ -284,6 +287,76 @@ static void veth_dev_free(struct net_device *dev)
free_netdev(dev);
}
+#ifdef CONFIG_CHECKPOINT
+static int veth_checkpoint(struct ckpt_ctx *ctx, struct net_device *dev)
+{
+ struct ckpt_hdr_netdev *h;
+ struct veth_priv *priv = netdev_priv(dev);
+ struct net_device *peer = priv->peer;
+ struct ckpt_netdev_addr *addrs;
+ int ret;
+ int n;
+
+ if (!peer) {
+ ckpt_err(ctx, -EINVAL, "veth device has no peer!\n");
+ return -EINVAL;
+ }
+
+ h = ckpt_netdev_base(ctx, dev, &addrs);
+ if (IS_ERR(h))
+ return PTR_ERR(h);
+
+ h->type = CKPT_NETDEV_VETH;
+
+ ret = h->veth.this_ref = ckpt_obj_lookup_add(ctx, dev,
+ CKPT_OBJ_NETDEV, &n);
+ if (ret < 0)
+ goto out;
+
+ ret = h->veth.peer_ref = ckpt_obj_lookup_add(ctx, peer,
+ CKPT_OBJ_NETDEV, &n);
+ if (ret < 0)
+ goto out;
+
+ ret = ckpt_write_obj(ctx, (struct ckpt_hdr *)h);
+ if (ret < 0)
+ goto out;
+
+ ret = ckpt_write_buffer(ctx, dev->name, IFNAMSIZ);
+ if (ret < 0)
+ goto out;
+
+ ret = ckpt_write_buffer(ctx, peer->name, IFNAMSIZ);
+ if (ret < 0)
+ goto out;
+
+ if (h->inet_addrs > 0) {
+ int len = (sizeof(struct ckpt_netdev_addr) * h->inet_addrs);
+ ret = ckpt_write_buffer(ctx, addrs, len);
+ if (ret)
+ goto out;
+ }
+
+ /* Only checkpoint peer if we're not going to arrive at it
+ * via another task's netns. Fail if the pipe exits
+ * our container to a netns not already in the hash
+ */
+ if (ckpt_netdev_in_init_netns(ctx, peer))
+ ret = checkpoint_obj(ctx, peer, CKPT_OBJ_NETDEV);
+ else if (!ckpt_obj_lookup(ctx, peer->nd_net, CKPT_OBJ_NET_NS)) {
+ ret = -EINVAL;
+ ckpt_err(ctx, ret,
+ "Peer %s of %s not in checkpointed namespaces\n",
+ peer->name, dev->name);
+ }
+ out:
+ ckpt_hdr_put(ctx, h);
+ kfree(addrs);
+
+ return ret;
+}
+#endif
+
static const struct net_device_ops veth_netdev_ops = {
.ndo_init = veth_dev_init,
.ndo_open = veth_open,
@@ -292,6 +365,9 @@ static const struct net_device_ops veth_netdev_ops = {
.ndo_change_mtu = veth_change_mtu,
.ndo_get_stats = veth_get_stats,
.ndo_set_mac_address = eth_mac_addr,
+#ifdef CONFIG_CHECKPOINT
+ .ndo_checkpoint = veth_checkpoint,
+#endif
};
static void veth_setup(struct net_device *dev)
--
1.6.2.5
^ permalink raw reply related
* [PATCH 1/5] Add checkpoint and collect hooks to net_device_ops
From: Dan Smith @ 2010-02-16 16:03 UTC (permalink / raw)
To: containers, netdev
In-Reply-To: <1266336187-19105-1-git-send-email-danms@us.ibm.com>
These will be implemented per-driver by those that support such
operations.
Signed-off-by: Dan Smith <danms@us.ibm.com>
---
include/linux/netdevice.h | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index a3fccc8..415a791 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -673,6 +673,12 @@ struct net_device_ops {
int (*ndo_fcoe_get_wwn)(struct net_device *dev,
u64 *wwn, int type);
#endif
+#ifdef CONFIG_CHECKPOINT
+ int (*ndo_collect)(struct ckpt_ctx *ctx,
+ struct net_device *dev);
+ int (*ndo_checkpoint)(struct ckpt_ctx *ctx,
+ struct net_device *dev);
+#endif
};
/*
--
1.6.2.5
^ permalink raw reply related
* Re: [PATCH net-next-2.6 v2 08/12] net-caif: add CAIF socket implementation
From: Marcel Holtmann @ 2010-02-16 15:57 UTC (permalink / raw)
To: sjur.brandeland
Cc: davem, netdev, stefano.babic, randy.dunlap, daniel.martensson,
kaber
In-Reply-To: <1266328017-28406-9-git-send-email-sjur.brandeland@stericsson.com>
Hi Sjur,
> +static int setsockopt(struct socket *sock,
> + int lvl, int opt, char __user *ov, unsigned int ol)
> +{
> + struct sock *sk = sock->sk;
> + struct caifsock *cf_sk = container_of(sk, struct caifsock, sk);
> + int prio, linksel;
> + struct ifreq ifreq;
> + struct caif_param caif_param;
> + if (lvl != SOL_CAIF) {
> + pr_debug("CAIF: %s(): setsockopt bad level\n", __func__);
> + return -ENOPROTOOPT;
> + }
> + if (STATE_IS_OPEN(cf_sk)) {
> + pr_debug("CAIF: %s(): setsockopt "
> + "cannot be done on a connected socket\n",
> + __func__);
> + return -ENOPROTOOPT;
> + }
> + switch (opt) {
> + case CAIFSO_LINK_SELECT:
> + if (ol < sizeof(int)) {
> + pr_debug("CAIF: %s(): setsockopt"
> + " CAIFSO_CHANNEL_CONFIG bad size\n", __func__);
> + return -EINVAL;
> + }
> + if (copy_from_user(&linksel, ov, sizeof(int)))
> + return -EINVAL;
> + lock_sock(&(cf_sk->sk));
> + cf_sk->config.phy_pref = linksel;
> + pr_debug("CAIF: %s(): Setting sockopt pref=%dn", __func__,
> + cf_sk->config.phy_pref);
> + release_sock(&cf_sk->sk);
> + return 0;
> +
> + case SO_PRIORITY:
> + if (ol < sizeof(int)) {
> + pr_debug("CAIF: %s(): setsockopt"
> + " SO_PRIORITY bad size\n", __func__);
> + return -EINVAL;
> + }
> + if (copy_from_user(&prio, ov, sizeof(int)))
> + return -EINVAL;
> + lock_sock(&(cf_sk->sk));
> + cf_sk->config.phy_pref = prio;
> + pr_debug("CAIF: %s(): Setting sockopt pref=%dn", __func__,
> + cf_sk->config.phy_pref);
> + release_sock(&cf_sk->sk);
> + return 0;
> +
> + case SO_BINDTODEVICE:
> + if (ol < sizeof(struct ifreq)) {
> + pr_debug("CAIF: %s(): setsockopt"
> + " SO_PRIORITY bad size\n", __func__);
> + return -EINVAL;
> + }
> + if (copy_from_user(&ifreq, ov, sizeof(ifreq)))
> + return -EFAULT;
> + lock_sock(&(cf_sk->sk));
> + strncpy(cf_sk->config.phy_name, ifreq.ifr_name,
> + sizeof(cf_sk->config.phy_name));
> + cf_sk->config.phy_name[sizeof(cf_sk->config.phy_name)-1] = 0;
> +
> + release_sock(&cf_sk->sk);
> + return 0;
I would have implemented SO_PRIORITY and SO_BINDTODEVICE on SOL_SOCKET
level. Having them on SOL_CAIF level is not really useful.
Regards
Marcel
^ permalink raw reply
* Re: IPv6 20/62: reassembly: replace magic number with macro definitions
From: Patrick McHardy @ 2010-02-16 15:47 UTC (permalink / raw)
To: Joe Perches; +Cc: Shan Wei, davem, netdev, netfilter-devel
In-Reply-To: <1266335018.29987.50.camel@Joe-Laptop.home>
Joe Perches wrote:
>> @@ -246,6 +246,8 @@ extern int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb);
>> int ip6_frag_nqueues(struct net *net);
>> int ip6_frag_mem(struct net *net);
>>
>> +#define IPV6_FRAG_HIGH_THRESH 262144 /* == 256*1024 */
>> +#define IPV6_FRAG_LOW_THRESH 196608 /* == 192*1024 */
>> #define IPV6_FRAG_TIMEOUT (60*HZ) /* 60 seconds */
>
> 196608 isn't a number I want to remember.
> Is this better as:
>
> #define IPV6_FRAG_HIGH_THRESH (256 * 1024) /* 262144 */
> #define IPV6_FRAG_LOW_THRESH (192 * 1024) /* 196608 */
Please send a patch, I'll apply it once these patches are in Dave's
tree.
^ permalink raw reply
* Re: IPv6 20/62: reassembly: replace magic number with macro definitions
From: Joe Perches @ 2010-02-16 15:43 UTC (permalink / raw)
To: Patrick McHardy, Shan Wei; +Cc: davem, netdev, netfilter-devel
In-Reply-To: <20100216145545.2796.47717.sendpatchset@x2.localnet>
On Tue, 2010-02-16 at 15:55 +0100, Patrick McHardy wrote:
> commit 7c070aa947d1a4105742378579c267f6e7fd08a1
> Author: Shan Wei <shanwei@cn.fujitsu.com>
> Date: Wed Jan 20 10:42:41 2010 +0100
>
> IPv6: reassembly: replace magic number with macro definitions
>
> Use macro to define high/low thresh value, refer to IPV6_FRAG_TIMEOUT.
>
> Signed-off-by: Shan Wei <shanwei@cn.fujitsu.com>
> Acked-by: David S. Miller <davem@davemloft.net>
> Signed-off-by: Patrick McHardy <kaber@trash.net>
>
> diff --git a/include/net/ipv6.h b/include/net/ipv6.h
> index ccab594..299bbf5 100644
> --- a/include/net/ipv6.h
> +++ b/include/net/ipv6.h
> @@ -246,6 +246,8 @@ extern int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb);
> int ip6_frag_nqueues(struct net *net);
> int ip6_frag_mem(struct net *net);
>
> +#define IPV6_FRAG_HIGH_THRESH 262144 /* == 256*1024 */
> +#define IPV6_FRAG_LOW_THRESH 196608 /* == 192*1024 */
> #define IPV6_FRAG_TIMEOUT (60*HZ) /* 60 seconds */
196608 isn't a number I want to remember.
Is this better as:
#define IPV6_FRAG_HIGH_THRESH (256 * 1024) /* 262144 */
#define IPV6_FRAG_LOW_THRESH (192 * 1024) /* 196608 */
^ permalink raw reply
* Re: Re: Re: [PATCH 18/23 v3] mlx4_core: Managing common port
From: Yevgeny Petrilin @ 2010-02-16 15:38 UTC (permalink / raw)
To: or.gerlitz; +Cc: yevgenyp, Roland Dreier, netdev, tziporet, liranl
On Sunday -10,January,-28163 09:59 PM, Or Gerlitz [or.gerlitz@gmail.com] wrote:
> On Wed, Feb 10, 2010 at 7:22 PM, Yevgeny Petrilin <yevgenyp@mellanox.co.il> wrote:
>> On Sunday -10,January,-28163 09:59 PM, Or Gerlitz [or.gerlitz@gmail.com] wrote:
>
>> The multicast bloom filter is a false-positive filter per port.
>> All multicast packets go through the Multicast tables mechanism where
>> every PF/VF is registered for every multicast address
>
> okay, so the bloom filter is going and exact match is coming, understood.
>
>
>>> As for the false-positive vlan filter, I understand that this means
>>> further filtering has to be applied by some driver. Where you thinking on the 802q driver? what about the case where a VF driver is assigned a vlan, does the mlx4 VF code does filtering?
>
>> The deal with the VLAN filter is similar, it includes all VIDs that some PF/VF requested.
>
> So for a given VID, a unicast packet carrying it will be dispatched to all the PFs/VFs which have registered this VID? I guess this isn't the case, so please elaborate.
No, this is not the case. My statement says that the VLAN filter became false positive as well.
Dispatching of packet is done by its destination Mac and not VID.
We will add support for dispatching packets by Mac+VID soon.
>
>> We plan to add a MAC+VLAN filter implementation, that would cancel the need in this filter.
>
> I'm still not clear in what level you expect the software filtering to happen
HW filtering, the SW configures the filter.
Yevgeny
^ permalink raw reply
* Re: ipv6: why disable ipv6 on last address removal?
From: Jiri Bohac @ 2010-02-16 15:28 UTC (permalink / raw)
To: David Miller; +Cc: yoshfuji, jbohac, netdev
In-Reply-To: <20100104.224436.107234750.davem@davemloft.net>
On Mon, Jan 04, 2010 at 10:44:36PM -0800, David Miller wrote:
> From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
> Date: Wed, 09 Dec 2009 16:39:15 +0900
>
> > Well, AFAIK, it is basically ancient thing.
> > Some (rather new) paramters are exactly related bringing
> > up each interface.
> >
> > Such parameters should be set _before_ it is brought up.
> > For now, people can do this using the "default" value.
>
> I think we should retain inet6 device private structure after
> we allocate it the first time that an ipv6 action occurs for
> the device, exactly so that settings made earlier can be
> retained.
Good, this was what my patch is doing. I still think this is as
simple as:
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2185,7 +2185,7 @@ static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx,
disable IPv6 on this interface.
*/
if (idev->addr_list == NULL)
- addrconf_ifdown(idev->dev, 1);
+ addrconf_ifdown(idev->dev, 0);
return 0;
}
}
It does the same thing as NETDEV_DOWN down instead of the current
NETDEV_UNREGISTER-like behaviour. Could this perhaps be tried in
-next?
Thanks,
--
Jiri Bohac <jbohac@suse.cz>
SUSE Labs, SUSE CZ
^ permalink raw reply
* Re: [PATCH 13/23 v3] mlx4: Unicast Loopback support
From: Yevgeny Petrilin @ 2010-02-16 15:28 UTC (permalink / raw)
To: or.gerlitz; +Cc: Yevgeny
On Sunday -10,January,-28163 09:59 PM, Or Gerlitz [or.gerlitz@gmail.com] wrote:
> Yevgeny Petrilin <yevgenyp@mellanox.co.il> wrote:
>> Or Gerlitz [or.gerlitz@gmail.com] wrote:
>
>>> I wasn't sure what is the use case here, isn't loopback handled by higher levels at the network stack?
>
>> The use case is two VMs using the same physical adapter.
>
> I am still not with you: are you referring to the case where each VM is being served by a different VF? in that case, the VF driver (mlx4_en) has no way to know its a "loopback" packet, and switching between VFs can be programmed to the PF by the PF driver (modified mlx4_core).
>
> If you are talking to the case both VMs are being served by the same PCI function --> same NIC then again, loopback is handled in higher level.
>
> Is there a 3rd use case?
>
> Or.
There is no third case. I am referring to the case where two VMs are served by two different VFs.
The mlx4_en driver doesn't know whether a packet is loopback or not, it assumes that all packets can
be loopbacks and writes the dmac to the control segment.
The HW checks this field and decides whether the packet is loopback or not (by checking whether the written mac
matches one of the registered macs on this device).
^ permalink raw reply
* netfilter 62/62: CONFIG_COMPAT: allow delta to exceed 32767
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit 3e5e524ffb5fcf2447eb5dd9f8e54ad22dd9baa7
Author: Florian Westphal <fwestphal@astaro.com>
Date: Mon Feb 15 18:17:10 2010 +0100
netfilter: CONFIG_COMPAT: allow delta to exceed 32767
with 32 bit userland and 64 bit kernels, it is unlikely but possible
that insertion of new rules fails even tough there are only about 2000
iptables rules.
This happens because the compat delta is using a short int.
Easily reproducible via "iptables -m limit" ; after about 2050
rules inserting new ones fails with -ELOOP.
Note that compat_delta included 2 bytes of padding on x86_64, so
structure size remains the same.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Patrick McHardy <kaber@trash.net>
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index c61758f..a18119f 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -588,7 +588,7 @@ extern void xt_compat_unlock(u_int8_t af);
extern int xt_compat_add_offset(u_int8_t af, unsigned int offset, short delta);
extern void xt_compat_flush_offsets(u_int8_t af);
-extern short xt_compat_calc_jump(u_int8_t af, unsigned int offset);
+extern int xt_compat_calc_jump(u_int8_t af, unsigned int offset);
extern int xt_compat_match_offset(const struct xt_match *match);
extern int xt_compat_match_from_user(struct xt_entry_match *m,
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 69c5628..0a12ced 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -39,7 +39,7 @@ MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tables backend module");
struct compat_delta {
struct compat_delta *next;
unsigned int offset;
- short delta;
+ int delta;
};
struct xt_af {
@@ -439,10 +439,10 @@ void xt_compat_flush_offsets(u_int8_t af)
}
EXPORT_SYMBOL_GPL(xt_compat_flush_offsets);
-short xt_compat_calc_jump(u_int8_t af, unsigned int offset)
+int xt_compat_calc_jump(u_int8_t af, unsigned int offset)
{
struct compat_delta *tmp;
- short delta;
+ int delta;
for (tmp = xt[af].compat_offsets, delta = 0; tmp; tmp = tmp->next)
if (tmp->offset < offset)
^ permalink raw reply related
* netfilter 61/62: ebtables: avoid explicit XT_ALIGN() in match/targets
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit fc0e3df4f00a5f62c2f2fce84bf496136b58c474
Author: Florian Westphal <fwestphal@astaro.com>
Date: Mon Feb 15 18:16:26 2010 +0100
netfilter: ebtables: avoid explicit XT_ALIGN() in match/targets
This will cause trouble once CONFIG_COMPAT support is added to ebtables.
xt_compat_*_offset() calculate the kernel/userland structure size delta
using:
XT_ALIGN(size) - COMPAT_XT_ALIGN(size)
If the match/target sizes are aligned at registration time,
delta is always zero.
Should have zero effect for existing systems: xtables uses
XT_ALIGN() whenever it deals with match/target sizes.
Signed-off-by: Florian Westphal <fwestphal@astaro.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
diff --git a/net/bridge/netfilter/ebt_802_3.c b/net/bridge/netfilter/ebt_802_3.c
index bd91dc5..5d11767 100644
--- a/net/bridge/netfilter/ebt_802_3.c
+++ b/net/bridge/netfilter/ebt_802_3.c
@@ -52,7 +52,7 @@ static struct xt_match ebt_802_3_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_802_3_mt,
.checkentry = ebt_802_3_mt_check,
- .matchsize = XT_ALIGN(sizeof(struct ebt_802_3_info)),
+ .matchsize = sizeof(struct ebt_802_3_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c
index b7ad604..e727697 100644
--- a/net/bridge/netfilter/ebt_arp.c
+++ b/net/bridge/netfilter/ebt_arp.c
@@ -120,7 +120,7 @@ static struct xt_match ebt_arp_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_arp_mt,
.checkentry = ebt_arp_mt_check,
- .matchsize = XT_ALIGN(sizeof(struct ebt_arp_info)),
+ .matchsize = sizeof(struct ebt_arp_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_arpreply.c b/net/bridge/netfilter/ebt_arpreply.c
index 76584cd..f392e9d 100644
--- a/net/bridge/netfilter/ebt_arpreply.c
+++ b/net/bridge/netfilter/ebt_arpreply.c
@@ -78,7 +78,7 @@ static struct xt_target ebt_arpreply_tg_reg __read_mostly = {
.hooks = (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_PRE_ROUTING),
.target = ebt_arpreply_tg,
.checkentry = ebt_arpreply_tg_check,
- .targetsize = XT_ALIGN(sizeof(struct ebt_arpreply_info)),
+ .targetsize = sizeof(struct ebt_arpreply_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c
index 6b49ea9..2bb40d7 100644
--- a/net/bridge/netfilter/ebt_dnat.c
+++ b/net/bridge/netfilter/ebt_dnat.c
@@ -54,7 +54,7 @@ static struct xt_target ebt_dnat_tg_reg __read_mostly = {
(1 << NF_BR_LOCAL_OUT) | (1 << NF_BR_BROUTING),
.target = ebt_dnat_tg,
.checkentry = ebt_dnat_tg_check,
- .targetsize = XT_ALIGN(sizeof(struct ebt_nat_info)),
+ .targetsize = sizeof(struct ebt_nat_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c
index d771bbf..5de6df6 100644
--- a/net/bridge/netfilter/ebt_ip.c
+++ b/net/bridge/netfilter/ebt_ip.c
@@ -110,7 +110,7 @@ static struct xt_match ebt_ip_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_ip_mt,
.checkentry = ebt_ip_mt_check,
- .matchsize = XT_ALIGN(sizeof(struct ebt_ip_info)),
+ .matchsize = sizeof(struct ebt_ip_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_ip6.c b/net/bridge/netfilter/ebt_ip6.c
index 784a657..bbf2534 100644
--- a/net/bridge/netfilter/ebt_ip6.c
+++ b/net/bridge/netfilter/ebt_ip6.c
@@ -122,7 +122,7 @@ static struct xt_match ebt_ip6_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_ip6_mt,
.checkentry = ebt_ip6_mt_check,
- .matchsize = XT_ALIGN(sizeof(struct ebt_ip6_info)),
+ .matchsize = sizeof(struct ebt_ip6_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_limit.c b/net/bridge/netfilter/ebt_limit.c
index f7bd919..9dd16e6 100644
--- a/net/bridge/netfilter/ebt_limit.c
+++ b/net/bridge/netfilter/ebt_limit.c
@@ -90,7 +90,7 @@ static struct xt_match ebt_limit_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_limit_mt,
.checkentry = ebt_limit_mt_check,
- .matchsize = XT_ALIGN(sizeof(struct ebt_limit_info)),
+ .matchsize = sizeof(struct ebt_limit_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index e4ea3fd..e873924 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -195,7 +195,7 @@ static struct xt_target ebt_log_tg_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.target = ebt_log_tg,
.checkentry = ebt_log_tg_check,
- .targetsize = XT_ALIGN(sizeof(struct ebt_log_info)),
+ .targetsize = sizeof(struct ebt_log_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c
index 2fee7e8..153e167 100644
--- a/net/bridge/netfilter/ebt_mark.c
+++ b/net/bridge/netfilter/ebt_mark.c
@@ -59,7 +59,7 @@ static struct xt_target ebt_mark_tg_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.target = ebt_mark_tg,
.checkentry = ebt_mark_tg_check,
- .targetsize = XT_ALIGN(sizeof(struct ebt_mark_t_info)),
+ .targetsize = sizeof(struct ebt_mark_t_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_mark_m.c b/net/bridge/netfilter/ebt_mark_m.c
index ea570f2..89abf40 100644
--- a/net/bridge/netfilter/ebt_mark_m.c
+++ b/net/bridge/netfilter/ebt_mark_m.c
@@ -41,7 +41,7 @@ static struct xt_match ebt_mark_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_mark_mt,
.checkentry = ebt_mark_mt_check,
- .matchsize = XT_ALIGN(sizeof(struct ebt_mark_m_info)),
+ .matchsize = sizeof(struct ebt_mark_m_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_nflog.c b/net/bridge/netfilter/ebt_nflog.c
index 2a63d99..40dbd24 100644
--- a/net/bridge/netfilter/ebt_nflog.c
+++ b/net/bridge/netfilter/ebt_nflog.c
@@ -51,7 +51,7 @@ static struct xt_target ebt_nflog_tg_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.target = ebt_nflog_tg,
.checkentry = ebt_nflog_tg_check,
- .targetsize = XT_ALIGN(sizeof(struct ebt_nflog_info)),
+ .targetsize = sizeof(struct ebt_nflog_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_pkttype.c b/net/bridge/netfilter/ebt_pkttype.c
index 883e96e..e2a07e6 100644
--- a/net/bridge/netfilter/ebt_pkttype.c
+++ b/net/bridge/netfilter/ebt_pkttype.c
@@ -36,7 +36,7 @@ static struct xt_match ebt_pkttype_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_pkttype_mt,
.checkentry = ebt_pkttype_mt_check,
- .matchsize = XT_ALIGN(sizeof(struct ebt_pkttype_info)),
+ .matchsize = sizeof(struct ebt_pkttype_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c
index c8a49f7..9be8fbc 100644
--- a/net/bridge/netfilter/ebt_redirect.c
+++ b/net/bridge/netfilter/ebt_redirect.c
@@ -59,7 +59,7 @@ static struct xt_target ebt_redirect_tg_reg __read_mostly = {
(1 << NF_BR_BROUTING),
.target = ebt_redirect_tg,
.checkentry = ebt_redirect_tg_check,
- .targetsize = XT_ALIGN(sizeof(struct ebt_redirect_info)),
+ .targetsize = sizeof(struct ebt_redirect_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c
index 8d04d4c..9c7b520 100644
--- a/net/bridge/netfilter/ebt_snat.c
+++ b/net/bridge/netfilter/ebt_snat.c
@@ -67,7 +67,7 @@ static struct xt_target ebt_snat_tg_reg __read_mostly = {
.hooks = (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_POST_ROUTING),
.target = ebt_snat_tg,
.checkentry = ebt_snat_tg_check,
- .targetsize = XT_ALIGN(sizeof(struct ebt_nat_info)),
+ .targetsize = sizeof(struct ebt_nat_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c
index 75e29a9..92a93d3 100644
--- a/net/bridge/netfilter/ebt_stp.c
+++ b/net/bridge/netfilter/ebt_stp.c
@@ -177,7 +177,7 @@ static struct xt_match ebt_stp_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_stp_mt,
.checkentry = ebt_stp_mt_check,
- .matchsize = XT_ALIGN(sizeof(struct ebt_stp_info)),
+ .matchsize = sizeof(struct ebt_stp_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
index ce50688..c6ac657 100644
--- a/net/bridge/netfilter/ebt_ulog.c
+++ b/net/bridge/netfilter/ebt_ulog.c
@@ -275,7 +275,7 @@ static struct xt_target ebt_ulog_tg_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.target = ebt_ulog_tg,
.checkentry = ebt_ulog_tg_check,
- .targetsize = XT_ALIGN(sizeof(struct ebt_ulog_info)),
+ .targetsize = sizeof(struct ebt_ulog_info),
.me = THIS_MODULE,
};
diff --git a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c
index 3dddd48..be1dd2e 100644
--- a/net/bridge/netfilter/ebt_vlan.c
+++ b/net/bridge/netfilter/ebt_vlan.c
@@ -163,7 +163,7 @@ static struct xt_match ebt_vlan_mt_reg __read_mostly = {
.family = NFPROTO_BRIDGE,
.match = ebt_vlan_mt,
.checkentry = ebt_vlan_mt_check,
- .matchsize = XT_ALIGN(sizeof(struct ebt_vlan_info)),
+ .matchsize = sizeof(struct ebt_vlan_info),
.me = THIS_MODULE,
};
^ permalink raw reply related
* netfilter 60/62: ebtables: abort if next_offset is too small
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit 1756de262e41112a8a8927808eb2f03d21fd4786
Author: Florian Westphal <fwestphal@astaro.com>
Date: Mon Feb 15 18:15:55 2010 +0100
netfilter: ebtables: abort if next_offset is too small
next_offset must be > 0, otherwise this loops forever.
The offset also contains the size of the ebt_entry structure
itself, so anything smaller is invalid.
Signed-off-by: Florian Westphal <fwestphal@astaro.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index bcdf02d..4370e96 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -444,6 +444,8 @@ static int ebt_verify_pointers(const struct ebt_replace *repl,
break;
if (left < e->next_offset)
break;
+ if (e->next_offset < sizeof(struct ebt_entry))
+ return -EINVAL;
offset += e->next_offset;
}
}
^ permalink raw reply related
* netfilter 59/62: ctnetlink: add zone support
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit ef00f89f1eb7e056aab9dfe068521e6f2320c94a
Author: Patrick McHardy <kaber@trash.net>
Date: Mon Feb 15 18:14:57 2010 +0100
netfilter: ctnetlink: add zone support
Parse and dump the conntrack zone in ctnetlink.
Signed-off-by: Patrick McHardy <kaber@trash.net>
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h
index ed4ef8d..9ed534c 100644
--- a/include/linux/netfilter/nfnetlink_conntrack.h
+++ b/include/linux/netfilter/nfnetlink_conntrack.h
@@ -40,6 +40,7 @@ enum ctattr_type {
CTA_NAT_SEQ_ADJ_ORIG,
CTA_NAT_SEQ_ADJ_REPLY,
CTA_SECMARK,
+ CTA_ZONE,
__CTA_MAX
};
#define CTA_MAX (__CTA_MAX - 1)
@@ -159,6 +160,7 @@ enum ctattr_expect {
CTA_EXPECT_TIMEOUT,
CTA_EXPECT_ID,
CTA_EXPECT_HELP_NAME,
+ CTA_EXPECT_ZONE,
__CTA_EXPECT_MAX
};
#define CTA_EXPECT_MAX (__CTA_EXPECT_MAX - 1)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 51089cf..8b05f36 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -39,6 +39,7 @@
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_tuple.h>
#include <net/netfilter/nf_conntrack_acct.h>
+#include <net/netfilter/nf_conntrack_zones.h>
#ifdef CONFIG_NF_NAT_NEEDED
#include <net/netfilter/nf_nat_core.h>
#include <net/netfilter/nf_nat_protocol.h>
@@ -379,6 +380,9 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
goto nla_put_failure;
nla_nest_end(skb, nest_parms);
+ if (nf_ct_zone(ct))
+ NLA_PUT_BE16(skb, CTA_ZONE, htons(nf_ct_zone(ct)));
+
if (ctnetlink_dump_status(skb, ct) < 0 ||
ctnetlink_dump_timeout(skb, ct) < 0 ||
ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
@@ -517,6 +521,9 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
goto nla_put_failure;
nla_nest_end(skb, nest_parms);
+ if (nf_ct_zone(ct))
+ NLA_PUT_BE16(skb, CTA_ZONE, htons(nf_ct_zone(ct)));
+
if (ctnetlink_dump_id(skb, ct) < 0)
goto nla_put_failure;
@@ -750,6 +757,21 @@ ctnetlink_parse_tuple(const struct nlattr * const cda[],
return 0;
}
+static int
+ctnetlink_parse_zone(const struct nlattr *attr, u16 *zone)
+{
+ if (attr)
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+ *zone = ntohs(nla_get_be16(attr));
+#else
+ return -EOPNOTSUPP;
+#endif
+ else
+ *zone = 0;
+
+ return 0;
+}
+
static const struct nla_policy help_nla_policy[CTA_HELP_MAX+1] = {
[CTA_HELP_NAME] = { .type = NLA_NUL_STRING },
};
@@ -781,6 +803,7 @@ static const struct nla_policy ct_nla_policy[CTA_MAX+1] = {
[CTA_ID] = { .type = NLA_U32 },
[CTA_NAT_DST] = { .type = NLA_NESTED },
[CTA_TUPLE_MASTER] = { .type = NLA_NESTED },
+ [CTA_ZONE] = { .type = NLA_U16 },
};
static int
@@ -794,7 +817,12 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
struct nf_conn *ct;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int8_t u3 = nfmsg->nfgen_family;
- int err = 0;
+ u16 zone;
+ int err;
+
+ err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
+ if (err < 0)
+ return err;
if (cda[CTA_TUPLE_ORIG])
err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3);
@@ -811,7 +839,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
return err;
- h = nf_conntrack_find_get(net, 0, &tuple);
+ h = nf_conntrack_find_get(net, zone, &tuple);
if (!h)
return -ENOENT;
@@ -856,12 +884,17 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
struct sk_buff *skb2 = NULL;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int8_t u3 = nfmsg->nfgen_family;
- int err = 0;
+ u16 zone;
+ int err;
if (nlh->nlmsg_flags & NLM_F_DUMP)
return netlink_dump_start(ctnl, skb, nlh, ctnetlink_dump_table,
ctnetlink_done);
+ err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
+ if (err < 0)
+ return err;
+
if (cda[CTA_TUPLE_ORIG])
err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3);
else if (cda[CTA_TUPLE_REPLY])
@@ -872,7 +905,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
return err;
- h = nf_conntrack_find_get(net, 0, &tuple);
+ h = nf_conntrack_find_get(net, zone, &tuple);
if (!h)
return -ENOENT;
@@ -1211,7 +1244,7 @@ ctnetlink_change_conntrack(struct nf_conn *ct,
}
static struct nf_conn *
-ctnetlink_create_conntrack(struct net *net,
+ctnetlink_create_conntrack(struct net *net, u16 zone,
const struct nlattr * const cda[],
struct nf_conntrack_tuple *otuple,
struct nf_conntrack_tuple *rtuple,
@@ -1221,7 +1254,7 @@ ctnetlink_create_conntrack(struct net *net,
int err = -EINVAL;
struct nf_conntrack_helper *helper;
- ct = nf_conntrack_alloc(net, 0, otuple, rtuple, GFP_ATOMIC);
+ ct = nf_conntrack_alloc(net, zone, otuple, rtuple, GFP_ATOMIC);
if (IS_ERR(ct))
return ERR_PTR(-ENOMEM);
@@ -1325,7 +1358,7 @@ ctnetlink_create_conntrack(struct net *net,
if (err < 0)
goto err2;
- master_h = nf_conntrack_find_get(net, 0, &master);
+ master_h = nf_conntrack_find_get(net, zone, &master);
if (master_h == NULL) {
err = -ENOENT;
goto err2;
@@ -1358,7 +1391,12 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
struct nf_conntrack_tuple_hash *h = NULL;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int8_t u3 = nfmsg->nfgen_family;
- int err = 0;
+ u16 zone;
+ int err;
+
+ err = ctnetlink_parse_zone(cda[CTA_ZONE], &zone);
+ if (err < 0)
+ return err;
if (cda[CTA_TUPLE_ORIG]) {
err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG, u3);
@@ -1374,9 +1412,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
spin_lock_bh(&nf_conntrack_lock);
if (cda[CTA_TUPLE_ORIG])
- h = __nf_conntrack_find(net, 0, &otuple);
+ h = __nf_conntrack_find(net, zone, &otuple);
else if (cda[CTA_TUPLE_REPLY])
- h = __nf_conntrack_find(net, 0, &rtuple);
+ h = __nf_conntrack_find(net, zone, &rtuple);
if (h == NULL) {
err = -ENOENT;
@@ -1384,7 +1422,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
struct nf_conn *ct;
enum ip_conntrack_events events;
- ct = ctnetlink_create_conntrack(net, cda, &otuple,
+ ct = ctnetlink_create_conntrack(net, zone, cda, &otuple,
&rtuple, u3);
if (IS_ERR(ct)) {
err = PTR_ERR(ct);
@@ -1698,7 +1736,8 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
struct sk_buff *skb2;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int8_t u3 = nfmsg->nfgen_family;
- int err = 0;
+ u16 zone;
+ int err;
if (nlh->nlmsg_flags & NLM_F_DUMP) {
return netlink_dump_start(ctnl, skb, nlh,
@@ -1706,6 +1745,10 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
ctnetlink_exp_done);
}
+ err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
+ if (err < 0)
+ return err;
+
if (cda[CTA_EXPECT_MASTER])
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, u3);
else
@@ -1714,7 +1757,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
return err;
- exp = nf_ct_expect_find_get(net, 0, &tuple);
+ exp = nf_ct_expect_find_get(net, zone, &tuple);
if (!exp)
return -ENOENT;
@@ -1761,16 +1804,21 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
struct hlist_node *n, *next;
u_int8_t u3 = nfmsg->nfgen_family;
unsigned int i;
+ u16 zone;
int err;
if (cda[CTA_EXPECT_TUPLE]) {
/* delete a single expect by tuple */
+ err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
+ if (err < 0)
+ return err;
+
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
if (err < 0)
return err;
/* bump usage count to 2 */
- exp = nf_ct_expect_find_get(net, 0, &tuple);
+ exp = nf_ct_expect_find_get(net, zone, &tuple);
if (!exp)
return -ENOENT;
@@ -1832,7 +1880,8 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x,
}
static int
-ctnetlink_create_expect(struct net *net, const struct nlattr * const cda[],
+ctnetlink_create_expect(struct net *net, u16 zone,
+ const struct nlattr * const cda[],
u_int8_t u3,
u32 pid, int report)
{
@@ -1855,7 +1904,7 @@ ctnetlink_create_expect(struct net *net, const struct nlattr * const cda[],
return err;
/* Look for master conntrack of this expectation */
- h = nf_conntrack_find_get(net, 0, &master_tuple);
+ h = nf_conntrack_find_get(net, zone, &master_tuple);
if (!h)
return -ENOENT;
ct = nf_ct_tuplehash_to_ctrack(h);
@@ -1900,25 +1949,30 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
struct nf_conntrack_expect *exp;
struct nfgenmsg *nfmsg = nlmsg_data(nlh);
u_int8_t u3 = nfmsg->nfgen_family;
- int err = 0;
+ u16 zone;
+ int err;
if (!cda[CTA_EXPECT_TUPLE]
|| !cda[CTA_EXPECT_MASK]
|| !cda[CTA_EXPECT_MASTER])
return -EINVAL;
+ err = ctnetlink_parse_zone(cda[CTA_EXPECT_ZONE], &zone);
+ if (err < 0)
+ return err;
+
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
if (err < 0)
return err;
spin_lock_bh(&nf_conntrack_lock);
- exp = __nf_ct_expect_find(net, 0, &tuple);
+ exp = __nf_ct_expect_find(net, zone, &tuple);
if (!exp) {
spin_unlock_bh(&nf_conntrack_lock);
err = -ENOENT;
if (nlh->nlmsg_flags & NLM_F_CREATE) {
- err = ctnetlink_create_expect(net, cda,
+ err = ctnetlink_create_expect(net, zone, cda,
u3,
NETLINK_CB(skb).pid,
nlmsg_report(nlh));
^ permalink raw reply related
* netfilter 58/62: nf_conntrack: add support for "conntrack zones"
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit 5d0aa2ccd4699a01cfdf14886191c249d7b45a01
Author: Patrick McHardy <kaber@trash.net>
Date: Mon Feb 15 18:13:33 2010 +0100
netfilter: nf_conntrack: add support for "conntrack zones"
Normally, each connection needs a unique identity. Conntrack zones allow
to specify a numerical zone using the CT target, connections in different
zones can use the same identity.
Example:
iptables -t raw -A PREROUTING -i veth0 -j CT --zone 1
iptables -t raw -A OUTPUT -o veth1 -j CT --zone 1
Signed-off-by: Patrick McHardy <kaber@trash.net>
diff --git a/include/linux/netfilter/xt_CT.h b/include/linux/netfilter/xt_CT.h
index 7fd0eff..1b56410 100644
--- a/include/linux/netfilter/xt_CT.h
+++ b/include/linux/netfilter/xt_CT.h
@@ -5,7 +5,7 @@
struct xt_ct_target_info {
u_int16_t flags;
- u_int16_t __unused;
+ u_int16_t zone;
u_int32_t ct_events;
u_int32_t exp_events;
char helper[16];
diff --git a/include/net/ip.h b/include/net/ip.h
index fb63371..7bc4787 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -352,8 +352,11 @@ enum ip_defrag_users {
IP_DEFRAG_LOCAL_DELIVER,
IP_DEFRAG_CALL_RA_CHAIN,
IP_DEFRAG_CONNTRACK_IN,
+ __IP_DEFRAG_CONNTRACK_IN_END = IP_DEFRAG_CONNTRACK_IN + USHORT_MAX,
IP_DEFRAG_CONNTRACK_OUT,
+ __IP_DEFRAG_CONNTRACK_OUT_END = IP_DEFRAG_CONNTRACK_OUT + USHORT_MAX,
IP_DEFRAG_CONNTRACK_BRIDGE_IN,
+ __IP_DEFRAG_CONNTRACK_BRIDGE_IN = IP_DEFRAG_CONNTRACK_BRIDGE_IN + USHORT_MAX,
IP_DEFRAG_VS_IN,
IP_DEFRAG_VS_OUT,
IP_DEFRAG_VS_FWD
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 299bbf5..639ec53 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -355,8 +355,11 @@ struct inet_frag_queue;
enum ip6_defrag_users {
IP6_DEFRAG_LOCAL_DELIVER,
IP6_DEFRAG_CONNTRACK_IN,
+ __IP6_DEFRAG_CONNTRACK_IN = IP6_DEFRAG_CONNTRACK_IN + USHORT_MAX,
IP6_DEFRAG_CONNTRACK_OUT,
+ __IP6_DEFRAG_CONNTRACK_OUT = IP6_DEFRAG_CONNTRACK_OUT + USHORT_MAX,
IP6_DEFRAG_CONNTRACK_BRIDGE_IN,
+ __IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHORT_MAX,
};
struct ip6_create_arg {
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 5b7d883..bde095f 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -198,7 +198,8 @@ extern void *nf_ct_alloc_hashtable(unsigned int *sizep, int *vmalloced, int null
extern void nf_ct_free_hashtable(void *hash, int vmalloced, unsigned int size);
extern struct nf_conntrack_tuple_hash *
-__nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple);
+__nf_conntrack_find(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple);
extern void nf_conntrack_hash_insert(struct nf_conn *ct);
extern void nf_ct_delete_from_lists(struct nf_conn *ct);
@@ -267,7 +268,7 @@ extern void
nf_ct_iterate_cleanup(struct net *net, int (*iter)(struct nf_conn *i, void *data), void *data);
extern void nf_conntrack_free(struct nf_conn *ct);
extern struct nf_conn *
-nf_conntrack_alloc(struct net *net,
+nf_conntrack_alloc(struct net *net, u16 zone,
const struct nf_conntrack_tuple *orig,
const struct nf_conntrack_tuple *repl,
gfp_t gfp);
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index 5a449b4..dffde8e 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -49,7 +49,8 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse,
/* Find a connection corresponding to a tuple. */
extern struct nf_conntrack_tuple_hash *
-nf_conntrack_find_get(struct net *net, const struct nf_conntrack_tuple *tuple);
+nf_conntrack_find_get(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple);
extern int __nf_conntrack_confirm(struct sk_buff *skb);
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index 4b47ec1..11e8150 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -74,13 +74,16 @@ int nf_conntrack_expect_init(struct net *net);
void nf_conntrack_expect_fini(struct net *net);
struct nf_conntrack_expect *
-__nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple);
+__nf_ct_expect_find(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple);
struct nf_conntrack_expect *
-nf_ct_expect_find_get(struct net *net, const struct nf_conntrack_tuple *tuple);
+nf_ct_expect_find_get(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple);
struct nf_conntrack_expect *
-nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple);
+nf_ct_find_expectation(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple);
void nf_ct_unlink_expect(struct nf_conntrack_expect *exp);
void nf_ct_remove_expectations(struct nf_conn *ct);
diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h
index e192dc1..2d2a1f9 100644
--- a/include/net/netfilter/nf_conntrack_extend.h
+++ b/include/net/netfilter/nf_conntrack_extend.h
@@ -8,6 +8,7 @@ enum nf_ct_ext_id {
NF_CT_EXT_NAT,
NF_CT_EXT_ACCT,
NF_CT_EXT_ECACHE,
+ NF_CT_EXT_ZONE,
NF_CT_EXT_NUM,
};
@@ -15,6 +16,7 @@ enum nf_ct_ext_id {
#define NF_CT_EXT_NAT_TYPE struct nf_conn_nat
#define NF_CT_EXT_ACCT_TYPE struct nf_conn_counter
#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache
+#define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone
/* Extensions: optional stuff which isn't permanently in struct. */
struct nf_ct_ext {
diff --git a/include/net/netfilter/nf_conntrack_zones.h b/include/net/netfilter/nf_conntrack_zones.h
new file mode 100644
index 0000000..0bbb2bd
--- /dev/null
+++ b/include/net/netfilter/nf_conntrack_zones.h
@@ -0,0 +1,23 @@
+#ifndef _NF_CONNTRACK_ZONES_H
+#define _NF_CONNTRACK_ZONES_H
+
+#include <net/netfilter/nf_conntrack_extend.h>
+
+#define NF_CT_DEFAULT_ZONE 0
+
+struct nf_conntrack_zone {
+ u16 id;
+};
+
+static inline u16 nf_ct_zone(const struct nf_conn *ct)
+{
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+ struct nf_conntrack_zone *nf_ct_zone;
+ nf_ct_zone = nf_ct_ext_find(ct, NF_CT_EXT_ZONE);
+ if (nf_ct_zone)
+ return nf_ct_zone->id;
+#endif
+ return NF_CT_DEFAULT_ZONE;
+}
+
+#endif /* _NF_CONNTRACK_ZONES_H */
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index d1ea38a..2bb1f87 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -22,6 +22,7 @@
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_l3proto.h>
+#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
#include <net/netfilter/nf_nat_helper.h>
@@ -266,7 +267,7 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
return -EINVAL;
}
- h = nf_conntrack_find_get(sock_net(sk), &tuple);
+ h = nf_conntrack_find_get(sock_net(sk), NF_CT_DEFAULT_ZONE, &tuple);
if (h) {
struct sockaddr_in sin;
struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h);
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 327826a..7404bde 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -18,6 +18,7 @@
#include <net/netfilter/nf_conntrack_tuple.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_log.h>
static unsigned int nf_ct_icmp_timeout __read_mostly = 30*HZ;
@@ -114,13 +115,14 @@ static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb,
/* Returns conntrack if it dealt with ICMP, and filled in skb fields */
static int
-icmp_error_message(struct net *net, struct sk_buff *skb,
+icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
enum ip_conntrack_info *ctinfo,
unsigned int hooknum)
{
struct nf_conntrack_tuple innertuple, origtuple;
const struct nf_conntrack_l4proto *innerproto;
const struct nf_conntrack_tuple_hash *h;
+ u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
NF_CT_ASSERT(skb->nfct == NULL);
@@ -146,7 +148,7 @@ icmp_error_message(struct net *net, struct sk_buff *skb,
*ctinfo = IP_CT_RELATED;
- h = nf_conntrack_find_get(net, &innertuple);
+ h = nf_conntrack_find_get(net, zone, &innertuple);
if (!h) {
pr_debug("icmp_error_message: no match\n");
return -NF_ACCEPT;
@@ -209,7 +211,7 @@ icmp_error(struct net *net, struct nf_conn *tmpl,
icmph->type != ICMP_REDIRECT)
return NF_ACCEPT;
- return icmp_error_message(net, skb, ctinfo, hooknum);
+ return icmp_error_message(net, tmpl, skb, ctinfo, hooknum);
}
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index f6f4668..d498a70 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -16,6 +16,7 @@
#include <linux/netfilter_bridge.h>
#include <linux/netfilter_ipv4.h>
+#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/ipv4/nf_defrag_ipv4.h>
#include <net/netfilter/nf_conntrack.h>
@@ -39,15 +40,20 @@ static int nf_ct_ipv4_gather_frags(struct sk_buff *skb, u_int32_t user)
static enum ip_defrag_users nf_ct_defrag_user(unsigned int hooknum,
struct sk_buff *skb)
{
+ u16 zone = NF_CT_DEFAULT_ZONE;
+
+ if (skb->nfct)
+ zone = nf_ct_zone((struct nf_conn *)skb->nfct);
+
#ifdef CONFIG_BRIDGE_NETFILTER
if (skb->nf_bridge &&
skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
- return IP_DEFRAG_CONNTRACK_BRIDGE_IN;
+ return IP_DEFRAG_CONNTRACK_BRIDGE_IN + zone;
#endif
if (hooknum == NF_INET_PRE_ROUTING)
- return IP_DEFRAG_CONNTRACK_IN;
+ return IP_DEFRAG_CONNTRACK_IN + zone;
else
- return IP_DEFRAG_CONNTRACK_OUT;
+ return IP_DEFRAG_CONNTRACK_OUT + zone;
}
static unsigned int ipv4_conntrack_defrag(unsigned int hooknum,
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 26066a2..4595281 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -30,6 +30,7 @@
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
+#include <net/netfilter/nf_conntrack_zones.h>
static DEFINE_SPINLOCK(nf_nat_lock);
@@ -69,13 +70,14 @@ EXPORT_SYMBOL_GPL(nf_nat_proto_put);
/* We keep an extra hash for each conntrack, for fast searching. */
static inline unsigned int
-hash_by_src(const struct net *net, const struct nf_conntrack_tuple *tuple)
+hash_by_src(const struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple)
{
unsigned int hash;
/* Original src, to ensure we map it consistently if poss. */
hash = jhash_3words((__force u32)tuple->src.u3.ip,
- (__force u32)tuple->src.u.all,
+ (__force u32)tuple->src.u.all ^ zone,
tuple->dst.protonum, 0);
return ((u64)hash * net->ipv4.nat_htable_size) >> 32;
}
@@ -139,12 +141,12 @@ same_src(const struct nf_conn *ct,
/* Only called for SRC manip */
static int
-find_appropriate_src(struct net *net,
+find_appropriate_src(struct net *net, u16 zone,
const struct nf_conntrack_tuple *tuple,
struct nf_conntrack_tuple *result,
const struct nf_nat_range *range)
{
- unsigned int h = hash_by_src(net, tuple);
+ unsigned int h = hash_by_src(net, zone, tuple);
const struct nf_conn_nat *nat;
const struct nf_conn *ct;
const struct hlist_node *n;
@@ -152,7 +154,7 @@ find_appropriate_src(struct net *net,
rcu_read_lock();
hlist_for_each_entry_rcu(nat, n, &net->ipv4.nat_bysource[h], bysource) {
ct = nat->ct;
- if (same_src(ct, tuple)) {
+ if (same_src(ct, tuple) && nf_ct_zone(ct) == zone) {
/* Copy source part from reply tuple. */
nf_ct_invert_tuplepr(result,
&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
@@ -175,7 +177,7 @@ find_appropriate_src(struct net *net,
the ip with the lowest src-ip/dst-ip/proto usage.
*/
static void
-find_best_ips_proto(struct nf_conntrack_tuple *tuple,
+find_best_ips_proto(u16 zone, struct nf_conntrack_tuple *tuple,
const struct nf_nat_range *range,
const struct nf_conn *ct,
enum nf_nat_manip_type maniptype)
@@ -209,7 +211,7 @@ find_best_ips_proto(struct nf_conntrack_tuple *tuple,
maxip = ntohl(range->max_ip);
j = jhash_2words((__force u32)tuple->src.u3.ip,
range->flags & IP_NAT_RANGE_PERSISTENT ?
- 0 : (__force u32)tuple->dst.u3.ip, 0);
+ 0 : (__force u32)tuple->dst.u3.ip ^ zone, 0);
j = ((u64)j * (maxip - minip + 1)) >> 32;
*var_ipp = htonl(minip + j);
}
@@ -229,6 +231,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
{
struct net *net = nf_ct_net(ct);
const struct nf_nat_protocol *proto;
+ u16 zone = nf_ct_zone(ct);
/* 1) If this srcip/proto/src-proto-part is currently mapped,
and that same mapping gives a unique tuple within the given
@@ -239,7 +242,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
manips not an issue. */
if (maniptype == IP_NAT_MANIP_SRC &&
!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) {
- if (find_appropriate_src(net, orig_tuple, tuple, range)) {
+ if (find_appropriate_src(net, zone, orig_tuple, tuple, range)) {
pr_debug("get_unique_tuple: Found current src map\n");
if (!nf_nat_used_tuple(tuple, ct))
return;
@@ -249,7 +252,7 @@ get_unique_tuple(struct nf_conntrack_tuple *tuple,
/* 2) Select the least-used IP/proto combination in the given
range. */
*tuple = *orig_tuple;
- find_best_ips_proto(tuple, range, ct, maniptype);
+ find_best_ips_proto(zone, tuple, range, ct, maniptype);
/* 3) The per-protocol part of the manip is made to map into
the range to make a unique tuple. */
@@ -327,7 +330,8 @@ nf_nat_setup_info(struct nf_conn *ct,
if (have_to_hash) {
unsigned int srchash;
- srchash = hash_by_src(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+ srchash = hash_by_src(net, nf_ct_zone(ct),
+ &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
spin_lock_bh(&nf_nat_lock);
/* nf_conntrack_alter_reply might re-allocate exntension aera */
nat = nfct_nat(ct);
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
index 9eb1710..4c06003 100644
--- a/net/ipv4/netfilter/nf_nat_pptp.c
+++ b/net/ipv4/netfilter/nf_nat_pptp.c
@@ -25,6 +25,7 @@
#include <net/netfilter/nf_nat_rule.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_expect.h>
+#include <net/netfilter/nf_conntrack_zones.h>
#include <linux/netfilter/nf_conntrack_proto_gre.h>
#include <linux/netfilter/nf_conntrack_pptp.h>
@@ -74,7 +75,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
pr_debug("trying to unexpect other dir: ");
nf_ct_dump_tuple_ip(&t);
- other_exp = nf_ct_expect_find_get(net, &t);
+ other_exp = nf_ct_expect_find_get(net, nf_ct_zone(ct), &t);
if (other_exp) {
nf_ct_unexpect_related(other_exp);
nf_ct_expect_put(other_exp);
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 55ce22e..996c3f4 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -27,6 +27,7 @@
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_l3proto.h>
#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
#include <net/netfilter/nf_log.h>
@@ -191,15 +192,20 @@ out:
static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
struct sk_buff *skb)
{
+ u16 zone = NF_CT_DEFAULT_ZONE;
+
+ if (skb->nfct)
+ zone = nf_ct_zone((struct nf_conn *)skb->nfct);
+
#ifdef CONFIG_BRIDGE_NETFILTER
if (skb->nf_bridge &&
skb->nf_bridge->mask & BRNF_NF_BRIDGE_PREROUTING)
- return IP6_DEFRAG_CONNTRACK_BRIDGE_IN;
+ return IP6_DEFRAG_CONNTRACK_BRIDGE_IN + zone;
#endif
if (hooknum == NF_INET_PRE_ROUTING)
- return IP6_DEFRAG_CONNTRACK_IN;
+ return IP6_DEFRAG_CONNTRACK_IN + zone;
else
- return IP6_DEFRAG_CONNTRACK_OUT;
+ return IP6_DEFRAG_CONNTRACK_OUT + zone;
}
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index d772dc2..9be8177 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -23,6 +23,7 @@
#include <net/netfilter/nf_conntrack_tuple.h>
#include <net/netfilter/nf_conntrack_l4proto.h>
#include <net/netfilter/nf_conntrack_core.h>
+#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/ipv6/nf_conntrack_icmpv6.h>
#include <net/netfilter/nf_log.h>
@@ -128,7 +129,7 @@ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb,
}
static int
-icmpv6_error_message(struct net *net,
+icmpv6_error_message(struct net *net, struct nf_conn *tmpl,
struct sk_buff *skb,
unsigned int icmp6off,
enum ip_conntrack_info *ctinfo,
@@ -137,6 +138,7 @@ icmpv6_error_message(struct net *net,
struct nf_conntrack_tuple intuple, origtuple;
const struct nf_conntrack_tuple_hash *h;
const struct nf_conntrack_l4proto *inproto;
+ u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
NF_CT_ASSERT(skb->nfct == NULL);
@@ -163,7 +165,7 @@ icmpv6_error_message(struct net *net,
*ctinfo = IP_CT_RELATED;
- h = nf_conntrack_find_get(net, &intuple);
+ h = nf_conntrack_find_get(net, zone, &intuple);
if (!h) {
pr_debug("icmpv6_error: no match\n");
return -NF_ACCEPT;
@@ -216,7 +218,7 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl,
if (icmp6h->icmp6_type >= 128)
return NF_ACCEPT;
- return icmpv6_error_message(net, skb, dataoff, ctinfo, hooknum);
+ return icmpv6_error_message(net, tmpl, skb, dataoff, ctinfo, hooknum);
}
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 4469d45..18d77b5 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -83,6 +83,19 @@ config NF_CONNTRACK_SECMARK
If unsure, say 'N'.
+config NF_CONNTRACK_ZONES
+ bool 'Connection tracking zones'
+ depends on NETFILTER_ADVANCED
+ depends on NETFILTER_XT_TARGET_CT
+ help
+ This option enables support for connection tracking zones.
+ Normally, each connection needs to have a unique system wide
+ identity. Connection tracking zones allow to have multiple
+ connections using the same identity, as long as they are
+ contained in different zones.
+
+ If unsure, say `N'.
+
config NF_CONNTRACK_EVENTS
bool "Connection tracking events"
depends on NETFILTER_ADVANCED
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 65351ed..0c9bbe9 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -42,6 +42,7 @@
#include <net/netfilter/nf_conntrack_extend.h>
#include <net/netfilter/nf_conntrack_acct.h>
#include <net/netfilter/nf_conntrack_ecache.h>
+#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_nat.h>
#include <net/netfilter/nf_nat_core.h>
@@ -68,7 +69,7 @@ static int nf_conntrack_hash_rnd_initted;
static unsigned int nf_conntrack_hash_rnd;
static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple,
- unsigned int size, unsigned int rnd)
+ u16 zone, unsigned int size, unsigned int rnd)
{
unsigned int n;
u_int32_t h;
@@ -79,16 +80,16 @@ static u_int32_t __hash_conntrack(const struct nf_conntrack_tuple *tuple,
*/
n = (sizeof(tuple->src) + sizeof(tuple->dst.u3)) / sizeof(u32);
h = jhash2((u32 *)tuple, n,
- rnd ^ (((__force __u16)tuple->dst.u.all << 16) |
- tuple->dst.protonum));
+ zone ^ rnd ^ (((__force __u16)tuple->dst.u.all << 16) |
+ tuple->dst.protonum));
return ((u64)h * size) >> 32;
}
-static inline u_int32_t hash_conntrack(const struct net *net,
+static inline u_int32_t hash_conntrack(const struct net *net, u16 zone,
const struct nf_conntrack_tuple *tuple)
{
- return __hash_conntrack(tuple, net->ct.htable_size,
+ return __hash_conntrack(tuple, zone, net->ct.htable_size,
nf_conntrack_hash_rnd);
}
@@ -292,11 +293,12 @@ static void death_by_timeout(unsigned long ul_conntrack)
* - Caller must lock nf_conntrack_lock before calling this function
*/
struct nf_conntrack_tuple_hash *
-__nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple)
+__nf_conntrack_find(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple)
{
struct nf_conntrack_tuple_hash *h;
struct hlist_nulls_node *n;
- unsigned int hash = hash_conntrack(net, tuple);
+ unsigned int hash = hash_conntrack(net, zone, tuple);
/* Disable BHs the entire time since we normally need to disable them
* at least once for the stats anyway.
@@ -304,7 +306,8 @@ __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple)
local_bh_disable();
begin:
hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) {
- if (nf_ct_tuple_equal(tuple, &h->tuple)) {
+ if (nf_ct_tuple_equal(tuple, &h->tuple) &&
+ nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)) == zone) {
NF_CT_STAT_INC(net, found);
local_bh_enable();
return h;
@@ -326,21 +329,23 @@ EXPORT_SYMBOL_GPL(__nf_conntrack_find);
/* Find a connection corresponding to a tuple. */
struct nf_conntrack_tuple_hash *
-nf_conntrack_find_get(struct net *net, const struct nf_conntrack_tuple *tuple)
+nf_conntrack_find_get(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple)
{
struct nf_conntrack_tuple_hash *h;
struct nf_conn *ct;
rcu_read_lock();
begin:
- h = __nf_conntrack_find(net, tuple);
+ h = __nf_conntrack_find(net, zone, tuple);
if (h) {
ct = nf_ct_tuplehash_to_ctrack(h);
if (unlikely(nf_ct_is_dying(ct) ||
!atomic_inc_not_zero(&ct->ct_general.use)))
h = NULL;
else {
- if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple))) {
+ if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple) ||
+ nf_ct_zone(ct) != zone)) {
nf_ct_put(ct);
goto begin;
}
@@ -368,9 +373,11 @@ void nf_conntrack_hash_insert(struct nf_conn *ct)
{
struct net *net = nf_ct_net(ct);
unsigned int hash, repl_hash;
+ u16 zone;
- hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
- repl_hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+ zone = nf_ct_zone(ct);
+ hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+ repl_hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
__nf_conntrack_hash_insert(ct, hash, repl_hash);
}
@@ -387,6 +394,7 @@ __nf_conntrack_confirm(struct sk_buff *skb)
struct hlist_nulls_node *n;
enum ip_conntrack_info ctinfo;
struct net *net;
+ u16 zone;
ct = nf_ct_get(skb, &ctinfo);
net = nf_ct_net(ct);
@@ -398,8 +406,9 @@ __nf_conntrack_confirm(struct sk_buff *skb)
if (CTINFO2DIR(ctinfo) != IP_CT_DIR_ORIGINAL)
return NF_ACCEPT;
- hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
- repl_hash = hash_conntrack(net, &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
+ zone = nf_ct_zone(ct);
+ hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
+ repl_hash = hash_conntrack(net, zone, &ct->tuplehash[IP_CT_DIR_REPLY].tuple);
/* We're not in hash table, and we refuse to set up related
connections for unconfirmed conns. But packet copies and
@@ -418,11 +427,13 @@ __nf_conntrack_confirm(struct sk_buff *skb)
not in the hash. If there is, we lost race. */
hlist_nulls_for_each_entry(h, n, &net->ct.hash[hash], hnnode)
if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
- &h->tuple))
+ &h->tuple) &&
+ zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
goto out;
hlist_nulls_for_each_entry(h, n, &net->ct.hash[repl_hash], hnnode)
if (nf_ct_tuple_equal(&ct->tuplehash[IP_CT_DIR_REPLY].tuple,
- &h->tuple))
+ &h->tuple) &&
+ zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)))
goto out;
/* Remove from unconfirmed list */
@@ -469,15 +480,19 @@ nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple,
struct net *net = nf_ct_net(ignored_conntrack);
struct nf_conntrack_tuple_hash *h;
struct hlist_nulls_node *n;
- unsigned int hash = hash_conntrack(net, tuple);
+ struct nf_conn *ct;
+ u16 zone = nf_ct_zone(ignored_conntrack);
+ unsigned int hash = hash_conntrack(net, zone, tuple);
/* Disable BHs the entire time since we need to disable them at
* least once for the stats anyway.
*/
rcu_read_lock_bh();
hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[hash], hnnode) {
- if (nf_ct_tuplehash_to_ctrack(h) != ignored_conntrack &&
- nf_ct_tuple_equal(tuple, &h->tuple)) {
+ ct = nf_ct_tuplehash_to_ctrack(h);
+ if (ct != ignored_conntrack &&
+ nf_ct_tuple_equal(tuple, &h->tuple) &&
+ nf_ct_zone(ct) == zone) {
NF_CT_STAT_INC(net, found);
rcu_read_unlock_bh();
return 1;
@@ -540,7 +555,7 @@ static noinline int early_drop(struct net *net, unsigned int hash)
return dropped;
}
-struct nf_conn *nf_conntrack_alloc(struct net *net,
+struct nf_conn *nf_conntrack_alloc(struct net *net, u16 zone,
const struct nf_conntrack_tuple *orig,
const struct nf_conntrack_tuple *repl,
gfp_t gfp)
@@ -558,7 +573,7 @@ struct nf_conn *nf_conntrack_alloc(struct net *net,
if (nf_conntrack_max &&
unlikely(atomic_read(&net->ct.count) > nf_conntrack_max)) {
- unsigned int hash = hash_conntrack(net, orig);
+ unsigned int hash = hash_conntrack(net, zone, orig);
if (!early_drop(net, hash)) {
atomic_dec(&net->ct.count);
if (net_ratelimit())
@@ -595,13 +610,28 @@ struct nf_conn *nf_conntrack_alloc(struct net *net,
#ifdef CONFIG_NET_NS
ct->ct_net = net;
#endif
-
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+ if (zone) {
+ struct nf_conntrack_zone *nf_ct_zone;
+
+ nf_ct_zone = nf_ct_ext_add(ct, NF_CT_EXT_ZONE, GFP_ATOMIC);
+ if (!nf_ct_zone)
+ goto out_free;
+ nf_ct_zone->id = zone;
+ }
+#endif
/*
* changes to lookup keys must be done before setting refcnt to 1
*/
smp_wmb();
atomic_set(&ct->ct_general.use, 1);
return ct;
+
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+out_free:
+ kmem_cache_free(net->ct.nf_conntrack_cachep, ct);
+ return ERR_PTR(-ENOMEM);
+#endif
}
EXPORT_SYMBOL_GPL(nf_conntrack_alloc);
@@ -631,13 +661,14 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
struct nf_conntrack_tuple repl_tuple;
struct nf_conntrack_ecache *ecache;
struct nf_conntrack_expect *exp;
+ u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
if (!nf_ct_invert_tuple(&repl_tuple, tuple, l3proto, l4proto)) {
pr_debug("Can't invert tuple.\n");
return NULL;
}
- ct = nf_conntrack_alloc(net, tuple, &repl_tuple, GFP_ATOMIC);
+ ct = nf_conntrack_alloc(net, zone, tuple, &repl_tuple, GFP_ATOMIC);
if (IS_ERR(ct)) {
pr_debug("Can't allocate conntrack.\n");
return (struct nf_conntrack_tuple_hash *)ct;
@@ -657,7 +688,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
GFP_ATOMIC);
spin_lock_bh(&nf_conntrack_lock);
- exp = nf_ct_find_expectation(net, tuple);
+ exp = nf_ct_find_expectation(net, zone, tuple);
if (exp) {
pr_debug("conntrack: expectation arrives ct=%p exp=%p\n",
ct, exp);
@@ -713,6 +744,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
struct nf_conntrack_tuple tuple;
struct nf_conntrack_tuple_hash *h;
struct nf_conn *ct;
+ u16 zone = tmpl ? nf_ct_zone(tmpl) : NF_CT_DEFAULT_ZONE;
if (!nf_ct_get_tuple(skb, skb_network_offset(skb),
dataoff, l3num, protonum, &tuple, l3proto,
@@ -722,7 +754,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
}
/* look for tuple match */
- h = nf_conntrack_find_get(net, &tuple);
+ h = nf_conntrack_find_get(net, zone, &tuple);
if (!h) {
h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto,
skb, dataoff);
@@ -958,6 +990,14 @@ bool __nf_ct_kill_acct(struct nf_conn *ct,
}
EXPORT_SYMBOL_GPL(__nf_ct_kill_acct);
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+static struct nf_ct_ext_type nf_ct_zone_extend __read_mostly = {
+ .len = sizeof(struct nf_conntrack_zone),
+ .align = __alignof__(struct nf_conntrack_zone),
+ .id = NF_CT_EXT_ZONE,
+};
+#endif
+
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
#include <linux/netfilter/nfnetlink.h>
@@ -1139,6 +1179,9 @@ static void nf_conntrack_cleanup_init_net(void)
nf_conntrack_helper_fini();
nf_conntrack_proto_fini();
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+ nf_ct_extend_unregister(&nf_ct_zone_extend);
+#endif
}
static void nf_conntrack_cleanup_net(struct net *net)
@@ -1214,6 +1257,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
unsigned int hashsize, old_size;
struct hlist_nulls_head *hash, *old_hash;
struct nf_conntrack_tuple_hash *h;
+ struct nf_conn *ct;
if (current->nsproxy->net_ns != &init_net)
return -EOPNOTSUPP;
@@ -1240,8 +1284,10 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
while (!hlist_nulls_empty(&init_net.ct.hash[i])) {
h = hlist_nulls_entry(init_net.ct.hash[i].first,
struct nf_conntrack_tuple_hash, hnnode);
+ ct = nf_ct_tuplehash_to_ctrack(h);
hlist_nulls_del_rcu(&h->hnnode);
- bucket = __hash_conntrack(&h->tuple, hashsize,
+ bucket = __hash_conntrack(&h->tuple, nf_ct_zone(ct),
+ hashsize,
nf_conntrack_hash_rnd);
hlist_nulls_add_head_rcu(&h->hnnode, &hash[bucket]);
}
@@ -1299,6 +1345,11 @@ static int nf_conntrack_init_init_net(void)
if (ret < 0)
goto err_helper;
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+ ret = nf_ct_extend_register(&nf_ct_zone_extend);
+ if (ret < 0)
+ goto err_extend;
+#endif
/* Set up fake conntrack: to never be deleted, not in any hashes */
#ifdef CONFIG_NET_NS
nf_conntrack_untracked.ct_net = &init_net;
@@ -1309,6 +1360,10 @@ static int nf_conntrack_init_init_net(void)
return 0;
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+err_extend:
+ nf_conntrack_helper_fini();
+#endif
err_helper:
nf_conntrack_proto_fini();
err_proto:
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 6182fb1..acb29cc 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -27,6 +27,7 @@
#include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_tuple.h>
+#include <net/netfilter/nf_conntrack_zones.h>
unsigned int nf_ct_expect_hsize __read_mostly;
EXPORT_SYMBOL_GPL(nf_ct_expect_hsize);
@@ -84,7 +85,8 @@ static unsigned int nf_ct_expect_dst_hash(const struct nf_conntrack_tuple *tuple
}
struct nf_conntrack_expect *
-__nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple)
+__nf_ct_expect_find(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple)
{
struct nf_conntrack_expect *i;
struct hlist_node *n;
@@ -95,7 +97,8 @@ __nf_ct_expect_find(struct net *net, const struct nf_conntrack_tuple *tuple)
h = nf_ct_expect_dst_hash(tuple);
hlist_for_each_entry_rcu(i, n, &net->ct.expect_hash[h], hnode) {
- if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask))
+ if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
+ nf_ct_zone(i->master) == zone)
return i;
}
return NULL;
@@ -104,12 +107,13 @@ EXPORT_SYMBOL_GPL(__nf_ct_expect_find);
/* Just find a expectation corresponding to a tuple. */
struct nf_conntrack_expect *
-nf_ct_expect_find_get(struct net *net, const struct nf_conntrack_tuple *tuple)
+nf_ct_expect_find_get(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple)
{
struct nf_conntrack_expect *i;
rcu_read_lock();
- i = __nf_ct_expect_find(net, tuple);
+ i = __nf_ct_expect_find(net, zone, tuple);
if (i && !atomic_inc_not_zero(&i->use))
i = NULL;
rcu_read_unlock();
@@ -121,7 +125,8 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_find_get);
/* If an expectation for this connection is found, it gets delete from
* global list then returned. */
struct nf_conntrack_expect *
-nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple)
+nf_ct_find_expectation(struct net *net, u16 zone,
+ const struct nf_conntrack_tuple *tuple)
{
struct nf_conntrack_expect *i, *exp = NULL;
struct hlist_node *n;
@@ -133,7 +138,8 @@ nf_ct_find_expectation(struct net *net, const struct nf_conntrack_tuple *tuple)
h = nf_ct_expect_dst_hash(tuple);
hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) {
if (!(i->flags & NF_CT_EXPECT_INACTIVE) &&
- nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) {
+ nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) &&
+ nf_ct_zone(i->master) == zone) {
exp = i;
break;
}
@@ -204,7 +210,8 @@ static inline int expect_matches(const struct nf_conntrack_expect *a,
{
return a->master == b->master && a->class == b->class &&
nf_ct_tuple_equal(&a->tuple, &b->tuple) &&
- nf_ct_tuple_mask_equal(&a->mask, &b->mask);
+ nf_ct_tuple_mask_equal(&a->mask, &b->mask) &&
+ nf_ct_zone(a->master) == nf_ct_zone(b->master);
}
/* Generally a bad idea to call this: could have matched already. */
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 6636949..a1c8dd9 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -29,6 +29,7 @@
#include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_conntrack_ecache.h>
#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_zones.h>
#include <linux/netfilter/nf_conntrack_h323.h>
/* Parameters */
@@ -1216,7 +1217,7 @@ static struct nf_conntrack_expect *find_expect(struct nf_conn *ct,
tuple.dst.u.tcp.port = port;
tuple.dst.protonum = IPPROTO_TCP;
- exp = __nf_ct_expect_find(net, &tuple);
+ exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple);
if (exp && exp->master == ct)
return exp;
return NULL;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index db35eda..51089cf 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -811,7 +811,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
return err;
- h = nf_conntrack_find_get(net, &tuple);
+ h = nf_conntrack_find_get(net, 0, &tuple);
if (!h)
return -ENOENT;
@@ -872,7 +872,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
return err;
- h = nf_conntrack_find_get(net, &tuple);
+ h = nf_conntrack_find_get(net, 0, &tuple);
if (!h)
return -ENOENT;
@@ -1221,7 +1221,7 @@ ctnetlink_create_conntrack(struct net *net,
int err = -EINVAL;
struct nf_conntrack_helper *helper;
- ct = nf_conntrack_alloc(net, otuple, rtuple, GFP_ATOMIC);
+ ct = nf_conntrack_alloc(net, 0, otuple, rtuple, GFP_ATOMIC);
if (IS_ERR(ct))
return ERR_PTR(-ENOMEM);
@@ -1325,7 +1325,7 @@ ctnetlink_create_conntrack(struct net *net,
if (err < 0)
goto err2;
- master_h = nf_conntrack_find_get(net, &master);
+ master_h = nf_conntrack_find_get(net, 0, &master);
if (master_h == NULL) {
err = -ENOENT;
goto err2;
@@ -1374,9 +1374,9 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
spin_lock_bh(&nf_conntrack_lock);
if (cda[CTA_TUPLE_ORIG])
- h = __nf_conntrack_find(net, &otuple);
+ h = __nf_conntrack_find(net, 0, &otuple);
else if (cda[CTA_TUPLE_REPLY])
- h = __nf_conntrack_find(net, &rtuple);
+ h = __nf_conntrack_find(net, 0, &rtuple);
if (h == NULL) {
err = -ENOENT;
@@ -1714,7 +1714,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
return err;
- exp = nf_ct_expect_find_get(net, &tuple);
+ exp = nf_ct_expect_find_get(net, 0, &tuple);
if (!exp)
return -ENOENT;
@@ -1770,7 +1770,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
return err;
/* bump usage count to 2 */
- exp = nf_ct_expect_find_get(net, &tuple);
+ exp = nf_ct_expect_find_get(net, 0, &tuple);
if (!exp)
return -ENOENT;
@@ -1855,7 +1855,7 @@ ctnetlink_create_expect(struct net *net, const struct nlattr * const cda[],
return err;
/* Look for master conntrack of this expectation */
- h = nf_conntrack_find_get(net, &master_tuple);
+ h = nf_conntrack_find_get(net, 0, &master_tuple);
if (!h)
return -ENOENT;
ct = nf_ct_tuplehash_to_ctrack(h);
@@ -1912,7 +1912,7 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
return err;
spin_lock_bh(&nf_conntrack_lock);
- exp = __nf_ct_expect_find(net, &tuple);
+ exp = __nf_ct_expect_find(net, 0, &tuple);
if (!exp) {
spin_unlock_bh(&nf_conntrack_lock);
diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c
index 3807ac7..0889448 100644
--- a/net/netfilter/nf_conntrack_pptp.c
+++ b/net/netfilter/nf_conntrack_pptp.c
@@ -28,6 +28,7 @@
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_zones.h>
#include <linux/netfilter/nf_conntrack_proto_gre.h>
#include <linux/netfilter/nf_conntrack_pptp.h>
@@ -123,7 +124,7 @@ static void pptp_expectfn(struct nf_conn *ct,
pr_debug("trying to unexpect other dir: ");
nf_ct_dump_tuple(&inv_t);
- exp_other = nf_ct_expect_find_get(net, &inv_t);
+ exp_other = nf_ct_expect_find_get(net, nf_ct_zone(ct), &inv_t);
if (exp_other) {
/* delete other expectation. */
pr_debug("found\n");
@@ -136,17 +137,18 @@ static void pptp_expectfn(struct nf_conn *ct,
rcu_read_unlock();
}
-static int destroy_sibling_or_exp(struct net *net,
+static int destroy_sibling_or_exp(struct net *net, struct nf_conn *ct,
const struct nf_conntrack_tuple *t)
{
const struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_expect *exp;
struct nf_conn *sibling;
+ u16 zone = nf_ct_zone(ct);
pr_debug("trying to timeout ct or exp for tuple ");
nf_ct_dump_tuple(t);
- h = nf_conntrack_find_get(net, t);
+ h = nf_conntrack_find_get(net, zone, t);
if (h) {
sibling = nf_ct_tuplehash_to_ctrack(h);
pr_debug("setting timeout of conntrack %p to 0\n", sibling);
@@ -157,7 +159,7 @@ static int destroy_sibling_or_exp(struct net *net,
nf_ct_put(sibling);
return 1;
} else {
- exp = nf_ct_expect_find_get(net, t);
+ exp = nf_ct_expect_find_get(net, zone, t);
if (exp) {
pr_debug("unexpect_related of expect %p\n", exp);
nf_ct_unexpect_related(exp);
@@ -182,7 +184,7 @@ static void pptp_destroy_siblings(struct nf_conn *ct)
t.dst.protonum = IPPROTO_GRE;
t.src.u.gre.key = help->help.ct_pptp_info.pns_call_id;
t.dst.u.gre.key = help->help.ct_pptp_info.pac_call_id;
- if (!destroy_sibling_or_exp(net, &t))
+ if (!destroy_sibling_or_exp(net, ct, &t))
pr_debug("failed to timeout original pns->pac ct/exp\n");
/* try reply (pac->pns) tuple */
@@ -190,7 +192,7 @@ static void pptp_destroy_siblings(struct nf_conn *ct)
t.dst.protonum = IPPROTO_GRE;
t.src.u.gre.key = help->help.ct_pptp_info.pac_call_id;
t.dst.u.gre.key = help->help.ct_pptp_info.pns_call_id;
- if (!destroy_sibling_or_exp(net, &t))
+ if (!destroy_sibling_or_exp(net, ct, &t))
pr_debug("failed to timeout reply pac->pns ct/exp\n");
}
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index fbe8ff5..8dd75d9 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -23,6 +23,7 @@
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_conntrack_helper.h>
+#include <net/netfilter/nf_conntrack_zones.h>
#include <linux/netfilter/nf_conntrack_sip.h>
MODULE_LICENSE("GPL");
@@ -836,7 +837,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int dataoff,
rcu_read_lock();
do {
- exp = __nf_ct_expect_find(net, &tuple);
+ exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple);
if (!exp || exp->master == ct ||
nfct_help(exp->master)->helper != nfct_help(ct)->helper ||
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index e310f15..24a42ef 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -26,6 +26,7 @@
#include <net/netfilter/nf_conntrack_expect.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_acct.h>
+#include <net/netfilter/nf_conntrack_zones.h>
MODULE_LICENSE("GPL");
@@ -171,6 +172,11 @@ static int ct_seq_show(struct seq_file *s, void *v)
goto release;
#endif
+#ifdef CONFIG_NF_CONNTRACK_ZONES
+ if (seq_printf(s, "zone=%u ", nf_ct_zone(ct)))
+ goto release;
+#endif
+
if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use)))
goto release;
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index 8183a05..61c50fa 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -16,6 +16,7 @@
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_ecache.h>
+#include <net/netfilter/nf_conntrack_zones.h>
static unsigned int xt_ct_target(struct sk_buff *skb,
const struct xt_target_param *par)
@@ -69,11 +70,16 @@ static bool xt_ct_tg_check(const struct xt_tgchk_param *par)
goto out;
}
+#ifndef CONFIG_NF_CONNTRACK_ZONES
+ if (info->zone)
+ goto err1;
+#endif
+
if (nf_ct_l3proto_try_module_get(par->family) < 0)
goto err1;
memset(&t, 0, sizeof(t));
- ct = nf_conntrack_alloc(par->net, &t, &t, GFP_KERNEL);
+ ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL);
if (IS_ERR(ct))
goto err2;
diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c
index 0d9d18e..26997ce 100644
--- a/net/netfilter/xt_connlimit.c
+++ b/net/netfilter/xt_connlimit.c
@@ -28,6 +28,7 @@
#include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_core.h>
#include <net/netfilter/nf_conntrack_tuple.h>
+#include <net/netfilter/nf_conntrack_zones.h>
/* we will save the tuples of all connections we care about */
struct xt_connlimit_conn {
@@ -114,7 +115,8 @@ static int count_them(struct net *net,
/* check the saved connections */
list_for_each_entry_safe(conn, tmp, hash, list) {
- found = nf_conntrack_find_get(net, &conn->tuple);
+ found = nf_conntrack_find_get(net, NF_CT_DEFAULT_ZONE,
+ &conn->tuple);
found_ct = NULL;
if (found != NULL)
^ permalink raw reply related
* netfilter 57/62: nf_conntrack: pass template to l4proto ->error() handler
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit 8fea97ec1772bbf553d89187340ef624d548e115
Author: Patrick McHardy <kaber@trash.net>
Date: Mon Feb 15 17:45:08 2010 +0100
netfilter: nf_conntrack: pass template to l4proto ->error() handler
The error handlers might need the template to get the conntrack zone
introduced in the next patches to perform a conntrack lookup.
Signed-off-by: Patrick McHardy <kaber@trash.net>
diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
index ca6dcf3..e3d3ee3 100644
--- a/include/net/netfilter/nf_conntrack_l4proto.h
+++ b/include/net/netfilter/nf_conntrack_l4proto.h
@@ -49,8 +49,8 @@ struct nf_conntrack_l4proto {
/* Called when a conntrack entry is destroyed */
void (*destroy)(struct nf_conn *ct);
- int (*error)(struct net *net, struct sk_buff *skb, unsigned int dataoff,
- enum ip_conntrack_info *ctinfo,
+ int (*error)(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
+ unsigned int dataoff, enum ip_conntrack_info *ctinfo,
u_int8_t pf, unsigned int hooknum);
/* Print out the per-protocol part of the tuple. Return like seq_* */
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index 7afd39b..327826a 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -163,7 +163,8 @@ icmp_error_message(struct net *net, struct sk_buff *skb,
/* Small and modified version of icmp_rcv */
static int
-icmp_error(struct net *net, struct sk_buff *skb, unsigned int dataoff,
+icmp_error(struct net *net, struct nf_conn *tmpl,
+ struct sk_buff *skb, unsigned int dataoff,
enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum)
{
const struct icmphdr *icmph;
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index c7b8bd1..d772dc2 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -179,7 +179,8 @@ icmpv6_error_message(struct net *net,
}
static int
-icmpv6_error(struct net *net, struct sk_buff *skb, unsigned int dataoff,
+icmpv6_error(struct net *net, struct nf_conn *tmpl,
+ struct sk_buff *skb, unsigned int dataoff,
enum ip_conntrack_info *ctinfo, u_int8_t pf, unsigned int hooknum)
{
const struct icmp6hdr *icmp6h;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index bd83141..65351ed 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -799,7 +799,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
* inverse of the return code tells to the netfilter
* core what to do with the packet. */
if (l4proto->error != NULL) {
- ret = l4proto->error(net, skb, dataoff, &ctinfo, pf, hooknum);
+ ret = l4proto->error(net, tmpl, skb, dataoff, &ctinfo,
+ pf, hooknum);
if (ret <= 0) {
NF_CT_STAT_INC_ATOMIC(net, error);
NF_CT_STAT_INC_ATOMIC(net, invalid);
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index dd37550..9a28155 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -561,8 +561,9 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
return NF_ACCEPT;
}
-static int dccp_error(struct net *net, struct sk_buff *skb,
- unsigned int dataoff, enum ip_conntrack_info *ctinfo,
+static int dccp_error(struct net *net, struct nf_conn *tmpl,
+ struct sk_buff *skb, unsigned int dataoff,
+ enum ip_conntrack_info *ctinfo,
u_int8_t pf, unsigned int hooknum)
{
struct dccp_hdr _dh, *dh;
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index ad11805..9dd8cd4 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -760,7 +760,7 @@ static const u8 tcp_valid_flags[(TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG) + 1] =
};
/* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */
-static int tcp_error(struct net *net,
+static int tcp_error(struct net *net, struct nf_conn *tmpl,
struct sk_buff *skb,
unsigned int dataoff,
enum ip_conntrack_info *ctinfo,
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index 8d38f9a..8289088 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -91,8 +91,8 @@ static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb,
return true;
}
-static int udp_error(struct net *net, struct sk_buff *skb, unsigned int dataoff,
- enum ip_conntrack_info *ctinfo,
+static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
+ unsigned int dataoff, enum ip_conntrack_info *ctinfo,
u_int8_t pf,
unsigned int hooknum)
{
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c
index 0b1bc9b..263b5a7 100644
--- a/net/netfilter/nf_conntrack_proto_udplite.c
+++ b/net/netfilter/nf_conntrack_proto_udplite.c
@@ -89,7 +89,7 @@ static bool udplite_new(struct nf_conn *ct, const struct sk_buff *skb,
return true;
}
-static int udplite_error(struct net *net,
+static int udplite_error(struct net *net, struct nf_conn *tmpl,
struct sk_buff *skb,
unsigned int dataoff,
enum ip_conntrack_info *ctinfo,
^ permalink raw reply related
* netfilter 56/62: xtables: add const qualifiers
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit d5d1baa15f5b05e9110403724d5dc72d6d541e04
Author: Jan Engelhardt <jengelh@medozas.de>
Date: Fri Jun 26 07:51:59 2009 +0200
netfilter: xtables: add const qualifiers
This should make it easier to remove redundant arguments later.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 208f4e3..bcdf02d 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -82,7 +82,8 @@ static inline int ebt_do_match (struct ebt_entry_match *m,
return m->u.match->match(skb, par) ? EBT_MATCH : EBT_NOMATCH;
}
-static inline int ebt_dev_check(char *entry, const struct net_device *device)
+static inline int
+ebt_dev_check(const char *entry, const struct net_device *device)
{
int i = 0;
const char *devname;
@@ -100,8 +101,9 @@ static inline int ebt_dev_check(char *entry, const struct net_device *device)
#define FWINV2(bool,invflg) ((bool) ^ !!(e->invflags & invflg))
/* process standard matches */
-static inline int ebt_basic_match(struct ebt_entry *e, struct ethhdr *h,
- const struct net_device *in, const struct net_device *out)
+static inline int
+ebt_basic_match(const struct ebt_entry *e, const struct ethhdr *h,
+ const struct net_device *in, const struct net_device *out)
{
int verdict, i;
@@ -156,12 +158,12 @@ unsigned int ebt_do_table (unsigned int hook, struct sk_buff *skb,
int i, nentries;
struct ebt_entry *point;
struct ebt_counter *counter_base, *cb_base;
- struct ebt_entry_target *t;
+ const struct ebt_entry_target *t;
int verdict, sp = 0;
struct ebt_chainstack *cs;
struct ebt_entries *chaininfo;
- char *base;
- struct ebt_table_info *private;
+ const char *base;
+ const struct ebt_table_info *private;
bool hotdrop = false;
struct xt_match_param mtpar;
struct xt_target_param tgpar;
@@ -395,7 +397,7 @@ ebt_check_watcher(struct ebt_entry_watcher *w, struct xt_tgchk_param *par,
return 0;
}
-static int ebt_verify_pointers(struct ebt_replace *repl,
+static int ebt_verify_pointers(const struct ebt_replace *repl,
struct ebt_table_info *newinfo)
{
unsigned int limit = repl->entries_size;
@@ -466,8 +468,8 @@ static int ebt_verify_pointers(struct ebt_replace *repl,
* to parse the userspace data
*/
static inline int
-ebt_check_entry_size_and_hooks(struct ebt_entry *e,
- struct ebt_table_info *newinfo,
+ebt_check_entry_size_and_hooks(const struct ebt_entry *e,
+ const struct ebt_table_info *newinfo,
unsigned int *n, unsigned int *cnt,
unsigned int *totalcnt, unsigned int *udc_cnt)
{
@@ -622,9 +624,8 @@ ebt_cleanup_entry(struct ebt_entry *e, struct net *net, unsigned int *cnt)
}
static inline int
-ebt_check_entry(struct ebt_entry *e,
- struct net *net,
- struct ebt_table_info *newinfo,
+ebt_check_entry(struct ebt_entry *e, struct net *net,
+ const struct ebt_table_info *newinfo,
const char *name, unsigned int *cnt,
struct ebt_cl_stack *cl_s, unsigned int udc_cnt)
{
@@ -743,12 +744,12 @@ cleanup_matches:
* the hook mask for udc tells us from which base chains the udc can be
* accessed. This mask is a parameter to the check() functions of the extensions
*/
-static int check_chainloops(struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
+static int check_chainloops(const struct ebt_entries *chain, struct ebt_cl_stack *cl_s,
unsigned int udc_cnt, unsigned int hooknr, char *base)
{
int i, chain_nr = -1, pos = 0, nentries = chain->nentries, verdict;
- struct ebt_entry *e = (struct ebt_entry *)chain->data;
- struct ebt_entry_target *t;
+ const struct ebt_entry *e = (struct ebt_entry *)chain->data;
+ const struct ebt_entry_target *t;
while (pos < nentries || chain_nr != -1) {
/* end of udc, go back one 'recursion' step */
@@ -814,7 +815,7 @@ letscontinue:
}
/* do the parsing of the table/chains/entries/matches/watchers/targets, heh */
-static int translate_table(struct net *net, char *name,
+static int translate_table(struct net *net, const char *name,
struct ebt_table_info *newinfo)
{
unsigned int i, j, k, udc_cnt;
@@ -934,7 +935,7 @@ static int translate_table(struct net *net, char *name,
}
/* called under write_lock */
-static void get_counters(struct ebt_counter *oldcounters,
+static void get_counters(const struct ebt_counter *oldcounters,
struct ebt_counter *counters, unsigned int nentries)
{
int i, cpu;
@@ -957,7 +958,8 @@ static void get_counters(struct ebt_counter *oldcounters,
}
/* replace the table */
-static int do_replace(struct net *net, void __user *user, unsigned int len)
+static int do_replace(struct net *net, const void __user *user,
+ unsigned int len)
{
int ret, i, countersize;
struct ebt_table_info *newinfo;
@@ -1237,7 +1239,8 @@ void ebt_unregister_table(struct net *net, struct ebt_table *table)
}
/* userspace just supplied us with counters */
-static int update_counters(struct net *net, void __user *user, unsigned int len)
+static int update_counters(struct net *net, const void __user *user,
+ unsigned int len)
{
int i, ret;
struct ebt_counter *tmp;
@@ -1292,8 +1295,8 @@ free_tmp:
return ret;
}
-static inline int ebt_make_matchname(struct ebt_entry_match *m,
- char *base, char __user *ubase)
+static inline int ebt_make_matchname(const struct ebt_entry_match *m,
+ const char *base, char __user *ubase)
{
char __user *hlp = ubase + ((char *)m - base);
if (copy_to_user(hlp, m->u.match->name, EBT_FUNCTION_MAXNAMELEN))
@@ -1301,8 +1304,8 @@ static inline int ebt_make_matchname(struct ebt_entry_match *m,
return 0;
}
-static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
- char *base, char __user *ubase)
+static inline int ebt_make_watchername(const struct ebt_entry_watcher *w,
+ const char *base, char __user *ubase)
{
char __user *hlp = ubase + ((char *)w - base);
if (copy_to_user(hlp , w->u.watcher->name, EBT_FUNCTION_MAXNAMELEN))
@@ -1310,11 +1313,12 @@ static inline int ebt_make_watchername(struct ebt_entry_watcher *w,
return 0;
}
-static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *ubase)
+static inline int
+ebt_make_names(struct ebt_entry *e, const char *base, char __user *ubase)
{
int ret;
char __user *hlp;
- struct ebt_entry_target *t;
+ const struct ebt_entry_target *t;
if (e->bitmask == 0)
return 0;
@@ -1335,10 +1339,11 @@ static inline int ebt_make_names(struct ebt_entry *e, char *base, char __user *u
/* called with ebt_mutex locked */
static int copy_everything_to_user(struct ebt_table *t, void __user *user,
- int *len, int cmd)
+ const int *len, int cmd)
{
struct ebt_replace tmp;
- struct ebt_counter *counterstmp, *oldcounters;
+ struct ebt_counter *counterstmp;
+ const struct ebt_counter *oldcounters;
unsigned int entries_size, nentries;
char *entries;
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 2303dc9..4db5c1e 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -233,7 +233,14 @@ arpt_error(struct sk_buff *skb, const struct xt_target_param *par)
return NF_DROP;
}
-static inline struct arpt_entry *get_entry(void *base, unsigned int offset)
+static inline const struct arpt_entry_target *
+arpt_get_target_c(const struct arpt_entry *e)
+{
+ return arpt_get_target((struct arpt_entry *)e);
+}
+
+static inline struct arpt_entry *
+get_entry(const void *base, unsigned int offset)
{
return (struct arpt_entry *)(base + offset);
}
@@ -280,7 +287,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
arp = arp_hdr(skb);
do {
- struct arpt_entry_target *t;
+ const struct arpt_entry_target *t;
int hdr_len;
if (!arp_packet_match(arp, skb->dev, indev, outdev, &e->arp)) {
@@ -292,7 +299,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
(2 * skb->dev->addr_len);
ADD_COUNTER(e->counters, hdr_len, 1);
- t = arpt_get_target(e);
+ t = arpt_get_target_c(e);
/* Standard target? */
if (!t->u.kernel.target->target) {
@@ -358,7 +365,7 @@ static inline bool unconditional(const struct arpt_arp *arp)
/* Figures out from what hook each rule can be called: returns 0 if
* there are loops. Puts hook bitmask in comefrom.
*/
-static int mark_source_chains(struct xt_table_info *newinfo,
+static int mark_source_chains(const struct xt_table_info *newinfo,
unsigned int valid_hooks, void *entry0)
{
unsigned int hook;
@@ -379,7 +386,7 @@ static int mark_source_chains(struct xt_table_info *newinfo,
for (;;) {
const struct arpt_standard_target *t
- = (void *)arpt_get_target(e);
+ = (void *)arpt_get_target_c(e);
int visited = e->comefrom & (1 << hook);
if (e->comefrom & (1 << NF_ARP_NUMHOOKS)) {
@@ -463,7 +470,7 @@ static int mark_source_chains(struct xt_table_info *newinfo,
return 1;
}
-static inline int check_entry(struct arpt_entry *e, const char *name)
+static inline int check_entry(const struct arpt_entry *e, const char *name)
{
const struct arpt_entry_target *t;
@@ -475,7 +482,7 @@ static inline int check_entry(struct arpt_entry *e, const char *name)
if (e->target_offset + sizeof(struct arpt_entry_target) > e->next_offset)
return -EINVAL;
- t = arpt_get_target(e);
+ t = arpt_get_target_c(e);
if (e->target_offset + t->u.target_size > e->next_offset)
return -EINVAL;
@@ -540,14 +547,14 @@ out:
return ret;
}
-static bool check_underflow(struct arpt_entry *e)
+static bool check_underflow(const struct arpt_entry *e)
{
const struct arpt_entry_target *t;
unsigned int verdict;
if (!unconditional(&e->arp))
return false;
- t = arpt_get_target(e);
+ t = arpt_get_target_c(e);
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
return false;
verdict = ((struct arpt_standard_target *)t)->verdict;
@@ -557,8 +564,8 @@ static bool check_underflow(struct arpt_entry *e)
static inline int check_entry_size_and_hooks(struct arpt_entry *e,
struct xt_table_info *newinfo,
- unsigned char *base,
- unsigned char *limit,
+ const unsigned char *base,
+ const unsigned char *limit,
const unsigned int *hook_entries,
const unsigned int *underflows,
unsigned int valid_hooks,
@@ -768,11 +775,11 @@ static void get_counters(const struct xt_table_info *t,
local_bh_enable();
}
-static struct xt_counters *alloc_counters(struct xt_table *table)
+static struct xt_counters *alloc_counters(const struct xt_table *table)
{
unsigned int countersize;
struct xt_counters *counters;
- struct xt_table_info *private = table->private;
+ const struct xt_table_info *private = table->private;
/* We need atomic snapshot of counters: rest doesn't change
* (other than comefrom, which userspace doesn't care
@@ -790,11 +797,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table)
}
static int copy_entries_to_user(unsigned int total_size,
- struct xt_table *table,
+ const struct xt_table *table,
void __user *userptr)
{
unsigned int off, num;
- struct arpt_entry *e;
+ const struct arpt_entry *e;
struct xt_counters *counters;
struct xt_table_info *private = table->private;
int ret = 0;
@@ -814,7 +821,7 @@ static int copy_entries_to_user(unsigned int total_size,
/* FIXME: use iterator macros --RR */
/* ... then go back and fix counters and names */
for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
- struct arpt_entry_target *t;
+ const struct arpt_entry_target *t;
e = (struct arpt_entry *)(loc_cpu_entry + off);
if (copy_to_user(userptr + off
@@ -825,7 +832,7 @@ static int copy_entries_to_user(unsigned int total_size,
goto free_counters;
}
- t = arpt_get_target(e);
+ t = arpt_get_target_c(e);
if (copy_to_user(userptr + off + e->target_offset
+ offsetof(struct arpt_entry_target,
u.user.name),
@@ -860,18 +867,18 @@ static int compat_standard_to_user(void __user *dst, const void *src)
return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
}
-static int compat_calc_entry(struct arpt_entry *e,
+static int compat_calc_entry(const struct arpt_entry *e,
const struct xt_table_info *info,
- void *base, struct xt_table_info *newinfo)
+ const void *base, struct xt_table_info *newinfo)
{
- struct arpt_entry_target *t;
+ const struct arpt_entry_target *t;
unsigned int entry_offset;
int off, i, ret;
off = sizeof(struct arpt_entry) - sizeof(struct compat_arpt_entry);
entry_offset = (void *)e - base;
- t = arpt_get_target(e);
+ t = arpt_get_target_c(e);
off += xt_compat_target_offset(t->u.kernel.target);
newinfo->size -= off;
ret = xt_compat_add_offset(NFPROTO_ARP, entry_offset, off);
@@ -907,7 +914,8 @@ static int compat_table_info(const struct xt_table_info *info,
}
#endif
-static int get_info(struct net *net, void __user *user, int *len, int compat)
+static int get_info(struct net *net, void __user *user,
+ const int *len, int compat)
{
char name[ARPT_TABLE_MAXNAMELEN];
struct xt_table *t;
@@ -966,7 +974,7 @@ static int get_info(struct net *net, void __user *user, int *len, int compat)
}
static int get_entries(struct net *net, struct arpt_get_entries __user *uptr,
- int *len)
+ const int *len)
{
int ret;
struct arpt_get_entries get;
@@ -1080,7 +1088,8 @@ static int __do_replace(struct net *net, const char *name,
return ret;
}
-static int do_replace(struct net *net, void __user *user, unsigned int len)
+static int do_replace(struct net *net, const void __user *user,
+ unsigned int len)
{
int ret;
struct arpt_replace tmp;
@@ -1140,8 +1149,8 @@ add_counter_to_entry(struct arpt_entry *e,
return 0;
}
-static int do_add_counters(struct net *net, void __user *user, unsigned int len,
- int compat)
+static int do_add_counters(struct net *net, const void __user *user,
+ unsigned int len, int compat)
{
unsigned int i, curcpu;
struct xt_counters_info tmp;
@@ -1245,10 +1254,10 @@ static inline int
check_compat_entry_size_and_hooks(struct compat_arpt_entry *e,
struct xt_table_info *newinfo,
unsigned int *size,
- unsigned char *base,
- unsigned char *limit,
- unsigned int *hook_entries,
- unsigned int *underflows,
+ const unsigned char *base,
+ const unsigned char *limit,
+ const unsigned int *hook_entries,
+ const unsigned int *underflows,
unsigned int *i,
const char *name)
{
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 2a4f745..e94c18b 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -176,7 +176,7 @@ ipt_error(struct sk_buff *skb, const struct xt_target_param *par)
/* Performance critical - called for every packet */
static inline bool
-do_match(struct ipt_entry_match *m, const struct sk_buff *skb,
+do_match(const struct ipt_entry_match *m, const struct sk_buff *skb,
struct xt_match_param *par)
{
par->match = m->u.kernel.match;
@@ -191,7 +191,7 @@ do_match(struct ipt_entry_match *m, const struct sk_buff *skb,
/* Performance critical */
static inline struct ipt_entry *
-get_entry(void *base, unsigned int offset)
+get_entry(const void *base, unsigned int offset)
{
return (struct ipt_entry *)(base + offset);
}
@@ -206,6 +206,13 @@ static inline bool unconditional(const struct ipt_ip *ip)
#undef FWINV
}
+/* for const-correctness */
+static inline const struct ipt_entry_target *
+ipt_get_target_c(const struct ipt_entry *e)
+{
+ return ipt_get_target((struct ipt_entry *)e);
+}
+
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
static const char *const hooknames[] = {
@@ -240,11 +247,11 @@ static struct nf_loginfo trace_loginfo = {
/* Mildly perf critical (only if packet tracing is on) */
static inline int
-get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e,
+get_chainname_rulenum(const struct ipt_entry *s, const struct ipt_entry *e,
const char *hookname, const char **chainname,
const char **comment, unsigned int *rulenum)
{
- struct ipt_standard_target *t = (void *)ipt_get_target(s);
+ const struct ipt_standard_target *t = (void *)ipt_get_target_c(s);
if (strcmp(t->target.u.kernel.target->name, IPT_ERROR_TARGET) == 0) {
/* Head of user chain: ERROR target with chainname */
@@ -270,15 +277,15 @@ get_chainname_rulenum(struct ipt_entry *s, struct ipt_entry *e,
return 0;
}
-static void trace_packet(struct sk_buff *skb,
+static void trace_packet(const struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
const char *tablename,
- struct xt_table_info *private,
- struct ipt_entry *e)
+ const struct xt_table_info *private,
+ const struct ipt_entry *e)
{
- void *table_base;
+ const void *table_base;
const struct ipt_entry *root;
const char *hookname, *chainname, *comment;
unsigned int rulenum = 0;
@@ -322,9 +329,9 @@ ipt_do_table(struct sk_buff *skb,
/* Initializing verdict to NF_DROP keeps gcc happy. */
unsigned int verdict = NF_DROP;
const char *indev, *outdev;
- void *table_base;
+ const void *table_base;
struct ipt_entry *e, *back;
- struct xt_table_info *private;
+ const struct xt_table_info *private;
struct xt_match_param mtpar;
struct xt_target_param tgpar;
@@ -357,7 +364,7 @@ ipt_do_table(struct sk_buff *skb,
back = get_entry(table_base, private->underflow[hook]);
do {
- struct ipt_entry_target *t;
+ const struct ipt_entry_target *t;
IP_NF_ASSERT(e);
IP_NF_ASSERT(back);
@@ -450,7 +457,7 @@ ipt_do_table(struct sk_buff *skb,
/* Figures out from what hook each rule can be called: returns 0 if
there are loops. Puts hook bitmask in comefrom. */
static int
-mark_source_chains(struct xt_table_info *newinfo,
+mark_source_chains(const struct xt_table_info *newinfo,
unsigned int valid_hooks, void *entry0)
{
unsigned int hook;
@@ -468,8 +475,8 @@ mark_source_chains(struct xt_table_info *newinfo,
e->counters.pcnt = pos;
for (;;) {
- struct ipt_standard_target *t
- = (void *)ipt_get_target(e);
+ const struct ipt_standard_target *t
+ = (void *)ipt_get_target_c(e);
int visited = e->comefrom & (1 << hook);
if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
@@ -578,9 +585,9 @@ cleanup_match(struct ipt_entry_match *m, struct net *net, unsigned int *i)
}
static int
-check_entry(struct ipt_entry *e, const char *name)
+check_entry(const struct ipt_entry *e, const char *name)
{
- struct ipt_entry_target *t;
+ const struct ipt_entry_target *t;
if (!ip_checkentry(&e->ip)) {
duprintf("ip_tables: ip check failed %p %s.\n", e, name);
@@ -591,7 +598,7 @@ check_entry(struct ipt_entry *e, const char *name)
e->next_offset)
return -EINVAL;
- t = ipt_get_target(e);
+ t = ipt_get_target_c(e);
if (e->target_offset + t->u.target_size > e->next_offset)
return -EINVAL;
@@ -718,14 +725,14 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
return ret;
}
-static bool check_underflow(struct ipt_entry *e)
+static bool check_underflow(const struct ipt_entry *e)
{
const struct ipt_entry_target *t;
unsigned int verdict;
if (!unconditional(&e->ip))
return false;
- t = ipt_get_target(e);
+ t = ipt_get_target_c(e);
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
return false;
verdict = ((struct ipt_standard_target *)t)->verdict;
@@ -736,8 +743,8 @@ static bool check_underflow(struct ipt_entry *e)
static int
check_entry_size_and_hooks(struct ipt_entry *e,
struct xt_table_info *newinfo,
- unsigned char *base,
- unsigned char *limit,
+ const unsigned char *base,
+ const unsigned char *limit,
const unsigned int *hook_entries,
const unsigned int *underflows,
unsigned int valid_hooks,
@@ -952,11 +959,11 @@ get_counters(const struct xt_table_info *t,
local_bh_enable();
}
-static struct xt_counters * alloc_counters(struct xt_table *table)
+static struct xt_counters *alloc_counters(const struct xt_table *table)
{
unsigned int countersize;
struct xt_counters *counters;
- struct xt_table_info *private = table->private;
+ const struct xt_table_info *private = table->private;
/* We need atomic snapshot of counters: rest doesn't change
(other than comefrom, which userspace doesn't care
@@ -974,11 +981,11 @@ static struct xt_counters * alloc_counters(struct xt_table *table)
static int
copy_entries_to_user(unsigned int total_size,
- struct xt_table *table,
+ const struct xt_table *table,
void __user *userptr)
{
unsigned int off, num;
- struct ipt_entry *e;
+ const struct ipt_entry *e;
struct xt_counters *counters;
const struct xt_table_info *private = table->private;
int ret = 0;
@@ -1030,7 +1037,7 @@ copy_entries_to_user(unsigned int total_size,
}
}
- t = ipt_get_target(e);
+ t = ipt_get_target_c(e);
if (copy_to_user(userptr + off + e->target_offset
+ offsetof(struct ipt_entry_target,
u.user.name),
@@ -1066,24 +1073,24 @@ static int compat_standard_to_user(void __user *dst, const void *src)
}
static inline int
-compat_calc_match(struct ipt_entry_match *m, int *size)
+compat_calc_match(const struct ipt_entry_match *m, int *size)
{
*size += xt_compat_match_offset(m->u.kernel.match);
return 0;
}
-static int compat_calc_entry(struct ipt_entry *e,
+static int compat_calc_entry(const struct ipt_entry *e,
const struct xt_table_info *info,
- void *base, struct xt_table_info *newinfo)
+ const void *base, struct xt_table_info *newinfo)
{
- struct ipt_entry_target *t;
+ const struct ipt_entry_target *t;
unsigned int entry_offset;
int off, i, ret;
off = sizeof(struct ipt_entry) - sizeof(struct compat_ipt_entry);
entry_offset = (void *)e - base;
IPT_MATCH_ITERATE(e, compat_calc_match, &off);
- t = ipt_get_target(e);
+ t = ipt_get_target_c(e);
off += xt_compat_target_offset(t->u.kernel.target);
newinfo->size -= off;
ret = xt_compat_add_offset(AF_INET, entry_offset, off);
@@ -1119,7 +1126,8 @@ static int compat_table_info(const struct xt_table_info *info,
}
#endif
-static int get_info(struct net *net, void __user *user, int *len, int compat)
+static int get_info(struct net *net, void __user *user,
+ const int *len, int compat)
{
char name[IPT_TABLE_MAXNAMELEN];
struct xt_table *t;
@@ -1179,7 +1187,8 @@ static int get_info(struct net *net, void __user *user, int *len, int compat)
}
static int
-get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len)
+get_entries(struct net *net, struct ipt_get_entries __user *uptr,
+ const int *len)
{
int ret;
struct ipt_get_entries get;
@@ -1289,7 +1298,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
}
static int
-do_replace(struct net *net, void __user *user, unsigned int len)
+do_replace(struct net *net, const void __user *user, unsigned int len)
{
int ret;
struct ipt_replace tmp;
@@ -1350,7 +1359,8 @@ add_counter_to_entry(struct ipt_entry *e,
}
static int
-do_add_counters(struct net *net, void __user *user, unsigned int len, int compat)
+do_add_counters(struct net *net, const void __user *user,
+ unsigned int len, int compat)
{
unsigned int i, curcpu;
struct xt_counters_info tmp;
@@ -1546,10 +1556,10 @@ static int
check_compat_entry_size_and_hooks(struct compat_ipt_entry *e,
struct xt_table_info *newinfo,
unsigned int *size,
- unsigned char *base,
- unsigned char *limit,
- unsigned int *hook_entries,
- unsigned int *underflows,
+ const unsigned char *base,
+ const unsigned char *limit,
+ const unsigned int *hook_entries,
+ const unsigned int *underflows,
unsigned int *i,
const char *name)
{
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 3ff4fd5..4185099 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -208,7 +208,7 @@ ip6t_error(struct sk_buff *skb, const struct xt_target_param *par)
/* Performance critical - called for every packet */
static inline bool
-do_match(struct ip6t_entry_match *m, const struct sk_buff *skb,
+do_match(const struct ip6t_entry_match *m, const struct sk_buff *skb,
struct xt_match_param *par)
{
par->match = m->u.kernel.match;
@@ -222,7 +222,7 @@ do_match(struct ip6t_entry_match *m, const struct sk_buff *skb,
}
static inline struct ip6t_entry *
-get_entry(void *base, unsigned int offset)
+get_entry(const void *base, unsigned int offset)
{
return (struct ip6t_entry *)(base + offset);
}
@@ -236,6 +236,12 @@ static inline bool unconditional(const struct ip6t_ip6 *ipv6)
return memcmp(ipv6, &uncond, sizeof(uncond)) == 0;
}
+static inline const struct ip6t_entry_target *
+ip6t_get_target_c(const struct ip6t_entry *e)
+{
+ return ip6t_get_target((struct ip6t_entry *)e);
+}
+
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)
/* This cries for unification! */
@@ -271,11 +277,11 @@ static struct nf_loginfo trace_loginfo = {
/* Mildly perf critical (only if packet tracing is on) */
static inline int
-get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e,
+get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e,
const char *hookname, const char **chainname,
const char **comment, unsigned int *rulenum)
{
- struct ip6t_standard_target *t = (void *)ip6t_get_target(s);
+ const struct ip6t_standard_target *t = (void *)ip6t_get_target_c(s);
if (strcmp(t->target.u.kernel.target->name, IP6T_ERROR_TARGET) == 0) {
/* Head of user chain: ERROR target with chainname */
@@ -301,15 +307,15 @@ get_chainname_rulenum(struct ip6t_entry *s, struct ip6t_entry *e,
return 0;
}
-static void trace_packet(struct sk_buff *skb,
+static void trace_packet(const struct sk_buff *skb,
unsigned int hook,
const struct net_device *in,
const struct net_device *out,
const char *tablename,
- struct xt_table_info *private,
- struct ip6t_entry *e)
+ const struct xt_table_info *private,
+ const struct ip6t_entry *e)
{
- void *table_base;
+ const void *table_base;
const struct ip6t_entry *root;
const char *hookname, *chainname, *comment;
unsigned int rulenum = 0;
@@ -352,9 +358,9 @@ ip6t_do_table(struct sk_buff *skb,
/* Initializing verdict to NF_DROP keeps gcc happy. */
unsigned int verdict = NF_DROP;
const char *indev, *outdev;
- void *table_base;
+ const void *table_base;
struct ip6t_entry *e, *back;
- struct xt_table_info *private;
+ const struct xt_table_info *private;
struct xt_match_param mtpar;
struct xt_target_param tgpar;
@@ -385,7 +391,7 @@ ip6t_do_table(struct sk_buff *skb,
back = get_entry(table_base, private->underflow[hook]);
do {
- struct ip6t_entry_target *t;
+ const struct ip6t_entry_target *t;
IP_NF_ASSERT(e);
IP_NF_ASSERT(back);
@@ -400,7 +406,7 @@ ip6t_do_table(struct sk_buff *skb,
ntohs(ipv6_hdr(skb)->payload_len) +
sizeof(struct ipv6hdr), 1);
- t = ip6t_get_target(e);
+ t = ip6t_get_target_c(e);
IP_NF_ASSERT(t->u.kernel.target);
#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \
@@ -482,7 +488,7 @@ ip6t_do_table(struct sk_buff *skb,
/* Figures out from what hook each rule can be called: returns 0 if
there are loops. Puts hook bitmask in comefrom. */
static int
-mark_source_chains(struct xt_table_info *newinfo,
+mark_source_chains(const struct xt_table_info *newinfo,
unsigned int valid_hooks, void *entry0)
{
unsigned int hook;
@@ -500,8 +506,8 @@ mark_source_chains(struct xt_table_info *newinfo,
e->counters.pcnt = pos;
for (;;) {
- struct ip6t_standard_target *t
- = (void *)ip6t_get_target(e);
+ const struct ip6t_standard_target *t
+ = (void *)ip6t_get_target_c(e);
int visited = e->comefrom & (1 << hook);
if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
@@ -610,9 +616,9 @@ cleanup_match(struct ip6t_entry_match *m, struct net *net, unsigned int *i)
}
static int
-check_entry(struct ip6t_entry *e, const char *name)
+check_entry(const struct ip6t_entry *e, const char *name)
{
- struct ip6t_entry_target *t;
+ const struct ip6t_entry_target *t;
if (!ip6_checkentry(&e->ipv6)) {
duprintf("ip_tables: ip check failed %p %s.\n", e, name);
@@ -623,7 +629,7 @@ check_entry(struct ip6t_entry *e, const char *name)
e->next_offset)
return -EINVAL;
- t = ip6t_get_target(e);
+ t = ip6t_get_target_c(e);
if (e->target_offset + t->u.target_size > e->next_offset)
return -EINVAL;
@@ -750,14 +756,14 @@ find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
return ret;
}
-static bool check_underflow(struct ip6t_entry *e)
+static bool check_underflow(const struct ip6t_entry *e)
{
const struct ip6t_entry_target *t;
unsigned int verdict;
if (!unconditional(&e->ipv6))
return false;
- t = ip6t_get_target(e);
+ t = ip6t_get_target_c(e);
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
return false;
verdict = ((struct ip6t_standard_target *)t)->verdict;
@@ -768,8 +774,8 @@ static bool check_underflow(struct ip6t_entry *e)
static int
check_entry_size_and_hooks(struct ip6t_entry *e,
struct xt_table_info *newinfo,
- unsigned char *base,
- unsigned char *limit,
+ const unsigned char *base,
+ const unsigned char *limit,
const unsigned int *hook_entries,
const unsigned int *underflows,
unsigned int valid_hooks,
@@ -984,11 +990,11 @@ get_counters(const struct xt_table_info *t,
local_bh_enable();
}
-static struct xt_counters *alloc_counters(struct xt_table *table)
+static struct xt_counters *alloc_counters(const struct xt_table *table)
{
unsigned int countersize;
struct xt_counters *counters;
- struct xt_table_info *private = table->private;
+ const struct xt_table_info *private = table->private;
/* We need atomic snapshot of counters: rest doesn't change
(other than comefrom, which userspace doesn't care
@@ -1006,11 +1012,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table)
static int
copy_entries_to_user(unsigned int total_size,
- struct xt_table *table,
+ const struct xt_table *table,
void __user *userptr)
{
unsigned int off, num;
- struct ip6t_entry *e;
+ const struct ip6t_entry *e;
struct xt_counters *counters;
const struct xt_table_info *private = table->private;
int ret = 0;
@@ -1062,7 +1068,7 @@ copy_entries_to_user(unsigned int total_size,
}
}
- t = ip6t_get_target(e);
+ t = ip6t_get_target_c(e);
if (copy_to_user(userptr + off + e->target_offset
+ offsetof(struct ip6t_entry_target,
u.user.name),
@@ -1098,24 +1104,24 @@ static int compat_standard_to_user(void __user *dst, const void *src)
}
static inline int
-compat_calc_match(struct ip6t_entry_match *m, int *size)
+compat_calc_match(const struct ip6t_entry_match *m, int *size)
{
*size += xt_compat_match_offset(m->u.kernel.match);
return 0;
}
-static int compat_calc_entry(struct ip6t_entry *e,
+static int compat_calc_entry(const struct ip6t_entry *e,
const struct xt_table_info *info,
- void *base, struct xt_table_info *newinfo)
+ const void *base, struct xt_table_info *newinfo)
{
- struct ip6t_entry_target *t;
+ const struct ip6t_entry_target *t;
unsigned int entry_offset;
int off, i, ret;
off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
entry_offset = (void *)e - base;
IP6T_MATCH_ITERATE(e, compat_calc_match, &off);
- t = ip6t_get_target(e);
+ t = ip6t_get_target_c(e);
off += xt_compat_target_offset(t->u.kernel.target);
newinfo->size -= off;
ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
@@ -1151,7 +1157,8 @@ static int compat_table_info(const struct xt_table_info *info,
}
#endif
-static int get_info(struct net *net, void __user *user, int *len, int compat)
+static int get_info(struct net *net, void __user *user,
+ const int *len, int compat)
{
char name[IP6T_TABLE_MAXNAMELEN];
struct xt_table *t;
@@ -1211,7 +1218,8 @@ static int get_info(struct net *net, void __user *user, int *len, int compat)
}
static int
-get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len)
+get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
+ const int *len)
{
int ret;
struct ip6t_get_entries get;
@@ -1322,7 +1330,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
}
static int
-do_replace(struct net *net, void __user *user, unsigned int len)
+do_replace(struct net *net, const void __user *user, unsigned int len)
{
int ret;
struct ip6t_replace tmp;
@@ -1383,7 +1391,7 @@ add_counter_to_entry(struct ip6t_entry *e,
}
static int
-do_add_counters(struct net *net, void __user *user, unsigned int len,
+do_add_counters(struct net *net, const void __user *user, unsigned int len,
int compat)
{
unsigned int i, curcpu;
@@ -1582,10 +1590,10 @@ static int
check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
struct xt_table_info *newinfo,
unsigned int *size,
- unsigned char *base,
- unsigned char *limit,
- unsigned int *hook_entries,
- unsigned int *underflows,
+ const unsigned char *base,
+ const unsigned char *limit,
+ const unsigned int *hook_entries,
+ const unsigned int *underflows,
unsigned int *i,
const char *name)
{
^ permalink raw reply related
* netfilter 55/62: xtables: constify args in compat copying functions
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit 739674fb7febf116e7d647031fab16989a08a965
Author: Jan Engelhardt <jengelh@medozas.de>
Date: Fri Jun 26 08:23:19 2009 +0200
netfilter: xtables: constify args in compat copying functions
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h
index a0a144a..c61758f 100644
--- a/include/linux/netfilter/x_tables.h
+++ b/include/linux/netfilter/x_tables.h
@@ -286,8 +286,8 @@ struct xt_match {
void (*destroy)(const struct xt_mtdtor_param *);
#ifdef CONFIG_COMPAT
/* Called when userspace align differs from kernel space one */
- void (*compat_from_user)(void *dst, void *src);
- int (*compat_to_user)(void __user *dst, void *src);
+ void (*compat_from_user)(void *dst, const void *src);
+ int (*compat_to_user)(void __user *dst, const void *src);
#endif
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me;
@@ -328,8 +328,8 @@ struct xt_target {
void (*destroy)(const struct xt_tgdtor_param *);
#ifdef CONFIG_COMPAT
/* Called when userspace align differs from kernel space one */
- void (*compat_from_user)(void *dst, void *src);
- int (*compat_to_user)(void __user *dst, void *src);
+ void (*compat_from_user)(void *dst, const void *src);
+ int (*compat_to_user)(void __user *dst, const void *src);
#endif
/* Set this to THIS_MODULE if you are a module, otherwise NULL */
struct module *me;
@@ -593,13 +593,13 @@ extern short xt_compat_calc_jump(u_int8_t af, unsigned int offset);
extern int xt_compat_match_offset(const struct xt_match *match);
extern int xt_compat_match_from_user(struct xt_entry_match *m,
void **dstptr, unsigned int *size);
-extern int xt_compat_match_to_user(struct xt_entry_match *m,
+extern int xt_compat_match_to_user(const struct xt_entry_match *m,
void __user **dstptr, unsigned int *size);
extern int xt_compat_target_offset(const struct xt_target *target);
extern void xt_compat_target_from_user(struct xt_entry_target *t,
void **dstptr, unsigned int *size);
-extern int xt_compat_target_to_user(struct xt_entry_target *t,
+extern int xt_compat_target_to_user(const struct xt_entry_target *t,
void __user **dstptr, unsigned int *size);
#endif /* CONFIG_COMPAT */
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 72723ea..2303dc9 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -842,7 +842,7 @@ static int copy_entries_to_user(unsigned int total_size,
}
#ifdef CONFIG_COMPAT
-static void compat_standard_from_user(void *dst, void *src)
+static void compat_standard_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
@@ -851,7 +851,7 @@ static void compat_standard_from_user(void *dst, void *src)
memcpy(dst, &v, sizeof(v));
}
-static int compat_standard_to_user(void __user *dst, void *src)
+static int compat_standard_to_user(void __user *dst, const void *src)
{
compat_int_t cv = *(int *)src;
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 2057b1b..2a4f745 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1047,7 +1047,7 @@ copy_entries_to_user(unsigned int total_size,
}
#ifdef CONFIG_COMPAT
-static void compat_standard_from_user(void *dst, void *src)
+static void compat_standard_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
@@ -1056,7 +1056,7 @@ static void compat_standard_from_user(void *dst, void *src)
memcpy(dst, &v, sizeof(v));
}
-static int compat_standard_to_user(void __user *dst, void *src)
+static int compat_standard_to_user(void __user *dst, const void *src)
{
compat_int_t cv = *(int *)src;
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index 399061c..09a5d3f 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -338,7 +338,7 @@ struct compat_ipt_ulog_info {
char prefix[ULOG_PREFIX_LEN];
};
-static void ulog_tg_compat_from_user(void *dst, void *src)
+static void ulog_tg_compat_from_user(void *dst, const void *src)
{
const struct compat_ipt_ulog_info *cl = src;
struct ipt_ulog_info l = {
@@ -351,7 +351,7 @@ static void ulog_tg_compat_from_user(void *dst, void *src)
memcpy(dst, &l, sizeof(l));
}
-static int ulog_tg_compat_to_user(void __user *dst, void *src)
+static int ulog_tg_compat_to_user(void __user *dst, const void *src)
{
const struct ipt_ulog_info *l = src;
struct compat_ipt_ulog_info cl = {
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index dcd7825..3ff4fd5 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -1079,7 +1079,7 @@ copy_entries_to_user(unsigned int total_size,
}
#ifdef CONFIG_COMPAT
-static void compat_standard_from_user(void *dst, void *src)
+static void compat_standard_from_user(void *dst, const void *src)
{
int v = *(compat_int_t *)src;
@@ -1088,7 +1088,7 @@ static void compat_standard_from_user(void *dst, void *src)
memcpy(dst, &v, sizeof(v));
}
-static int compat_standard_to_user(void __user *dst, void *src)
+static int compat_standard_to_user(void __user *dst, const void *src)
{
compat_int_t cv = *(int *)src;
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 1250319..69c5628 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -485,8 +485,8 @@ int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr,
}
EXPORT_SYMBOL_GPL(xt_compat_match_from_user);
-int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr,
- unsigned int *size)
+int xt_compat_match_to_user(const struct xt_entry_match *m,
+ void __user **dstptr, unsigned int *size)
{
const struct xt_match *match = m->u.kernel.match;
struct compat_xt_entry_match __user *cm = *dstptr;
@@ -588,8 +588,8 @@ void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr,
}
EXPORT_SYMBOL_GPL(xt_compat_target_from_user);
-int xt_compat_target_to_user(struct xt_entry_target *t, void __user **dstptr,
- unsigned int *size)
+int xt_compat_target_to_user(const struct xt_entry_target *t,
+ void __user **dstptr, unsigned int *size)
{
const struct xt_target *target = t->u.kernel.target;
struct compat_xt_entry_target __user *ct = *dstptr;
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index 017c959..e47fb80 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -775,7 +775,7 @@ struct compat_xt_hashlimit_info {
compat_uptr_t master;
};
-static void hashlimit_mt_compat_from_user(void *dst, void *src)
+static void hashlimit_mt_compat_from_user(void *dst, const void *src)
{
int off = offsetof(struct compat_xt_hashlimit_info, hinfo);
@@ -783,7 +783,7 @@ static void hashlimit_mt_compat_from_user(void *dst, void *src)
memset(dst + off, 0, sizeof(struct compat_xt_hashlimit_info) - off);
}
-static int hashlimit_mt_compat_to_user(void __user *dst, void *src)
+static int hashlimit_mt_compat_to_user(void __user *dst, const void *src)
{
int off = offsetof(struct compat_xt_hashlimit_info, hinfo);
diff --git a/net/netfilter/xt_limit.c b/net/netfilter/xt_limit.c
index 2773be6..a0ca533 100644
--- a/net/netfilter/xt_limit.c
+++ b/net/netfilter/xt_limit.c
@@ -148,7 +148,7 @@ struct compat_xt_rateinfo {
/* To keep the full "prev" timestamp, the upper 32 bits are stored in the
* master pointer, which does not need to be preserved. */
-static void limit_mt_compat_from_user(void *dst, void *src)
+static void limit_mt_compat_from_user(void *dst, const void *src)
{
const struct compat_xt_rateinfo *cm = src;
struct xt_rateinfo m = {
@@ -162,7 +162,7 @@ static void limit_mt_compat_from_user(void *dst, void *src)
memcpy(dst, &m, sizeof(m));
}
-static int limit_mt_compat_to_user(void __user *dst, void *src)
+static int limit_mt_compat_to_user(void __user *dst, const void *src)
{
const struct xt_rateinfo *m = src;
struct compat_xt_rateinfo cm = {
^ permalink raw reply related
* netfilter 54/62: xtables: print details on size mismatch
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit b402405d71beed8e4df354844353f66b4e18269f
Author: Jan Engelhardt <jengelh@medozas.de>
Date: Thu Jun 25 18:32:12 2009 +0200
netfilter: xtables: print details on size mismatch
Print which revision has been used and which size are which
(kernel/user) for easier debugging.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 255ab06..1250319 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -366,8 +366,10 @@ int xt_check_match(struct xt_mtchk_param *par,
* ebt_among is exempt from centralized matchsize checking
* because it uses a dynamic-size data set.
*/
- pr_err("%s_tables: %s match: invalid size %u != %u\n",
+ pr_err("%s_tables: %s.%u match: invalid size "
+ "%u (kernel) != (user) %u\n",
xt_prefix[par->family], par->match->name,
+ par->match->revision,
XT_ALIGN(par->match->matchsize), size);
return -EINVAL;
}
@@ -516,8 +518,10 @@ int xt_check_target(struct xt_tgchk_param *par,
unsigned int size, u_int8_t proto, bool inv_proto)
{
if (XT_ALIGN(par->target->targetsize) != size) {
- pr_err("%s_tables: %s target: invalid size %u != %u\n",
+ pr_err("%s_tables: %s.%u target: invalid size "
+ "%u (kernel) != (user) %u\n",
xt_prefix[par->family], par->target->name,
+ par->target->revision,
XT_ALIGN(par->target->targetsize), size);
return -EINVAL;
}
^ permalink raw reply related
* netfilter 53/62: get rid of the grossness in netfilter.h
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit 2249065f4b22b493bae2caf549b86f175f33188e
Author: Jan Engelhardt <jengelh@medozas.de>
Date: Sat Jun 13 04:13:26 2009 +0200
netfilter: get rid of the grossness in netfilter.h
GCC is now smart enough to follow the inline trail correctly.
vmlinux size remain the same.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 2f22816..7007945 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -196,25 +196,36 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
coders :)
*/
-/* This is gross, but inline doesn't cut it for avoiding the function
- call in fast path: gcc doesn't inline (needs value tracking?). --RR */
-
-/* HX: It's slightly less gross now. */
-
-#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) \
-({int __ret; \
-if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, thresh)) == 1)\
- __ret = (okfn)(skb); \
-__ret;})
+static inline int
+NF_HOOK_THRESH(uint8_t pf, unsigned int hook, struct sk_buff *skb,
+ struct net_device *in, struct net_device *out,
+ int (*okfn)(struct sk_buff *), int thresh)
+{
+ int ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, thresh);
+ if (ret == 1)
+ ret = okfn(skb);
+ return ret;
+}
-#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) \
-({int __ret; \
-if ((cond) || (__ret = nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, INT_MIN)) == 1)\
- __ret = (okfn)(skb); \
-__ret;})
+static inline int
+NF_HOOK_COND(uint8_t pf, unsigned int hook, struct sk_buff *skb,
+ struct net_device *in, struct net_device *out,
+ int (*okfn)(struct sk_buff *), bool cond)
+{
+ int ret = 1;
+ if (cond ||
+ (ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, INT_MIN) == 1))
+ ret = okfn(skb);
+ return ret;
+}
-#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \
- NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, INT_MIN)
+static inline int
+NF_HOOK(uint8_t pf, unsigned int hook, struct sk_buff *skb,
+ struct net_device *in, struct net_device *out,
+ int (*okfn)(struct sk_buff *))
+{
+ return NF_HOOK_THRESH(pf, hook, skb, in, out, okfn, INT_MIN);
+}
/* Call setsockopt() */
int nf_setsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt,
^ permalink raw reply related
* netfilter 52/62: reduce NF_HOOK by one argument
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit 23f3733d440b918ccb7746718f77256334cf6176
Author: Jan Engelhardt <jengelh@medozas.de>
Date: Fri Jun 5 17:31:46 2009 +0200
netfilter: reduce NF_HOOK by one argument
No changes in vmlinux filesize.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 78f33d2..2f22816 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -163,11 +163,8 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
struct sk_buff *skb,
struct net_device *indev,
struct net_device *outdev,
- int (*okfn)(struct sk_buff *), int thresh,
- int cond)
+ int (*okfn)(struct sk_buff *), int thresh)
{
- if (!cond)
- return 1;
#ifndef CONFIG_NETFILTER_DEBUG
if (list_empty(&nf_hooks[pf][hook]))
return 1;
@@ -179,7 +176,7 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
struct net_device *indev, struct net_device *outdev,
int (*okfn)(struct sk_buff *))
{
- return nf_hook_thresh(pf, hook, skb, indev, outdev, okfn, INT_MIN, 1);
+ return nf_hook_thresh(pf, hook, skb, indev, outdev, okfn, INT_MIN);
}
/* Activate hook; either okfn or kfree_skb called, unless a hook
@@ -206,13 +203,13 @@ static inline int nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
#define NF_HOOK_THRESH(pf, hook, skb, indev, outdev, okfn, thresh) \
({int __ret; \
-if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, thresh, 1)) == 1)\
+if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, thresh)) == 1)\
__ret = (okfn)(skb); \
__ret;})
#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) \
({int __ret; \
-if ((__ret=nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, INT_MIN, cond)) == 1)\
+if ((cond) || (__ret = nf_hook_thresh(pf, hook, (skb), indev, outdev, okfn, INT_MIN)) == 1)\
__ret = (okfn)(skb); \
__ret;})
@@ -328,8 +325,7 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook,
struct sk_buff *skb,
struct net_device *indev,
struct net_device *outdev,
- int (*okfn)(struct sk_buff *), int thresh,
- int cond)
+ int (*okfn)(struct sk_buff *), int thresh)
{
return okfn(skb);
}
^ permalink raw reply related
* netfilter 51/62: iptables: remove unused function arguments
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit fa96a0e2e67fe34a3d994e3f354a5c229dd14286
Author: Jan Engelhardt <jengelh@medozas.de>
Date: Sun Nov 1 00:36:40 2009 +0100
netfilter: iptables: remove unused function arguments
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index c833330..b9b8346 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -36,11 +36,7 @@ static const struct xt_table packet_mangler = {
};
static unsigned int
-ipt_local_hook(unsigned int hook,
- struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+ipt_mangle_out(struct sk_buff *skb, const struct net_device *out)
{
unsigned int ret;
const struct iphdr *iph;
@@ -60,7 +56,7 @@ ipt_local_hook(unsigned int hook,
daddr = iph->daddr;
tos = iph->tos;
- ret = ipt_do_table(skb, hook, in, out,
+ ret = ipt_do_table(skb, NF_INET_LOCAL_OUT, NULL, out,
dev_net(out)->ipv4.iptable_mangle);
/* Reroute for ANY change. */
if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) {
@@ -86,7 +82,7 @@ iptable_mangle_hook(unsigned int hook,
int (*okfn)(struct sk_buff *))
{
if (hook == NF_INET_LOCAL_OUT)
- return ipt_local_hook(hook, skb, in, out, okfn);
+ return ipt_mangle_out(skb, out);
if (hook == NF_INET_POST_ROUTING)
return ipt_do_table(skb, hook, in, out,
dev_net(out)->ipv4.iptable_mangle);
diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c
index b6216de..7844e55 100644
--- a/net/ipv6/netfilter/ip6table_mangle.c
+++ b/net/ipv6/netfilter/ip6table_mangle.c
@@ -30,12 +30,8 @@ static const struct xt_table packet_mangler = {
};
static unsigned int
-ip6t_local_out_hook(unsigned int hook,
- struct sk_buff *skb,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
+ip6t_mangle_out(struct sk_buff *skb, const struct net_device *out)
{
-
unsigned int ret;
struct in6_addr saddr, daddr;
u_int8_t hop_limit;
@@ -60,7 +56,7 @@ ip6t_local_out_hook(unsigned int hook,
/* flowlabel and prio (includes version, which shouldn't change either */
flowlabel = *((u_int32_t *)ipv6_hdr(skb));
- ret = ip6t_do_table(skb, hook, NULL, out,
+ ret = ip6t_do_table(skb, NF_INET_LOCAL_OUT, NULL, out,
dev_net(out)->ipv6.ip6table_mangle);
if (ret != NF_DROP && ret != NF_STOLEN &&
@@ -80,7 +76,7 @@ ip6table_mangle_hook(unsigned int hook, struct sk_buff *skb,
int (*okfn)(struct sk_buff *))
{
if (hook == NF_INET_LOCAL_OUT)
- return ip6t_local_out_hook(hook, skb, out, okfn);
+ return ip6t_mangle_out(skb, out);
if (hook == NF_INET_POST_ROUTING)
return ip6t_do_table(skb, hook, in, out,
dev_net(out)->ipv6.ip6table_mangle);
^ permalink raw reply related
* netfilter 49/62: don't use INIT_RCU_HEAD()
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit ca1c2e2da9637c131436bf6d6ae41b58f5353afe
Author: Alexey Dobriyan <adobriyan@gmail.com>
Date: Fri Feb 12 06:25:36 2010 +0100
netfilter: don't use INIT_RCU_HEAD()
call_rcu() will unconditionally reinitialize RCU head anyway.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Reviewed-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 33b85f8..6182fb1 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -232,7 +232,6 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
new->master = me;
atomic_set(&new->use, 1);
- INIT_RCU_HEAD(&new->rcu);
return new;
}
EXPORT_SYMBOL_GPL(nf_ct_expect_alloc);
diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c
index fef95be..fdc8fb4 100644
--- a/net/netfilter/nf_conntrack_extend.c
+++ b/net/netfilter/nf_conntrack_extend.c
@@ -59,7 +59,6 @@ nf_ct_ext_create(struct nf_ct_ext **ext, enum nf_ct_ext_id id, gfp_t gfp)
if (!*ext)
return NULL;
- INIT_RCU_HEAD(&(*ext)->rcu);
(*ext)->offset[id] = off;
(*ext)->len = len;
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 90cf36d..7ba4abc 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -112,7 +112,6 @@ instance_create(u_int16_t queue_num, int pid)
inst->copy_mode = NFQNL_COPY_NONE;
spin_lock_init(&inst->lock);
INIT_LIST_HEAD(&inst->queue_list);
- INIT_RCU_HEAD(&inst->rcu);
if (!try_module_get(THIS_MODULE)) {
err = -EAGAIN;
^ permalink raw reply related
* netfilter 50/62: xt_recent: inform user when hitcount is too large
From: Patrick McHardy @ 2010-02-16 14:56 UTC (permalink / raw)
To: davem; +Cc: netdev, Patrick McHardy, netfilter-devel
In-Reply-To: <20100216145517.2796.40634.sendpatchset@x2.localnet>
commit 98e6d2d5ee26bf56850a10eb64139c68fb09ba19
Author: Jan Engelhardt <jengelh@medozas.de>
Date: Mon Feb 15 16:31:35 2010 +0100
netfilter: xt_recent: inform user when hitcount is too large
It is one of these things that iptables cannot catch and which can
cause "Invalid argument" to be printed. Without a hint in dmesg, it is
not going to be helpful.
Signed-off-by: Jan Engelhardt <jengelh@medozas.de>
Signed-off-by: Patrick McHardy <kaber@trash.net>
diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c
index 2033331..132cfaa 100644
--- a/net/netfilter/xt_recent.c
+++ b/net/netfilter/xt_recent.c
@@ -53,7 +53,7 @@ module_param(ip_list_perms, uint, 0400);
module_param(ip_list_uid, uint, 0400);
module_param(ip_list_gid, uint, 0400);
MODULE_PARM_DESC(ip_list_tot, "number of IPs to remember per list");
-MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP to remember (max. 255)");
+MODULE_PARM_DESC(ip_pkt_list_tot, "number of packets per IP address to remember (max. 255)");
MODULE_PARM_DESC(ip_list_hash_size, "size of hash table used to look up IPs");
MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/xt_recent/* files");
MODULE_PARM_DESC(ip_list_uid,"owner of /proc/net/xt_recent/* files");
@@ -306,8 +306,12 @@ static bool recent_mt_check(const struct xt_mtchk_param *par)
if ((info->check_set & (XT_RECENT_SET | XT_RECENT_REMOVE)) &&
(info->seconds || info->hit_count))
return false;
- if (info->hit_count > ip_pkt_list_tot)
+ if (info->hit_count > ip_pkt_list_tot) {
+ pr_info(KBUILD_MODNAME ": hitcount (%u) is larger than "
+ "packets to be remembered (%u)\n",
+ info->hit_count, ip_pkt_list_tot);
return false;
+ }
if (info->name[0] == '\0' ||
strnlen(info->name, XT_RECENT_NAME_LEN) == XT_RECENT_NAME_LEN)
return false;
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox