* [PATCH 1/2] netfilter: ctnetlink: fix return value of ctnetlink_get_expect()
From: pablo @ 2011-12-24 18:52 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324752768-5853-1-git-send-email-pablo@netfilter.org>
From: Pablo Neira Ayuso <pablo@netfilter.org>
This fixes one bogus error that is returned to user-space:
libnetfilter_conntrack/utils# ./expect_get
TEST: get expectation (-1)(Unknown error 18446744073709551504)
This patch includes the correct handling for EAGAIN (nfnetlink
uses this error value to restart the operation after module
auto-loading).
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_conntrack_netlink.c | 15 ++++++++++-----
1 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index ef21b22..3d7ea7a 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1869,25 +1869,30 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
err = -ENOMEM;
skb2 = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (skb2 == NULL)
+ if (skb2 == NULL) {
+ nf_ct_expect_put(exp);
goto out;
+ }
rcu_read_lock();
err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid,
nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, exp);
rcu_read_unlock();
+ nf_ct_expect_put(exp);
if (err <= 0)
goto free;
- nf_ct_expect_put(exp);
+ err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
+ if (err < 0)
+ goto out;
- return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
+ return 0;
free:
kfree_skb(skb2);
out:
- nf_ct_expect_put(exp);
- return err;
+ /* this avoids a loop in nfnetlink. */
+ return err == -EAGAIN ? -ENOBUFS : err;
}
static int
--
1.7.2.5
^ permalink raw reply related
* [PATCH 2/2] netfilter: ctnetlink: fix scheduling while atomic if helper is autoloaded
From: pablo @ 2011-12-24 18:52 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324752768-5853-1-git-send-email-pablo@netfilter.org>
From: Pablo Neira Ayuso <pablo@netfilter.org>
This patch fixes one scheduling while atomic error:
[ 385.565186] ctnetlink v0.93: registering with nfnetlink.
[ 385.565349] BUG: scheduling while atomic: lt-expect_creat/16163/0x00000200
It can be triggered with utils/expect_create included in
libnetfilter_conntrack if the FTP helper is not loaded.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_conntrack_netlink.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 3d7ea7a..b697777 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1358,12 +1358,15 @@ ctnetlink_create_conntrack(struct net *net, u16 zone,
nf_ct_protonum(ct));
if (helper == NULL) {
rcu_read_unlock();
+ spin_unlock_bh(&nf_conntrack_lock);
#ifdef CONFIG_MODULES
if (request_module("nfct-helper-%s", helpname) < 0) {
+ spin_lock_bh(&nf_conntrack_lock);
err = -EOPNOTSUPP;
goto err1;
}
+ spin_lock_bh(&nf_conntrack_lock);
rcu_read_lock();
helper = __nf_conntrack_helper_find(helpname,
nf_ct_l3num(ct),
--
1.7.2.5
^ permalink raw reply related
* Re: [PATCH] netem: dont call vfree() under spinlock and BH disabled
From: Stephen Hemminger @ 2011-12-24 19:18 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <1324704531.2915.43.camel@edumazet-laptop>
On Sat, 24 Dec 2011 06:28:51 +0100
Eric Dumazet <eric.dumazet@gmail.com> wrote:
> commit 6373a9a286 (netem: use vmalloc for distribution table) added a
> regression, since vfree() is called while holding a spinlock and BH
> being disabled.
>
> Fix this by doing the pointers swap in critical section, and freeing
> after spinlock release.
>
> Also add __GFP_NOWARN to the kmalloc() try, since we fallback to
> vmalloc().
>
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
> ---
> net/sched/sch_netem.c | 7 ++++---
> 1 file changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
> index eb3b9a8..a4ab207 100644
> --- a/net/sched/sch_netem.c
> +++ b/net/sched/sch_netem.c
> @@ -488,7 +488,7 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
> return -EINVAL;
>
> s = sizeof(struct disttable) + n * sizeof(s16);
> - d = kmalloc(s, GFP_KERNEL);
> + d = kmalloc(s, GFP_KERNEL | __GFP_NOWARN);
> if (!d)
> d = vmalloc(s);
> if (!d)
> @@ -501,9 +501,10 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr)
> root_lock = qdisc_root_sleeping_lock(sch);
>
> spin_lock_bh(root_lock);
> - dist_free(q->delay_dist);
> - q->delay_dist = d;
> + swap(q->delay_dist, d);
> spin_unlock_bh(root_lock);
> +
> + dist_free(d);
> return 0;
> }
Acked-by: Stephen Hemminger <shemminger@vyatta.com>
^ permalink raw reply
* Re: [PATCH iproute2] netem: fix a typo in explain()
From: Stephen Hemminger @ 2011-12-24 19:21 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev
In-Reply-To: <1324701553.2915.32.camel@edumazet-laptop>
On Sat, 24 Dec 2011 05:39:13 +0100
Eric Dumazet <eric.dumazet@gmail.com> wrote:
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
> ---
> tc/q_netem.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/tc/q_netem.c b/tc/q_netem.c
> index e9a601b..b1fd452 100644
> --- a/tc/q_netem.c
> +++ b/tc/q_netem.c
> @@ -38,7 +38,7 @@ static void explain(void)
> " [ loss random PERCENT [CORRELATION]]\n" \
> " [ loss state P13 [P31 [P32 [P23 P14]]]\n" \
> " [ loss gemodel PERCENT [R [1-H [1-K]]]\n" \
> -" [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n");
> +" [ reorder PERCENT [CORRELATION] [ gap DISTANCE ]]\n");
> }
>
> static void explain1(const char *arg)
>
>
Applied
^ permalink raw reply
* PRIO qdisc classes and filters
From: John A. Sullivan III @ 2011-12-24 19:36 UTC (permalink / raw)
To: netdev
Hello, all. Sorry for such pestering; I really do spend a lot of time
in Internet research before posting believe it or not!
Is it my imagination or is it not possible to attach a filter to a PRIO
qdisc class? I only succeed in attaching filters to root or the qdisc
itself.
tc qdisc add dev eth1 root handle 2: prio bands 2 priomap 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
root@testswitch01:~# tc filter add dev eth1 parent 2:2 protocol ip prio 1 u32 match u32 0 0 flowid 1:1
RTNETLINK answers: Invalid argument
We have an error talking to the kernel
root@testswitch01:~# tc filter add dev eth1 parent 2:0 protocol ip prio 1 u32 match u32 0 0 flowid 1:0
root@testswitch01:~# tc filter del dev eth1 parent 2:0 protocol ip prio 1 u32 match u32 0 0 flowid 1:0
root@testswitch01:~# tc filter add dev eth1 parent 2:1 protocol ip prio 1 u32 match u32 0 0 flowid 1:0
RTNETLINK answers: Invalid argument
We have an error talking to the kernel
I am trying to use PRIO simply as a container so that I can apply two
separate filters to the same traffic. Thanks - John
^ permalink raw reply
* Re: [PATCH] netem: dont call vfree() under spinlock and BH disabled
From: David Miller @ 2011-12-24 21:10 UTC (permalink / raw)
To: shemminger; +Cc: eric.dumazet, netdev
In-Reply-To: <20111224111854.479d497e@nehalam.linuxnetplumber.net>
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Sat, 24 Dec 2011 11:18:54 -0800
> On Sat, 24 Dec 2011 06:28:51 +0100
> Eric Dumazet <eric.dumazet@gmail.com> wrote:
>
>> commit 6373a9a286 (netem: use vmalloc for distribution table) added a
>> regression, since vfree() is called while holding a spinlock and BH
>> being disabled.
>>
>> Fix this by doing the pointers swap in critical section, and freeing
>> after spinlock release.
>>
>> Also add __GFP_NOWARN to the kmalloc() try, since we fallback to
>> vmalloc().
>>
>> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
...
> Acked-by: Stephen Hemminger <shemminger@vyatta.com>
Applied, thanks.
^ permalink raw reply
* Re: [PATCH 0/2] late fixes for netfilter's ctnetlink
From: David Miller @ 2011-12-24 21:11 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel, netdev
In-Reply-To: <1324752768-5853-1-git-send-email-pablo@netfilter.org>
From: pablo@netfilter.org
Date: Sat, 24 Dec 2011 19:52:46 +0100
> These are a couple of late fixes for ctnetlink.
>
> You can pull them from:
>
> git://1984.lsi.us.es/net nf
Pulled, thanks!
^ permalink raw reply
* Re: [PATCH net-next] rfs: better sizing of dev_flow_table
From: David Miller @ 2011-12-24 21:19 UTC (permalink / raw)
To: eric.dumazet; +Cc: therbert, netdev, chavey, xi.wang
In-Reply-To: <1324745809.2915.52.camel@edumazet-laptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Sat, 24 Dec 2011 17:56:49 +0100
> Aim of this patch is to provide full range of rps_flow_cnt on 64bit arches.
>
> Theorical limit on number of flows is 2^32
>
> Fix some buggy RPS/RFS macros as well.
>
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
> CC: Tom Herbert <therbert@google.com>
> CC: Xi Wang <xi.wang@gmail.com>
> CC: Laurent Chavey <chavey@google.com>
Applied, thanks.
^ permalink raw reply
* Problems with route classifiers
From: John A. Sullivan III @ 2011-12-25 0:39 UTC (permalink / raw)
To: netdev
Hello, all. Mountains of expensive frustration today :(
I'm still working on creating a test WAN environment using netem with
netem functioning on both egress and ingress. I understand that we
cannot use both netem and sfq in ingress for reasons discussed in other
threads.
But, I thought, there has to be a way based upon creative configuration;
there's always a way in Linux given some good old fashioned Yankee
ingenuity. So, I thought, if we can't get the packet on the way in,
we'll get it on the way out - at least for forwarded traffic. Well
redirect the internal interfaces into ifb1 for processing through netem
if the packet came from the Internet interface.
I didn't want to use marking lest it interfere with other marks, e.g.,
Endian devices have consumed all available marks for their policy
routing. So, I thought I'd use route fromif classifiers and a couple of
dummy PRIO qdiscs to make it work.
Let's assume eth1 is Internet, eth0 is internal, and that ifb1 is
already configured for netem. Here's what I thought I could do:
tc qdisc add dev eth0 root handle 10: prio bands 2 priomap 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
tc qdisc add dev eth0 parent 10:1 handle 11: prio - this handles the real traffic
tc qdisc add dev eth0 parent 10:2 handle 12: prio - this is just a stub for a filter
For some reason, it seems like I can only attach filters to PRIO qdiscs
and not classes.
Then, the filters (and the problems):
tc filter add dev eth0 parent 12:0 protocol ip prio 1 flowid 11:0 u32 match u32 0 0 action mirred egress redirect dev ifb1
This should get us into ifb1 and then back to the main PRIO qdisc but, I
never got this far because of the problems of getting traffic into 12:0.
This is what I tried:
tc filter add dev eth0 parent 10: protocol ip prio 1 route fromif eth1 flowid 12:0
What is wrong? ip link ls shows the interface is tagged as eth1. If I
log the iptables traffic on the forward chain, I see it knows IN=eth1.
Neither tc -s filter show dev eth0 parent 12:0 nor tc -s class show dev
eth0 show any packets flowing into 12:2 (I created route filter first
and never got to create the redirect filter so I was expecting packets
on 12:2). Thanks - John
^ permalink raw reply
* Re: [PATCH] net: meth: Add set_rx_mode hook to fix ICMPv6 neighbor discovery
From: Joshua Kinard @ 2011-12-25 1:45 UTC (permalink / raw)
To: netdev, Linux MIPS List
In-Reply-To: <4EED3A3D.9080503@gentoo.org>
SGI IP32 (O2)'s ethernet driver (meth) lacks meth_set_rx_mode, which
prevents IPv6 from working completely because any ICMPv6 neighbor
solicitation requests aren't picked up by the driver. So the machine can
ping out and connect to other systems, but other systems will have a very
hard time connecting to the O2.
Signed-off-by: Joshua Kinard <kumba@gentoo.org>
---
arch/mips/include/asm/ip32/mace.h | 52 +++++++++++++++----------------
drivers/net/ethernet/sgi/meth.c | 62 ++++++++++++++++++++++++++++++++++----
2 files changed, 82 insertions(+), 32 deletions(-)
diff -Naurp a/arch/mips/include/asm/ip32/mace.h
b/arch/mips/include/asm/ip32/mace.h
--- a/arch/mips/include/asm/ip32/mace.h 2011-12-24 16:19:46.703561171 -0500
+++ b/arch/mips/include/asm/ip32/mace.h 2011-12-24 16:27:40.613556791 -0500
@@ -95,35 +95,35 @@ struct mace_video {
* Ethernet interface
*/
struct mace_ethernet {
- volatile unsigned long mac_ctrl;
- volatile unsigned long int_stat;
- volatile unsigned long dma_ctrl;
- volatile unsigned long timer;
- volatile unsigned long tx_int_al;
- volatile unsigned long rx_int_al;
- volatile unsigned long tx_info;
- volatile unsigned long tx_info_al;
- volatile unsigned long rx_buff;
- volatile unsigned long rx_buff_al1;
- volatile unsigned long rx_buff_al2;
- volatile unsigned long diag;
- volatile unsigned long phy_data;
- volatile unsigned long phy_regs;
- volatile unsigned long phy_trans_go;
- volatile unsigned long backoff_seed;
+ volatile u64 mac_ctrl;
+ volatile u64 int_stat;
+ volatile u64 dma_ctrl;
+ volatile u64 timer;
+ volatile u64 tx_int_al;
+ volatile u64 rx_int_al;
+ volatile u64 tx_info;
+ volatile u64 tx_info_al;
+ volatile u64 rx_buff;
+ volatile u64 rx_buff_al1;
+ volatile u64 rx_buff_al2;
+ volatile u64 diag;
+ volatile u64 phy_data;
+ volatile u64 phy_regs;
+ volatile u64 phy_trans_go;
+ volatile u64 backoff_seed;
/*===================================*/
- volatile unsigned long imq_reserved[4];
- volatile unsigned long mac_addr;
- volatile unsigned long mac_addr2;
- volatile unsigned long mcast_filter;
- volatile unsigned long tx_ring_base;
+ volatile u64 imq_reserved[4];
+ volatile u64 mac_addr;
+ volatile u64 mac_addr2;
+ volatile u64 mcast_filter;
+ volatile u64 tx_ring_base;
/* Following are read-only registers for debugging */
- volatile unsigned long tx_pkt1_hdr;
- volatile unsigned long tx_pkt1_ptr[3];
- volatile unsigned long tx_pkt2_hdr;
- volatile unsigned long tx_pkt2_ptr[3];
+ volatile u64 tx_pkt1_hdr;
+ volatile u64 tx_pkt1_ptr[3];
+ volatile u64 tx_pkt2_hdr;
+ volatile u64 tx_pkt2_ptr[3];
/*===================================*/
- volatile unsigned long rx_fifo;
+ volatile u64 rx_fifo;
};
/*
diff -Naurp a/drivers/net/ethernet/sgi/meth.c b/drivers/net/ethernet/sgi/meth.c
--- a/drivers/net/ethernet/sgi/meth.c 2011-12-24 16:20:06.743560985 -0500
+++ b/drivers/net/ethernet/sgi/meth.c 2011-12-24 16:27:18.743556993 -0500
@@ -28,6 +28,7 @@
#include <linux/tcp.h> /* struct tcphdr */
#include <linux/skbuff.h>
#include <linux/mii.h> /* MII definitions */
+#include <linux/crc32.h>
#include <asm/ip32/mace.h>
#include <asm/ip32/ip32_ints.h>
@@ -48,9 +49,6 @@
#define MFE_RX_DEBUG 0
#endif
-
-static const char *meth_str="SGI O2 Fast Ethernet";
-
/* The maximum time waited (in jiffies) before assuming a Tx failed. (400ms) */
#define TX_TIMEOUT (400*HZ/1000)
@@ -58,27 +56,44 @@ static int timeout = TX_TIMEOUT;
module_param(timeout, int, 0);
/*
+ * Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+ * MACE Ethernet uses a 64 element hash table based on the Ethernet CRC.
+ */
+#define METH_MCF_LIMIT 32
+
+/* Driver name */
+#define METH_DRV_NAME "SGI O2 Fast Ethernet"
+
+/*
* This structure is private to each device. It is used to pass
* packets in and out, so there is place for a packet
*/
struct meth_private {
/* in-memory copy of MAC Control register */
- unsigned long mac_ctrl;
+ u64 mac_ctrl;
+
/* in-memory copy of DMA Control register */
- unsigned long dma_ctrl;
+ u64 dma_ctrl;
+
/* address of PHY, used by mdio_* functions, initialized in mdio_probe */
unsigned long phy_addr;
+
+ /* TX bits */
tx_packet *tx_ring;
dma_addr_t tx_ring_dma;
struct sk_buff *tx_skbs[TX_RING_ENTRIES];
dma_addr_t tx_skb_dmas[TX_RING_ENTRIES];
unsigned long tx_read, tx_write, tx_count;
+ /* RX bits */
rx_packet *rx_ring[RX_RING_ENTRIES];
dma_addr_t rx_ring_dmas[RX_RING_ENTRIES];
struct sk_buff *rx_skbs[RX_RING_ENTRIES];
unsigned long rx_write;
+ /* Multicast filter. */
+ u64 mcast_filter;
+
spinlock_t meth_lock;
};
@@ -323,7 +338,7 @@ static int meth_open(struct net_device *
if (ret < 0)
goto out_free_tx_ring;
- ret = request_irq(dev->irq, meth_interrupt, 0, meth_str, dev);
+ ret = request_irq(dev->irq, meth_interrupt, 0, METH_DRV_NAME, dev);
if (ret) {
printk(KERN_ERR "%s: Can't get irq %d\n", dev->name, dev->irq);
goto out_free_rx_ring;
@@ -765,6 +780,40 @@ static int meth_ioctl(struct net_device
}
}
+static void meth_set_rx_mode(struct net_device *dev)
+{
+ struct meth_private *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ netif_stop_queue(dev);
+ spin_lock_irqsave(&priv->meth_lock, flags);
+ priv->mac_ctrl &= ~METH_PROMISC;
+
+ if (dev->flags & IFF_PROMISC) {
+ priv->mac_ctrl |= METH_PROMISC;
+ priv->mcast_filter = 0xffffffffffffffffUL;
+ } else if ((netdev_mc_count(dev) > METH_MCF_LIMIT) ||
+ (dev->flags & IFF_ALLMULTI)) {
+ priv->mac_ctrl |= METH_ACCEPT_AMCAST;
+ priv->mcast_filter = 0xffffffffffffffffUL;
+ } else {
+ struct netdev_hw_addr *ha;
+ priv->mac_ctrl |= METH_ACCEPT_MCAST;
+
+ netdev_for_each_mc_addr(ha, dev)
+ set_bit((ether_crc(ETH_ALEN, ha->addr) >> 26),
+ (volatile unsigned long *)&priv->mcast_filter);
+ }
+
+ /* Write the changes to the chip registers. */
+ mace->eth.mac_ctrl = priv->mac_ctrl;
+ mace->eth.mcast_filter = priv->mcast_filter;
+
+ /* Done! */
+ spin_unlock_irqrestore(&priv->meth_lock, flags);
+ netif_wake_queue(dev);
+}
+
static const struct net_device_ops meth_netdev_ops = {
.ndo_open = meth_open,
.ndo_stop = meth_release,
@@ -774,6 +823,7 @@ static const struct net_device_ops meth_
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
+ .ndo_set_rx_mode = meth_set_rx_mode,
};
/*
^ permalink raw reply
* [PATCH 08/19] netfilter: ctnetlink: support individual atomic-get-and-reset of counters
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Pablo Neira Ayuso <pablo@netfilter.org>
This allows to use the get operation to atomically get-and-reset
counters.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_conntrack_netlink.c | 11 +++++++++++
1 files changed, 11 insertions(+), 0 deletions(-)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 77d209c..636617c 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1015,6 +1015,17 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
goto out;
+ if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) {
+ struct nf_conn_counter *acct;
+
+ acct = nf_conn_acct_find(ct);
+ if (acct) {
+ atomic64_set(&acct[IP_CT_DIR_ORIGINAL].bytes, 0);
+ atomic64_set(&acct[IP_CT_DIR_ORIGINAL].packets, 0);
+ atomic64_set(&acct[IP_CT_DIR_REPLY].bytes, 0);
+ atomic64_set(&acct[IP_CT_DIR_REPLY].packets, 0);
+ }
+ }
return 0;
free:
--
1.7.2.5
^ permalink raw reply related
* [PATCH 11/19] netfilter: nf_nat: use hash random for bysource hash
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Patrick McHardy <kaber@trash.net>
Use nf_conntrack_hash_rnd in NAT bysource hash to avoid hash chain attacks.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/ipv4/netfilter/nf_nat_core.c | 2 +-
net/netfilter/nf_conntrack_core.c | 1 +
2 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 58ab7a4..76600f8 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -57,7 +57,7 @@ hash_by_src(const struct net *net, u16 zone,
/* 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 ^ zone,
- tuple->dst.protonum, 0);
+ tuple->dst.protonum, nf_conntrack_hash_rnd);
return ((u64)hash * net->ipv4.nat_htable_size) >> 32;
}
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 8b2842e..b76090f 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -67,6 +67,7 @@ DEFINE_PER_CPU(struct nf_conn, nf_conntrack_untracked);
EXPORT_PER_CPU_SYMBOL(nf_conntrack_untracked);
unsigned int nf_conntrack_hash_rnd __read_mostly;
+EXPORT_SYMBOL_GPL(nf_conntrack_hash_rnd);
static u32 hash_conntrack_raw(const struct nf_conntrack_tuple *tuple, u16 zone)
{
--
1.7.2.5
^ permalink raw reply related
* [PATCH 13/19] netfilter: nat: remove module reference counting from NAT protocols
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Patrick McHardy <kaber@trash.net>
The only remaining user of NAT protocol module reference counting is NAT
ctnetlink support. Since this is a fairly short sequence of code, convert
over to use RCU and remove module reference counting.
Module unregistration is already protected by RCU using synchronize_rcu(),
so no further changes are necessary.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_nat_protocol.h | 2 --
net/ipv4/netfilter/nf_nat_core.c | 25 +++----------------------
net/ipv4/netfilter/nf_nat_proto_dccp.c | 1 -
net/ipv4/netfilter/nf_nat_proto_gre.c | 1 -
net/ipv4/netfilter/nf_nat_proto_icmp.c | 1 -
net/ipv4/netfilter/nf_nat_proto_sctp.c | 1 -
net/ipv4/netfilter/nf_nat_proto_tcp.c | 1 -
net/ipv4/netfilter/nf_nat_proto_udp.c | 1 -
net/ipv4/netfilter/nf_nat_proto_udplite.c | 1 -
net/ipv4/netfilter/nf_nat_proto_unknown.c | 1 -
10 files changed, 3 insertions(+), 32 deletions(-)
diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h
index 7156c00..eaad0ac 100644
--- a/include/net/netfilter/nf_nat_protocol.h
+++ b/include/net/netfilter/nf_nat_protocol.h
@@ -10,8 +10,6 @@ struct nf_nat_protocol {
/* Protocol number. */
unsigned int protonum;
- struct module *me;
-
/* Translate a packet to the target according to manip type.
Return true if succeeded. */
bool (*manip_pkt)(struct sk_buff *skb,
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 610eb44..5e1bd85 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -575,26 +575,6 @@ static struct nf_ct_ext_type nat_extend __read_mostly = {
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_conntrack.h>
-static const struct nf_nat_protocol *
-nf_nat_proto_find_get(u_int8_t protonum)
-{
- const struct nf_nat_protocol *p;
-
- rcu_read_lock();
- p = __nf_nat_proto_find(protonum);
- if (!try_module_get(p->me))
- p = &nf_nat_unknown_protocol;
- rcu_read_unlock();
-
- return p;
-}
-
-static void
-nf_nat_proto_put(const struct nf_nat_protocol *p)
-{
- module_put(p->me);
-}
-
static const struct nla_policy protonat_nla_policy[CTA_PROTONAT_MAX+1] = {
[CTA_PROTONAT_PORT_MIN] = { .type = NLA_U16 },
[CTA_PROTONAT_PORT_MAX] = { .type = NLA_U16 },
@@ -612,10 +592,11 @@ static int nfnetlink_parse_nat_proto(struct nlattr *attr,
if (err < 0)
return err;
- npt = nf_nat_proto_find_get(nf_ct_protonum(ct));
+ rcu_read_lock();
+ npt = __nf_nat_proto_find(nf_ct_protonum(ct));
if (npt->nlattr_to_range)
err = npt->nlattr_to_range(tb, range);
- nf_nat_proto_put(npt);
+ rcu_read_unlock();
return err;
}
diff --git a/net/ipv4/netfilter/nf_nat_proto_dccp.c b/net/ipv4/netfilter/nf_nat_proto_dccp.c
index c43d5b3..466d63d 100644
--- a/net/ipv4/netfilter/nf_nat_proto_dccp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_dccp.c
@@ -80,7 +80,6 @@ dccp_manip_pkt(struct sk_buff *skb,
static const struct nf_nat_protocol nf_nat_protocol_dccp = {
.protonum = IPPROTO_DCCP,
- .me = THIS_MODULE,
.manip_pkt = dccp_manip_pkt,
.in_range = nf_nat_proto_in_range,
.unique_tuple = dccp_unique_tuple,
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c
index 9b1c629..35cd158 100644
--- a/net/ipv4/netfilter/nf_nat_proto_gre.c
+++ b/net/ipv4/netfilter/nf_nat_proto_gre.c
@@ -119,7 +119,6 @@ gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff,
static const struct nf_nat_protocol gre = {
.protonum = IPPROTO_GRE,
- .me = THIS_MODULE,
.manip_pkt = gre_manip_pkt,
.in_range = nf_nat_proto_in_range,
.unique_tuple = gre_unique_tuple,
diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c
index 8f87b4b..036c009 100644
--- a/net/ipv4/netfilter/nf_nat_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c
@@ -74,7 +74,6 @@ icmp_manip_pkt(struct sk_buff *skb,
const struct nf_nat_protocol nf_nat_protocol_icmp = {
.protonum = IPPROTO_ICMP,
- .me = THIS_MODULE,
.manip_pkt = icmp_manip_pkt,
.in_range = icmp_in_range,
.unique_tuple = icmp_unique_tuple,
diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/ipv4/netfilter/nf_nat_proto_sctp.c
index 4e70dc6..50283ab 100644
--- a/net/ipv4/netfilter/nf_nat_proto_sctp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_sctp.c
@@ -70,7 +70,6 @@ sctp_manip_pkt(struct sk_buff *skb,
static const struct nf_nat_protocol nf_nat_protocol_sctp = {
.protonum = IPPROTO_SCTP,
- .me = THIS_MODULE,
.manip_pkt = sctp_manip_pkt,
.in_range = nf_nat_proto_in_range,
.unique_tuple = sctp_unique_tuple,
diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c
index 6fcc865..e0e2ba8 100644
--- a/net/ipv4/netfilter/nf_nat_proto_tcp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c
@@ -82,7 +82,6 @@ tcp_manip_pkt(struct sk_buff *skb,
const struct nf_nat_protocol nf_nat_protocol_tcp = {
.protonum = IPPROTO_TCP,
- .me = THIS_MODULE,
.manip_pkt = tcp_manip_pkt,
.in_range = nf_nat_proto_in_range,
.unique_tuple = tcp_unique_tuple,
diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c
index 18ea44e..bde94cd 100644
--- a/net/ipv4/netfilter/nf_nat_proto_udp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_udp.c
@@ -73,7 +73,6 @@ udp_manip_pkt(struct sk_buff *skb,
const struct nf_nat_protocol nf_nat_protocol_udp = {
.protonum = IPPROTO_UDP,
- .me = THIS_MODULE,
.manip_pkt = udp_manip_pkt,
.in_range = nf_nat_proto_in_range,
.unique_tuple = udp_unique_tuple,
diff --git a/net/ipv4/netfilter/nf_nat_proto_udplite.c b/net/ipv4/netfilter/nf_nat_proto_udplite.c
index a17b75b..58e9a3a 100644
--- a/net/ipv4/netfilter/nf_nat_proto_udplite.c
+++ b/net/ipv4/netfilter/nf_nat_proto_udplite.c
@@ -72,7 +72,6 @@ udplite_manip_pkt(struct sk_buff *skb,
static const struct nf_nat_protocol nf_nat_protocol_udplite = {
.protonum = IPPROTO_UDPLITE,
- .me = THIS_MODULE,
.manip_pkt = udplite_manip_pkt,
.in_range = nf_nat_proto_in_range,
.unique_tuple = udplite_unique_tuple,
diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/ipv4/netfilter/nf_nat_proto_unknown.c
index ab8e8c1..e0afe81 100644
--- a/net/ipv4/netfilter/nf_nat_proto_unknown.c
+++ b/net/ipv4/netfilter/nf_nat_proto_unknown.c
@@ -46,7 +46,6 @@ unknown_manip_pkt(struct sk_buff *skb,
}
const struct nf_nat_protocol nf_nat_unknown_protocol = {
- /* .me isn't set: getting a ref to this cannot fail. */
.manip_pkt = unknown_manip_pkt,
.in_range = unknown_in_range,
.unique_tuple = unknown_unique_tuple,
--
1.7.2.5
^ permalink raw reply related
* [PATCH 14/19] netfilter: nf_nat: remove obsolete code from nf_nat_icmp_reply_translation()
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Patrick McHardy <kaber@trash.net>
The inner tuple that is extracted from the packet is unused. The code also
doesn't have any useful side-effects like verifying the packet does contain
enough data to extract the inner tuple since conntrack already does the
same, so remove it.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/ipv4/netfilter/nf_nat_core.c | 14 +-------------
1 files changed, 1 insertions(+), 13 deletions(-)
diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c
index 5e1bd85..acdd002 100644
--- a/net/ipv4/netfilter/nf_nat_core.c
+++ b/net/ipv4/netfilter/nf_nat_core.c
@@ -30,7 +30,6 @@
#include <net/netfilter/nf_nat_helper.h>
#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);
@@ -414,8 +413,7 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
struct icmphdr icmp;
struct iphdr ip;
} *inside;
- const struct nf_conntrack_l4proto *l4proto;
- struct nf_conntrack_tuple inner, target;
+ struct nf_conntrack_tuple target;
int hdrlen = ip_hdrlen(skb);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
unsigned long statusbit;
@@ -463,16 +461,6 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct,
"dir %s\n", skb, manip,
dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
- /* rcu_read_lock()ed by nf_hook_slow */
- l4proto = __nf_ct_l4proto_find(PF_INET, inside->ip.protocol);
-
- if (!nf_ct_get_tuple(skb, hdrlen + sizeof(struct icmphdr),
- (hdrlen +
- sizeof(struct icmphdr) + inside->ip.ihl * 4),
- (u_int16_t)AF_INET, inside->ip.protocol,
- &inner, l3proto, l4proto))
- return 0;
-
/* Change inner back to look like incoming packet. We do the
opposite manip on this hook to normal, because it might not
pass all hooks (locally-generated ICMP). Consider incoming
--
1.7.2.5
^ permalink raw reply related
* [PATCH 15/19] netfilter: nf_nat: remove obsolete check in nf_nat_mangle_udp_packet()
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Patrick McHardy <kaber@trash.net>
The packet size check originates from a time when UDP helpers could
accidentally mangle incorrect packets (NEWNAT) and is unnecessary
nowadays since the conntrack helpers invoke the NAT helpers for the
proper packet directly.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/ipv4/netfilter/nf_nat_helper.c | 6 ------
1 files changed, 0 insertions(+), 6 deletions(-)
diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c
index 049e8b7..af65958 100644
--- a/net/ipv4/netfilter/nf_nat_helper.c
+++ b/net/ipv4/netfilter/nf_nat_helper.c
@@ -253,12 +253,6 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb,
struct udphdr *udph;
int datalen, oldlen;
- /* UDP helpers might accidentally mangle the wrong packet */
- iph = ip_hdr(skb);
- if (skb->len < iph->ihl*4 + sizeof(*udph) +
- match_offset + match_len)
- return 0;
-
if (!skb_make_writable(skb, skb->len))
return 0;
--
1.7.2.5
^ permalink raw reply related
* [PATCH 16/19] netfilter: ctnetlink: remove dead NAT code
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Patrick McHardy <kaber@trash.net>
The NAT range to nlattr conversation callbacks and helpers are entirely
dead code and are also useless since there are no NAT ranges in conntrack
context, they are only used for initially selecting a tuple. The final NAT
information is contained in the selected tuples of the conntrack entry.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_nat_protocol.h | 5 -----
net/ipv4/netfilter/nf_nat_proto_common.c | 14 +-------------
net/ipv4/netfilter/nf_nat_proto_dccp.c | 1 -
net/ipv4/netfilter/nf_nat_proto_gre.c | 1 -
net/ipv4/netfilter/nf_nat_proto_icmp.c | 1 -
net/ipv4/netfilter/nf_nat_proto_sctp.c | 1 -
net/ipv4/netfilter/nf_nat_proto_tcp.c | 1 -
net/ipv4/netfilter/nf_nat_proto_udp.c | 1 -
net/ipv4/netfilter/nf_nat_proto_udplite.c | 1 -
9 files changed, 1 insertions(+), 25 deletions(-)
diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h
index eaad0ac..7b0b511 100644
--- a/include/net/netfilter/nf_nat_protocol.h
+++ b/include/net/netfilter/nf_nat_protocol.h
@@ -32,9 +32,6 @@ struct nf_nat_protocol {
enum nf_nat_manip_type maniptype,
const struct nf_conn *ct);
- int (*range_to_nlattr)(struct sk_buff *skb,
- const struct nf_nat_ipv4_range *range);
-
int (*nlattr_to_range)(struct nlattr *tb[],
struct nf_nat_ipv4_range *range);
};
@@ -64,8 +61,6 @@ extern void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_conn *ct,
u_int16_t *rover);
-extern int nf_nat_proto_range_to_nlattr(struct sk_buff *skb,
- const struct nf_nat_ipv4_range *range);
extern int nf_nat_proto_nlattr_to_range(struct nlattr *tb[],
struct nf_nat_ipv4_range *range);
diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c
index 47fff91..9993bc9 100644
--- a/net/ipv4/netfilter/nf_nat_proto_common.c
+++ b/net/ipv4/netfilter/nf_nat_proto_common.c
@@ -96,18 +96,6 @@ void nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple,
EXPORT_SYMBOL_GPL(nf_nat_proto_unique_tuple);
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
-int nf_nat_proto_range_to_nlattr(struct sk_buff *skb,
- const struct nf_nat_ipv4_range *range)
-{
- NLA_PUT_BE16(skb, CTA_PROTONAT_PORT_MIN, range->min.all);
- NLA_PUT_BE16(skb, CTA_PROTONAT_PORT_MAX, range->max.all);
- return 0;
-
-nla_put_failure:
- return -1;
-}
-EXPORT_SYMBOL_GPL(nf_nat_proto_nlattr_to_range);
-
int nf_nat_proto_nlattr_to_range(struct nlattr *tb[],
struct nf_nat_ipv4_range *range)
{
@@ -122,5 +110,5 @@ int nf_nat_proto_nlattr_to_range(struct nlattr *tb[],
}
return 0;
}
-EXPORT_SYMBOL_GPL(nf_nat_proto_range_to_nlattr);
+EXPORT_SYMBOL_GPL(nf_nat_proto_nlattr_to_range);
#endif
diff --git a/net/ipv4/netfilter/nf_nat_proto_dccp.c b/net/ipv4/netfilter/nf_nat_proto_dccp.c
index 466d63d..3f67138 100644
--- a/net/ipv4/netfilter/nf_nat_proto_dccp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_dccp.c
@@ -84,7 +84,6 @@ static const struct nf_nat_protocol nf_nat_protocol_dccp = {
.in_range = nf_nat_proto_in_range,
.unique_tuple = dccp_unique_tuple,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
- .range_to_nlattr = nf_nat_proto_range_to_nlattr,
.nlattr_to_range = nf_nat_proto_nlattr_to_range,
#endif
};
diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c
index 35cd158..46ba0b9 100644
--- a/net/ipv4/netfilter/nf_nat_proto_gre.c
+++ b/net/ipv4/netfilter/nf_nat_proto_gre.c
@@ -123,7 +123,6 @@ static const struct nf_nat_protocol gre = {
.in_range = nf_nat_proto_in_range,
.unique_tuple = gre_unique_tuple,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
- .range_to_nlattr = nf_nat_proto_range_to_nlattr,
.nlattr_to_range = nf_nat_proto_nlattr_to_range,
#endif
};
diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c
index 036c009..b351728 100644
--- a/net/ipv4/netfilter/nf_nat_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c
@@ -78,7 +78,6 @@ const struct nf_nat_protocol nf_nat_protocol_icmp = {
.in_range = icmp_in_range,
.unique_tuple = icmp_unique_tuple,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
- .range_to_nlattr = nf_nat_proto_range_to_nlattr,
.nlattr_to_range = nf_nat_proto_nlattr_to_range,
#endif
};
diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/ipv4/netfilter/nf_nat_proto_sctp.c
index 50283ab..3cce9b6 100644
--- a/net/ipv4/netfilter/nf_nat_proto_sctp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_sctp.c
@@ -74,7 +74,6 @@ static const struct nf_nat_protocol nf_nat_protocol_sctp = {
.in_range = nf_nat_proto_in_range,
.unique_tuple = sctp_unique_tuple,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
- .range_to_nlattr = nf_nat_proto_range_to_nlattr,
.nlattr_to_range = nf_nat_proto_nlattr_to_range,
#endif
};
diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c
index e0e2ba8..9fb4b4e 100644
--- a/net/ipv4/netfilter/nf_nat_proto_tcp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c
@@ -86,7 +86,6 @@ const struct nf_nat_protocol nf_nat_protocol_tcp = {
.in_range = nf_nat_proto_in_range,
.unique_tuple = tcp_unique_tuple,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
- .range_to_nlattr = nf_nat_proto_range_to_nlattr,
.nlattr_to_range = nf_nat_proto_nlattr_to_range,
#endif
};
diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c
index bde94cd..9883336 100644
--- a/net/ipv4/netfilter/nf_nat_proto_udp.c
+++ b/net/ipv4/netfilter/nf_nat_proto_udp.c
@@ -77,7 +77,6 @@ const struct nf_nat_protocol nf_nat_protocol_udp = {
.in_range = nf_nat_proto_in_range,
.unique_tuple = udp_unique_tuple,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
- .range_to_nlattr = nf_nat_proto_range_to_nlattr,
.nlattr_to_range = nf_nat_proto_nlattr_to_range,
#endif
};
diff --git a/net/ipv4/netfilter/nf_nat_proto_udplite.c b/net/ipv4/netfilter/nf_nat_proto_udplite.c
index 58e9a3a..d24d10a 100644
--- a/net/ipv4/netfilter/nf_nat_proto_udplite.c
+++ b/net/ipv4/netfilter/nf_nat_proto_udplite.c
@@ -76,7 +76,6 @@ static const struct nf_nat_protocol nf_nat_protocol_udplite = {
.in_range = nf_nat_proto_in_range,
.unique_tuple = udplite_unique_tuple,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
- .range_to_nlattr = nf_nat_proto_range_to_nlattr,
.nlattr_to_range = nf_nat_proto_nlattr_to_range,
#endif
};
--
1.7.2.5
^ permalink raw reply related
* [PATCH 17/19] netfilter: ctnetlink: get and zero operations must be atomic
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Pablo Neira Ayuso <pablo@netfilter.org>
The get and zero operations have to be done in an atomic context,
otherwise counters added between them will be lost.
This problem was spotted by Changli Gao while discussing the
nfacct infrastructure.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_conntrack_netlink.c | 84 ++++++++++++++++------------------
1 files changed, 39 insertions(+), 45 deletions(-)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 4f9c941..8503334 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -203,25 +203,18 @@ nla_put_failure:
}
static int
-ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct,
- enum ip_conntrack_dir dir)
+dump_counters(struct sk_buff *skb, u64 pkts, u64 bytes,
+ enum ip_conntrack_dir dir)
{
enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
struct nlattr *nest_count;
- const struct nf_conn_counter *acct;
-
- acct = nf_conn_acct_find(ct);
- if (!acct)
- return 0;
nest_count = nla_nest_start(skb, type | NLA_F_NESTED);
if (!nest_count)
goto nla_put_failure;
- NLA_PUT_BE64(skb, CTA_COUNTERS_PACKETS,
- cpu_to_be64(atomic64_read(&acct[dir].packets)));
- NLA_PUT_BE64(skb, CTA_COUNTERS_BYTES,
- cpu_to_be64(atomic64_read(&acct[dir].bytes)));
+ NLA_PUT_BE64(skb, CTA_COUNTERS_PACKETS, cpu_to_be64(pkts));
+ NLA_PUT_BE64(skb, CTA_COUNTERS_BYTES, cpu_to_be64(bytes));
nla_nest_end(skb, nest_count);
@@ -232,6 +225,27 @@ nla_put_failure:
}
static int
+ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct,
+ enum ip_conntrack_dir dir, int type)
+{
+ struct nf_conn_counter *acct;
+ u64 pkts, bytes;
+
+ acct = nf_conn_acct_find(ct);
+ if (!acct)
+ return 0;
+
+ if (type == IPCTNL_MSG_CT_GET_CTRZERO) {
+ pkts = atomic64_xchg(&acct[dir].packets, 0);
+ bytes = atomic64_xchg(&acct[dir].bytes, 0);
+ } else {
+ pkts = atomic64_read(&acct[dir].packets);
+ bytes = atomic64_read(&acct[dir].bytes);
+ }
+ return dump_counters(skb, pkts, bytes, dir);
+}
+
+static int
ctnetlink_dump_timestamp(struct sk_buff *skb, const struct nf_conn *ct)
{
struct nlattr *nest_count;
@@ -393,15 +407,15 @@ nla_put_failure:
}
static int
-ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
- int event, struct nf_conn *ct)
+ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, u32 type,
+ struct nf_conn *ct)
{
struct nlmsghdr *nlh;
struct nfgenmsg *nfmsg;
struct nlattr *nest_parms;
- unsigned int flags = pid ? NLM_F_MULTI : 0;
+ unsigned int flags = pid ? NLM_F_MULTI : 0, event;
- event |= NFNL_SUBSYS_CTNETLINK << 8;
+ event = (NFNL_SUBSYS_CTNETLINK << 8 | IPCTNL_MSG_CT_NEW);
nlh = nlmsg_put(skb, pid, seq, event, sizeof(*nfmsg), flags);
if (nlh == NULL)
goto nlmsg_failure;
@@ -430,8 +444,8 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
if (ctnetlink_dump_status(skb, ct) < 0 ||
ctnetlink_dump_timeout(skb, ct) < 0 ||
- ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
- ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 ||
+ ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL, type) < 0 ||
+ ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY, type) < 0 ||
ctnetlink_dump_timestamp(skb, ct) < 0 ||
ctnetlink_dump_protoinfo(skb, ct) < 0 ||
ctnetlink_dump_helpinfo(skb, ct) < 0 ||
@@ -612,8 +626,10 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
goto nla_put_failure;
if (events & (1 << IPCT_DESTROY)) {
- if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 ||
- ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 ||
+ if (ctnetlink_dump_counters(skb, ct,
+ IP_CT_DIR_ORIGINAL, type) < 0 ||
+ ctnetlink_dump_counters(skb, ct,
+ IP_CT_DIR_REPLY, type) < 0 ||
ctnetlink_dump_timestamp(skb, ct) < 0)
goto nla_put_failure;
} else {
@@ -709,24 +725,13 @@ restart:
}
if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq,
- IPCTNL_MSG_CT_NEW, ct) < 0) {
+ NFNL_MSG_TYPE(
+ cb->nlh->nlmsg_type),
+ ct) < 0) {
nf_conntrack_get(&ct->ct_general);
cb->args[1] = (unsigned long)ct;
goto out;
}
-
- if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) ==
- IPCTNL_MSG_CT_GET_CTRZERO) {
- struct nf_conn_counter *acct;
-
- acct = nf_conn_acct_find(ct);
- if (acct) {
- atomic64_set(&acct[IP_CT_DIR_ORIGINAL].bytes, 0);
- atomic64_set(&acct[IP_CT_DIR_ORIGINAL].packets, 0);
- atomic64_set(&acct[IP_CT_DIR_REPLY].bytes, 0);
- atomic64_set(&acct[IP_CT_DIR_REPLY].packets, 0);
- }
- }
}
if (cb->args[1]) {
cb->args[1] = 0;
@@ -1005,7 +1010,7 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
rcu_read_lock();
err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq,
- IPCTNL_MSG_CT_NEW, ct);
+ NFNL_MSG_TYPE(nlh->nlmsg_type), ct);
rcu_read_unlock();
nf_ct_put(ct);
if (err <= 0)
@@ -1015,17 +1020,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
goto out;
- if (NFNL_MSG_TYPE(nlh->nlmsg_type) == IPCTNL_MSG_CT_GET_CTRZERO) {
- struct nf_conn_counter *acct;
-
- acct = nf_conn_acct_find(ct);
- if (acct) {
- atomic64_set(&acct[IP_CT_DIR_ORIGINAL].bytes, 0);
- atomic64_set(&acct[IP_CT_DIR_ORIGINAL].packets, 0);
- atomic64_set(&acct[IP_CT_DIR_REPLY].bytes, 0);
- atomic64_set(&acct[IP_CT_DIR_REPLY].packets, 0);
- }
- }
return 0;
free:
--
1.7.2.5
^ permalink raw reply related
* [PATCH 00/19] netfilter updates for net-next (upcoming 3.3)
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
From: Pablo Neira Ayuso <pablo@netfilter.org>
Hi Dave,
The following patchset includes the Netfilter updates for net-next.
It contains:
- New reverse path filter matches for xtables from Florian Westphal.
- Use of atomic64_t for the conntrack packet and bytes counters, instead
of using spinlock to protect counters updates from Eric Dumazet.
- One enhancement for the SH scheduler (IPVS) from Michael Maxim.
- Seven patches from Patrick McHardy to cleanup several aspects of the
existing NAT code.
- The rework of the user-space expectation support by myself.
- Several updates for ctnetlink by myself.
- The new nfacct infrastructure and the corresponding xtables match
by myself.
You can pull these changes from:
git://1984.lsi.us.es/net-next nf-next
Please, apply!
Thanks!
Eric Dumazet (1):
netfilter: nf_conntrack: use atomic64 for accounting counters
Florian Westphal (4):
net: ipv4: export fib_lookup and fib_table_lookup
netfilter: add ipv4 reverse path filter match
ipv6: add ip6_route_lookup
netfilter: add ipv6 reverse path filter match
Michael Maxim (1):
IPVS: Modify the SH scheduler to use weights
Pablo Neira Ayuso (6):
netfilter: ctnetlink: use expect instead of master tuple in get operation
netfilter: ctnetlink: support individual atomic-get-and-reset of counters
netfilter: rework user-space expectation helper support
netfilter: ctnetlink: get and zero operations must be atomic
netfilter: add extended accounting infrastructure over nfnetlink
netfilter: xtables: add nfacct match to support extended accounting
Patrick McHardy (7):
netfilter: nf_nat: export NAT definitions to userspace
netfilter: nf_nat: use hash random for bysource hash
netfilter: nf_nat: add missing nla_policy entry for CTA_NAT_PROTO attribute
netfilter: nat: remove module reference counting from NAT protocols
netfilter: nf_nat: remove obsolete code from nf_nat_icmp_reply_translation()
netfilter: nf_nat: remove obsolete check in nf_nat_mangle_udp_packet()
netfilter: ctnetlink: remove dead NAT code
include/linux/netfilter/Kbuild | 3 +
include/linux/netfilter/nf_conntrack_common.h | 4 +
.../linux/netfilter/nf_conntrack_tuple_common.h | 27 ++
include/linux/netfilter/nf_nat.h | 25 ++
include/linux/netfilter/nfnetlink.h | 3 +-
include/linux/netfilter/nfnetlink_acct.h | 36 ++
include/linux/netfilter/xt_CT.h | 3 +-
include/linux/netfilter/xt_nfacct.h | 13 +
include/linux/netfilter/xt_rpfilter.h | 23 ++
include/linux/netfilter_ipv4/Kbuild | 1 -
include/linux/netfilter_ipv4/nf_nat.h | 58 ----
include/net/ip6_route.h | 2 +
include/net/netfilter/nf_conntrack_acct.h | 4 +-
include/net/netfilter/nf_conntrack_expect.h | 1 -
include/net/netfilter/nf_conntrack_tuple.h | 1 -
include/net/netfilter/nf_nat.h | 10 +-
include/net/netfilter/nf_nat_core.h | 2 +-
include/net/netfilter/nf_nat_protocol.h | 17 +-
net/ipv4/fib_rules.c | 1 +
net/ipv4/fib_trie.c | 1 +
net/ipv4/netfilter/Kconfig | 10 +
net/ipv4/netfilter/Makefile | 1 +
net/ipv4/netfilter/ipt_MASQUERADE.c | 16 +-
net/ipv4/netfilter/ipt_NETMAP.c | 14 +-
net/ipv4/netfilter/ipt_REDIRECT.c | 16 +-
net/ipv4/netfilter/ipt_rpfilter.c | 141 ++++++++
net/ipv4/netfilter/nf_nat_core.c | 96 ++----
net/ipv4/netfilter/nf_nat_h323.c | 20 +-
net/ipv4/netfilter/nf_nat_helper.c | 16 +-
net/ipv4/netfilter/nf_nat_pptp.c | 14 +-
net/ipv4/netfilter/nf_nat_proto_common.c | 36 +--
net/ipv4/netfilter/nf_nat_proto_dccp.c | 6 +-
net/ipv4/netfilter/nf_nat_proto_gre.c | 10 +-
net/ipv4/netfilter/nf_nat_proto_icmp.c | 6 +-
net/ipv4/netfilter/nf_nat_proto_sctp.c | 6 +-
net/ipv4/netfilter/nf_nat_proto_tcp.c | 6 +-
net/ipv4/netfilter/nf_nat_proto_udp.c | 6 +-
net/ipv4/netfilter/nf_nat_proto_udplite.c | 6 +-
net/ipv4/netfilter/nf_nat_proto_unknown.c | 3 +-
net/ipv4/netfilter/nf_nat_rule.c | 22 +-
net/ipv4/netfilter/nf_nat_sip.c | 10 +-
net/ipv4/netfilter/nf_nat_standalone.c | 2 +-
net/ipv6/netfilter/Kconfig | 10 +
net/ipv6/netfilter/Makefile | 1 +
net/ipv6/netfilter/ip6t_rpfilter.c | 133 ++++++++
net/ipv6/route.c | 7 +
net/netfilter/Kconfig | 18 +
net/netfilter/Makefile | 2 +
net/netfilter/ipvs/Kconfig | 15 +
net/netfilter/ipvs/ip_vs_sh.c | 18 +-
net/netfilter/nf_conntrack_acct.c | 4 +-
net/netfilter/nf_conntrack_core.c | 15 +-
net/netfilter/nf_conntrack_expect.c | 63 ++---
net/netfilter/nf_conntrack_helper.c | 12 +
net/netfilter/nf_conntrack_netlink.c | 82 +++--
net/netfilter/nfnetlink_acct.c | 352 ++++++++++++++++++++
net/netfilter/xt_CT.c | 8 +-
net/netfilter/xt_connbytes.c | 32 +-
net/netfilter/xt_nfacct.c | 76 +++++
59 files changed, 1168 insertions(+), 378 deletions(-)
create mode 100644 include/linux/netfilter/nf_nat.h
create mode 100644 include/linux/netfilter/nfnetlink_acct.h
create mode 100644 include/linux/netfilter/xt_nfacct.h
create mode 100644 include/linux/netfilter/xt_rpfilter.h
delete mode 100644 include/linux/netfilter_ipv4/nf_nat.h
create mode 100644 net/ipv4/netfilter/ipt_rpfilter.c
create mode 100644 net/ipv6/netfilter/ip6t_rpfilter.c
create mode 100644 net/netfilter/nfnetlink_acct.c
create mode 100644 net/netfilter/xt_nfacct.c
--
1.7.2.5
^ permalink raw reply
* [PATCH 01/19] net: ipv4: export fib_lookup and fib_table_lookup
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
The reverse path filter module will use fib_lookup.
If CONFIG_IP_MULTIPLE_TABLES is not set, fib_lookup is
only a static inline helper that calls fib_table_lookup,
so export that too.
Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/ipv4/fib_rules.c | 1 +
net/ipv4/fib_trie.c | 1 +
2 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 46339ba..799fc79 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -67,6 +67,7 @@ int fib_lookup(struct net *net, struct flowi4 *flp, struct fib_result *res)
return err;
}
+EXPORT_SYMBOL_GPL(fib_lookup);
static int fib4_rule_action(struct fib_rule *rule, struct flowi *flp,
int flags, struct fib_lookup_arg *arg)
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 37b6711..d04b13a 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1607,6 +1607,7 @@ found:
rcu_read_unlock();
return ret;
}
+EXPORT_SYMBOL_GPL(fib_table_lookup);
/*
* Remove the leaf and return parent.
--
1.7.2.5
^ permalink raw reply related
* [PATCH 02/19] netfilter: add ipv4 reverse path filter match
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
This tries to do the same thing as fib_validate_source(), but differs
in several aspects.
The most important difference is that the reverse path filter built into
fib_validate_source uses the oif as iif when performing the reverse
lookup. We do not do this, as the oif is not yet known by the time the
PREROUTING hook is invoked.
We can't wait until FORWARD chain because by the time FORWARD is invoked
ipv4 forward path may have already sent icmp messages is response
to to-be-discarded-via-rpfilter packets.
To avoid the such an additional lookup in PREROUTING, Patrick McHardy
suggested to attach the path information directly in the match
(i.e., just do what the standard ipv4 path does a bit earlier in PREROUTING).
This works, but it also has a few caveats. Most importantly, when using
marks in PREROUTING to re-route traffic based on the nfmark, -m rpfilter
would have to be used after the nfmark has been set; otherwise the nfmark
would have no effect (because the route is already attached).
Another problem would be interaction with -j TPROXY, as this target sets an
nfmark and uses ACCEPT instead of continue, i.e. such a version of
-m rpfilter cannot be used for the initial to-be-intercepted packets.
In case in turns out that the oif is required, we can add Patricks
suggestion with a new match option (e.g. --rpf-use-oif) to keep ruleset
compatibility.
Another difference to current builtin ipv4 rpfilter is that packets subject to ipsec
transformation are not automatically excluded. If you want this, simply
combine -m rpfilter with the policy match.
Packets arriving on loopback interfaces always match.
Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/linux/netfilter/xt_rpfilter.h | 23 ++++++
net/ipv4/netfilter/Kconfig | 10 +++
net/ipv4/netfilter/Makefile | 1 +
net/ipv4/netfilter/ipt_rpfilter.c | 141 +++++++++++++++++++++++++++++++++
4 files changed, 175 insertions(+), 0 deletions(-)
create mode 100644 include/linux/netfilter/xt_rpfilter.h
create mode 100644 net/ipv4/netfilter/ipt_rpfilter.c
diff --git a/include/linux/netfilter/xt_rpfilter.h b/include/linux/netfilter/xt_rpfilter.h
new file mode 100644
index 0000000..8358d4f
--- /dev/null
+++ b/include/linux/netfilter/xt_rpfilter.h
@@ -0,0 +1,23 @@
+#ifndef _XT_RPATH_H
+#define _XT_RPATH_H
+
+#include <linux/types.h>
+
+enum {
+ XT_RPFILTER_LOOSE = 1 << 0,
+ XT_RPFILTER_VALID_MARK = 1 << 1,
+ XT_RPFILTER_ACCEPT_LOCAL = 1 << 2,
+ XT_RPFILTER_INVERT = 1 << 3,
+#ifdef __KERNEL__
+ XT_RPFILTER_OPTION_MASK = XT_RPFILTER_LOOSE |
+ XT_RPFILTER_VALID_MARK |
+ XT_RPFILTER_ACCEPT_LOCAL |
+ XT_RPFILTER_INVERT,
+#endif
+};
+
+struct xt_rpfilter_info {
+ __u8 flags;
+};
+
+#endif
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index f19f218..7e1f5cd 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -82,6 +82,16 @@ config IP_NF_MATCH_ECN
To compile it as a module, choose M here. If unsure, say N.
+config IP_NF_MATCH_RPFILTER
+ tristate '"rpfilter" reverse path filter match support'
+ depends on NETFILTER_ADVANCED
+ ---help---
+ This option allows you to match packets whose replies would
+ go out via the interface the packet came in.
+
+ To compile it as a module, choose M here. If unsure, say N.
+ The module will be called ipt_rpfilter.
+
config IP_NF_MATCH_TTL
tristate '"ttl" match support'
depends on NETFILTER_ADVANCED
diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile
index dca2082..123dd88 100644
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -50,6 +50,7 @@ obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
# matches
obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
+obj-$(CONFIG_IP_NF_MATCH_RPFILTER) += ipt_rpfilter.o
# targets
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
diff --git a/net/ipv4/netfilter/ipt_rpfilter.c b/net/ipv4/netfilter/ipt_rpfilter.c
new file mode 100644
index 0000000..31371be
--- /dev/null
+++ b/net/ipv4/netfilter/ipt_rpfilter.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2011 Florian Westphal <fw@strlen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * based on fib_frontend.c; Author: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <net/ip.h>
+#include <net/ip_fib.h>
+#include <net/route.h>
+
+#include <linux/netfilter/xt_rpfilter.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
+MODULE_DESCRIPTION("iptables: ipv4 reverse path filter match");
+
+/* don't try to find route from mcast/bcast/zeronet */
+static __be32 rpfilter_get_saddr(__be32 addr)
+{
+ if (ipv4_is_multicast(addr) || ipv4_is_lbcast(addr) ||
+ ipv4_is_zeronet(addr))
+ return 0;
+ return addr;
+}
+
+static bool rpfilter_lookup_reverse(struct flowi4 *fl4,
+ const struct net_device *dev, u8 flags)
+{
+ struct fib_result res;
+ bool dev_match;
+ struct net *net = dev_net(dev);
+ int ret __maybe_unused;
+
+ if (fib_lookup(net, fl4, &res))
+ return false;
+
+ if (res.type != RTN_UNICAST) {
+ if (res.type != RTN_LOCAL || !(flags & XT_RPFILTER_ACCEPT_LOCAL))
+ return false;
+ }
+ dev_match = false;
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+ for (ret = 0; ret < res.fi->fib_nhs; ret++) {
+ struct fib_nh *nh = &res.fi->fib_nh[ret];
+
+ if (nh->nh_dev == dev) {
+ dev_match = true;
+ break;
+ }
+ }
+#else
+ if (FIB_RES_DEV(res) == dev)
+ dev_match = true;
+#endif
+ if (dev_match || flags & XT_RPFILTER_LOOSE)
+ return FIB_RES_NH(res).nh_scope <= RT_SCOPE_HOST;
+ return dev_match;
+}
+
+static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct xt_rpfilter_info *info;
+ const struct iphdr *iph;
+ struct flowi4 flow;
+ bool invert;
+
+ info = par->matchinfo;
+ invert = info->flags & XT_RPFILTER_INVERT;
+
+ if (par->in->flags & IFF_LOOPBACK)
+ return true ^ invert;
+
+ iph = ip_hdr(skb);
+ if (ipv4_is_multicast(iph->daddr)) {
+ if (ipv4_is_zeronet(iph->saddr))
+ return ipv4_is_local_multicast(iph->daddr) ^ invert;
+ flow.flowi4_iif = 0;
+ } else {
+ flow.flowi4_iif = dev_net(par->in)->loopback_dev->ifindex;
+ }
+
+ flow.daddr = iph->saddr;
+ flow.saddr = rpfilter_get_saddr(iph->daddr);
+ flow.flowi4_oif = 0;
+ flow.flowi4_mark = info->flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
+ flow.flowi4_tos = RT_TOS(iph->tos);
+ flow.flowi4_scope = RT_SCOPE_UNIVERSE;
+
+ return rpfilter_lookup_reverse(&flow, par->in, info->flags) ^ invert;
+}
+
+static int rpfilter_check(const struct xt_mtchk_param *par)
+{
+ const struct xt_rpfilter_info *info = par->matchinfo;
+ unsigned int options = ~XT_RPFILTER_OPTION_MASK;
+ if (info->flags & options) {
+ pr_info("unknown options encountered");
+ return -EINVAL;
+ }
+
+ if (strcmp(par->table, "mangle") != 0 &&
+ strcmp(par->table, "raw") != 0) {
+ pr_info("match only valid in the \'raw\' "
+ "or \'mangle\' tables, not \'%s\'.\n", par->table);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct xt_match rpfilter_mt_reg __read_mostly = {
+ .name = "rpfilter",
+ .family = NFPROTO_IPV4,
+ .checkentry = rpfilter_check,
+ .match = rpfilter_mt,
+ .matchsize = sizeof(struct xt_rpfilter_info),
+ .hooks = (1 << NF_INET_PRE_ROUTING),
+ .me = THIS_MODULE
+};
+
+static int __init rpfilter_mt_init(void)
+{
+ return xt_register_match(&rpfilter_mt_reg);
+}
+
+static void __exit rpfilter_mt_exit(void)
+{
+ xt_unregister_match(&rpfilter_mt_reg);
+}
+
+module_init(rpfilter_mt_init);
+module_exit(rpfilter_mt_exit);
--
1.7.2.5
^ permalink raw reply related
* [PATCH 04/19] netfilter: add ipv6 reverse path filter match
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
This is not merged with the ipv4 match into xt_rpfilter.c
to avoid ipv6 module dependency issues.
Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/ipv6/netfilter/Kconfig | 10 +++
net/ipv6/netfilter/Makefile | 1 +
net/ipv6/netfilter/ip6t_rpfilter.c | 133 ++++++++++++++++++++++++++++++++++++
3 files changed, 144 insertions(+), 0 deletions(-)
create mode 100644 net/ipv6/netfilter/ip6t_rpfilter.c
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index f792b34..9a68fb5 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -125,6 +125,16 @@ config IP6_NF_MATCH_MH
To compile it as a module, choose M here. If unsure, say N.
+config IP6_NF_MATCH_RPFILTER
+ tristate '"rpfilter" reverse path filter match support'
+ depends on NETFILTER_ADVANCED
+ ---help---
+ This option allows you to match packets whose replies would
+ go out via the interface the packet came in.
+
+ To compile it as a module, choose M here. If unsure, say N.
+ The module will be called ip6t_rpfilter.
+
config IP6_NF_MATCH_RT
tristate '"rt" Routing header match support'
depends on NETFILTER_ADVANCED
diff --git a/net/ipv6/netfilter/Makefile b/net/ipv6/netfilter/Makefile
index abfee91..2eaed96 100644
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o
obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o
obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o
obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o
+obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o
obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
# targets
diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c
new file mode 100644
index 0000000..5d1d8b0
--- /dev/null
+++ b/net/ipv6/netfilter/ip6t_rpfilter.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2011 Florian Westphal <fw@strlen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/route.h>
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+
+#include <linux/netfilter/xt_rpfilter.h>
+#include <linux/netfilter/x_tables.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
+MODULE_DESCRIPTION("Xtables: IPv6 reverse path filter match");
+
+static bool rpfilter_addr_unicast(const struct in6_addr *addr)
+{
+ int addr_type = ipv6_addr_type(addr);
+ return addr_type & IPV6_ADDR_UNICAST;
+}
+
+static bool rpfilter_lookup_reverse6(const struct sk_buff *skb,
+ const struct net_device *dev, u8 flags)
+{
+ struct rt6_info *rt;
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ bool ret = false;
+ struct flowi6 fl6 = {
+ .flowlabel = (* (__be32 *) iph) & IPV6_FLOWINFO_MASK,
+ .flowi6_proto = iph->nexthdr,
+ .daddr = iph->saddr,
+ };
+ int lookup_flags;
+
+ if (rpfilter_addr_unicast(&iph->daddr)) {
+ memcpy(&fl6.saddr, &iph->daddr, sizeof(struct in6_addr));
+ lookup_flags = RT6_LOOKUP_F_HAS_SADDR;
+ } else {
+ lookup_flags = 0;
+ }
+
+ fl6.flowi6_mark = flags & XT_RPFILTER_VALID_MARK ? skb->mark : 0;
+ if ((flags & XT_RPFILTER_LOOSE) == 0) {
+ fl6.flowi6_oif = dev->ifindex;
+ lookup_flags |= RT6_LOOKUP_F_IFACE;
+ }
+
+ rt = (void *) ip6_route_lookup(dev_net(dev), &fl6, lookup_flags);
+ if (rt->dst.error)
+ goto out;
+
+ if (rt->rt6i_flags & (RTF_REJECT|RTF_ANYCAST))
+ goto out;
+
+ if (rt->rt6i_flags & RTF_LOCAL) {
+ ret = flags & XT_RPFILTER_ACCEPT_LOCAL;
+ goto out;
+ }
+
+ if (rt->rt6i_idev->dev == dev || (flags & XT_RPFILTER_LOOSE))
+ ret = true;
+ out:
+ dst_release(&rt->dst);
+ return ret;
+}
+
+static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
+{
+ const struct xt_rpfilter_info *info = par->matchinfo;
+ int saddrtype;
+ struct ipv6hdr *iph;
+ bool invert = info->flags & XT_RPFILTER_INVERT;
+
+ if (par->in->flags & IFF_LOOPBACK)
+ return true ^ invert;
+
+ iph = ipv6_hdr(skb);
+ saddrtype = ipv6_addr_type(&iph->saddr);
+ if (unlikely(saddrtype == IPV6_ADDR_ANY))
+ return true ^ invert; /* not routable: forward path will drop it */
+
+ return rpfilter_lookup_reverse6(skb, par->in, info->flags) ^ invert;
+}
+
+static int rpfilter_check(const struct xt_mtchk_param *par)
+{
+ const struct xt_rpfilter_info *info = par->matchinfo;
+ unsigned int options = ~XT_RPFILTER_OPTION_MASK;
+
+ if (info->flags & options) {
+ pr_info("unknown options encountered");
+ return -EINVAL;
+ }
+
+ if (strcmp(par->table, "mangle") != 0 &&
+ strcmp(par->table, "raw") != 0) {
+ pr_info("match only valid in the \'raw\' "
+ "or \'mangle\' tables, not \'%s\'.\n", par->table);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct xt_match rpfilter_mt_reg __read_mostly = {
+ .name = "rpfilter",
+ .family = NFPROTO_IPV6,
+ .checkentry = rpfilter_check,
+ .match = rpfilter_mt,
+ .matchsize = sizeof(struct xt_rpfilter_info),
+ .hooks = (1 << NF_INET_PRE_ROUTING),
+ .me = THIS_MODULE
+};
+
+static int __init rpfilter_mt_init(void)
+{
+ return xt_register_match(&rpfilter_mt_reg);
+}
+
+static void __exit rpfilter_mt_exit(void)
+{
+ xt_unregister_match(&rpfilter_mt_reg);
+}
+
+module_init(rpfilter_mt_init);
+module_exit(rpfilter_mt_exit);
--
1.7.2.5
^ permalink raw reply related
* [PATCH 06/19] netfilter: nf_conntrack: use atomic64 for accounting counters
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Eric Dumazet <eric.dumazet@gmail.com>
We can use atomic64_t infrastructure to avoid taking a spinlock in fast
path, and remove inaccuracies while reading values in
ctnetlink_dump_counters() and connbytes_mt() on 32bit arches.
Suggested by Pablo.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/netfilter/nf_conntrack_acct.h | 4 +-
net/netfilter/nf_conntrack_acct.c | 4 +-
net/netfilter/nf_conntrack_core.c | 14 ++++--------
net/netfilter/nf_conntrack_netlink.c | 12 +++++++---
net/netfilter/xt_connbytes.c | 32 ++++++++++++++--------------
5 files changed, 33 insertions(+), 33 deletions(-)
diff --git a/include/net/netfilter/nf_conntrack_acct.h b/include/net/netfilter/nf_conntrack_acct.h
index 4e9c63a..463ae8e 100644
--- a/include/net/netfilter/nf_conntrack_acct.h
+++ b/include/net/netfilter/nf_conntrack_acct.h
@@ -15,8 +15,8 @@
#include <net/netfilter/nf_conntrack_extend.h>
struct nf_conn_counter {
- u_int64_t packets;
- u_int64_t bytes;
+ atomic64_t packets;
+ atomic64_t bytes;
};
static inline
diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c
index 369df3f..9332906 100644
--- a/net/netfilter/nf_conntrack_acct.c
+++ b/net/netfilter/nf_conntrack_acct.c
@@ -46,8 +46,8 @@ seq_print_acct(struct seq_file *s, const struct nf_conn *ct, int dir)
return 0;
return seq_printf(s, "packets=%llu bytes=%llu ",
- (unsigned long long)acct[dir].packets,
- (unsigned long long)acct[dir].bytes);
+ (unsigned long long)atomic64_read(&acct[dir].packets),
+ (unsigned long long)atomic64_read(&acct[dir].bytes));
};
EXPORT_SYMBOL_GPL(seq_print_acct);
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 7202b06..8b2842e 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -1044,10 +1044,8 @@ acct:
acct = nf_conn_acct_find(ct);
if (acct) {
- spin_lock_bh(&ct->lock);
- acct[CTINFO2DIR(ctinfo)].packets++;
- acct[CTINFO2DIR(ctinfo)].bytes += skb->len;
- spin_unlock_bh(&ct->lock);
+ atomic64_inc(&acct[CTINFO2DIR(ctinfo)].packets);
+ atomic64_add(skb->len, &acct[CTINFO2DIR(ctinfo)].bytes);
}
}
}
@@ -1063,11 +1061,9 @@ bool __nf_ct_kill_acct(struct nf_conn *ct,
acct = nf_conn_acct_find(ct);
if (acct) {
- spin_lock_bh(&ct->lock);
- acct[CTINFO2DIR(ctinfo)].packets++;
- acct[CTINFO2DIR(ctinfo)].bytes +=
- skb->len - skb_network_offset(skb);
- spin_unlock_bh(&ct->lock);
+ atomic64_inc(&acct[CTINFO2DIR(ctinfo)].packets);
+ atomic64_add(skb->len - skb_network_offset(skb),
+ &acct[CTINFO2DIR(ctinfo)].bytes);
}
}
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index ef21b22..a36e655 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -219,9 +219,9 @@ ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct,
goto nla_put_failure;
NLA_PUT_BE64(skb, CTA_COUNTERS_PACKETS,
- cpu_to_be64(acct[dir].packets));
+ cpu_to_be64(atomic64_read(&acct[dir].packets)));
NLA_PUT_BE64(skb, CTA_COUNTERS_BYTES,
- cpu_to_be64(acct[dir].bytes));
+ cpu_to_be64(atomic64_read(&acct[dir].bytes)));
nla_nest_end(skb, nest_count);
@@ -720,8 +720,12 @@ restart:
struct nf_conn_counter *acct;
acct = nf_conn_acct_find(ct);
- if (acct)
- memset(acct, 0, sizeof(struct nf_conn_counter[IP_CT_DIR_MAX]));
+ if (acct) {
+ atomic64_set(&acct[IP_CT_DIR_ORIGINAL].bytes, 0);
+ atomic64_set(&acct[IP_CT_DIR_ORIGINAL].packets, 0);
+ atomic64_set(&acct[IP_CT_DIR_REPLY].bytes, 0);
+ atomic64_set(&acct[IP_CT_DIR_REPLY].packets, 0);
+ }
}
}
if (cb->args[1]) {
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
index 5b13850..2b8418c 100644
--- a/net/netfilter/xt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -40,46 +40,46 @@ connbytes_mt(const struct sk_buff *skb, struct xt_action_param *par)
case XT_CONNBYTES_PKTS:
switch (sinfo->direction) {
case XT_CONNBYTES_DIR_ORIGINAL:
- what = counters[IP_CT_DIR_ORIGINAL].packets;
+ what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
break;
case XT_CONNBYTES_DIR_REPLY:
- what = counters[IP_CT_DIR_REPLY].packets;
+ what = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
break;
case XT_CONNBYTES_DIR_BOTH:
- what = counters[IP_CT_DIR_ORIGINAL].packets;
- what += counters[IP_CT_DIR_REPLY].packets;
+ what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
+ what += atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
break;
}
break;
case XT_CONNBYTES_BYTES:
switch (sinfo->direction) {
case XT_CONNBYTES_DIR_ORIGINAL:
- what = counters[IP_CT_DIR_ORIGINAL].bytes;
+ what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
break;
case XT_CONNBYTES_DIR_REPLY:
- what = counters[IP_CT_DIR_REPLY].bytes;
+ what = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
break;
case XT_CONNBYTES_DIR_BOTH:
- what = counters[IP_CT_DIR_ORIGINAL].bytes;
- what += counters[IP_CT_DIR_REPLY].bytes;
+ what = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
+ what += atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
break;
}
break;
case XT_CONNBYTES_AVGPKT:
switch (sinfo->direction) {
case XT_CONNBYTES_DIR_ORIGINAL:
- bytes = counters[IP_CT_DIR_ORIGINAL].bytes;
- pkts = counters[IP_CT_DIR_ORIGINAL].packets;
+ bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes);
+ pkts = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets);
break;
case XT_CONNBYTES_DIR_REPLY:
- bytes = counters[IP_CT_DIR_REPLY].bytes;
- pkts = counters[IP_CT_DIR_REPLY].packets;
+ bytes = atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
+ pkts = atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
break;
case XT_CONNBYTES_DIR_BOTH:
- bytes = counters[IP_CT_DIR_ORIGINAL].bytes +
- counters[IP_CT_DIR_REPLY].bytes;
- pkts = counters[IP_CT_DIR_ORIGINAL].packets +
- counters[IP_CT_DIR_REPLY].packets;
+ bytes = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].bytes) +
+ atomic64_read(&counters[IP_CT_DIR_REPLY].bytes);
+ pkts = atomic64_read(&counters[IP_CT_DIR_ORIGINAL].packets) +
+ atomic64_read(&counters[IP_CT_DIR_REPLY].packets);
break;
}
if (pkts != 0)
--
1.7.2.5
^ permalink raw reply related
* [PATCH 07/19] netfilter: ctnetlink: use expect instead of master tuple in get operation
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Pablo Neira Ayuso <pablo@netfilter.org>
Use the expect tuple (if possible) instead of the master tuple for
the get operation. If two or more expectations come from the same
master, the returned expectation may not be the one that user-space
is requesting.
This is how it works for the expect deletion operation.
Although I think that nobody has been seriously using this. We
accept both possibilities, using the expect tuple if possible.
I decided to do it like this to avoid breaking backward
compatibility.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_conntrack_netlink.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index a36e655..77d209c 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1851,7 +1851,9 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
return err;
- if (cda[CTA_EXPECT_MASTER])
+ if (cda[CTA_EXPECT_TUPLE])
+ err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
+ else if (cda[CTA_EXPECT_MASTER])
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, u3);
else
return -EINVAL;
--
1.7.2.5
^ permalink raw reply related
* [PATCH 03/19] ipv6: add ip6_route_lookup
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Florian Westphal <fw@strlen.de>
like rt6_lookup, but allows caller to pass in flowi6 structure.
Will be used by the upcoming ipv6 netfilter reverse path filter
match.
Signed-off-by: Florian Westphal <fw@strlen.de>
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/net/ip6_route.h | 2 ++
net/ipv6/route.c | 7 +++++++
2 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 5e91b72..9c9399c 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -70,6 +70,8 @@ extern void ip6_route_input(struct sk_buff *skb);
extern struct dst_entry * ip6_route_output(struct net *net,
const struct sock *sk,
struct flowi6 *fl6);
+extern struct dst_entry * ip6_route_lookup(struct net *net,
+ struct flowi6 *fl6, int flags);
extern int ip6_route_init(void);
extern void ip6_route_cleanup(void);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 1138b0a..ab48b02 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -658,6 +658,13 @@ out:
}
+struct dst_entry * ip6_route_lookup(struct net *net, struct flowi6 *fl6,
+ int flags)
+{
+ return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup);
+}
+EXPORT_SYMBOL_GPL(ip6_route_lookup);
+
struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr,
const struct in6_addr *saddr, int oif, int strict)
{
--
1.7.2.5
^ permalink raw reply related
* [PATCH 09/19] netfilter: rework user-space expectation helper support
From: pablo @ 2011-12-25 1:57 UTC (permalink / raw)
To: netfilter-devel; +Cc: davem, netdev
In-Reply-To: <1324778255-2830-1-git-send-email-pablo@netfilter.org>
From: Pablo Neira Ayuso <pablo@netfilter.org>
This partially reworks bc01befdcf3e40979eb518085a075cbf0aacede0
which added userspace expectation support.
This patch removes the nf_ct_userspace_expect_list since now we
force to use the new iptables CT target feature to add the helper
extension for conntracks that have attached expectations from
userspace.
A new version of the proof-of-concept code to implement userspace
helpers from userspace is available at:
http://people.netfilter.org/pablo/userspace-conntrack-helpers/nf-ftp-helper-POC.tar.bz2
This patch also modifies the CT target to allow to set the
conntrack's userspace helper status flags. This flag is used
to tell the conntrack system to explicitly allocate the helper
extension.
This helper extension is useful to link the userspace expectations
with the master conntrack that is being tracked from one userspace
helper.
This feature fixes a problem in the current approach of the
userspace helper support. Basically, if the master conntrack that
has got a userspace expectation vanishes, the expectations point to
one invalid memory address. Thus, triggering an oops in the
expectation deletion event path.
I decided not to add a new revision of the CT target because
I only needed to add a new flag for it. I'll document in this
issue in the iptables manpage. I have also changed the return
value from EINVAL to EOPNOTSUPP if one flag not supported is
specified. Thus, in the future adding new features that only
require a new flag can be added without a new revision.
There is no official code using this in userspace (apart from
the proof-of-concept) that uses this infrastructure but there
will be some by beginning 2012.
Reported-by: Sam Roberts <vieuxtech@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/linux/netfilter/nf_conntrack_common.h | 4 ++
include/linux/netfilter/xt_CT.h | 3 +-
include/net/netfilter/nf_conntrack_expect.h | 1 -
net/netfilter/nf_conntrack_expect.c | 63 ++++++++----------------
net/netfilter/nf_conntrack_helper.c | 12 +++++
net/netfilter/nf_conntrack_netlink.c | 5 ++-
net/netfilter/xt_CT.c | 8 ++-
7 files changed, 48 insertions(+), 48 deletions(-)
diff --git a/include/linux/netfilter/nf_conntrack_common.h b/include/linux/netfilter/nf_conntrack_common.h
index 0d3dd66..9e3a283 100644
--- a/include/linux/netfilter/nf_conntrack_common.h
+++ b/include/linux/netfilter/nf_conntrack_common.h
@@ -83,6 +83,10 @@ enum ip_conntrack_status {
/* Conntrack is a fake untracked entry */
IPS_UNTRACKED_BIT = 12,
IPS_UNTRACKED = (1 << IPS_UNTRACKED_BIT),
+
+ /* Conntrack has a userspace helper. */
+ IPS_USERSPACE_HELPER_BIT = 13,
+ IPS_USERSPACE_HELPER = (1 << IPS_USERSPACE_HELPER_BIT),
};
/* Connection tracking event types */
diff --git a/include/linux/netfilter/xt_CT.h b/include/linux/netfilter/xt_CT.h
index b56e768..6390f09 100644
--- a/include/linux/netfilter/xt_CT.h
+++ b/include/linux/netfilter/xt_CT.h
@@ -3,7 +3,8 @@
#include <linux/types.h>
-#define XT_CT_NOTRACK 0x1
+#define XT_CT_NOTRACK 0x1
+#define XT_CT_USERSPACE_HELPER 0x2
struct xt_ct_target_info {
__u16 flags;
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index 0f8a8c5..4619caa 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -91,7 +91,6 @@ static inline void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
void nf_ct_remove_expectations(struct nf_conn *ct);
void nf_ct_unexpect_related(struct nf_conntrack_expect *exp);
-void nf_ct_remove_userspace_expectations(void);
/* Allocate space for an expectation: this is mandatory before calling
nf_ct_expect_related. You will have to call put afterwards. */
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 340c80d..bebb167 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -38,8 +38,6 @@ unsigned int nf_ct_expect_max __read_mostly;
static struct kmem_cache *nf_ct_expect_cachep __read_mostly;
-static HLIST_HEAD(nf_ct_userspace_expect_list);
-
/* nf_conntrack_expect helper functions */
void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
u32 pid, int report)
@@ -47,14 +45,14 @@ void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp,
struct nf_conn_help *master_help = nfct_help(exp->master);
struct net *net = nf_ct_exp_net(exp);
+ NF_CT_ASSERT(master_help);
NF_CT_ASSERT(!timer_pending(&exp->timeout));
hlist_del_rcu(&exp->hnode);
net->ct.expect_count--;
hlist_del(&exp->lnode);
- if (!(exp->flags & NF_CT_EXPECT_USERSPACE))
- master_help->expecting[exp->class]--;
+ master_help->expecting[exp->class]--;
nf_ct_expect_event_report(IPEXP_DESTROY, exp, pid, report);
nf_ct_expect_put(exp);
@@ -314,37 +312,34 @@ void nf_ct_expect_put(struct nf_conntrack_expect *exp)
}
EXPORT_SYMBOL_GPL(nf_ct_expect_put);
-static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
+static int nf_ct_expect_insert(struct nf_conntrack_expect *exp)
{
struct nf_conn_help *master_help = nfct_help(exp->master);
+ struct nf_conntrack_helper *helper;
struct net *net = nf_ct_exp_net(exp);
- const struct nf_conntrack_expect_policy *p;
unsigned int h = nf_ct_expect_dst_hash(&exp->tuple);
/* two references : one for hash insert, one for the timer */
atomic_add(2, &exp->use);
- if (master_help) {
- hlist_add_head(&exp->lnode, &master_help->expectations);
- master_help->expecting[exp->class]++;
- } else if (exp->flags & NF_CT_EXPECT_USERSPACE)
- hlist_add_head(&exp->lnode, &nf_ct_userspace_expect_list);
+ hlist_add_head(&exp->lnode, &master_help->expectations);
+ master_help->expecting[exp->class]++;
hlist_add_head_rcu(&exp->hnode, &net->ct.expect_hash[h]);
net->ct.expect_count++;
setup_timer(&exp->timeout, nf_ct_expectation_timed_out,
(unsigned long)exp);
- if (master_help) {
- p = &rcu_dereference_protected(
- master_help->helper,
- lockdep_is_held(&nf_conntrack_lock)
- )->expect_policy[exp->class];
- exp->timeout.expires = jiffies + p->timeout * HZ;
+ helper = rcu_dereference_protected(master_help->helper,
+ lockdep_is_held(&nf_conntrack_lock));
+ if (helper) {
+ exp->timeout.expires = jiffies +
+ helper->expect_policy[exp->class].timeout * HZ;
}
add_timer(&exp->timeout);
NF_CT_STAT_INC(net, expect_create);
+ return 0;
}
/* Race with expectations being used means we could have none to find; OK. */
@@ -389,14 +384,13 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
struct nf_conntrack_expect *i;
struct nf_conn *master = expect->master;
struct nf_conn_help *master_help = nfct_help(master);
+ struct nf_conntrack_helper *helper;
struct net *net = nf_ct_exp_net(expect);
struct hlist_node *n;
unsigned int h;
int ret = 1;
- /* Don't allow expectations created from kernel-space with no helper */
- if (!(expect->flags & NF_CT_EXPECT_USERSPACE) &&
- (!master_help || (master_help && !master_help->helper))) {
+ if (!master_help) {
ret = -ESHUTDOWN;
goto out;
}
@@ -414,11 +408,10 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
}
}
/* Will be over limit? */
- if (master_help) {
- p = &rcu_dereference_protected(
- master_help->helper,
- lockdep_is_held(&nf_conntrack_lock)
- )->expect_policy[expect->class];
+ helper = rcu_dereference_protected(master_help->helper,
+ lockdep_is_held(&nf_conntrack_lock));
+ if (helper) {
+ p = &helper->expect_policy[expect->class];
if (p->max_expected &&
master_help->expecting[expect->class] >= p->max_expected) {
evict_oldest_expect(master, expect);
@@ -450,8 +443,9 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
if (ret <= 0)
goto out;
- ret = 0;
- nf_ct_expect_insert(expect);
+ ret = nf_ct_expect_insert(expect);
+ if (ret < 0)
+ goto out;
spin_unlock_bh(&nf_conntrack_lock);
nf_ct_expect_event_report(IPEXP_NEW, expect, pid, report);
return ret;
@@ -461,21 +455,6 @@ out:
}
EXPORT_SYMBOL_GPL(nf_ct_expect_related_report);
-void nf_ct_remove_userspace_expectations(void)
-{
- struct nf_conntrack_expect *exp;
- struct hlist_node *n, *next;
-
- hlist_for_each_entry_safe(exp, n, next,
- &nf_ct_userspace_expect_list, lnode) {
- if (del_timer(&exp->timeout)) {
- nf_ct_unlink_expect(exp);
- nf_ct_expect_put(exp);
- }
- }
-}
-EXPORT_SYMBOL_GPL(nf_ct_remove_userspace_expectations);
-
#ifdef CONFIG_PROC_FS
struct ct_expect_iter_state {
struct seq_net_private p;
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index 93c4bdb..c9e0de0 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -121,6 +121,18 @@ int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl,
int ret = 0;
if (tmpl != NULL) {
+ /* we've got a userspace helper. */
+ if (tmpl->status & IPS_USERSPACE_HELPER) {
+ help = nf_ct_helper_ext_add(ct, flags);
+ if (help == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ rcu_assign_pointer(help->helper, NULL);
+ __set_bit(IPS_USERSPACE_HELPER_BIT, &ct->status);
+ ret = 0;
+ goto out;
+ }
help = nfct_help(tmpl);
if (help != NULL)
helper = help->helper;
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 636617c..7395480 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -2040,6 +2040,10 @@ ctnetlink_create_expect(struct net *net, u16 zone,
}
help = nfct_help(ct);
if (!help) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+ if (test_bit(IPS_USERSPACE_HELPER_BIT, &ct->status)) {
if (!cda[CTA_EXPECT_TIMEOUT]) {
err = -EINVAL;
goto out;
@@ -2264,7 +2268,6 @@ static void __exit ctnetlink_exit(void)
{
pr_info("ctnetlink: unregistering from nfnetlink.\n");
- nf_ct_remove_userspace_expectations();
unregister_pernet_subsys(&ctnetlink_net_ops);
nfnetlink_subsys_unregister(&ctnl_exp_subsys);
nfnetlink_subsys_unregister(&ctnl_subsys);
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index 0221d10..8e87123 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -62,8 +62,8 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par)
int ret = 0;
u8 proto;
- if (info->flags & ~XT_CT_NOTRACK)
- return -EINVAL;
+ if (info->flags & ~(XT_CT_NOTRACK | XT_CT_USERSPACE_HELPER))
+ return -EOPNOTSUPP;
if (info->flags & XT_CT_NOTRACK) {
ct = nf_ct_untracked_get();
@@ -92,7 +92,9 @@ static int xt_ct_tg_check(const struct xt_tgchk_param *par)
GFP_KERNEL))
goto err3;
- if (info->helper[0]) {
+ if (info->flags & XT_CT_USERSPACE_HELPER) {
+ __set_bit(IPS_USERSPACE_HELPER_BIT, &ct->status);
+ } else if (info->helper[0]) {
ret = -ENOENT;
proto = xt_ct_find_proto(par);
if (!proto) {
--
1.7.2.5
^ 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