* [PATCH net 02/15] bonding: use netpoll_poll_dev() helper
From: Eric Dumazet @ 2018-09-21 22:27 UTC (permalink / raw)
To: David S . Miller
Cc: netdev, Eric Dumazet, Michael Chan, Ariel Elior, Eric Dumazet,
Tariq Toukan, Saeed Mahameed, Jeff Kirsher, Jakub Kicinski,
Song Liu, Jay Vosburgh, Veaceslav Falico, Andy Gospodarek
In-Reply-To: <20180921222752.101307-1-edumazet@google.com>
We want to allow NAPI drivers to no longer provide
ndo_poll_controller() method, as it has been proven problematic.
team driver must not look at its presence, but instead call
netpoll_poll_dev() which factorize the needed actions.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Jay Vosburgh <j.vosburgh@gmail.com>
Cc: Veaceslav Falico <vfalico@gmail.com>
Cc: Andy Gospodarek <andy@greyhouse.net>
---
drivers/net/bonding/bond_main.c | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index a764a83f99dabe54585dbad7dba40b6601177c03..0d87e11e7f1d84537fe43d95249b1bd3a2ce291d 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -971,16 +971,13 @@ static void bond_poll_controller(struct net_device *bond_dev)
struct slave *slave = NULL;
struct list_head *iter;
struct ad_info ad_info;
- struct netpoll_info *ni;
- const struct net_device_ops *ops;
if (BOND_MODE(bond) == BOND_MODE_8023AD)
if (bond_3ad_get_active_agg_info(bond, &ad_info))
return;
bond_for_each_slave_rcu(bond, slave, iter) {
- ops = slave->dev->netdev_ops;
- if (!bond_slave_is_up(slave) || !ops->ndo_poll_controller)
+ if (!bond_slave_is_up(slave))
continue;
if (BOND_MODE(bond) == BOND_MODE_8023AD) {
@@ -992,11 +989,7 @@ static void bond_poll_controller(struct net_device *bond_dev)
continue;
}
- ni = rcu_dereference_bh(slave->dev->npinfo);
- if (down_trylock(&ni->dev_lock))
- continue;
- ops->ndo_poll_controller(slave->dev);
- up(&ni->dev_lock);
+ netpoll_poll_dev(slave->dev);
}
}
--
2.19.0.444.g18242da7ef-goog
^ permalink raw reply related
* [PATCH net 01/15] netpoll: make ndo_poll_controller() optional
From: Eric Dumazet @ 2018-09-21 22:27 UTC (permalink / raw)
To: David S . Miller
Cc: netdev, Eric Dumazet, Michael Chan, Ariel Elior, Eric Dumazet,
Tariq Toukan, Saeed Mahameed, Jeff Kirsher, Jakub Kicinski,
Song Liu, Jay Vosburgh, Veaceslav Falico, Andy Gospodarek
In-Reply-To: <20180921222752.101307-1-edumazet@google.com>
As diagnosed by Song Liu, ndo_poll_controller() can
be very dangerous on loaded hosts, since the cpu
calling ndo_poll_controller() might steal all NAPI
contexts (for all RX/TX queues of the NIC). This capture
can last for unlimited amount of time, since one
cpu is generally not able to drain all the queues under load.
It seems that all networking drivers that do use NAPI
for their TX completions, should not provide a ndo_poll_controller().
NAPI drivers have netpoll support already handled
in core networking stack, since netpoll_poll_dev()
uses poll_napi(dev) to iterate through registered
NAPI contexts for a device.
This patch allows netpoll_poll_dev() to process NAPI
contexts even for drivers not providing ndo_poll_controller(),
allowing for following patches in NAPI drivers.
Also we export netpoll_poll_dev() so that it can be called
by bonding/team drivers in following patches.
Reported-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Tested-by: Song Liu <songliubraving@fb.com>
---
include/linux/netpoll.h | 5 +++--
net/core/netpoll.c | 19 +++++++------------
2 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h
index 67662d01130a7b4f69c8b4ec176f59b11e8ae33d..3ef82d3a78db51d958858470f8158f72cfd74fb3 100644
--- a/include/linux/netpoll.h
+++ b/include/linux/netpoll.h
@@ -49,8 +49,9 @@ struct netpoll_info {
};
#ifdef CONFIG_NETPOLL
-extern void netpoll_poll_disable(struct net_device *dev);
-extern void netpoll_poll_enable(struct net_device *dev);
+void netpoll_poll_dev(struct net_device *dev);
+void netpoll_poll_disable(struct net_device *dev);
+void netpoll_poll_enable(struct net_device *dev);
#else
static inline void netpoll_poll_disable(struct net_device *dev) { return; }
static inline void netpoll_poll_enable(struct net_device *dev) { return; }
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index 57557a6a950cc9cdff959391576a03381d328c1a..3219a2932463096566ce8ff336ecdf699422dd65 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -187,16 +187,16 @@ static void poll_napi(struct net_device *dev)
}
}
-static void netpoll_poll_dev(struct net_device *dev)
+void netpoll_poll_dev(struct net_device *dev)
{
- const struct net_device_ops *ops;
struct netpoll_info *ni = rcu_dereference_bh(dev->npinfo);
+ const struct net_device_ops *ops;
/* Don't do any rx activity if the dev_lock mutex is held
* the dev_open/close paths use this to block netpoll activity
* while changing device state
*/
- if (down_trylock(&ni->dev_lock))
+ if (!ni || down_trylock(&ni->dev_lock))
return;
if (!netif_running(dev)) {
@@ -205,13 +205,8 @@ static void netpoll_poll_dev(struct net_device *dev)
}
ops = dev->netdev_ops;
- if (!ops->ndo_poll_controller) {
- up(&ni->dev_lock);
- return;
- }
-
- /* Process pending work on NIC */
- ops->ndo_poll_controller(dev);
+ if (ops->ndo_poll_controller)
+ ops->ndo_poll_controller(dev);
poll_napi(dev);
@@ -219,6 +214,7 @@ static void netpoll_poll_dev(struct net_device *dev)
zap_completion_queue();
}
+EXPORT_SYMBOL(netpoll_poll_dev);
void netpoll_poll_disable(struct net_device *dev)
{
@@ -613,8 +609,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
strlcpy(np->dev_name, ndev->name, IFNAMSIZ);
INIT_WORK(&np->cleanup_work, netpoll_async_cleanup);
- if ((ndev->priv_flags & IFF_DISABLE_NETPOLL) ||
- !ndev->netdev_ops->ndo_poll_controller) {
+ if (ndev->priv_flags & IFF_DISABLE_NETPOLL) {
np_err(np, "%s doesn't support polling, aborting\n",
np->dev_name);
err = -ENOTSUPP;
--
2.19.0.444.g18242da7ef-goog
^ permalink raw reply related
* [PATCH net 00/15] netpoll: avoid capture effects for NAPI drivers
From: Eric Dumazet @ 2018-09-21 22:27 UTC (permalink / raw)
To: David S . Miller
Cc: netdev, Eric Dumazet, Michael Chan, Ariel Elior, Eric Dumazet,
Tariq Toukan, Saeed Mahameed, Jeff Kirsher, Jakub Kicinski,
Song Liu, Jay Vosburgh, Veaceslav Falico, Andy Gospodarek
As diagnosed by Song Liu, ndo_poll_controller() can
be very dangerous on loaded hosts, since the cpu
calling ndo_poll_controller() might steal all NAPI
contexts (for all RX/TX queues of the NIC).
This capture, showing one ksoftirqd eating all cycles
can last for unlimited amount of time, since one
cpu is generally not able to drain all the queues under load.
It seems that all networking drivers that do use NAPI
for their TX completions, should not provide a ndo_poll_controller() :
Most NAPI drivers have netpoll support already handled
in core networking stack, since netpoll_poll_dev()
uses poll_napi(dev) to iterate through registered
NAPI contexts for a device.
This patch series take care of the first round, we will
handle other drivers in future rounds.
Eric Dumazet (15):
netpoll: make ndo_poll_controller() optional
bonding: use netpoll_poll_dev() helper
ixgbe: remove ndo_poll_controller
ixgbevf: remove ndo_poll_controller
fm10k: remove ndo_poll_controller
ixgb: remove ndo_poll_controller
igb: remove ndo_poll_controller
ice: remove ndo_poll_controller
i40evf: remove ndo_poll_controller
mlx4: remove ndo_poll_controller
mlx5: remove ndo_poll_controller
bnx2x: remove ndo_poll_controller
bnxt: remove ndo_poll_controller
nfp: remove ndo_poll_controller
tun: remove ndo_poll_controller
drivers/net/bonding/bond_main.c | 11 +----
.../net/ethernet/broadcom/bnx2x/bnx2x_main.c | 16 -------
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 18 --------
drivers/net/ethernet/intel/fm10k/fm10k.h | 3 --
.../net/ethernet/intel/fm10k/fm10k_netdev.c | 3 --
drivers/net/ethernet/intel/fm10k/fm10k_pci.c | 22 ----------
.../net/ethernet/intel/i40evf/i40evf_main.c | 26 -----------
drivers/net/ethernet/intel/ice/ice_main.c | 27 ------------
drivers/net/ethernet/intel/igb/igb_main.c | 30 -------------
drivers/net/ethernet/intel/ixgb/ixgb_main.c | 25 -----------
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 25 -----------
.../net/ethernet/intel/ixgbevf/ixgbevf_main.c | 21 ---------
.../net/ethernet/mellanox/mlx4/en_netdev.c | 20 ---------
.../net/ethernet/mellanox/mlx5/core/en_main.c | 19 --------
.../ethernet/netronome/nfp/nfp_net_common.c | 18 --------
drivers/net/tun.c | 43 -------------------
include/linux/netpoll.h | 5 ++-
net/core/netpoll.c | 19 +++-----
18 files changed, 12 insertions(+), 339 deletions(-)
--
2.19.0.444.g18242da7ef-goog
^ permalink raw reply
* Re: [PATCH bpf-next 2/3] bpf: emit RECORD_MMAP events for bpf prog load/unload
From: Alexei Starovoitov @ 2018-09-21 22:13 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: Peter Zijlstra, Alexei Starovoitov, David S . Miller, daniel,
netdev, kernel-team
In-Reply-To: <20180921122500.GA17312@kernel.org>
On Fri, Sep 21, 2018 at 09:25:00AM -0300, Arnaldo Carvalho de Melo wrote:
>
> > I have considered adding MUNMAP to match existing MMAP, but went
> > without it because I didn't want to introduce new bit in perf_event_attr
> > and emit these new events in a misbalanced conditional way for prog load/unload.
> > Like old perf is asking kernel for mmap events via mmap bit, so prog load events
>
> By prog load events you mean that old perf, having perf_event_attr.mmap = 1 ||
> perf_event_attr.mmap2 = 1 will cause the new kernel to emit
> PERF_RECORD_MMAP records for the range of addresses that a BPF program
> is being loaded on, right?
right. it would be weird when prog load events are there, but not unload.
> > will be in perf.data, but old perf report won't recognize them anyway.
>
> Why not? It should lookup the symbol and find it in the rb_tree of maps,
> with a DSO name equal to what was in the PERF_RECORD_MMAP emitted by the
> BPF core, no? It'll be an unresolved symbol, but a resolved map.
>
> > Whereas new perf would certainly want to catch bpf events and will set
> > both mmap and mumap bits.
>
> new perf with your code will find a symbol, not a map, because your code
> catches a special case PERF_RECORD_MMAP and instead of creating a
> 'struct map' will create a 'struct symbol' and insert it in the kallsyms
> 'struct map', right?
right.
bpf progs are more similar to kernel functions than to modules.
For modules it makes sense to create a new map and insert symbols into it.
For bpf JITed images there is no DSO to parse.
Single bpf elf file may contain multiple bpf progs and each prog may contain
multiple bpf functions. They will be loaded at different time and
will have different life time.
> In theory the old perf should catch the PERF_RECORD_MMAP with a string
> in the filename part and insert a new map into the kernel mmap rb_tree,
> and then samples would be resolved to this map, but since there is no
> backing DSO with a symtab, it would stop at that, just stating that the
> map is called NAME-OF-BPF-PROGRAM. This is all from memory, possibly
> there is something in there that makes it ignore this PERF_RECORD_MMAP
> emitted by the BPF kernel code when loading a new program.
In /proc/kcore there is already a section for module range.
Hence when perf processes bpf load/unload events the map is already created.
Therefore the patch 3 only searches for it and inserts new symbol into it.
In that sense the reuse of RECORD_MMAP event for bpf progs is indeed
not exactly clean, since no new map is created.
It's probably better to introduce PERF_RECORD_[INSERT|ERASE]_KSYM events ?
Such event potentially can be used for offline ksym resolution.
perf could process /proc/kallsyms during perf record and emit all of them
as synthetic PERF_RECORD_INSERT_KSYM into perf.data, so perf report can run
on a different server and still find the right symbols.
I guess, we can do bpf specific events too and keep RECORD_MMAP as-is.
How about single PERF_RECORD_BPF event with internal flag for load/unload ?
> Right, that is another unfortunate state of affairs, kernel module
> load/unload should already be supported, reported by the kernel via a
> proper PERF_RECORD_MODULE_LOAD/UNLOAD
I agree with Peter here. It would nice, but low priority.
modules are mostly static. Loaded once and stay there.
> There is another longstanding TODO list entry: PERF_RECORD_MMAP records
> should include a build-id, to avoid either userspace getting confused
> when there is an update of some mmap DSO, for long running sessions, for
> instance, or to have to scan the just recorded perf.data file for DSOs
> with samples to then read it from the file system (more races).
>
> Have you ever considered having a build-id for bpf objects that could be
> used here?
build-id concept is not applicable to bpf.
bpf elf files on the disc don't have good correlation with what is
running in the kernel. bpf bytestream is converted and optimized
by the verifier. Then JITed.
So debug info left in .o file and original bpf bytestream in .o are
mostly useless.
For bpf programs we have 'program tag'. It is computed over original
bpf bytestream, so both kernel and user space can compute it.
In libbcc we use /var/tmp/bcc/bpf_prog_TAG/ directory to store original
source code of the program, so users looking at kernel stack traces
with bpf_prog_TAG can find the source.
It's similar to build-id, but not going to help perf to annotate
actual x86 instructions inside JITed image and show src code.
Since JIT runs in the kernel this problem cannot be solved by user space only.
It's a difficult problem and we have a plan to tackle that,
but it's step 2. A bunch of infra is needed on bpf side to
preserve the association during src_in_C -> original bpf insns ->
translated bpf insns -> JITed asm.
Then report it back to user space and then teach perf to properly annotate progs.
> Will the JITed code from some BPF bytecode be different if the same
> bytecode is JITed in several machines, all having the exact same
> hardware?
Yes. JITed code will be different depending on sysctl knobs (like const blinding)
So the same original bpf byte stream loaded at different times
may have different JITed image.
Even without security features like blinding the JIT can be different.
the bpf maps are separate from bpf progs. The bpf map is created first.
Then the same bpf instruction stream (depending on map type that it uses)
may be optimized by the verifier differently causing difference in JIT.
> > (instead of passing kallsyms's bpf prog name in event->mmap.filename)
> > but bpf functions don't have their own prog_id. Multiple bpf funcs
> > with different JITed blobs are considered to be a part of single prog_id.
> > So as a step one I'm only extending RECORD_MMAP with addr and kallsym
> > name of bpf function/prog.
> > As a step two the plan is to add notification mechanism for prog load/unload
> > that will include prog_id and design new synthetic RECORD_* events in
> > perf user space that will contain JITed code, line info, BTF, etc.
>
> So, will the kernel JIT a bytecode, load it somewhere and run it, then,
> when unloading it, keep it somewhere (a filesystem with some limits,
> etc) so that at some later time (with some timeouts) tooling can, using
> its id/buildid cookie get the contents and symbol table to have a better
> annotation experience?
yes. The plan is to let perf fetch JITed image via BPF_OBJ_GET_INFO_BY_FD cmd
during perf record run and store it inside perf.data in synthetic records.
Then perf report can annotate it later.
> Using /proc/kcore as right now we should be able to annotate the BPF JIT
> as it is loaded, in 'perf top', for instance, with your suggested code,
> because we would have a symbol resolved that spans the whole bpf
> program, I'll try applying your patch and seeing how it goes.
yes. /proc/kcore helps to annotate during perf report when progs
are still loaded, but user experience sucks.
Like for networking bpf performance testing the user needs to:
- load the program
- start blasting traffic to trigger prog execution
- perf record -a sleep 5
- stop traffic
- perf report -> to analyze what's going on in bpf prog
- unload prog
All steps are manual.
We need to get to the point where we can:
- perf record -a ./my_bpf_test
- perf report
where my_bpf_test will load, attach, run traffic, detach, unload.
Most of selftests/bpf/* are done this way, but we cannot profile
them at the moment.
^ permalink raw reply
* Re: [PATCH rdma-next 0/4] mlx5 vport loopback
From: Leon Romanovsky @ 2018-09-21 21:40 UTC (permalink / raw)
To: Doug Ledford
Cc: Jason Gunthorpe, RDMA mailing list, Mark Bloch, Yishai Hadas,
Saeed Mahameed, linux-netdev
In-Reply-To: <bbc9bf5b9c4aa99cabc52444a6551afa0e0a6631.camel@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 661 bytes --]
On Fri, Sep 21, 2018 at 04:05:53PM -0400, Doug Ledford wrote:
> On Fri, 2018-09-21 at 22:33 +0300, Leon Romanovsky wrote:
> > Hope it makes it clear now.
>
> Clear enough. Between yours and Jason's explanation I think it's well
> covered.
>
> > Are you ok with me/Saeed taking first patch to our branch so you will be
> > able to take the rest?
>
> Yep. Let me know a tag when it's ready to merge.
Done, it doesn't have tag.
Commit d773ff41a7c ("net/mlx5: Rename incorrect naming in IFC file")
Thanks
>
> --
> Doug Ledford <dledford@redhat.com>
> GPG KeyID: B826A3330E572FDD
> Key fingerprint = AE6B 1BDA 122B 23B4 265B 1274 B826 A333 0E57 2FDD
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* [PATCH v2 net] mpls: allow routes on ip6gre devices
From: Saif Hasan @ 2018-09-21 21:30 UTC (permalink / raw)
To: netdev; +Cc: David S . Miller, Calvin Owens, Saif Hasan, Saif Hasan
Summary:
This appears to be necessary and sufficient change to enable `MPLS` on
`ip6gre` tunnels (RFC4023).
This diff allows IP6GRE devices to be recognized by MPLS kernel module
and hence user can configure interface to accept packets with mpls
headers as well setup mpls routes on them.
Test Plan:
Test plan consists of multiple containers connected via GRE-V6 tunnel.
Then carrying out testing steps as below.
- Carry out necessary sysctl settings on all containers
```
sysctl -w net.mpls.platform_labels=65536
sysctl -w net.mpls.ip_ttl_propagate=1
sysctl -w net.mpls.conf.lo.input=1
```
- Establish IP6GRE tunnels
```
ip -6 tunnel add name if_1_2_1 mode ip6gre \
local 2401:db00:21:6048:feed:0::1 \
remote 2401:db00:21:6048:feed:0::2 key 1
ip link set dev if_1_2_1 up
sysctl -w net.mpls.conf.if_1_2_1.input=1
ip -4 addr add 169.254.0.2/31 dev if_1_2_1 scope link
ip -6 tunnel add name if_1_3_1 mode ip6gre \
local 2401:db00:21:6048:feed:0::1 \
remote 2401:db00:21:6048:feed:0::3 key 1
ip link set dev if_1_3_1 up
sysctl -w net.mpls.conf.if_1_3_1.input=1
ip -4 addr add 169.254.0.4/31 dev if_1_3_1 scope link
```
- Install MPLS encap rules on node-1 towards node-2
```
ip route add 192.168.0.11/32 nexthop encap mpls 32/64 \
via inet 169.254.0.3 dev if_1_2_1
```
- Install MPLS forwarding rules on node-2 and node-3
```
// node2
ip -f mpls route add 32 via inet 169.254.0.7 dev if_2_4_1
// node3
ip -f mpls route add 64 via inet 169.254.0.12 dev if_4_3_1
```
- Ping 192.168.0.11 (node4) from 192.168.0.1 (node1) (where routing
towards 192.168.0.1 is via IP route directly towards node1 from node4)
```
ping 192.168.0.11
```
- tcpdump on interface to capture ping packets wrapped within MPLS
header which inturn wrapped within IP6GRE header
```
16:43:41.121073 IP6
2401:db00:21:6048:feed::1 > 2401:db00:21:6048:feed::2:
DSTOPT GREv0, key=0x1, length 100:
MPLS (label 32, exp 0, ttl 255) (label 64, exp 0, [S], ttl 255)
IP 192.168.0.1 > 192.168.0.11:
ICMP echo request, id 1208, seq 45, length 64
0x0000: 6000 2cdb 006c 3c3f 2401 db00 0021 6048 `.,..l<?$....!`H
0x0010: feed 0000 0000 0001 2401 db00 0021 6048 ........$....!`H
0x0020: feed 0000 0000 0002 2f00 0401 0401 0100 ......../.......
0x0030: 2000 8847 0000 0001 0002 00ff 0004 01ff ...G............
0x0040: 4500 0054 3280 4000 ff01 c7cb c0a8 0001 E..T2.@.........
0x0050: c0a8 000b 0800 a8d7 04b8 002d 2d3c a05b ...........--<.[
0x0060: 0000 0000 bcd8 0100 0000 0000 1011 1213 ................
0x0070: 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 .............!"#
0x0080: 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 $%&'()*+,-./0123
0x0090: 3435 3637 4567
```
Signed-off-by: Saif Hasan <has@fb.com>
---
net/mpls/af_mpls.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 7a4de6d618b1..8fbe6cdbe255 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -1533,10 +1533,14 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
unsigned int flags;
if (event == NETDEV_REGISTER) {
- /* For now just support Ethernet, IPGRE, SIT and IPIP devices */
+
+ /* For now just support Ethernet, IPGRE, IP6GRE, SIT and
+ * IPIP devices
+ */
if (dev->type == ARPHRD_ETHER ||
dev->type == ARPHRD_LOOPBACK ||
dev->type == ARPHRD_IPGRE ||
+ dev->type == ARPHRD_IP6GRE ||
dev->type == ARPHRD_SIT ||
dev->type == ARPHRD_TUNNEL) {
mdev = mpls_add_dev(dev);
^ permalink raw reply related
* [PATCH] mpls: allow routes on ip6gre devices
From: Saif Hasan @ 2018-09-19 19:19 UTC (permalink / raw)
To: netdev; +Cc: David S . Miller, Calvin Owens, Saif Hasan, Saif Hasan
Summary:
This appears to be necessary and sufficient change to enable `MPLS` on
`ip6gre` tunnels (RFC4023).
This diff allows IP6GRE devices to be recognized by MPLS kernel module
and hence user can configure interface to accept packets with mpls
headers as well setup mpls routes on them.
Test Plan:
Test plan consists of multiple containers connected via GRE-V6 tunnel.
Then carrying out testing steps as below.
- Carry out necessary sysctl settings on all containers
```
sysctl -w net.mpls.platform_labels=65536
sysctl -w net.mpls.ip_ttl_propagate=1
sysctl -w net.mpls.conf.lo.input=1
```
- Establish IP6GRE tunnels
```
ip -6 tunnel add name if_1_2_1 mode ip6gre \
local 2401:db00:21:6048:feed:0::1 \
remote 2401:db00:21:6048:feed:0::2 key 1
ip link set dev if_1_2_1 up
sysctl -w net.mpls.conf.if_1_2_1.input=1
ip -4 addr add 169.254.0.2/31 dev if_1_2_1 scope link
ip -6 tunnel add name if_1_3_1 mode ip6gre \
local 2401:db00:21:6048:feed:0::1 \
remote 2401:db00:21:6048:feed:0::3 key 1
ip link set dev if_1_3_1 up
sysctl -w net.mpls.conf.if_1_3_1.input=1
ip -4 addr add 169.254.0.4/31 dev if_1_3_1 scope link
```
- Install MPLS encap rules on node-1 towards node-2
```
ip route add 192.168.0.11/32 nexthop encap mpls 32/64 \
via inet 169.254.0.3 dev if_1_2_1
```
- Install MPLS forwarding rules on node-2 and node-3
```
// node2
ip -f mpls route add 32 via inet 169.254.0.7 dev if_2_4_1
// node3
ip -f mpls route add 64 via inet 169.254.0.12 dev if_4_3_1
```
- Ping 192.168.0.11 (node4) from 192.168.0.1 (node1) (where routing
towards 192.168.0.1 is via IP route directly towards node1 from node4)
```
ping 192.168.0.11
```
- tcpdump on interface to capture ping packets wrapped within MPLS
header which inturn wrapped within IP6GRE header
```
16:43:41.121073 IP6
2401:db00:21:6048:feed::1 > 2401:db00:21:6048:feed::2:
DSTOPT GREv0, key=0x1, length 100:
MPLS (label 32, exp 0, ttl 255) (label 64, exp 0, [S], ttl 255)
IP 192.168.0.1 > 192.168.0.11:
ICMP echo request, id 1208, seq 45, length 64
0x0000: 6000 2cdb 006c 3c3f 2401 db00 0021 6048 `.,..l<?$....!`H
0x0010: feed 0000 0000 0001 2401 db00 0021 6048 ........$....!`H
0x0020: feed 0000 0000 0002 2f00 0401 0401 0100 ......../.......
0x0030: 2000 8847 0000 0001 0002 00ff 0004 01ff ...G............
0x0040: 4500 0054 3280 4000 ff01 c7cb c0a8 0001 E..T2.@.........
0x0050: c0a8 000b 0800 a8d7 04b8 002d 2d3c a05b ...........--<.[
0x0060: 0000 0000 bcd8 0100 0000 0000 1011 1213 ................
0x0070: 1415 1617 1819 1a1b 1c1d 1e1f 2021 2223 .............!"#
0x0080: 2425 2627 2829 2a2b 2c2d 2e2f 3031 3233 $%&'()*+,-./0123
0x0090: 3435 3637 4567
```
Signed-off-by: Saif Hasan <has@fb.com>
---
net/mpls/af_mpls.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 7a4de6d618b1..aeb5bf2f7595 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -1533,10 +1533,11 @@ static int mpls_dev_notify(struct notifier_block *this, unsigned long event,
unsigned int flags;
if (event == NETDEV_REGISTER) {
- /* For now just support Ethernet, IPGRE, SIT and IPIP devices */
+ /* For now just support Ethernet, IPGRE, IP6GRE, SIT and IPIP devices */
if (dev->type == ARPHRD_ETHER ||
dev->type == ARPHRD_LOOPBACK ||
dev->type == ARPHRD_IPGRE ||
+ dev->type == ARPHRD_IP6GRE ||
dev->type == ARPHRD_SIT ||
dev->type == ARPHRD_TUNNEL) {
mdev = mpls_add_dev(dev);
^ permalink raw reply related
* [PATCH iproute2 1/1] Makefile: Add check target
From: Petr Vorel @ 2018-09-21 20:29 UTC (permalink / raw)
To: netdev; +Cc: Petr Vorel, Stephen Hemminger
Signed-off-by: Petr Vorel <petr.vorel@gmail.com>
---
Makefile | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Makefile b/Makefile
index 25de3893..b7488add 100644
--- a/Makefile
+++ b/Makefile
@@ -77,6 +77,7 @@ help:
@echo " clean - remove products of build"
@echo " distclean - remove configuration and build"
@echo " install - install binaries on local machine"
+ @echo " check - run tests"
@echo " cscope - build cscope database"
@echo " snapshot - generate version number header"
@echo ""
@@ -118,6 +119,9 @@ clobber:
distclean: clobber
+check:
+ cd testsuite && $(MAKE) && $(MAKE) alltests
+
cscope:
cscope -b -q -R -Iinclude -sip -slib -smisc -snetem -stc
--
2.19.0.rc2
^ permalink raw reply related
* Re: [PATCH] decnet: Remove unnecessary check for dev->name
From: Stephen Hemminger @ 2018-09-21 20:18 UTC (permalink / raw)
To: Nathan Chancellor
Cc: David S. Miller, linux-decnet-user, netdev, linux-kernel
In-Reply-To: <20180921193034.808-1-natechancellor@gmail.com>
On Fri, 21 Sep 2018 12:30:34 -0700
Nathan Chancellor <natechancellor@gmail.com> wrote:
> Clang warns that the address of a pointer will always evaluated as true
> in a boolean context.
>
> net/decnet/dn_dev.c:1366:10: warning: address of array 'dev->name' will
> always evaluate to 'true' [-Wpointer-bool-conversion]
> dev->name ? dev->name : "???",
> ~~~~~^~~~ ~
> 1 warning generated.
>
> Link: https://github.com/ClangBuiltLinux/linux/issues/116
> Signed-off-by: Nathan Chancellor <natechancellor@gmail.com>
Makes sense name in net_device is an array.
Reviewed-by: Stephen Hemminger <stephen@networkplumber.org>
^ permalink raw reply
* Re: [PATCH iproute2] Makefile: add help target
From: David Ahern @ 2018-09-21 20:09 UTC (permalink / raw)
To: Stephen Hemminger, netdev
In-Reply-To: <20180921161632.29544-1-stephen@networkplumber.org>
On 9/21/18 9:16 AM, Stephen Hemminger wrote:
> Add help target to Makefile.
>
> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
> ---
> Makefile | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
Acked-by: David Ahern <dsahern@gmail.com>
^ permalink raw reply
* Re: [PATCH rdma-next 0/4] mlx5 vport loopback
From: Doug Ledford @ 2018-09-21 20:05 UTC (permalink / raw)
To: Leon Romanovsky
Cc: Jason Gunthorpe, RDMA mailing list, Mark Bloch, Yishai Hadas,
Saeed Mahameed, linux-netdev
In-Reply-To: <20180921193335.GV3519@mtr-leonro.mtl.com>
[-- Attachment #1: Type: text/plain, Size: 481 bytes --]
On Fri, 2018-09-21 at 22:33 +0300, Leon Romanovsky wrote:
> Hope it makes it clear now.
Clear enough. Between yours and Jason's explanation I think it's well
covered.
> Are you ok with me/Saeed taking first patch to our branch so you will be
> able to take the rest?
Yep. Let me know a tag when it's ready to merge.
--
Doug Ledford <dledford@redhat.com>
GPG KeyID: B826A3330E572FDD
Key fingerprint = AE6B 1BDA 122B 23B4 265B 1274 B826 A333 0E57 2FDD
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH v3 net-next] dt-bindings: can: rcar_can: document r8a77965 support
From: Eugeniu Rosca @ 2018-09-21 19:48 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: Simon Horman, Kieran Bingham, Sergei Shtylyov,
Wolfgang Grandegger, David S . Miller, Rob Herring, Mark Rutland,
linux-can, netdev, devicetree, Magnus Damm, linux-renesas-soc,
Eugeniu Rosca, Eugeniu Rosca
In-Reply-To: <50048177-96ad-cbda-6845-20ffc32d025a@pengutronix.de>
Hi Marc,
On Mon, Aug 27, 2018 at 12:08:48PM +0200, Marc Kleine-Budde wrote:
> On 08/20/2018 04:49 PM, Eugeniu Rosca wrote:
> > From: Eugeniu Rosca <rosca.eugeniu@gmail.com>
> >
> > Document the support for rcar_can on R8A77965 SoC devices.
> > Add R8A77965 to the list of SoCs which require the "assigned-clocks" and
> > "assigned-clock-rates" properties (thanks, Sergei).
> >
> > Signed-off-by: Eugeniu Rosca <erosca@de.adit-jv.com>
> > Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
> > Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
>
> Added to linux-can.
I can't find the patch in below repositories:
- https://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
- https://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
Could you please let me know what "linux-can" means?
>
> Marc
>
> --
> Pengutronix e.K. | Marc Kleine-Budde |
> Industrial Linux Solutions | Phone: +49-231-2826-924 |
> Vertretung West/Dortmund | Fax: +49-5121-206917-5555 |
> Amtsgericht Hildesheim, HRA 2686 | http://www.pengutronix.de |
Thanks,
Eugeniu.
^ permalink raw reply
* Re: [PATCH rdma-next 0/4] mlx5 vport loopback
From: Jason Gunthorpe @ 2018-09-21 19:40 UTC (permalink / raw)
To: Doug Ledford
Cc: Leon Romanovsky, Leon Romanovsky, RDMA mailing list, Mark Bloch,
Yishai Hadas, Saeed Mahameed, linux-netdev
In-Reply-To: <4d9969b9424642dc4c50ca698c57c41654f7006a.camel@redhat.com>
On Fri, Sep 21, 2018 at 03:14:36PM -0400, Doug Ledford wrote:
> On Mon, 2018-09-17 at 13:30 +0300, Leon Romanovsky wrote:
> > From: Leon Romanovsky <leonro@mellanox.com>
> >
> > Hi,
> >
> > This is short series from Mark which extends handling of loopback
> > traffic. Originally mlx5 IB dynamically enabled/disabled both unicast
> > and multicast based on number of users. However RAW ethernet QPs need
> > more granular access.
> >
> > Thanks
> >
> > Mark Bloch (4):
> > net/mlx5: Rename incorrect naming in IFC file
> > RDMA/mlx5: Refactor transport domain bookkeeping logic
> > RDMA/mlx5: Allow creating RAW ethernet QP with loopback support
> > RDMA/mlx5: Enable vport loopback when user context or QP mandate
>
> I've reviewed this series and I'm OK with it, but the first patch is for
> net/mlx5. How are you expecting the series to be applied? Are you
> wanting me or Jason to take the entire series, or does the first patch
> need to go through the mlx5 tree and get picked up by Dave and us, and
> then we take the rest? This is unclear to me...
Saeed or Leon will apply the net/mlx5 patches when netdev and RDMA
approves the series, such as with the above approval.
Our job is to take the branch from
git://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux.git mellanox/mlx5-next
So it is a two step process where it is approved on the mailing list
then Saeed/Leon will respond with the branch commits.
Depending on need I've been doing either a 'series merge' which looks
like this:
commit 8193abb6a8171c775503acd041eb957cc7e9e7f4
Merge: c1dfc0114c901b 25bb36e75d7d62
Author: Jason Gunthorpe <jgg@mellanox.com>
Date: Wed Jul 4 13:19:46 2018 -0600
Merge branch 'mlx5-dump-fill-mkey' into rdma.git for-next
For dependencies, branch based on 'mellanox/mlx5-next' of
git://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux.git
Pull Dump and fill MKEY from Leon Romanovsky:
====================
MLX5 IB HCA offers the memory key, dump_fill_mkey to increase performance,
when used in a send or receive operations.
It is used to force local HCA operations to skip the PCI bus access, while
keeping track of the processed length in the ibv_sge handling.
In this three patch series, we expose various bits in our HW spec
file (mlx5_ifc.h), move unneeded for mlx5_core FW command and export such
memory key to user space thought our mlx5-abi header file.
====================
Botched auto-merge in mlx5_ib_alloc_ucontext() resolved by hand.
* branch 'mlx5-dump-fill-mkey':
IB/mlx5: Expose dump and fill memory key
net/mlx5: Add hardware definitions for dump_fill_mkey
net/mlx5: Limit scope of dump_fill_mkey function
net/mlx5: Rate limit errors in command interface
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Which preserves the cover letter, so I prefer it.
This only works if the RDMA patches have no dependency on the latest
RDMA tree.
The Mellanox branch may have additional patches beyond the series in
question, this just means they have progressed on the netdev side, I
usually trim them out of the 'git merge --log' section for greater
clarity.
Otherwise, merge the Mellanox branch with the right commit IDs and
then apply the RDMA patches, such as here:
commit eda98779f7d318cf96f030bbc5b23f034b69b80a
Merge: 4fca037783512c 664000b6bb4352
Author: Jason Gunthorpe <jgg@mellanox.com>
Date: Tue Jul 24 13:10:23 2018 -0600
Merge branch 'mellanox/mlx5-next' into rdma.git for-next
From git://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux.git
This is required to resolve dependencies of the next series of RDMA
patches.
* branch 'mellanox/mlx5-next':
net/mlx5: Add support for flow table destination number
net/mlx5: Add forward compatible support for the FTE match data
net/mlx5: Fix tristate and description for MLX5 module
net/mlx5: Better return types for CQE API
net/mlx5: Use ERR_CAST() instead of coding it
net/mlx5: Add missing SET_DRIVER_VERSION command translation
net/mlx5: Add XRQ commands definitions
net/mlx5: Add core support for double vlan push/pop steering action
net/mlx5: Expose MPEGC (Management PCIe General Configuration) structures
net/mlx5: FW tracer, add hardware structures
net/mlx5: fix uaccess beyond "count" in debugfs read/write handlers
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
It is up to Saeed to sync this branch with netdev.
Neither RDMA or netdev should apply patches marked for net/mlx5 - they
must go through the shared branch to avoid conflicts.
Jason
^ permalink raw reply
* Re: [PATCH rdma-next 0/4] mlx5 vport loopback
From: Leon Romanovsky @ 2018-09-21 19:33 UTC (permalink / raw)
To: Doug Ledford
Cc: Jason Gunthorpe, RDMA mailing list, Mark Bloch, Yishai Hadas,
Saeed Mahameed, linux-netdev
In-Reply-To: <4d9969b9424642dc4c50ca698c57c41654f7006a.camel@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 2506 bytes --]
On Fri, Sep 21, 2018 at 03:14:36PM -0400, Doug Ledford wrote:
> On Mon, 2018-09-17 at 13:30 +0300, Leon Romanovsky wrote:
> > From: Leon Romanovsky <leonro@mellanox.com>
> >
> > Hi,
> >
> > This is short series from Mark which extends handling of loopback
> > traffic. Originally mlx5 IB dynamically enabled/disabled both unicast
> > and multicast based on number of users. However RAW ethernet QPs need
> > more granular access.
> >
> > Thanks
> >
> > Mark Bloch (4):
> > net/mlx5: Rename incorrect naming in IFC file
> > RDMA/mlx5: Refactor transport domain bookkeeping logic
> > RDMA/mlx5: Allow creating RAW ethernet QP with loopback support
> > RDMA/mlx5: Enable vport loopback when user context or QP mandate
>
> I've reviewed this series and I'm OK with it, but the first patch is for
> net/mlx5. How are you expecting the series to be applied? Are you
> wanting me or Jason to take the entire series, or does the first patch
> need to go through the mlx5 tree and get picked up by Dave and us, and
> then we take the rest? This is unclear to me...
Thanks Doug,
The preferable flow for such patches is that I or Saeed will apply
net/mlx5 patch (mlx5-next) on top of our shared branch after you or Jason
or Dave ack on whole series.
The shared branch is located in:
https://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux.git/log/?h=mlx5-next
As you can see, it is clear branch of our shared commits and it is based
on -rc1 to be sure no pollution of both subsystems will be done.
It ensures that netdev won't get RDMA patches and vice versa.
For RDMA, once we apply such mlx5-next patch, Jason usually merges of
this branch into his rdma-next and applies on top of it extra non
mlx5-next patches.
https://git.kernel.org/pub/scm/linux/kernel/git/rdma/rdma.git/commit/?h=for-next&id=af68ccbc1131ddd8dcda65b015cd9919b352485a
For netdev, it is a little bit different, because Saeed works with pull
requests and he creates merge commit before sending his pull request.
This model allows us to ensure that changes are pulled only when it is
really needed and there is a chance that Dave won't ever pull this
mlx5-next branch in this cycle because Saeed won't have any patches
depend on it.
Hope it makes it clear now.
Are you ok with me/Saeed taking first patch to our branch so you will be
able to take the rest?
Thanks
>
> --
> Doug Ledford <dledford@redhat.com>
> GPG KeyID: B826A3330E572FDD
> Key fingerprint = AE6B 1BDA 122B 23B4 265B 1274 B826 A333 0E57 2FDD
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* Re: [PATCH net-next v2 08/10] net: sched: protect block idr with spinlock
From: Cong Wang @ 2018-09-21 19:33 UTC (permalink / raw)
To: Vlad Buslov
Cc: Linux Kernel Network Developers, Jamal Hadi Salim, Jiri Pirko,
David Miller, Stephen Hemminger, Kirill Tkhai, Nicolas Dichtel,
Greg KH, mark.rutland, Leon Romanovsky, Paul E. McKenney,
Florian Westphal, David Ahern, christian, lucien xin,
Jakub Kicinski, Jiri Benc
In-Reply-To: <vbftvmkzkln.fsf@reg-r-vrt-018-180.mtr.labs.mlnx>
On Thu, Sep 20, 2018 at 12:36 AM Vlad Buslov <vladbu@mellanox.com> wrote:
>
>
> On Wed 19 Sep 2018 at 22:09, Cong Wang <xiyou.wangcong@gmail.com> wrote:
> > On Mon, Sep 17, 2018 at 12:19 AM Vlad Buslov <vladbu@mellanox.com> wrote:
> >> @@ -482,16 +483,25 @@ static int tcf_block_insert(struct tcf_block *block, struct net *net,
> >> struct netlink_ext_ack *extack)
> >> {
> >> struct tcf_net *tn = net_generic(net, tcf_net_id);
> >> + int err;
> >> +
> >> + idr_preload(GFP_KERNEL);
> >> + spin_lock(&tn->idr_lock);
> >> + err = idr_alloc_u32(&tn->idr, block, &block->index, block->index,
> >> + GFP_NOWAIT);
> >
> >
> > Why GFP_NOWAIT rather than GFP_ATOMIC here?
>
> I checked how idr_preload is used in kernel and in most places following
> allocation uses GFP_NOWAIT (including idr-test.c). You suggest I should
> change it to GFP_ATOMIC?
No, I am just curious, as GFP_ATOMIC is more widely used when holding
spinlock. I thought you have a special reason to use GFP_NOWAIT here,
but anyway, GFP_NOWAIT is probably fine too.
^ permalink raw reply
* Re: [PATCH net-next v2 05/10] net: sched: use Qdisc rcu API instead of relying on rtnl lock
From: Cong Wang @ 2018-09-21 19:29 UTC (permalink / raw)
To: Vlad Buslov
Cc: Linux Kernel Network Developers, Jamal Hadi Salim, Jiri Pirko,
David Miller, Stephen Hemminger, Kirill Tkhai, Nicolas Dichtel,
Greg KH, mark.rutland, Leon Romanovsky, Paul E. McKenney,
Florian Westphal, David Ahern, christian, lucien xin,
Jakub Kicinski, Jiri Benc
In-Reply-To: <vbfva70zlb9.fsf@reg-r-vrt-018-180.mtr.labs.mlnx>
On Thu, Sep 20, 2018 at 12:21 AM Vlad Buslov <vladbu@mellanox.com> wrote:
>
>
> On Wed 19 Sep 2018 at 22:04, Cong Wang <xiyou.wangcong@gmail.com> wrote:
> > On Mon, Sep 17, 2018 at 12:19 AM Vlad Buslov <vladbu@mellanox.com> wrote:
> >> +static void tcf_qdisc_put(struct Qdisc *q, bool rtnl_held)
> >> +{
> >> + if (!q)
> >> + return;
> >> +
> >> + if (rtnl_held)
> >> + qdisc_put(q);
> >> + else
> >> + qdisc_put_unlocked(q);
> >> +}
> >
> > This is very ugly. You should know whether RTNL is held or
> > not when calling it.
> >
> > What's more, all of your code passes true, so why do you
> > need a parameter for rtnl_held?
>
> It passes true because currently rule update handlers still registered
> as locked. This is a preparation for next patch set where this would be
> changed to proper variable that depends on qdics and classifier type.
You can always add it when you really need it.
I doubt you need such a tiny wrapper even in the next patchset,
as it can be easily folded into callers.
^ permalink raw reply
* Re: [PATCH rdma-next 0/4] mlx5 vport loopback
From: Doug Ledford @ 2018-09-21 19:14 UTC (permalink / raw)
To: Leon Romanovsky, Jason Gunthorpe
Cc: Leon Romanovsky, RDMA mailing list, Mark Bloch, Yishai Hadas,
Saeed Mahameed, linux-netdev
In-Reply-To: <20180917103049.18235-1-leon@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 1137 bytes --]
On Mon, 2018-09-17 at 13:30 +0300, Leon Romanovsky wrote:
> From: Leon Romanovsky <leonro@mellanox.com>
>
> Hi,
>
> This is short series from Mark which extends handling of loopback
> traffic. Originally mlx5 IB dynamically enabled/disabled both unicast
> and multicast based on number of users. However RAW ethernet QPs need
> more granular access.
>
> Thanks
>
> Mark Bloch (4):
> net/mlx5: Rename incorrect naming in IFC file
> RDMA/mlx5: Refactor transport domain bookkeeping logic
> RDMA/mlx5: Allow creating RAW ethernet QP with loopback support
> RDMA/mlx5: Enable vport loopback when user context or QP mandate
I've reviewed this series and I'm OK with it, but the first patch is for
net/mlx5. How are you expecting the series to be applied? Are you
wanting me or Jason to take the entire series, or does the first patch
need to go through the mlx5 tree and get picked up by Dave and us, and
then we take the rest? This is unclear to me...
--
Doug Ledford <dledford@redhat.com>
GPG KeyID: B826A3330E572FDD
Key fingerprint = AE6B 1BDA 122B 23B4 265B 1274 B826 A333 0E57 2FDD
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH][next-next][v2] netlink: avoid to allocate full skb when sending to many devices
From: Cong Wang @ 2018-09-21 19:08 UTC (permalink / raw)
To: Li,Rongqing; +Cc: Linux Kernel Network Developers
In-Reply-To: <1537433690-24335-1-git-send-email-lirongqing@baidu.com>
On Thu, Sep 20, 2018 at 1:58 AM Li RongQing <lirongqing@baidu.com> wrote:
>
> if skb->head is vmalloc address, when this skb is delivered, full
> allocation for this skb is required, if there are many devices,
> the full allocation will be called for every devices
So why do you in practice need many netlink tap devices?
tap devices are now isolated in each netns, so at max you need
one tap device per netns in practice.
^ permalink raw reply
* Re: [PATCH net] ip6_tunnel: be careful when accessing the inner header
From: Cong Wang @ 2018-09-21 18:51 UTC (permalink / raw)
To: Paolo Abeni
Cc: Linux Kernel Network Developers, David Miller,
Alexander Potapenko
In-Reply-To: <78ef06b7731007ff16b00962c58f36f87d689d65.1537362057.git.pabeni@redhat.com>
On Wed, Sep 19, 2018 at 6:04 AM Paolo Abeni <pabeni@redhat.com> wrote:
> diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
> index 419960b0ba16..a0b6932c3afd 100644
> --- a/net/ipv6/ip6_tunnel.c
> +++ b/net/ipv6/ip6_tunnel.c
> @@ -1234,7 +1234,7 @@ static inline int
> ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
> {
> struct ip6_tnl *t = netdev_priv(dev);
> - const struct iphdr *iph = ip_hdr(skb);
> + const struct iphdr *iph;
> int encap_limit = -1;
> struct flowi6 fl6;
> __u8 dsfield;
> @@ -1242,6 +1242,11 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
> u8 tproto;
> int err;
>
> + /* ensure we can access the full inner ip header */
> + if (!pskb_may_pull(skb, sizeof(struct iphdr)))
> + return -1;
> +
> + iph = ip_hdr(skb);
Hmm...
How do IPv4 tunnels ensure they have the right inner header to access?
ip_tunnel_xmit() uses skb_inner_network_header() to access inner header
which doesn't have any check either AFAIK.
^ permalink raw reply
* Re: [PATCH net] af_key: free SKBs under RCU protection
From: stranche @ 2018-09-21 18:44 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev, steffen.klassert
In-Reply-To: <56017947-4712-6014-4625-79dc7555c880@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 427 bytes --]
On 2018-09-21 11:40, Eric Dumazet wrote:
> On 09/21/2018 10:09 AM, stranche@codeaurora.org wrote:
>
>> I also tried reverting 7f6b9dbd5afb ("af_key: locking change") and
>> running the
>> test there and I still see the crash, so it doesn't seem to be an RCU
>> specific
>> issue.
>>
>> Is there anything else that could be causing this?
>
> What about you share your repro ?
Sure. Syzkaller reproducer source is attached.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: KASAN_use-after-free_Read_in_sock_rfree.c --]
[-- Type: text/x-c; name=KASAN_use-after-free_Read_in_sock_rfree.c, Size: 32898 bytes --]
// autogenerated by syzkaller (http://github.com/google/syzkaller)
#define _GNU_SOURCE
#include <endian.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <linux/futex.h>
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <time.h>
#include <sys/prctl.h>
#include <dirent.h>
#include <sys/mount.h>
#include <errno.h>
#include <sched.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/if_tun.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <net/if_arp.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <linux/net.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/mount.h>
__attribute__((noreturn)) static void doexit(int status) {
volatile unsigned i;
syscall(__NR_exit_group, status);
for (i = 0;; i++) {
}
}
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <setjmp.h>
#include <signal.h>
#include <string.h>
const int kFailStatus = 67;
const int kRetryStatus = 69;
static void fail(const char* msg, ...) {
int e = errno;
va_list args;
va_start(args, msg);
vfprintf(stderr, msg, args);
va_end(args);
fprintf(stderr, " (errno %d)\n", e);
doexit((e == ENOMEM || e == EAGAIN) ? kRetryStatus : kFailStatus);
}
static void exitf(const char* msg, ...) {
int e = errno;
va_list args;
va_start(args, msg);
vfprintf(stderr, msg, args);
va_end(args);
fprintf(stderr, " (errno %d)\n", e);
doexit(kRetryStatus);
}
static __thread int skip_segv;
static __thread jmp_buf segv_env;
static void segv_handler(int sig, siginfo_t* info, void* uctx) {
uintptr_t addr = (uintptr_t) info->si_addr;
const uintptr_t prog_start = 1 << 20;
const uintptr_t prog_end = 100 << 20;
if (__atomic_load_n(&skip_segv, __ATOMIC_RELAXED) &&
(addr < prog_start || addr > prog_end)) {
_longjmp(segv_env, 1);
}
doexit(sig);
}
static void install_segv_handler() {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = SIG_IGN;
syscall(SYS_rt_sigaction, 0x20, &sa, NULL, 8);
syscall(SYS_rt_sigaction, 0x21, &sa, NULL, 8);
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = segv_handler;
sa.sa_flags = SA_NODEFER | SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGBUS, &sa, NULL);
}
#define NONFAILING(...) { __atomic_fetch_add(&skip_segv, 1, __ATOMIC_SEQ_CST); if (_setjmp(segv_env) == 0) { __VA_ARGS__; } __atomic_fetch_sub(&skip_segv, 1, __ATOMIC_SEQ_CST); }
static uint64_t current_time_ms() {
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts)) fail("clock_gettime failed");
return (uint64_t) ts.tv_sec * 1000 + (uint64_t) ts.tv_nsec / 1000000;
}
static void use_temporary_dir() {
char tmpdir_template[] = "./syzkaller.XXXXXX";
char* tmpdir = mkdtemp(tmpdir_template);
if (!tmpdir) fail("failed to mkdtemp");
if (chmod(tmpdir, 0777)) fail("failed to chmod");
if (chdir(tmpdir)) fail("failed to chdir");
}
static void vsnprintf_check(char* str, size_t size, const char* format,
va_list args) {
int rv;
rv = vsnprintf(str, size, format, args);
if (rv < 0) fail("tun: snprintf failed");
if ((size_t) rv >= size)
fail("tun: string '%s...' doesn't fit into buffer", str);
}
static void snprintf_check(char* str, size_t size, const char* format, ...) {
va_list args;
va_start(args, format);
vsnprintf_check(str, size, format, args);
va_end(args);
}
#define COMMAND_MAX_LEN 128
#define PATH_PREFIX "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin "
#define PATH_PREFIX_LEN (sizeof(PATH_PREFIX) - 1)
static void execute_command(bool panic, const char* format, ...) {
va_list args;
char command[PATH_PREFIX_LEN + COMMAND_MAX_LEN];
int rv;
va_start(args, format);
memcpy(command, PATH_PREFIX, PATH_PREFIX_LEN);
vsnprintf_check(command + PATH_PREFIX_LEN, COMMAND_MAX_LEN, format, args);
va_end(args);
rv = system(command);
if (rv) {
if (panic) fail("command '%s' failed: %d", &command[0], rv);
}
}
static int tunfd = -1;
static int tun_frags_enabled;
#define SYZ_TUN_MAX_PACKET_SIZE 1000
#define TUN_IFACE "syz_tun"
#define LOCAL_MAC "aa:aa:aa:aa:aa:aa"
#define REMOTE_MAC "aa:aa:aa:aa:aa:bb"
#define LOCAL_IPV4 "172.20.20.170"
#define REMOTE_IPV4 "172.20.20.187"
#define LOCAL_IPV6 "fe80::aa"
#define REMOTE_IPV6 "fe80::bb"
#define IFF_NAPI 0x0010
#define IFF_NAPI_FRAGS 0x0020
static void initialize_tun(void) {
tunfd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
if (tunfd == -1) {
printf("tun: can't open /dev/net/tun: please enable CONFIG_TUN=y\n");
printf("otherwise fuzzing or reproducing might not work as intended\n");
return;
}
const int kTunFd = 252;
if (dup2(tunfd, kTunFd) < 0) fail("dup2(tunfd, kTunFd) failed");
close(tunfd);
tunfd = kTunFd;
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, TUN_IFACE, IFNAMSIZ);
ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_NAPI | IFF_NAPI_FRAGS;
if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0) {
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
if (ioctl(tunfd, TUNSETIFF, (void*)&ifr) < 0)
fail("tun: ioctl(TUNSETIFF) failed");
}
if (ioctl(tunfd, TUNGETIFF, (void*)&ifr) < 0)
fail("tun: ioctl(TUNGETIFF) failed");
tun_frags_enabled = (ifr.ifr_flags & IFF_NAPI_FRAGS) != 0;
execute_command(1, "sysctl -w net.ipv6.conf.%s.accept_dad=0", TUN_IFACE);
execute_command(1, "sysctl -w net.ipv6.conf.%s.router_solicitations=0",
TUN_IFACE);
execute_command(1, "ip link set dev %s address %s", TUN_IFACE, LOCAL_MAC);
execute_command(1, "ip addr add %s/24 dev %s", LOCAL_IPV4, TUN_IFACE);
execute_command(1, "ip -6 addr add %s/120 dev %s", LOCAL_IPV6, TUN_IFACE);
execute_command(1, "ip neigh add %s lladdr %s dev %s nud permanent",
REMOTE_IPV4, REMOTE_MAC, TUN_IFACE);
execute_command(1, "ip -6 neigh add %s lladdr %s dev %s nud permanent",
REMOTE_IPV6, REMOTE_MAC, TUN_IFACE);
execute_command(1, "ip link set dev %s up", TUN_IFACE);
}
#define DEV_IPV4 "172.20.20.%d"
#define DEV_IPV6 "fe80::%02hx"
#define DEV_MAC "aa:aa:aa:aa:aa:%02hx"
static void initialize_netdevices(void) {
unsigned i;
const char* devtypes[] = { "ip6gretap", "bridge", "vcan", "bond", "team" };
const char* devnames[] = {
"lo", "sit0", "bridge0", "vcan0", "tunl0", "gre0", "gretap0", "ip_vti0",
"ip6_vti0", "ip6tnl0", "ip6gre0", "ip6gretap0", "erspan0", "bond0", "veth0",
"veth1", "team0", "veth0_to_bridge", "veth1_to_bridge", "veth0_to_bond",
"veth1_to_bond", "veth0_to_team", "veth1_to_team"
};
const char* devmasters[] = { "bridge", "bond", "team" };
for (i = 0; i < sizeof(devtypes) / (sizeof(devtypes[0])); i++)
execute_command(0, "ip link add dev %s0 type %s", devtypes[i], devtypes[i]);
execute_command(0, "ip link add type veth");
for (i = 0; i < sizeof(devmasters) / (sizeof(devmasters[0])); i++) {
execute_command(
0, "ip link add name %s_slave_0 type veth peer name veth0_to_%s",
devmasters[i], devmasters[i]);
execute_command(
0, "ip link add name %s_slave_1 type veth peer name veth1_to_%s",
devmasters[i], devmasters[i]);
execute_command(0, "ip link set %s_slave_0 master %s0", devmasters[i],
devmasters[i]);
execute_command(0, "ip link set %s_slave_1 master %s0", devmasters[i],
devmasters[i]);
execute_command(0, "ip link set veth0_to_%s up", devmasters[i]);
execute_command(0, "ip link set veth1_to_%s up", devmasters[i]);
}
execute_command(0, "ip link set bridge_slave_0 up");
execute_command(0, "ip link set bridge_slave_1 up");
for (i = 0; i < sizeof(devnames) / (sizeof(devnames[0])); i++) {
char addr[32];
snprintf_check(addr, sizeof(addr), DEV_IPV4, i + 10);
execute_command(0, "ip -4 addr add %s/24 dev %s", addr, devnames[i]);
snprintf_check(addr, sizeof(addr), DEV_IPV6, i + 10);
execute_command(0, "ip -6 addr add %s/120 dev %s", addr, devnames[i]);
snprintf_check(addr, sizeof(addr), DEV_MAC, i + 10);
execute_command(0, "ip link set dev %s address %s", devnames[i], addr);
execute_command(0, "ip link set dev %s up", devnames[i]);
}
}
static int read_tun(char* data, int size) {
if (tunfd < 0) return -1;
int rv = read(tunfd, data, size);
if (rv < 0) {
if (errno == EAGAIN) return -1;
if (errno == EBADFD) return -1;
fail("tun: read failed with %d", rv);
}
return rv;
}
static void flush_tun() {
char data[SYZ_TUN_MAX_PACKET_SIZE];
while (read_tun(&data[0], sizeof(data)) != -1)
;
}
static bool write_file(const char* file, const char* what, ...) {
char buf[1024];
va_list args;
va_start(args, what);
vsnprintf(buf, sizeof(buf), what, args);
va_end(args);
buf[sizeof(buf) - 1] = 0;
int len = strlen(buf);
int fd = open(file, O_WRONLY | O_CLOEXEC);
if (fd == -1) return false;
if (write(fd, buf, len) != len) {
int err = errno;
close(fd);
errno = err;
return false;
}
close(fd);
return true;
}
static void setup_cgroups() {
if (mkdir("/syzcgroup", 0777)) {
}
if (mkdir("/syzcgroup/unified", 0777)) {
}
if (mount("none", "/syzcgroup/unified", "cgroup2", 0, NULL)) {
}
if (chmod("/syzcgroup/unified", 0777)) {
}
if (!write_file("/syzcgroup/unified/cgroup.subtree_control",
"+cpu +memory +io +pids +rdma")) {
}
if (mkdir("/syzcgroup/cpu", 0777)) {
}
if (mount("none", "/syzcgroup/cpu", "cgroup", 0,
"cpuset,cpuacct,perf_event,hugetlb")) {
}
if (!write_file("/syzcgroup/cpu/cgroup.clone_children", "1")) {
}
if (chmod("/syzcgroup/cpu", 0777)) {
}
if (mkdir("/syzcgroup/net", 0777)) {
}
if (mount("none", "/syzcgroup/net", "cgroup", 0,
"net_cls,net_prio,devices,freezer")) {
}
if (chmod("/syzcgroup/net", 0777)) {
}
}
static void setup_binfmt_misc() {
if (!write_file("/proc/sys/fs/binfmt_misc/register",
":syz0:M:0:syz0::./file0:")) {
}
if (!write_file("/proc/sys/fs/binfmt_misc/register",
":syz1:M:1:yz1::./file0:POC")) {
}
}
static void loop();
static void sandbox_common() {
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
setpgrp();
setsid();
struct rlimit rlim;
rlim.rlim_cur = rlim.rlim_max = 160 << 20;
setrlimit(RLIMIT_AS, &rlim);
rlim.rlim_cur = rlim.rlim_max = 8 << 20;
setrlimit(RLIMIT_MEMLOCK, &rlim);
rlim.rlim_cur = rlim.rlim_max = 136 << 20;
setrlimit(RLIMIT_FSIZE, &rlim);
rlim.rlim_cur = rlim.rlim_max = 1 << 20;
setrlimit(RLIMIT_STACK, &rlim);
rlim.rlim_cur = rlim.rlim_max = 0;
setrlimit(RLIMIT_CORE, &rlim);
/*if (unshare(CLONE_NEWNS)) {
}
if (unshare(CLONE_NEWIPC)) {
}
if (unshare(0x02000000)) {
}
if (unshare(CLONE_NEWUTS)) {
}
if (unshare(CLONE_SYSVSEM)) {
}*/
}
static int do_sandbox_none(void) {
int pid = fork();
if (pid < 0) fail("sandbox fork failed");
if (pid) return pid;
sandbox_common();
initialize_tun();
loop();
doexit(1);
}
#define XT_TABLE_SIZE 1536
#define XT_MAX_ENTRIES 10
struct xt_counters {
uint64_t pcnt, bcnt;
};
struct ipt_getinfo {
char name[32];
unsigned int valid_hooks;
unsigned int hook_entry[5];
unsigned int underflow[5];
unsigned int num_entries;
unsigned int size;
};
struct ipt_get_entries {
char name[32];
unsigned int size;
void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
};
struct ipt_replace {
char name[32];
unsigned int valid_hooks;
unsigned int num_entries;
unsigned int size;
unsigned int hook_entry[5];
unsigned int underflow[5];
unsigned int num_counters;
struct xt_counters* counters;
char entrytable[XT_TABLE_SIZE];
};
struct ipt_table_desc {
const char* name;
struct ipt_getinfo info;
struct ipt_replace replace;
};
static struct ipt_table_desc ipv4_tables[] = {
{.name = "filter" }, {.name = "nat" }, {.name = "mangle" }, {.name = "raw" },
{.name = "security" },
};
static struct ipt_table_desc ipv6_tables[] = {
{.name = "filter" }, {.name = "nat" }, {.name = "mangle" }, {.name = "raw" },
{.name = "security" },
};
#define IPT_BASE_CTL 64
#define IPT_SO_SET_REPLACE (IPT_BASE_CTL)
#define IPT_SO_GET_INFO (IPT_BASE_CTL)
#define IPT_SO_GET_ENTRIES (IPT_BASE_CTL + 1)
struct arpt_getinfo {
char name[32];
unsigned int valid_hooks;
unsigned int hook_entry[3];
unsigned int underflow[3];
unsigned int num_entries;
unsigned int size;
};
struct arpt_get_entries {
char name[32];
unsigned int size;
void* entrytable[XT_TABLE_SIZE / sizeof(void*)];
};
struct arpt_replace {
char name[32];
unsigned int valid_hooks;
unsigned int num_entries;
unsigned int size;
unsigned int hook_entry[3];
unsigned int underflow[3];
unsigned int num_counters;
struct xt_counters* counters;
char entrytable[XT_TABLE_SIZE];
};
struct arpt_table_desc {
const char* name;
struct arpt_getinfo info;
struct arpt_replace replace;
};
static struct arpt_table_desc arpt_tables[] = { {.name = "filter" }, };
#define ARPT_BASE_CTL 96
#define ARPT_SO_SET_REPLACE (ARPT_BASE_CTL)
#define ARPT_SO_GET_INFO (ARPT_BASE_CTL)
#define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1)
static void checkpoint_iptables(struct ipt_table_desc* tables, int num_tables,
int family, int level) {
struct ipt_get_entries entries;
socklen_t optlen;
int fd, i;
fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
if (fd == -1) {
switch (errno) {
case EAFNOSUPPORT:
case ENOPROTOOPT:
return;
}
fail("socket(%d, SOCK_STREAM, IPPROTO_TCP)", family);
}
for (i = 0; i < num_tables; i++) {
struct ipt_table_desc* table = &tables[i];
strcpy(table->info.name, table->name);
strcpy(table->replace.name, table->name);
optlen = sizeof(table->info);
if (getsockopt(fd, level, IPT_SO_GET_INFO, &table->info, &optlen)) {
switch (errno) {
case EPERM:
case ENOENT:
case ENOPROTOOPT:
continue;
}
fail("getsockopt(IPT_SO_GET_INFO)");
}
if (table->info.size > sizeof(table->replace.entrytable))
fail("table size is too large: %u", table->info.size);
if (table->info.num_entries > XT_MAX_ENTRIES)
fail("too many counters: %u", table->info.num_entries);
memset(&entries, 0, sizeof(entries));
strcpy(entries.name, table->name);
entries.size = table->info.size;
optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
fail("getsockopt(IPT_SO_GET_ENTRIES)");
table->replace.valid_hooks = table->info.valid_hooks;
table->replace.num_entries = table->info.num_entries;
table->replace.size = table->info.size;
memcpy(table->replace.hook_entry, table->info.hook_entry,
sizeof(table->replace.hook_entry));
memcpy(table->replace.underflow, table->info.underflow,
sizeof(table->replace.underflow));
memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
}
close(fd);
}
static void reset_iptables(struct ipt_table_desc* tables, int num_tables,
int family, int level) {
struct xt_counters counters[XT_MAX_ENTRIES];
struct ipt_get_entries entries;
struct ipt_getinfo info;
socklen_t optlen;
int fd, i;
fd = socket(family, SOCK_STREAM, IPPROTO_TCP);
if (fd == -1) {
switch (errno) {
case EAFNOSUPPORT:
case ENOPROTOOPT:
return;
}
fail("socket(%d, SOCK_STREAM, IPPROTO_TCP)", family);
}
for (i = 0; i < num_tables; i++) {
struct ipt_table_desc* table = &tables[i];
if (table->info.valid_hooks == 0) continue;
memset(&info, 0, sizeof(info));
strcpy(info.name, table->name);
optlen = sizeof(info);
if (getsockopt(fd, level, IPT_SO_GET_INFO, &info, &optlen))
fail("getsockopt(IPT_SO_GET_INFO)");
if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
memset(&entries, 0, sizeof(entries));
strcpy(entries.name, table->name);
entries.size = table->info.size;
optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
if (getsockopt(fd, level, IPT_SO_GET_ENTRIES, &entries, &optlen))
fail("getsockopt(IPT_SO_GET_ENTRIES)");
if (memcmp(table->replace.entrytable, entries.entrytable,
table->info.size) == 0)
continue;
}
table->replace.num_counters = info.num_entries;
table->replace.counters = counters;
optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
table->replace.size;
if (setsockopt(fd, level, IPT_SO_SET_REPLACE, &table->replace, optlen))
fail("setsockopt(IPT_SO_SET_REPLACE)");
}
close(fd);
}
static void checkpoint_arptables(void) {
struct arpt_get_entries entries;
socklen_t optlen;
unsigned i;
int fd;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd == -1) fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
struct arpt_table_desc* table = &arpt_tables[i];
strcpy(table->info.name, table->name);
strcpy(table->replace.name, table->name);
optlen = sizeof(table->info);
if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &table->info, &optlen)) {
switch (errno) {
case EPERM:
case ENOENT:
case ENOPROTOOPT:
continue;
}
fail("getsockopt(ARPT_SO_GET_INFO)");
}
if (table->info.size > sizeof(table->replace.entrytable))
fail("table size is too large: %u", table->info.size);
if (table->info.num_entries > XT_MAX_ENTRIES)
fail("too many counters: %u", table->info.num_entries);
memset(&entries, 0, sizeof(entries));
strcpy(entries.name, table->name);
entries.size = table->info.size;
optlen = sizeof(entries) - sizeof(entries.entrytable) + table->info.size;
if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
fail("getsockopt(ARPT_SO_GET_ENTRIES)");
table->replace.valid_hooks = table->info.valid_hooks;
table->replace.num_entries = table->info.num_entries;
table->replace.size = table->info.size;
memcpy(table->replace.hook_entry, table->info.hook_entry,
sizeof(table->replace.hook_entry));
memcpy(table->replace.underflow, table->info.underflow,
sizeof(table->replace.underflow));
memcpy(table->replace.entrytable, entries.entrytable, table->info.size);
}
close(fd);
}
static void reset_arptables() {
struct xt_counters counters[XT_MAX_ENTRIES];
struct arpt_get_entries entries;
struct arpt_getinfo info;
socklen_t optlen;
unsigned i;
int fd;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd == -1) fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
for (i = 0; i < sizeof(arpt_tables) / sizeof(arpt_tables[0]); i++) {
struct arpt_table_desc* table = &arpt_tables[i];
if (table->info.valid_hooks == 0) continue;
memset(&info, 0, sizeof(info));
strcpy(info.name, table->name);
optlen = sizeof(info);
if (getsockopt(fd, SOL_IP, ARPT_SO_GET_INFO, &info, &optlen))
fail("getsockopt(ARPT_SO_GET_INFO)");
if (memcmp(&table->info, &info, sizeof(table->info)) == 0) {
memset(&entries, 0, sizeof(entries));
strcpy(entries.name, table->name);
entries.size = table->info.size;
optlen = sizeof(entries) - sizeof(entries.entrytable) + entries.size;
if (getsockopt(fd, SOL_IP, ARPT_SO_GET_ENTRIES, &entries, &optlen))
fail("getsockopt(ARPT_SO_GET_ENTRIES)");
if (memcmp(table->replace.entrytable, entries.entrytable,
table->info.size) == 0)
continue;
}
table->replace.num_counters = info.num_entries;
table->replace.counters = counters;
optlen = sizeof(table->replace) - sizeof(table->replace.entrytable) +
table->replace.size;
if (setsockopt(fd, SOL_IP, ARPT_SO_SET_REPLACE, &table->replace, optlen))
fail("setsockopt(ARPT_SO_SET_REPLACE)");
}
close(fd);
}
#include <linux/if.h>
#include <linux/netfilter_bridge/ebtables.h>
struct ebt_table_desc {
const char* name;
struct ebt_replace replace;
char entrytable[XT_TABLE_SIZE];
};
static struct ebt_table_desc ebt_tables[] = {
{.name = "filter" }, {.name = "nat" }, {.name = "broute" },
};
static void checkpoint_ebtables(void) {
socklen_t optlen;
unsigned i;
int fd;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd == -1) fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
struct ebt_table_desc* table = &ebt_tables[i];
strcpy(table->replace.name, table->name);
optlen = sizeof(table->replace);
if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_INFO, &table->replace,
&optlen)) {
switch (errno) {
case EPERM:
case ENOENT:
case ENOPROTOOPT:
continue;
}
fail("getsockopt(EBT_SO_GET_INIT_INFO)");
}
if (table->replace.entries_size > sizeof(table->entrytable))
fail("table size is too large: %u", table->replace.entries_size);
table->replace.num_counters = 0;
table->replace.entries = table->entrytable;
optlen = sizeof(table->replace) + table->replace.entries_size;
if (getsockopt(fd, SOL_IP, EBT_SO_GET_INIT_ENTRIES, &table->replace,
&optlen))
fail("getsockopt(EBT_SO_GET_INIT_ENTRIES)");
}
close(fd);
}
static void reset_ebtables() {
struct ebt_replace replace;
char entrytable[XT_TABLE_SIZE];
socklen_t optlen;
unsigned i, j, h;
int fd;
fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd == -1) fail("socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)");
for (i = 0; i < sizeof(ebt_tables) / sizeof(ebt_tables[0]); i++) {
struct ebt_table_desc* table = &ebt_tables[i];
if (table->replace.valid_hooks == 0) continue;
memset(&replace, 0, sizeof(replace));
strcpy(replace.name, table->name);
optlen = sizeof(replace);
if (getsockopt(fd, SOL_IP, EBT_SO_GET_INFO, &replace, &optlen))
fail("getsockopt(EBT_SO_GET_INFO)");
replace.num_counters = 0;
table->replace.entries = 0;
for (h = 0; h < NF_BR_NUMHOOKS; h++)
table->replace.hook_entry[h] = 0;
if (memcmp(&table->replace, &replace, sizeof(table->replace)) == 0) {
memset(&entrytable, 0, sizeof(entrytable));
replace.entries = entrytable;
optlen = sizeof(replace) + replace.entries_size;
if (getsockopt(fd, SOL_IP, EBT_SO_GET_ENTRIES, &replace, &optlen))
fail("getsockopt(EBT_SO_GET_ENTRIES)");
if (memcmp(table->entrytable, entrytable, replace.entries_size) == 0)
continue;
}
for (j = 0, h = 0; h < NF_BR_NUMHOOKS; h++) {
if (table->replace.valid_hooks & (1 << h)) {
table->replace.hook_entry[h] =
(struct ebt_entries*)table->entrytable + j;
j++;
}
}
table->replace.entries = table->entrytable;
optlen = sizeof(table->replace) + table->replace.entries_size;
if (setsockopt(fd, SOL_IP, EBT_SO_SET_ENTRIES, &table->replace, optlen))
fail("setsockopt(EBT_SO_SET_ENTRIES)");
}
close(fd);
}
static void checkpoint_net_namespace(void) {
checkpoint_ebtables();
checkpoint_arptables();
checkpoint_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
AF_INET, SOL_IP);
checkpoint_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
AF_INET6, SOL_IPV6);
}
static void reset_net_namespace(void) {
reset_ebtables();
reset_arptables();
reset_iptables(ipv4_tables, sizeof(ipv4_tables) / sizeof(ipv4_tables[0]),
AF_INET, SOL_IP);
reset_iptables(ipv6_tables, sizeof(ipv6_tables) / sizeof(ipv6_tables[0]),
AF_INET6, SOL_IPV6);
}
static void remove_dir(const char* dir) {
DIR* dp;
struct dirent* ep;
int iter = 0;
retry:
while (umount2(dir, MNT_DETACH) == 0) {
}
dp = opendir(dir);
if (dp == NULL) {
if (errno == EMFILE) {
exitf("opendir(%s) failed due to NOFILE, exiting", dir);
}
exitf("opendir(%s) failed", dir);
}
while ((ep = readdir(dp))) {
if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0) continue;
char filename[FILENAME_MAX];
snprintf(filename, sizeof(filename), "%s/%s", dir, ep->d_name);
struct stat st;
if (lstat(filename, &st)) exitf("lstat(%s) failed", filename);
if (S_ISDIR(st.st_mode)) {
remove_dir(filename);
continue;
}
int i;
for (i = 0;; i++) {
if (unlink(filename) == 0) break;
if (errno == EROFS) {
break;
}
if (errno != EBUSY || i > 100) exitf("unlink(%s) failed", filename);
if (umount2(filename, MNT_DETACH)) exitf("umount(%s) failed", filename);
}
}
closedir(dp);
int i;
for (i = 0;; i++) {
if (rmdir(dir) == 0) break;
if (i < 100) {
if (errno == EROFS) {
break;
}
if (errno == EBUSY) {
if (umount2(dir, MNT_DETACH)) exitf("umount(%s) failed", dir);
continue;
}
if (errno == ENOTEMPTY) {
if (iter < 100) {
iter++;
goto retry;
}
}
}
exitf("rmdir(%s) failed", dir);
}
}
static void execute_one();
extern unsigned long long procid;
static void loop() {
if(0)
checkpoint_net_namespace();
char cgroupdir[64];
snprintf(cgroupdir, sizeof(cgroupdir), "/syzcgroup/unified/syz%llu", procid);
char cgroupdir_cpu[64];
snprintf(cgroupdir_cpu, sizeof(cgroupdir_cpu), "/syzcgroup/cpu/syz%llu",
procid);
char cgroupdir_net[64];
snprintf(cgroupdir_net, sizeof(cgroupdir_net), "/syzcgroup/net/syz%llu",
procid);
if (mkdir(cgroupdir, 0777)) {
}
if (mkdir(cgroupdir_cpu, 0777)) {
}
if (mkdir(cgroupdir_net, 0777)) {
}
int pid = getpid();
char procs_file[128];
snprintf(procs_file, sizeof(procs_file), "%s/cgroup.procs", cgroupdir);
if (!write_file(procs_file, "%d", pid)) {
}
snprintf(procs_file, sizeof(procs_file), "%s/cgroup.procs", cgroupdir_cpu);
if (!write_file(procs_file, "%d", pid)) {
}
snprintf(procs_file, sizeof(procs_file), "%s/cgroup.procs", cgroupdir_net);
if (!write_file(procs_file, "%d", pid)) {
}
int iter;
for (iter = 0;; iter++) {
char cwdbuf[32];
sprintf(cwdbuf, "./%d", iter);
if (mkdir(cwdbuf, 0777)) fail("failed to mkdir");
int pid = fork();
if (pid < 0) fail("clone failed");
if (pid == 0) {
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
setpgrp();
if (chdir(cwdbuf)) fail("failed to chdir");
if (symlink(cgroupdir, "./cgroup")) {
}
if (symlink(cgroupdir_cpu, "./cgroup.cpu")) {
}
if (symlink(cgroupdir_net, "./cgroup.net")) {
}
flush_tun();
execute_one();
doexit(0);
}
int status = 0;
uint64_t start = current_time_ms();
for (;;) {
int res = waitpid(-1, &status, __WALL | WNOHANG);
if (res == pid) {
break;
}
usleep(1000);
if (current_time_ms() - start < 3 * 1000) continue;
kill(-pid, SIGKILL);
kill(pid, SIGKILL);
while (waitpid(-1, &status, __WALL) != pid) {
}
break;
}
remove_dir(cwdbuf);
if(0)
reset_net_namespace();
}
}
struct thread_t {
int created, running, call;
pthread_t th;
};
static struct thread_t threads[16];
static void execute_call(int call);
static int running;
static int collide;
static void* thr(void* arg) {
struct thread_t* th = (struct thread_t*)arg;
for (;;) {
while (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE))
syscall(SYS_futex, &th->running, FUTEX_WAIT, 0, 0);
execute_call(th->call);
__atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
__atomic_store_n(&th->running, 0, __ATOMIC_RELEASE);
syscall(SYS_futex, &th->running, FUTEX_WAKE);
}
return 0;
}
static void execute(int num_calls) {
int call, thread;
running = 0;
for (call = 0; call < num_calls; call++) {
for (thread = 0; thread < sizeof(threads) / sizeof(threads[0]); thread++) {
struct thread_t* th = &threads[thread];
if (!th->created) {
th->created = 1;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 128 << 10);
pthread_create(&th->th, &attr, thr, th);
}
if (!__atomic_load_n(&th->running, __ATOMIC_ACQUIRE)) {
th->call = call;
__atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
__atomic_store_n(&th->running, 1, __ATOMIC_RELEASE);
syscall(SYS_futex, &th->running, FUTEX_WAKE);
if (collide && call % 2) break;
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 20 * 1000 * 1000;
syscall(SYS_futex, &th->running, FUTEX_WAIT, 1, &ts);
if (running) usleep((call == num_calls - 1) ? 10000 : 1000);
break;
}
}
}
}
#ifndef __NR_mmap
#define __NR_mmap 222
#endif
#ifndef __NR_socket
#define __NR_socket 198
#endif
#ifndef __NR_sendmsg
#define __NR_sendmsg 211
#endif
uint64_t r[1] = {0xffffffffffffffff};
unsigned long long procid;
void execute_call(int call)
{
long res; switch (call) {
case 0:
res = syscall(__NR_socket, 0xf, 3, 2);
if (res != -1)
r[0] = res;
break;
case 1:
NONFAILING(*(uint64_t*)0x20000180 = 0);
NONFAILING(*(uint32_t*)0x20000188 = 0);
NONFAILING(*(uint64_t*)0x20000190 = 0x20000340);
NONFAILING(*(uint64_t*)0x20000340 = 0x20000080);
NONFAILING(memcpy((void*)0x20000080, "\x02\x0b\x80\x01\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16));
NONFAILING(*(uint64_t*)0x20000348 = 0x10);
NONFAILING(*(uint64_t*)0x20000198 = 1);
NONFAILING(*(uint64_t*)0x200001a0 = 0);
NONFAILING(*(uint64_t*)0x200001a8 = 0);
NONFAILING(*(uint32_t*)0x200001b0 = 0);
syscall(__NR_sendmsg, r[0], 0x20000180, 0);
break;
}
}
void execute_one()
{
syscall(SYS_write, 1, "executing program\n", strlen("executing program\n"));
execute(2);
collide = 1;
execute(2);
}
int main()
{
syscall(__NR_mmap, 0x20000000, 0x1000000, 3, 0x32, -1, 0);
char *cwd = get_current_dir_name();
for (procid = 0; procid < 18; procid++) {
if (fork() == 0) {
install_segv_handler();
for (;;) {
if (chdir(cwd))
fail("failed to chdir");
use_temporary_dir();
int pid = do_sandbox_none();
int status = 0;
while (waitpid(pid, &status, __WALL) != pid) {}
}
}
}
sleep(1000000);
return 0;
}
^ permalink raw reply
* Re: [PATCH 00/22] various dynamic_debug patches
From: Jason Baron @ 2018-09-22 0:27 UTC (permalink / raw)
To: Rasmus Villemoes, Andrew Morton
Cc: linux-kernel, Greg Kroah-Hartman, netdev, Petr Mladek,
Steven Rostedt, linux-btrfs, linux-acpi, x86
In-Reply-To: <20180919220444.23190-1-linux@rasmusvillemoes.dk>
On 09/19/2018 06:04 PM, Rasmus Villemoes wrote:
> This started as an experiment to see how hard it would be to change
> the four pointers in struct _ddebug into relative offsets, a la
> CONFIG_GENERIC_BUG_RELATIVE_POINTERS, thus saving 16 bytes per
> pr_debug site (and thus exactly making up for the extra space used by
> the introduction of jump labels in 9049fc74). I stumbled on a few
> things that are probably worth fixing regardless of whether the latter
> half of this series is deemed worthwhile.
>
> Patch relationships: 1-2, 3-4, 5-6 and 15-16 can be applied
> individually, though 2, 4 and 6 probably makes most sense in the
> context of the final goal of the series.
>
> 7-12 I believe make sense on their own. Patch 13 again only makes
> sense if we go all the way, and 14 and 17 depend on 13.
>
> 18-21 are more preparatory patches, and finally 22 switch over x86-64
> to use CONFIG_DYNAMIC_DEBUG_RELATIVE_POINTERS. I've tested that the
> end result boots under virtme and that the dynamic_debug control file
> has the expected contents.
>
I would like to to see all these patches included. Feel free to add:
Acked-by: Jason Baron <jbaron@akamai.com>
I've been wanting to add DYNAMIC_DEBUG_BRANCH to the
[dev,net,pr].*ratelimited functions. That should reduce the size of the
text as well.
Thanks,
-Jason
^ permalink raw reply
* [PATCH 3.16 21/63] Bluetooth: hidp: buffer overflow in hidp_process_report
From: Ben Hutchings @ 2018-09-22 0:15 UTC (permalink / raw)
To: linux-kernel, stable
Cc: akpm, netdev, Benjamin Tissoires, Kees Cook, David S. Miller,
linux-bluetooth, kernel-team, security, Johan Hedberg,
Marcel Holtmann, Mark Salyzyn
In-Reply-To: <lsq.1537575341.194909669@decadent.org.uk>
3.16.58-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Mark Salyzyn <salyzyn@android.com>
commit 7992c18810e568b95c869b227137a2215702a805 upstream.
CVE-2018-9363
The buffer length is unsigned at all layers, but gets cast to int and
checked in hidp_process_report and can lead to a buffer overflow.
Switch len parameter to unsigned int to resolve issue.
This affects 3.18 and newer kernels.
Signed-off-by: Mark Salyzyn <salyzyn@android.com>
Fixes: a4b1b5877b514b276f0f31efe02388a9c2836728 ("HID: Bluetooth: hidp: make sure input buffers are big enough")
Cc: Marcel Holtmann <marcel@holtmann.org>
Cc: Johan Hedberg <johan.hedberg@gmail.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Kees Cook <keescook@chromium.org>
Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Cc: linux-bluetooth@vger.kernel.org
Cc: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Cc: security@kernel.org
Cc: kernel-team@android.com
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
net/bluetooth/hidp/core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -429,8 +429,8 @@ static void hidp_del_timer(struct hidp_s
del_timer(&session->timer);
}
-static void hidp_process_report(struct hidp_session *session,
- int type, const u8 *data, int len, int intr)
+static void hidp_process_report(struct hidp_session *session, int type,
+ const u8 *data, unsigned int len, int intr)
{
if (len > HID_MAX_BUFFER_SIZE)
len = HID_MAX_BUFFER_SIZE;
^ permalink raw reply
* Re: [PATCH] RDS: IB: Use DEFINE_PER_CPU_SHARED_ALIGNED for rds_ib_stats
From: Santosh Shilimkar @ 2018-09-21 18:17 UTC (permalink / raw)
To: Nathan Chancellor, David S. Miller
Cc: netdev, linux-rdma, linux-kernel, Nick Desaulniers
In-Reply-To: <20180921180451.18711-1-natechancellor@gmail.com>
On 9/21/2018 11:04 AM, Nathan Chancellor wrote:
> Clang warns when two declarations' section attributes don't match.
>
> net/rds/ib_stats.c:40:1: warning: section does not match previous
> declaration [-Wsection]
> DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_ib_statistics, rds_ib_stats);
> ^
> ./include/linux/percpu-defs.h:142:2: note: expanded from macro
> 'DEFINE_PER_CPU_SHARED_ALIGNED'
> DEFINE_PER_CPU_SECTION(type, name,
> PER_CPU_SHARED_ALIGNED_SECTION) \
> ^
> ./include/linux/percpu-defs.h:93:9: note: expanded from macro
> 'DEFINE_PER_CPU_SECTION'
> extern __PCPU_ATTRS(sec) __typeof__(type) name;
> \
> ^
> ./include/linux/percpu-defs.h:49:26: note: expanded from macro
> '__PCPU_ATTRS'
> __percpu __attribute__((section(PER_CPU_BASE_SECTION sec)))
> \
> ^
> net/rds/ib.h:446:1: note: previous attribute is here
> DECLARE_PER_CPU(struct rds_ib_statistics, rds_ib_stats);
> ^
> ./include/linux/percpu-defs.h:111:2: note: expanded from macro
> 'DECLARE_PER_CPU'
> DECLARE_PER_CPU_SECTION(type, name, "")
> ^
> ./include/linux/percpu-defs.h:87:9: note: expanded from macro
> 'DECLARE_PER_CPU_SECTION'
> extern __PCPU_ATTRS(sec) __typeof__(type) name
> ^
> ./include/linux/percpu-defs.h:49:26: note: expanded from macro
> '__PCPU_ATTRS'
> __percpu __attribute__((section(PER_CPU_BASE_SECTION sec)))
> \
> ^
> 1 warning generated.
>
> The initial definition was added in commit ec16227e1414 ("RDS/IB:
> Infiniband transport") and the cache aligned definition was added in
> commit e6babe4cc4ce ("RDS/IB: Stats and sysctls") right after. The
> definition probably should have been updated in net/rds/ib.h, which is
> what this patch does.
>
> Link: https://github.com/ClangBuiltLinux/linux/issues/114
> Signed-off-by: Nathan Chancellor <natechancellor@gmail.com>
> ---
Looks fine. Thanks !!
Acked-by: Santosh Shilimkar <santosh.shilimkar@oracle.com>
^ permalink raw reply
* [PATCH net-next 3/3] selftests/net: add ipv6 tests to ip_defrag selftest
From: Peter Oskolkov @ 2018-09-21 18:17 UTC (permalink / raw)
To: David Miller, netdev; +Cc: Peter Oskolkov
In-Reply-To: <20180921181717.113242-1-posk@google.com>
This patch adds ipv6 defragmentation tests to ip_defrag selftest,
to complement existing ipv4 tests.
Signed-off-by: Peter Oskolkov <posk@google.com>
---
tools/testing/selftests/net/ip_defrag.c | 249 +++++++++++++++--------
tools/testing/selftests/net/ip_defrag.sh | 39 ++--
2 files changed, 190 insertions(+), 98 deletions(-)
diff --git a/tools/testing/selftests/net/ip_defrag.c b/tools/testing/selftests/net/ip_defrag.c
index 55fdcdc78eef..2366dc6bce71 100644
--- a/tools/testing/selftests/net/ip_defrag.c
+++ b/tools/testing/selftests/net/ip_defrag.c
@@ -23,21 +23,28 @@ static bool cfg_overlap;
static unsigned short cfg_port = 9000;
const struct in_addr addr4 = { .s_addr = __constant_htonl(INADDR_LOOPBACK + 2) };
+const struct in6_addr addr6 = IN6ADDR_LOOPBACK_INIT;
#define IP4_HLEN (sizeof(struct iphdr))
#define IP6_HLEN (sizeof(struct ip6_hdr))
#define UDP_HLEN (sizeof(struct udphdr))
-static int msg_len;
+/* IPv6 fragment header lenth. */
+#define FRAG_HLEN 8
+
+static int payload_len;
static int max_frag_len;
#define MSG_LEN_MAX 60000 /* Max UDP payload length. */
#define IP4_MF (1u << 13) /* IPv4 MF flag. */
+#define IP6_MF (1) /* IPv6 MF flag. */
+
+#define CSUM_MANGLED_0 (0xffff)
static uint8_t udp_payload[MSG_LEN_MAX];
static uint8_t ip_frame[IP_MAXPACKET];
-static uint16_t ip_id = 0xabcd;
+static uint32_t ip_id = 0xabcd;
static int msg_counter;
static int frag_counter;
static unsigned int seed;
@@ -48,25 +55,25 @@ static void recv_validate_udp(int fd_udp)
ssize_t ret;
static uint8_t recv_buff[MSG_LEN_MAX];
- ret = recv(fd_udp, recv_buff, msg_len, 0);
+ ret = recv(fd_udp, recv_buff, payload_len, 0);
msg_counter++;
if (cfg_overlap) {
if (ret != -1)
- error(1, 0, "recv: expected timeout; got %d; seed = %u",
- (int)ret, seed);
+ error(1, 0, "recv: expected timeout; got %d",
+ (int)ret);
if (errno != ETIMEDOUT && errno != EAGAIN)
- error(1, errno, "recv: expected timeout: %d; seed = %u",
- errno, seed);
+ error(1, errno, "recv: expected timeout: %d",
+ errno);
return; /* OK */
}
if (ret == -1)
- error(1, errno, "recv: msg_len = %d max_frag_len = %d",
- msg_len, max_frag_len);
- if (ret != msg_len)
- error(1, 0, "recv: wrong size: %d vs %d", (int)ret, msg_len);
- if (memcmp(udp_payload, recv_buff, msg_len))
+ error(1, errno, "recv: payload_len = %d max_frag_len = %d",
+ payload_len, max_frag_len);
+ if (ret != payload_len)
+ error(1, 0, "recv: wrong size: %d vs %d", (int)ret, payload_len);
+ if (memcmp(udp_payload, recv_buff, payload_len))
error(1, 0, "recv: wrong data");
}
@@ -92,31 +99,95 @@ static uint32_t raw_checksum(uint8_t *buf, int len, uint32_t sum)
static uint16_t udp_checksum(struct ip *iphdr, struct udphdr *udphdr)
{
uint32_t sum = 0;
+ uint16_t res;
sum = raw_checksum((uint8_t *)&iphdr->ip_src, 2 * sizeof(iphdr->ip_src),
- IPPROTO_UDP + (uint32_t)(UDP_HLEN + msg_len));
- sum = raw_checksum((uint8_t *)udp_payload, msg_len, sum);
+ IPPROTO_UDP + (uint32_t)(UDP_HLEN + payload_len));
+ sum = raw_checksum((uint8_t *)udphdr, UDP_HLEN, sum);
+ sum = raw_checksum((uint8_t *)udp_payload, payload_len, sum);
+ res = 0xffff & ~sum;
+ if (res)
+ return htons(res);
+ else
+ return CSUM_MANGLED_0;
+}
+
+static uint16_t udp6_checksum(struct ip6_hdr *iphdr, struct udphdr *udphdr)
+{
+ uint32_t sum = 0;
+ uint16_t res;
+
+ sum = raw_checksum((uint8_t *)&iphdr->ip6_src, 2 * sizeof(iphdr->ip6_src),
+ IPPROTO_UDP);
+ sum = raw_checksum((uint8_t *)&udphdr->len, sizeof(udphdr->len), sum);
sum = raw_checksum((uint8_t *)udphdr, UDP_HLEN, sum);
- return htons(0xffff & ~sum);
+ sum = raw_checksum((uint8_t *)udp_payload, payload_len, sum);
+ res = 0xffff & ~sum;
+ if (res)
+ return htons(res);
+ else
+ return CSUM_MANGLED_0;
}
static void send_fragment(int fd_raw, struct sockaddr *addr, socklen_t alen,
- struct ip *iphdr, int offset)
+ int offset, bool ipv6)
{
int frag_len;
int res;
+ int payload_offset = offset > 0 ? offset - UDP_HLEN : 0;
+ uint8_t *frag_start = ipv6 ? ip_frame + IP6_HLEN + FRAG_HLEN :
+ ip_frame + IP4_HLEN;
+
+ if (offset == 0) {
+ struct udphdr udphdr;
+ udphdr.source = htons(cfg_port + 1);
+ udphdr.dest = htons(cfg_port);
+ udphdr.len = htons(UDP_HLEN + payload_len);
+ udphdr.check = 0;
+ if (ipv6)
+ udphdr.check = udp6_checksum((struct ip6_hdr *)ip_frame, &udphdr);
+ else
+ udphdr.check = udp_checksum((struct ip *)ip_frame, &udphdr);
+ memcpy(frag_start, &udphdr, UDP_HLEN);
+ }
- if (msg_len - offset <= max_frag_len) {
- /* This is the last fragment. */
- frag_len = IP4_HLEN + msg_len - offset;
- iphdr->ip_off = htons((offset + UDP_HLEN) / 8);
+ if (ipv6) {
+ struct ip6_hdr *ip6hdr = (struct ip6_hdr *)ip_frame;
+ struct ip6_frag *fraghdr = (struct ip6_frag *)(ip_frame + IP6_HLEN);
+ if (payload_len - payload_offset <= max_frag_len && offset > 0) {
+ /* This is the last fragment. */
+ frag_len = FRAG_HLEN + payload_len - payload_offset;
+ fraghdr->ip6f_offlg = htons(offset);
+ } else {
+ frag_len = FRAG_HLEN + max_frag_len;
+ fraghdr->ip6f_offlg = htons(offset | IP6_MF);
+ }
+ ip6hdr->ip6_plen = htons(frag_len);
+ if (offset == 0)
+ memcpy(frag_start + UDP_HLEN, udp_payload,
+ frag_len - FRAG_HLEN - UDP_HLEN);
+ else
+ memcpy(frag_start, udp_payload + payload_offset,
+ frag_len - FRAG_HLEN);
+ frag_len += IP6_HLEN;
} else {
- frag_len = IP4_HLEN + max_frag_len;
- iphdr->ip_off = htons((offset + UDP_HLEN) / 8 | IP4_MF);
+ struct ip *iphdr = (struct ip *)ip_frame;
+ if (payload_len - payload_offset <= max_frag_len && offset > 0) {
+ /* This is the last fragment. */
+ frag_len = IP4_HLEN + payload_len - payload_offset;
+ iphdr->ip_off = htons(offset / 8);
+ } else {
+ frag_len = IP4_HLEN + max_frag_len;
+ iphdr->ip_off = htons(offset / 8 | IP4_MF);
+ }
+ iphdr->ip_len = htons(frag_len);
+ if (offset == 0)
+ memcpy(frag_start + UDP_HLEN, udp_payload,
+ frag_len - IP4_HLEN - UDP_HLEN);
+ else
+ memcpy(frag_start, udp_payload + payload_offset,
+ frag_len - IP4_HLEN);
}
- iphdr->ip_len = htons(frag_len);
- memcpy(ip_frame + IP4_HLEN, udp_payload + offset,
- frag_len - IP4_HLEN);
res = sendto(fd_raw, ip_frame, frag_len, 0, addr, alen);
if (res < 0)
@@ -127,9 +198,11 @@ static void send_fragment(int fd_raw, struct sockaddr *addr, socklen_t alen,
frag_counter++;
}
-static void send_udp_frags_v4(int fd_raw, struct sockaddr *addr, socklen_t alen)
+static void send_udp_frags(int fd_raw, struct sockaddr *addr,
+ socklen_t alen, bool ipv6)
{
struct ip *iphdr = (struct ip *)ip_frame;
+ struct ip6_hdr *ip6hdr = (struct ip6_hdr *)ip_frame;
struct udphdr udphdr;
int res;
int offset;
@@ -142,31 +215,55 @@ static void send_udp_frags_v4(int fd_raw, struct sockaddr *addr, socklen_t alen)
* Odd fragments (1st, 3rd, 5th, etc.) are sent out first, then
* even fragments (0th, 2nd, etc.) are sent out.
*/
- memset(iphdr, 0, sizeof(*iphdr));
- iphdr->ip_hl = 5;
- iphdr->ip_v = 4;
- iphdr->ip_tos = 0;
- iphdr->ip_id = htons(ip_id++);
- iphdr->ip_ttl = 0x40;
- iphdr->ip_p = IPPROTO_UDP;
- iphdr->ip_src.s_addr = htonl(INADDR_LOOPBACK);
- iphdr->ip_dst = addr4;
- iphdr->ip_sum = 0;
+ if (ipv6) {
+ struct ip6_frag *fraghdr = (struct ip6_frag *)(ip_frame + IP6_HLEN);
+ ((struct sockaddr_in6 *)addr)->sin6_port = 0;
+ memset(ip6hdr, 0, sizeof(*ip6hdr));
+ ip6hdr->ip6_flow = htonl(6<<28); /* Version. */
+ ip6hdr->ip6_nxt = IPPROTO_FRAGMENT;
+ ip6hdr->ip6_hops = 255;
+ ip6hdr->ip6_src = addr6;
+ ip6hdr->ip6_dst = addr6;
+ fraghdr->ip6f_nxt = IPPROTO_UDP;
+ fraghdr->ip6f_reserved = 0;
+ fraghdr->ip6f_ident = htonl(ip_id++);
+ } else {
+ memset(iphdr, 0, sizeof(*iphdr));
+ iphdr->ip_hl = 5;
+ iphdr->ip_v = 4;
+ iphdr->ip_tos = 0;
+ iphdr->ip_id = htons(ip_id++);
+ iphdr->ip_ttl = 0x40;
+ iphdr->ip_p = IPPROTO_UDP;
+ iphdr->ip_src.s_addr = htonl(INADDR_LOOPBACK);
+ iphdr->ip_dst = addr4;
+ iphdr->ip_sum = 0;
+ }
/* Odd fragments. */
- offset = 0;
- while (offset < msg_len) {
- send_fragment(fd_raw, addr, alen, iphdr, offset);
+ offset = max_frag_len;
+ while (offset < (UDP_HLEN + payload_len)) {
+ send_fragment(fd_raw, addr, alen, offset, ipv6);
offset += 2 * max_frag_len;
}
if (cfg_overlap) {
/* Send an extra random fragment. */
- offset = rand() % (UDP_HLEN + msg_len - 1);
+ offset = rand() % (UDP_HLEN + payload_len - 1);
/* sendto() returns EINVAL if offset + frag_len is too small. */
- frag_len = IP4_HLEN + UDP_HLEN + rand() % 256;
- iphdr->ip_off = htons(offset / 8 | IP4_MF);
- iphdr->ip_len = htons(frag_len);
+ if (ipv6) {
+ struct ip6_frag *fraghdr = (struct ip6_frag *)(ip_frame + IP6_HLEN);
+ frag_len = max_frag_len + rand() % 256;
+ /* In IPv6 if !!(frag_len % 8), the fragment is dropped. */
+ frag_len &= ~0x7;
+ fraghdr->ip6f_offlg = htons(offset / 8 | IP6_MF);
+ ip6hdr->ip6_plen = htons(frag_len);
+ frag_len += IP6_HLEN;
+ } else {
+ frag_len = IP4_HLEN + UDP_HLEN + rand() % 256;
+ iphdr->ip_off = htons(offset / 8 | IP4_MF);
+ iphdr->ip_len = htons(frag_len);
+ }
res = sendto(fd_raw, ip_frame, frag_len, 0, addr, alen);
if (res < 0)
error(1, errno, "sendto overlap");
@@ -175,48 +272,26 @@ static void send_udp_frags_v4(int fd_raw, struct sockaddr *addr, socklen_t alen)
frag_counter++;
}
- /* Zeroth fragment (UDP header). */
- frag_len = IP4_HLEN + UDP_HLEN;
- iphdr->ip_len = htons(frag_len);
- iphdr->ip_off = htons(IP4_MF);
-
- udphdr.source = htons(cfg_port + 1);
- udphdr.dest = htons(cfg_port);
- udphdr.len = htons(UDP_HLEN + msg_len);
- udphdr.check = 0;
- udphdr.check = udp_checksum(iphdr, &udphdr);
-
- memcpy(ip_frame + IP4_HLEN, &udphdr, UDP_HLEN);
- res = sendto(fd_raw, ip_frame, frag_len, 0, addr, alen);
- if (res < 0)
- error(1, errno, "sendto UDP header");
- if (res != frag_len)
- error(1, 0, "sendto UDP header: %d vs %d", (int)res, frag_len);
- frag_counter++;
-
- /* Even fragments. */
- offset = max_frag_len;
- while (offset < msg_len) {
- send_fragment(fd_raw, addr, alen, iphdr, offset);
+ /* Event fragments. */
+ offset = 0;
+ while (offset < (UDP_HLEN + payload_len)) {
+ send_fragment(fd_raw, addr, alen, offset, ipv6);
offset += 2 * max_frag_len;
}
}
-static void run_test(struct sockaddr *addr, socklen_t alen)
+static void run_test(struct sockaddr *addr, socklen_t alen, bool ipv6)
{
- int fd_tx_udp, fd_tx_raw, fd_rx_udp;
+ int fd_tx_raw, fd_rx_udp;
struct timeval tv = { .tv_sec = 0, .tv_usec = 10 * 1000 };
int idx;
+ int min_frag_len = ipv6 ? 1280 : 8;
/* Initialize the payload. */
for (idx = 0; idx < MSG_LEN_MAX; ++idx)
udp_payload[idx] = idx % 256;
/* Open sockets. */
- fd_tx_udp = socket(addr->sa_family, SOCK_DGRAM, 0);
- if (fd_tx_udp == -1)
- error(1, errno, "socket tx_udp");
-
fd_tx_raw = socket(addr->sa_family, SOCK_RAW, IPPROTO_RAW);
if (fd_tx_raw == -1)
error(1, errno, "socket tx_raw");
@@ -230,22 +305,21 @@ static void run_test(struct sockaddr *addr, socklen_t alen)
if (setsockopt(fd_rx_udp, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)))
error(1, errno, "setsockopt rcv timeout");
- for (msg_len = 1; msg_len < MSG_LEN_MAX; msg_len += (rand() % 4096)) {
+ for (payload_len = min_frag_len; payload_len < MSG_LEN_MAX;
+ payload_len += (rand() % 4096)) {
if (cfg_verbose)
- printf("msg_len: %d\n", msg_len);
- max_frag_len = addr->sa_family == AF_INET ? 8 : 1280;
- for (; max_frag_len < 1500 && max_frag_len <= msg_len;
- max_frag_len += 8) {
- send_udp_frags_v4(fd_tx_raw, addr, alen);
+ printf("payload_len: %d\n", payload_len);
+ max_frag_len = min_frag_len;
+ do {
+ send_udp_frags(fd_tx_raw, addr, alen, ipv6);
recv_validate_udp(fd_rx_udp);
- }
+ max_frag_len += 8 * (rand() % 8);
+ } while (max_frag_len < (1500 - FRAG_HLEN) && max_frag_len <= payload_len);
}
/* Cleanup. */
if (close(fd_tx_raw))
error(1, errno, "close tx_raw");
- if (close(fd_tx_udp))
- error(1, errno, "close tx_udp");
if (close(fd_rx_udp))
error(1, errno, "close rx_udp");
@@ -265,13 +339,18 @@ static void run_test_v4(void)
addr.sin_port = htons(cfg_port);
addr.sin_addr = addr4;
- run_test((void *)&addr, sizeof(addr));
+ run_test((void *)&addr, sizeof(addr), false /* !ipv6 */);
}
static void run_test_v6(void)
{
- fprintf(stderr, "NOT IMPL.\n");
- exit(1);
+ struct sockaddr_in6 addr = {0};
+
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons(cfg_port);
+ addr.sin6_addr = addr6;
+
+ run_test((void *)&addr, sizeof(addr), true /* ipv6 */);
}
static void parse_opts(int argc, char **argv)
@@ -303,6 +382,8 @@ int main(int argc, char **argv)
parse_opts(argc, argv);
seed = time(NULL);
srand(seed);
+ /* Print the seed to track/reproduce potential failures. */
+ printf("seed = %d\n", seed);
if (cfg_do_ipv4)
run_test_v4();
diff --git a/tools/testing/selftests/net/ip_defrag.sh b/tools/testing/selftests/net/ip_defrag.sh
index 78743adcca9e..3a4042d918f0 100755
--- a/tools/testing/selftests/net/ip_defrag.sh
+++ b/tools/testing/selftests/net/ip_defrag.sh
@@ -6,23 +6,34 @@
set +x
set -e
-echo "ipv4 defrag"
+readonly NETNS="ns-$(mktemp -u XXXXXX)"
+
+setup() {
+ ip netns add "${NETNS}"
+ ip -netns "${NETNS}" link set lo up
+ ip netns exec "${NETNS}" sysctl -w net.ipv4.ipfrag_high_thresh=9000000 &> /dev/null
+ ip netns exec "${NETNS}" sysctl -w net.ipv4.ipfrag_low_thresh=7000000 &> /dev/null
+ ip netns exec "${NETNS}" sysctl -w net.ipv6.ip6frag_high_thresh=9000000 &> /dev/null
+ ip netns exec "${NETNS}" sysctl -w net.ipv6.ip6frag_low_thresh=7000000 &> /dev/null
+}
-run_v4() {
-sysctl -w net.ipv4.ipfrag_high_thresh=9000000 &> /dev/null
-sysctl -w net.ipv4.ipfrag_low_thresh=7000000 &> /dev/null
-./ip_defrag -4
+cleanup() {
+ ip netns del "${NETNS}"
}
-export -f run_v4
-./in_netns.sh "run_v4"
+trap cleanup EXIT
+setup
+
+echo "ipv4 defrag"
+ip netns exec "${NETNS}" ./ip_defrag -4
+
echo "ipv4 defrag with overlaps"
-run_v4o() {
-sysctl -w net.ipv4.ipfrag_high_thresh=9000000 &> /dev/null
-sysctl -w net.ipv4.ipfrag_low_thresh=7000000 &> /dev/null
-./ip_defrag -4o
-}
-export -f run_v4o
+ip netns exec "${NETNS}" ./ip_defrag -4o
+
+echo "ipv6 defrag"
+ip netns exec "${NETNS}" ./ip_defrag -6
+
+echo "ipv6 defrag with overlaps"
+ip netns exec "${NETNS}" ./ip_defrag -6o
-./in_netns.sh "run_v4o"
--
2.19.0.444.g18242da7ef-goog
^ permalink raw reply related
* [PATCH net-next 2/3] net/ipfrag: let ip[6]frag_high_thresh in ns be higher than in init_net
From: Peter Oskolkov @ 2018-09-21 18:17 UTC (permalink / raw)
To: David Miller, netdev; +Cc: Peter Oskolkov
In-Reply-To: <20180921181717.113242-1-posk@google.com>
Currently, ip[6]frag_high_thresh sysctl values in new namespaces are
hard-limited to those of the root/init ns.
There are at least two use cases when it would be desirable to
set the high_thresh values higher in a child namespace vs the global hard
limit:
- a security/ddos protection policy may lower the thresholds in the
root/init ns but allow for a special exception in a child namespace
- testing: a test running in a namespace may want to set these
thresholds higher in its namespace than what is in the root/init ns
The new behavior:
# ip netns add testns
# ip netns exec testns bash
# sysctl -w net.ipv4.ipfrag_high_thresh=9000000
net.ipv4.ipfrag_high_thresh = 9000000
# sysctl net.ipv4.ipfrag_high_thresh
net.ipv4.ipfrag_high_thresh = 9000000
# sysctl -w net.ipv6.ip6frag_high_thresh=9000000
net.ipv6.ip6frag_high_thresh = 9000000
# sysctl net.ipv6.ip6frag_high_thresh
net.ipv6.ip6frag_high_thresh = 9000000
The old behavior:
# ip netns add testns
# ip netns exec testns bash
# sysctl -w net.ipv4.ipfrag_high_thresh=9000000
net.ipv4.ipfrag_high_thresh = 9000000
# sysctl net.ipv4.ipfrag_high_thresh
net.ipv4.ipfrag_high_thresh = 4194304
# sysctl -w net.ipv6.ip6frag_high_thresh=9000000
net.ipv6.ip6frag_high_thresh = 9000000
# sysctl net.ipv6.ip6frag_high_thresh
net.ipv6.ip6frag_high_thresh = 4194304
Signed-off-by: Peter Oskolkov <posk@google.com>
---
net/ieee802154/6lowpan/reassembly.c | 1 -
net/ipv4/ip_fragment.c | 1 -
net/ipv6/reassembly.c | 1 -
3 files changed, 3 deletions(-)
diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
index 09ffbf5ce8fa..d14226ecfde4 100644
--- a/net/ieee802154/6lowpan/reassembly.c
+++ b/net/ieee802154/6lowpan/reassembly.c
@@ -463,7 +463,6 @@ static int __net_init lowpan_frags_ns_sysctl_register(struct net *net)
table[0].data = &ieee802154_lowpan->frags.high_thresh;
table[0].extra1 = &ieee802154_lowpan->frags.low_thresh;
- table[0].extra2 = &init_net.ieee802154_lowpan.frags.high_thresh;
table[1].data = &ieee802154_lowpan->frags.low_thresh;
table[1].extra2 = &ieee802154_lowpan->frags.high_thresh;
table[2].data = &ieee802154_lowpan->frags.timeout;
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 13f4d189e12b..9b0158fa431f 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -822,7 +822,6 @@ static int __net_init ip4_frags_ns_ctl_register(struct net *net)
table[0].data = &net->ipv4.frags.high_thresh;
table[0].extra1 = &net->ipv4.frags.low_thresh;
- table[0].extra2 = &init_net.ipv4.frags.high_thresh;
table[1].data = &net->ipv4.frags.low_thresh;
table[1].extra2 = &net->ipv4.frags.high_thresh;
table[2].data = &net->ipv4.frags.timeout;
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 536c1d172cba..5c3c92713096 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -554,7 +554,6 @@ static int __net_init ip6_frags_ns_sysctl_register(struct net *net)
table[0].data = &net->ipv6.frags.high_thresh;
table[0].extra1 = &net->ipv6.frags.low_thresh;
- table[0].extra2 = &init_net.ipv6.frags.high_thresh;
table[1].data = &net->ipv6.frags.low_thresh;
table[1].extra2 = &net->ipv6.frags.high_thresh;
table[2].data = &net->ipv6.frags.timeout;
--
2.19.0.444.g18242da7ef-goog
^ 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