* Re: Re: [PATCH] net/packet: fix race condition between fanout_add and __unregister_prot_hook
From: Willem de Bruijn @ 2017-09-19 16:09 UTC (permalink / raw)
To: Nixiaoming
Cc: xiyou.wangcong@gmail.com, davem@davemloft.net,
edumazet@google.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <E490CD805F7529488761C40FD9D26EF1299D0CAD@DGGEMA505-MBX.china.huawei.com>
On Tue, Sep 19, 2017 at 3:21 AM, Nixiaoming <nixiaoming@huawei.com> wrote:
> On Fri, Sep 15, 2017 at 10:46 AM, Willem de Bruijn
>
> <willemdebruijn.kernel@gmail.com> wrote:
>
>>
>
>> In case of failure we also need to unlink and free match. I
>
>> sent the following:
>
>>
>
>> http://patchwork.ozlabs.org/patch/813945/
>
>
>
> + spin_lock(&po->bind_lock);
>
> + if (po->running &&
>
> + match->type == type &&
>
> match->prot_hook.type == po->prot_hook.type &&
>
> match->prot_hook.dev == po->prot_hook.dev) {
>
> err = -ENOSPC;
>
> @@ -1761,6 +1760,13 @@ static int fanout_add(struct sock *sk, u16 id, u16
> type_flags)
>
> err = 0;
>
> }
>
> }
>
> + spin_unlock(&po->bind_lock);
>
> +
>
> + if (err && !refcount_read(&match->sk_ref)) {
>
> + list_del(&match->list);
>
> + kfree(match);
>
> + }
>
>
>
>
>
> In the function fanout_add add spin_lock to protect po-> running and po->
> fanout,
>
> then whether it should be in the function fanout_release also add spin_lock
> protection ?
po->bind_lock is held when registering and unregistering the
protocol hook. fanout_release does access po->running or
prot_hook.
It is called from packet_release, which does hold the bind_lock
when unregistering the protocol hook.
^ permalink raw reply
* Re: [REGRESSION] Warning in tcp_fastretrans_alert() of net/ipv4/tcp_input.c
From: Oleksandr Natalenko @ 2017-09-19 16:05 UTC (permalink / raw)
To: Yuchung Cheng
Cc: Neal Cardwell, David S. Miller, Alexey Kuznetsov,
Hideaki YOSHIFUJI, Netdev
In-Reply-To: <CAK6E8=e7SE-M4r2nJ8K_FoDMVcN2xYdtw=MetvD5MvXMm9iA1Q@mail.gmail.com>
And 2 more events:
===
$ dmesg --time-format iso | grep RIP
…
2017-09-19T16:52:21,623328+0200 RIP: 0010:tcp_undo_cwnd_reduction+0xbd/0xd0
2017-09-19T16:52:40,455296+0200 RIP: 0010:tcp_fastretrans_alert+0x7c8/0x990
2017-09-19T16:52:41,047378+0200 RIP: 0010:tcp_undo_cwnd_reduction+0xbd/0xd0
…
2017-09-19T16:54:59,930726+0200 RIP: 0010:tcp_undo_cwnd_reduction+0xbd/0xd0
2017-09-19T16:55:07,985767+0200 RIP: 0010:tcp_fastretrans_alert+0x7c8/0x990
2017-09-19T16:55:41,911527+0200 RIP: 0010:tcp_undo_cwnd_reduction+0xbd/0xd0
…
===
On pondělí 18. září 2017 23:40:08 CEST Yuchung Cheng wrote:
> On Mon, Sep 18, 2017 at 1:46 PM, Oleksandr Natalenko
>
> <oleksandr@natalenko.name> wrote:
> > Actually, same warning was just triggered with RACK enabled. But main
> > warning was not triggered in this case.
>
> Thanks.
>
> I assume this kernel does not have the patch that Neal proposed in his
> first reply?
>
> The main warning needs to be triggered by another peculiar SACK that
> kicks the sender into recovery again (after undo). Please let it run
> longer if possible to see if we can get both. But the new data does
> indicate the we can (validly) be in CA_Open with retrans_out > 0.
>
> > ===
> > Sep 18 22:44:32 defiant kernel: ------------[ cut here ]------------
> > Sep 18 22:44:32 defiant kernel: WARNING: CPU: 1 PID: 702 at net/ipv4/
> > tcp_input.c:2392 tcp_undo_cwnd_reduction+0xbd/0xd0
> > Sep 18 22:44:32 defiant kernel: Modules linked in: netconsole ctr ccm
> > cls_bpf sch_htb act_mirred cls_u32 sch_ingress sit tunnel4 ip_tunnel
> > 8021q mrp nf_conntrack_ipv6 nf_defrag_ipv6 nft_ct nft_set_bitmap
> > nft_set_hash nft_set_rbtree nf_tables_inet nf_tables_ipv6 nft_masq_ipv4
> > nf_nat_masquerade_ipv4 nft_masq nft_nat nft_counter nft_meta
> > nft_chain_nat_ipv4 nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat
> > nf_conntrack libcrc32c crc32c_generic nf_tables_ipv4 nf_tables tun nct6775
> > nfnetlink hwmon_vid nls_iso8859_1 nls_cp437 vfat fat ext4
> > snd_hda_codec_hdmi mbcache jbd2 snd_hda_codec_realtek
> > snd_hda_codec_generic f2fs arc4 fscrypto intel_rapl iTCO_wdt ath9k
> > iTCO_vendor_support intel_powerclamp ath9k_common ath9k_hw coretemp
> > kvm_intel ath mac80211 kvm irqbypass intel_cstate cfg80211 pcspkr
> > snd_hda_intel snd_hda_codec r8169
> > Sep 18 22:44:32 defiant kernel: joydev evdev mii snd_hda_core mousedev
> > mei_txe input_leds i2c_i801 mac_hid i915 lpc_ich mei shpchp snd_hwdep
> > snd_intel_sst_acpi snd_intel_sst_core snd_soc_rt5670
> > snd_soc_sst_atom_hifi2_platform battery snd_soc_sst_match snd_soc_rl6231
> > drm_kms_helper hci_uart ov5693(C) ov2722(C) lm3554(C) btbcm btqca
> > v4l2_common snd_soc_core btintel snd_compress videodev snd_pcm_dmaengine
> > snd_pcm video bluetooth snd_timer drm media tpm_tis snd i2c_hid soundcore
> > tpm_tis_core rfkill_gpio ac97_bus soc_button_array ecdh_generic rfkill
> > crc16 tpm 8250_dw intel_gtt syscopyarea sysfillrect acpi_pad sysimgblt
> > intel_int0002_vgpio fb_sys_fops pinctrl_cherryview i2c_algo_bit button
> > sch_fq_codel tcp_bbr ifb ip_tables x_tables btrfs xor raid6_pq
> > algif_skcipher af_alg hid_logitech_hidpp hid_logitech_dj usbhid hid uas
> > Sep 18 22:44:32 defiant kernel: usb_storage dm_crypt dm_mod dax raid10
> > md_mod sd_mod crct10dif_pclmul crc32_pclmul crc32c_intel
> > ghash_clmulni_intel pcbc ahci aesni_intel xhci_pci libahci aes_x86_64
> > crypto_simd glue_helper xhci_hcd cryptd libata usbcore scsi_mod
> > usb_common serio sdhci_acpi sdhci led_class mmc_core
> > Sep 18 22:44:32 defiant kernel: CPU: 1 PID: 702 Comm: irq/123-enp3s0
> > Tainted: G WC 4.13.0-pf4 #1
> > Sep 18 22:44:32 defiant kernel: Hardware name: To Be Filled By O.E.M. To
> > Be
> > Filled By O.E.M./J3710-ITX, BIOS P1.30 03/30/2016
> > Sep 18 22:44:32 defiant kernel: task: ffff88923a738000 task.stack:
> > ffff958001500000
> > Sep 18 22:44:32 defiant kernel: RIP:
> > 0010:tcp_undo_cwnd_reduction+0xbd/0xd0
> > Sep 18 22:44:32 defiant kernel: RSP: 0018:ffff88927fc83a48 EFLAGS:
> > 00010202
> > Sep 18 22:44:32 defiant kernel: RAX: 0000000000000001 RBX:
> > ffff8892412d9800
> > RCX: ffff88927fc83b0c
> > Sep 18 22:44:32 defiant kernel: RDX: 000000007fffffff RSI:
> > 0000000000000001
> > RDI: ffff8892412d9800
> > Sep 18 22:44:32 defiant kernel: RBP: ffff88927fc83a50 R08:
> > 0000000000000000
> > R09: 0000000018dfb063
> > Sep 18 22:44:32 defiant kernel: R10: 0000000018dfd223 R11:
> > 0000000018dfb063
> > R12: 0000000000005320
> > Sep 18 22:44:32 defiant kernel: R13: ffff88927fc83b10 R14:
> > 0000000000000001
> > R15: ffff88927fc83b0c
> > Sep 18 22:44:32 defiant kernel: FS: 0000000000000000(0000)
> > GS:ffff88927fc80000(0000) knlGS:0000000000000000
> > Sep 18 22:44:32 defiant kernel: CS: 0010 DS: 0000 ES: 0000 CR0:
> > 0000000080050033
> > Sep 18 22:44:32 defiant kernel: CR2: 00007f1cd1a43620 CR3:
> > 0000000114a09000
> > CR4: 00000000001006e0
> > Sep 18 22:44:32 defiant kernel: Call Trace:
> > Sep 18 22:44:32 defiant kernel: <IRQ>
> > Sep 18 22:44:32 defiant kernel: tcp_try_undo_loss+0xb3/0xf0
> > Sep 18 22:44:32 defiant kernel: tcp_fastretrans_alert+0x746/0x990
> > Sep 18 22:44:32 defiant kernel: tcp_ack+0x741/0x1110
> > Sep 18 22:44:32 defiant kernel: tcp_rcv_established+0x325/0x770
> > Sep 18 22:44:32 defiant kernel: ? sk_filter_trim_cap+0xd4/0x1a0
> > Sep 18 22:44:32 defiant kernel: tcp_v4_do_rcv+0x90/0x1e0
> > Sep 18 22:44:32 defiant kernel: tcp_v4_rcv+0x950/0xa10
> > Sep 18 22:44:32 defiant kernel: ? nf_ct_deliver_cached_events+0xb8/0x110
> > [nf_conntrack]
> > Sep 18 22:44:32 defiant kernel: ip_local_deliver_finish+0x68/0x210
> > Sep 18 22:44:32 defiant kernel: ip_local_deliver+0xfa/0x110
> > Sep 18 22:44:32 defiant kernel: ? ip_rcv_finish+0x410/0x410
> > Sep 18 22:44:32 defiant kernel: ip_rcv_finish+0x120/0x410
> > Sep 18 22:44:32 defiant kernel: ip_rcv+0x28e/0x3b0
> > Sep 18 22:44:32 defiant kernel: ? inet_del_offload+0x40/0x40
> > Sep 18 22:44:32 defiant kernel: __netif_receive_skb_core+0x39b/0xb00
> > Sep 18 22:44:32 defiant kernel: ? netif_receive_skb_internal+0xa0/0x480
> > Sep 18 22:44:32 defiant kernel: ? dev_gro_receive+0x2eb/0x4a0
> > Sep 18 22:44:32 defiant kernel: __netif_receive_skb+0x18/0x60
> > Sep 18 22:44:32 defiant kernel: netif_receive_skb_internal+0x98/0x480
> > Sep 18 22:44:32 defiant kernel: netif_receive_skb+0x1c/0x80
> > Sep 18 22:44:32 defiant kernel: ifb_ri_tasklet+0x109/0x26a [ifb]
> > Sep 18 22:44:32 defiant kernel: tasklet_action+0x63/0x120
> > Sep 18 22:44:32 defiant kernel: __do_softirq+0xdf/0x2e5
> > Sep 18 22:44:32 defiant kernel: ? irq_finalize_oneshot.part.39+0xe0/0xe0
> > Sep 18 22:44:32 defiant kernel: do_softirq_own_stack+0x1c/0x30
> > Sep 18 22:44:32 defiant kernel: </IRQ>
> > Sep 18 22:44:32 defiant kernel: do_softirq.part.17+0x4e/0x60
> > Sep 18 22:44:32 defiant kernel: __local_bh_enable_ip+0x77/0x80
> > Sep 18 22:44:32 defiant kernel: irq_forced_thread_fn+0x5c/0x70
> > Sep 18 22:44:32 defiant kernel: irq_thread+0x131/0x1a0
> > Sep 18 22:44:32 defiant kernel: ? wake_threads_waitq+0x30/0x30
> > Sep 18 22:44:32 defiant kernel: kthread+0x126/0x140
> > Sep 18 22:44:32 defiant kernel: ? irq_thread_check_affinity+0x90/0x90
> > Sep 18 22:44:32 defiant kernel: ? kthread_create_on_node+0x70/0x70
> > Sep 18 22:44:32 defiant kernel: ret_from_fork+0x25/0x30
> > Sep 18 22:44:32 defiant kernel: Code: 5d c3 80 60 35 fb 48 8b 00 48 39 c2
> > 74 85 48 3b 83 50 01 00 00 75 eb e9 77 ff ff ff 89 83 48 06 00 00 80 a3
> > 1e 06 00 00 fb eb b3 <0f> ff 5b 5d c3 0f 1f 40 00 66 2e 0f 1f 84 00 00 00
> > 00 00 0f 1f Sep 18 22:44:32 defiant kernel: ---[ end trace
> > 1aea180efeedb474 ]--- ===
> >
> > On pondělí 18. září 2017 20:01:42 CEST Yuchung Cheng wrote:
> >> On Mon, Sep 18, 2017 at 10:59 AM, Oleksandr Natalenko
> >>
> >> <oleksandr@natalenko.name> wrote:
> >> > OK. Should I keep FACK disabled?
> >>
> >> Yes since it is disabled in the upstream by default. Although you can
> >> experiment FACK enabled additionally.
> >>
> >> Do we know the crash you first experienced is tied to this issue?
> >>
> >> > On pondělí 18. září 2017 19:51:21 CEST Yuchung Cheng wrote:
> >> >> Can you try this patch to verify my theory with tcp_recovery=0 and 1?
> >> >> thanks
> >> >>
> >> >> diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
> >> >> index 5af2f04f8859..9253d9ee7d0e 100644
> >> >> --- a/net/ipv4/tcp_input.c
> >> >> +++ b/net/ipv4/tcp_input.c
> >> >> @@ -2381,6 +2381,7 @@ static void tcp_undo_cwnd_reduction(struct sock
> >> >> *sk, bool unmark_loss)
> >> >>
> >> >> }
> >> >> tp->snd_cwnd_stamp = tcp_time_stamp;
> >> >> tp->undo_marker = 0;
> >> >>
> >> >> + WARN_ON(tp->retrans_out);
> >> >>
> >> >> }
^ permalink raw reply
* Re: [PATCH net-next 03/14] gtp: Call common functions to get tunnel routes and add dst_cache
From: Tom Herbert @ 2017-09-19 16:05 UTC (permalink / raw)
To: David Miller
Cc: Tom Herbert, Linux Kernel Network Developers, Pablo Neira Ayuso,
Harald Welte, Rohit Seth
In-Reply-To: <20170918.211751.1871429944584121281.davem@davemloft.net>
On Mon, Sep 18, 2017 at 9:17 PM, David Miller <davem@davemloft.net> wrote:
> From: Tom Herbert <tom@quantonium.net>
> Date: Mon, 18 Sep 2017 17:38:53 -0700
>
>> Call ip_tunnel_get_route and dst_cache to pdp context which should
>> improve performance by obviating the need to perform a route lookup
>> on every packet.
>>
>> Signed-off-by: Tom Herbert <tom@quantonium.net>
>
> Not caused by your changes, but something to think about:
>
>> -static struct rtable *ip4_route_output_gtp(struct flowi4 *fl4,
>> - const struct sock *sk,
>> - __be32 daddr)
>> -{
>> - memset(fl4, 0, sizeof(*fl4));
>> - fl4->flowi4_oif = sk->sk_bound_dev_if;
>> - fl4->daddr = daddr;
>> - fl4->saddr = inet_sk(sk)->inet_saddr;
>> - fl4->flowi4_tos = RT_CONN_FLAGS(sk);
>> - fl4->flowi4_proto = sk->sk_protocol;
>> -
>> - return ip_route_output_key(sock_net(sk), fl4);
>> -}
>
> This and the new dst caching code ignores any source address selection
> done by ip_route_output_key() or the new tunnel route lookup helpers.
>
> Either source address selection should be respected, or if saddr will
> never be modified by a route lookup for some specific reason here,
> that should be documented.
Yes, I noticed that. In this case the source address is intended to be
taken bound on the socket which would imply we aren't interested in
source address selection.
Tom
^ permalink raw reply
* [PATCH net-next 3/4] net: dsa: setup master ethtool after dsa_ptr
From: Vivien Didelot @ 2017-09-19 15:56 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
Andrew Lunn, Vivien Didelot
In-Reply-To: <20170919155700.14474-1-vivien.didelot@savoirfairelinux.com>
DSA overrides the master's ethtool ops so that we can inject its CPU
port's statistics. Because of that, we need to setup the ethtool ops
after the master's dsa_ptr pointer has been assigned, not before.
This patch setups the ethtool ops after dsa_ptr is assigned, and
restores them before it gets cleared.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
net/dsa/dsa2.c | 12 +++++++-----
net/dsa/legacy.c | 10 +++-------
2 files changed, 10 insertions(+), 12 deletions(-)
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index bd19304f862f..032f8bc3e788 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -433,16 +433,17 @@ static int dsa_dst_apply(struct dsa_switch_tree *dst)
return err;
}
- err = dsa_cpu_port_ethtool_setup(dst->cpu_dp);
- if (err)
- return err;
-
/* If we use a tagging format that doesn't have an ethertype
* field, make sure that all packets from this point on get
* sent to the tag format's receive function.
*/
wmb();
dst->cpu_dp->netdev->dsa_ptr = dst;
+
+ err = dsa_cpu_port_ethtool_setup(dst->cpu_dp);
+ if (err)
+ return err;
+
dst->applied = true;
return 0;
@@ -456,6 +457,8 @@ static void dsa_dst_unapply(struct dsa_switch_tree *dst)
if (!dst->applied)
return;
+ dsa_cpu_port_ethtool_restore(dst->cpu_dp);
+
dst->cpu_dp->netdev->dsa_ptr = NULL;
/* If we used a tagging format that doesn't have an ethertype
@@ -472,7 +475,6 @@ static void dsa_dst_unapply(struct dsa_switch_tree *dst)
dsa_ds_unapply(dst, ds);
}
- dsa_cpu_port_ethtool_restore(dst->cpu_dp);
dst->cpu_dp = NULL;
pr_info("DSA: tree %d unapplied\n", dst->tree);
diff --git a/net/dsa/legacy.c b/net/dsa/legacy.c
index 91e6f7981d39..163910699db7 100644
--- a/net/dsa/legacy.c
+++ b/net/dsa/legacy.c
@@ -206,10 +206,6 @@ static int dsa_switch_setup_one(struct dsa_switch *ds,
netdev_err(master, "[%d] : can't configure CPU and DSA ports\n",
index);
- ret = dsa_cpu_port_ethtool_setup(ds->dst->cpu_dp);
- if (ret)
- return ret;
-
return 0;
}
@@ -606,7 +602,7 @@ static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev,
wmb();
dev->dsa_ptr = dst;
- return 0;
+ return dsa_cpu_port_ethtool_setup(dst->cpu_dp);
}
static int dsa_probe(struct platform_device *pdev)
@@ -671,6 +667,8 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst)
{
int i;
+ dsa_cpu_port_ethtool_restore(dst->cpu_dp);
+
dst->cpu_dp->netdev->dsa_ptr = NULL;
/* If we used a tagging format that doesn't have an ethertype
@@ -686,8 +684,6 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst)
dsa_switch_destroy(ds);
}
- dsa_cpu_port_ethtool_restore(dst->cpu_dp);
-
dev_put(dst->cpu_dp->netdev);
}
--
2.14.1
^ permalink raw reply related
* Re: [PATCH net-next 00/14] gtp: Additional feature support
From: Tom Herbert @ 2017-09-19 15:59 UTC (permalink / raw)
To: Harald Welte
Cc: Tom Herbert, David S. Miller, Linux Kernel Network Developers,
Pablo Neira Ayuso, Rohit Seth
In-Reply-To: <20170919124352.l4k67ygb6xt4eloq@nataraja>
On Tue, Sep 19, 2017 at 5:43 AM, Harald Welte <laforge@gnumonks.org> wrote:
> Hi Tom,
>
> first of all, thanks a lot for your patch series. It makes me happy to
> see contributions on the GTP code :)
>
> On Mon, Sep 18, 2017 at 05:38:50PM -0700, Tom Herbert wrote:
>> - IPv6 support
>
> see my detailed comments in other mails. It's unfortunately only
> support for the already "deprecated" IPv6-only PDP contexts, not the
> more modern v4v6 type. In order to interoperate with old and new
> approach, all three cases (v4, v6 and v4v6) should be supported from one
> code base.
>
It sounds like something that can be subsequently added. Do you have a
reference to the spec?
>> - Configurable networking interfaces so that GTP kernel can be used
>> and tested without needing GSN network emulation (i.e. no user space
>> daemon needed).
>
> We have some pretty decent userspace utilities for configuring the GTP
> interfaces and tunnels in the libgtpnl repository, but if it helps
> people to have another way of configuration, I won't be against it.
>
AFAIK those userspace utilities don't support IPv6. Being able to
configure GTP like any other encapsulation will facilitate development
of IPv6 and other features.
> What we have to keep in mind is that the current model of 1:1 mapping of
> a "UDP socket' to a GTP netdevice is conceptually broken and needs to be
> refactored soon (without breaking backwards compatibility). See related
> earlier discussions with patches submitted by Andreas Schultz.
>
I don't think I changed the model, so this can evolve.
> Summary:
>
> In real-world GGSNs you often want to host multiple virtual GGSNs on a
> single GGSN (= UDP socket). Each virtual GGSN terminates into one
> external PDN (packet data network), which can be a private corporate vpn
> or any other IP network, with no routing between those networks.
>
Sounds like network virtualization and VNIs.
> Naively one would assume you "simply" run another virtual GGSN
> instance on another IP address, and then differentiate like that.
>
> However, the problem is that adding a new GGSN IP address will require
> manual configuration changes at each of your roaming partners (easily
> hundreds of operators!) and hence it is avoided at all cost due to the
> related long schedule, requirement for interop testing with each of them,
> etc.
>
> So what you do in reality at operators is that you operate many of those
> virtual GGSNs on the same IP:Port combination (and hence UDP socket),
> which means you have PDP contexts for vGGSN A which terminate on e.g.
> gtp0 and PDP contexts for vGGSN B on gtp1, and so on. The decision
> which gtp-device a given PDP context is a member is made by the GTP-C
> instance. In the kenel we'll have to decouple net-devices from sockets.
>
> So whatever new configuration mechanism or architectural changes we
> introduce, we need to make sure that those will accomodate the "new
> model" rather than introducing further dependencies for which we will
> have to maintain backwards compatibility workaronds later on.
>
>> - Port numbers are configurable
>
> I'm not sure if this is a useful feature. GTP is used only in
> operator-controlled networks and only on standard ports. It's not
> possible to negotiate any non-standard ports on the signaling plane
> either.
>
Bear in mind that we're not required to do everything the GTP spec
says. Adding port configuration is another one of those things that
gives us flexibility and and better capability to test without needing
a full blown GSN network. One feature I didn't implement was UDP
source for flow entropy-- as we've seen with other encapsulation
protocols this helps significantly to get good ECMP in the network. My
impression is GTP designers probably didn't think in terms of getting
best performance. But we can ;-)
>> - Addition of a dst_cache in the GTP structure and other cleanup
>
> looks fine to me.
>
>> - GSO,GRO
>> - Control of zero UDP checksums
>
> [...]
>
>> Additionally, this patch set also includes a couple of general support
>> capabilities:
>>
>> - A facility that allows application specific GSO callbacks
>> - Common functions to get a route fo for an IP tunnel
>
> This is where the "core netdev" folks will have to comment. I'm too
> remote from mainline kernel development these days and will focus on
> reviewing the GTP specific bits of your patch series.
>
Thanks. Obviously, I and many on this list have more expertise on the
core networking side than GTP, so your review is quite welcome.
>> For IPv6 support, the mobile subscriber needs to allow IPv6 addresses,
>> and the remote enpoint can be IPv6.
>
> Minor correction: The mobile subscriber specifically requests a PDP Type
> when establishing the PDP context via Session Management related
> signaling from MS/UE to SGSN. The SGSN simply translates this to GTP
> and then forwards it to the GGSN. So it's acutally not "allow" but
> "specifically request".
>
Okay.
>> Configured the matrix of IPv4/IPv6 mobile subscriber, IPv4/IPv6 remote
>> peer, and GTP version 0 and 1 (eight combinations). Observed
>> connectivity and proper GSO/GRO. Also, tested VXLAN for
>> regression.
>
> I presume those tests were done with manually configured GTP-devices and
> PDP contexts to the (patched) kernel GTP module? If so, I would like to
> strongly suggest interop testing with a different implementation, such
> as real phones on the MS/UE side and e.g. OsmoSGSN. That would,
> however, of course mean that the netlink related bits would have to be
> added to libgtpnl and OsmoGGSN (or ergw) so that you have a daemon for
> the control plane.
>
I also brought up open_ggsn. ggsn to sgsn.
> For IPv6 (and v4v6) PDP contexts there is quite a bit of extra headache
> related to the way how router solicitation/advertisements are modified
> in the 3GPP world.
>
> The address allocation in v4 is simple:
> * MS/UE requests dynamic or fixed IPv4 address via EUA IE of PDP context
> activation
> * GGSN responds with IPv4 address in EUA of Activate PDP context
> response (and then uses netlink to tell the kernel about that
> IPv4 address)
>
> In v6 or the v6 portion of v4v6 it works differently:
> * MS/UE requests dynamic or fixed IPv4 address in EUA IE of PDP context
> activation
> * GGSN responds with an IPv6 address, but that address is *not* used
> for communication, but simply used as an "interface identifier" to
> build a link-local address.
> * MS then uses router solicitation using that link-local address
> * GGSN responds with router advertisement, allocating a single /64
> prefix, from which the MS then generates a fully-qualified IPv6
> source address for communication.
>
> How did you envision this to be done with the v6 support you just added?
> At the very least, the /64 prefix matching would have to be implemented
> so that in fact all addresses within that /64 prefix are matched +
> encapsulated for a given PDP context in the downlink (to phone)
> direction.
>
> Also, I think the responsibility for the router advertisements would be
> in the kernel, too. Otherwise, a GTP-C userspace implementation would
> have to inject packets into the user plane (which is otherwise handled
> completely inside the kernel). Injecting packets would mean that in caes
> GTP sequence numbers are used, that userspace implementation would have
> to alter the sequence numbers of the kernel gtp.ko code using netlink,
> but therre would be race conditions, ...
>
> The router advertisements and neighbor advertisements basically have the
> semantics of one link per PDP context. Each of them is a point-to-point
> link, and it's not one router advertisement that's sent to all of the
> PDP contexts on that gtp-device.
>
> I know it all sucks. I'm still happy to see somebody tackling v6
> support in gtp.c :)
>
I would hope all the above you're describing is mostly control plane
matters. At least a good design decouples data palne and control
plane. I know that GTP is a bit convoluted in this regard.
Tom
^ permalink raw reply
* [PATCH net-next 4/4] net: dsa: move master ethtool code
From: Vivien Didelot @ 2017-09-19 15:57 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
Andrew Lunn, Vivien Didelot
In-Reply-To: <20170919155700.14474-1-vivien.didelot@savoirfairelinux.com>
DSA overrides the master device ethtool ops, so that it can inject stats
from its dedicated switch CPU port as well.
The related code is currently split in dsa.c and slave.c, but it only
scopes the master net device. Move it to a new master.c DSA core file.
This file will be later extented with master net device specific code.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
net/dsa/Makefile | 2 +-
net/dsa/dsa.c | 28 -------------
net/dsa/dsa2.c | 4 +-
net/dsa/dsa_priv.h | 7 ++--
net/dsa/legacy.c | 4 +-
net/dsa/master.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++
net/dsa/slave.c | 83 ------------------------------------
7 files changed, 129 insertions(+), 119 deletions(-)
create mode 100644 net/dsa/master.c
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index fcce25da937c..2e7ac8bab19d 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -1,6 +1,6 @@
# the core
obj-$(CONFIG_NET_DSA) += dsa_core.o
-dsa_core-y += dsa.o dsa2.o legacy.o port.o slave.o switch.o
+dsa_core-y += dsa.o dsa2.o legacy.o master.o port.o slave.o switch.o
# tagging formats
dsa_core-$(CONFIG_NET_DSA_TAG_BRCM) += tag_brcm.o
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index abadf7b49236..81c852e32821 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -112,34 +112,6 @@ const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol)
return ops;
}
-int dsa_cpu_port_ethtool_setup(struct dsa_port *cpu_dp)
-{
- struct dsa_switch *ds = cpu_dp->ds;
- struct net_device *master;
- struct ethtool_ops *cpu_ops;
-
- master = cpu_dp->netdev;
-
- cpu_ops = devm_kzalloc(ds->dev, sizeof(*cpu_ops), GFP_KERNEL);
- if (!cpu_ops)
- return -ENOMEM;
-
- cpu_dp->orig_ethtool_ops = master->ethtool_ops;
- if (cpu_dp->orig_ethtool_ops)
- memcpy(cpu_ops, cpu_dp->orig_ethtool_ops, sizeof(*cpu_ops));
-
- dsa_cpu_port_ethtool_init(cpu_ops);
- master->ethtool_ops = cpu_ops;
-
- return 0;
-}
-
-void dsa_cpu_port_ethtool_restore(struct dsa_port *cpu_dp)
-{
- cpu_dp->netdev->ethtool_ops = cpu_dp->orig_ethtool_ops;
- cpu_dp->orig_ethtool_ops = NULL;
-}
-
void dsa_cpu_dsa_destroy(struct dsa_port *port)
{
struct device_node *port_dn = port->dn;
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 032f8bc3e788..dcccaebde708 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -440,7 +440,7 @@ static int dsa_dst_apply(struct dsa_switch_tree *dst)
wmb();
dst->cpu_dp->netdev->dsa_ptr = dst;
- err = dsa_cpu_port_ethtool_setup(dst->cpu_dp);
+ err = dsa_master_ethtool_setup(dst->cpu_dp->netdev);
if (err)
return err;
@@ -457,7 +457,7 @@ static void dsa_dst_unapply(struct dsa_switch_tree *dst)
if (!dst->applied)
return;
- dsa_cpu_port_ethtool_restore(dst->cpu_dp);
+ dsa_master_ethtool_restore(dst->cpu_dp->netdev);
dst->cpu_dp->netdev->dsa_ptr = NULL;
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index 9c3eeb72462d..f616b3444418 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -97,8 +97,6 @@ struct dsa_slave_priv {
int dsa_cpu_dsa_setup(struct dsa_port *port);
void dsa_cpu_dsa_destroy(struct dsa_port *dport);
const struct dsa_device_ops *dsa_resolve_tag_protocol(int tag_protocol);
-int dsa_cpu_port_ethtool_setup(struct dsa_port *cpu_dp);
-void dsa_cpu_port_ethtool_restore(struct dsa_port *cpu_dp);
bool dsa_schedule_work(struct work_struct *work);
/* legacy.c */
@@ -112,6 +110,10 @@ int dsa_legacy_fdb_del(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr, u16 vid);
+/* master.c */
+int dsa_master_ethtool_setup(struct net_device *dev);
+void dsa_master_ethtool_restore(struct net_device *dev);
+
/* port.c */
int dsa_port_set_state(struct dsa_port *dp, u8 state,
struct switchdev_trans *trans);
@@ -139,7 +141,6 @@ int dsa_port_vlan_del(struct dsa_port *dp,
/* slave.c */
extern const struct dsa_device_ops notag_netdev_ops;
void dsa_slave_mii_bus_init(struct dsa_switch *ds);
-void dsa_cpu_port_ethtool_init(struct ethtool_ops *ops);
int dsa_slave_create(struct dsa_port *port, const char *name);
void dsa_slave_destroy(struct net_device *slave_dev);
int dsa_slave_suspend(struct net_device *slave_dev);
diff --git a/net/dsa/legacy.c b/net/dsa/legacy.c
index 163910699db7..ae505d8e4417 100644
--- a/net/dsa/legacy.c
+++ b/net/dsa/legacy.c
@@ -602,7 +602,7 @@ static int dsa_setup_dst(struct dsa_switch_tree *dst, struct net_device *dev,
wmb();
dev->dsa_ptr = dst;
- return dsa_cpu_port_ethtool_setup(dst->cpu_dp);
+ return dsa_master_ethtool_setup(dst->cpu_dp->netdev);
}
static int dsa_probe(struct platform_device *pdev)
@@ -667,7 +667,7 @@ static void dsa_remove_dst(struct dsa_switch_tree *dst)
{
int i;
- dsa_cpu_port_ethtool_restore(dst->cpu_dp);
+ dsa_master_ethtool_restore(dst->cpu_dp->netdev);
dst->cpu_dp->netdev->dsa_ptr = NULL;
diff --git a/net/dsa/master.c b/net/dsa/master.c
new file mode 100644
index 000000000000..5e5147ec5a44
--- /dev/null
+++ b/net/dsa/master.c
@@ -0,0 +1,120 @@
+/*
+ * Handling of a master device, switching frames via its switch fabric CPU port
+ *
+ * Copyright (c) 2017 Savoir-faire Linux Inc.
+ * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "dsa_priv.h"
+
+static void dsa_master_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats,
+ uint64_t *data)
+{
+ struct dsa_switch_tree *dst = dev->dsa_ptr;
+ struct dsa_port *port = dst->cpu_dp;
+ struct dsa_switch *ds = port->ds;
+ const struct ethtool_ops *ops = port->orig_ethtool_ops;
+ int count = 0;
+
+ if (ops && ops->get_sset_count && ops->get_ethtool_stats) {
+ count = ops->get_sset_count(dev, ETH_SS_STATS);
+ ops->get_ethtool_stats(dev, stats, data);
+ }
+
+ if (ds->ops->get_ethtool_stats)
+ ds->ops->get_ethtool_stats(ds, port->index, data + count);
+}
+
+static int dsa_master_get_sset_count(struct net_device *dev, int sset)
+{
+ struct dsa_switch_tree *dst = dev->dsa_ptr;
+ struct dsa_port *port = dst->cpu_dp;
+ struct dsa_switch *ds = port->ds;
+ const struct ethtool_ops *ops = port->orig_ethtool_ops;
+ int count = 0;
+
+ if (ops && ops->get_sset_count)
+ count += ops->get_sset_count(dev, sset);
+
+ if (sset == ETH_SS_STATS && ds->ops->get_sset_count)
+ count += ds->ops->get_sset_count(ds);
+
+ return count;
+}
+
+static void dsa_master_get_strings(struct net_device *dev, uint32_t stringset,
+ uint8_t *data)
+{
+ struct dsa_switch_tree *dst = dev->dsa_ptr;
+ struct dsa_port *port = dst->cpu_dp;
+ struct dsa_switch *ds = port->ds;
+ const struct ethtool_ops *ops = port->orig_ethtool_ops;
+ int len = ETH_GSTRING_LEN;
+ int mcount = 0, count;
+ unsigned int i;
+ uint8_t pfx[4];
+ uint8_t *ndata;
+
+ snprintf(pfx, sizeof(pfx), "p%.2d", port->index);
+ /* We do not want to be NULL-terminated, since this is a prefix */
+ pfx[sizeof(pfx) - 1] = '_';
+
+ if (ops && ops->get_sset_count && ops->get_strings) {
+ mcount = ops->get_sset_count(dev, ETH_SS_STATS);
+ ops->get_strings(dev, stringset, data);
+ }
+
+ if (stringset == ETH_SS_STATS && ds->ops->get_strings) {
+ ndata = data + mcount * len;
+ /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle
+ * the output after to prepend our CPU port prefix we
+ * constructed earlier
+ */
+ ds->ops->get_strings(ds, port->index, ndata);
+ count = ds->ops->get_sset_count(ds);
+ for (i = 0; i < count; i++) {
+ memmove(ndata + (i * len + sizeof(pfx)),
+ ndata + i * len, len - sizeof(pfx));
+ memcpy(ndata + i * len, pfx, sizeof(pfx));
+ }
+ }
+}
+
+int dsa_master_ethtool_setup(struct net_device *dev)
+{
+ struct dsa_switch_tree *dst = dev->dsa_ptr;
+ struct dsa_port *port = dst->cpu_dp;
+ struct dsa_switch *ds = port->ds;
+ struct ethtool_ops *ops;
+
+ ops = devm_kzalloc(ds->dev, sizeof(*ops), GFP_KERNEL);
+ if (!ops)
+ return -ENOMEM;
+
+ port->orig_ethtool_ops = dev->ethtool_ops;
+ if (port->orig_ethtool_ops)
+ memcpy(ops, port->orig_ethtool_ops, sizeof(*ops));
+
+ ops->get_sset_count = dsa_master_get_sset_count;
+ ops->get_ethtool_stats = dsa_master_get_ethtool_stats;
+ ops->get_strings = dsa_master_get_strings;
+
+ dev->ethtool_ops = ops;
+
+ return 0;
+}
+
+void dsa_master_ethtool_restore(struct net_device *dev)
+{
+ struct dsa_switch_tree *dst = dev->dsa_ptr;
+ struct dsa_port *port = dst->cpu_dp;
+
+ dev->ethtool_ops = port->orig_ethtool_ops;
+ port->orig_ethtool_ops = NULL;
+}
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 2ff4f907d137..d51b10450e1b 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -567,82 +567,6 @@ static void dsa_slave_get_strings(struct net_device *dev,
}
}
-static void dsa_cpu_port_get_ethtool_stats(struct net_device *dev,
- struct ethtool_stats *stats,
- uint64_t *data)
-{
- struct dsa_switch_tree *dst = dev->dsa_ptr;
- struct dsa_port *cpu_dp = dsa_get_cpu_port(dst);
- struct dsa_switch *ds = cpu_dp->ds;
- const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
- s8 cpu_port = cpu_dp->index;
- int count = 0;
-
- if (ops && ops->get_sset_count && ops->get_ethtool_stats) {
- count = ops->get_sset_count(dev, ETH_SS_STATS);
- ops->get_ethtool_stats(dev, stats, data);
- }
-
- if (ds->ops->get_ethtool_stats)
- ds->ops->get_ethtool_stats(ds, cpu_port, data + count);
-}
-
-static int dsa_cpu_port_get_sset_count(struct net_device *dev, int sset)
-{
- struct dsa_switch_tree *dst = dev->dsa_ptr;
- struct dsa_port *cpu_dp = dsa_get_cpu_port(dst);
- struct dsa_switch *ds = cpu_dp->ds;
- const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
- int count = 0;
-
- if (ops && ops->get_sset_count)
- count += ops->get_sset_count(dev, sset);
-
- if (sset == ETH_SS_STATS && ds->ops->get_sset_count)
- count += ds->ops->get_sset_count(ds);
-
- return count;
-}
-
-static void dsa_cpu_port_get_strings(struct net_device *dev,
- uint32_t stringset, uint8_t *data)
-{
- struct dsa_switch_tree *dst = dev->dsa_ptr;
- struct dsa_port *cpu_dp = dsa_get_cpu_port(dst);
- struct dsa_switch *ds = cpu_dp->ds;
- const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
- s8 cpu_port = cpu_dp->index;
- int len = ETH_GSTRING_LEN;
- int mcount = 0, count;
- unsigned int i;
- uint8_t pfx[4];
- uint8_t *ndata;
-
- snprintf(pfx, sizeof(pfx), "p%.2d", cpu_port);
- /* We do not want to be NULL-terminated, since this is a prefix */
- pfx[sizeof(pfx) - 1] = '_';
-
- if (ops && ops->get_sset_count && ops->get_strings) {
- mcount = ops->get_sset_count(dev, ETH_SS_STATS);
- ops->get_strings(dev, stringset, data);
- }
-
- if (stringset == ETH_SS_STATS && ds->ops->get_strings) {
- ndata = data + mcount * len;
- /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle
- * the output after to prepend our CPU port prefix we
- * constructed earlier
- */
- ds->ops->get_strings(ds, cpu_port, ndata);
- count = ds->ops->get_sset_count(ds);
- for (i = 0; i < count; i++) {
- memmove(ndata + (i * len + sizeof(pfx)),
- ndata + i * len, len - sizeof(pfx));
- memcpy(ndata + i * len, pfx, sizeof(pfx));
- }
- }
-}
-
static void dsa_slave_get_ethtool_stats(struct net_device *dev,
struct ethtool_stats *stats,
uint64_t *data)
@@ -979,13 +903,6 @@ static void dsa_slave_get_stats64(struct net_device *dev,
}
}
-void dsa_cpu_port_ethtool_init(struct ethtool_ops *ops)
-{
- ops->get_sset_count = dsa_cpu_port_get_sset_count;
- ops->get_ethtool_stats = dsa_cpu_port_get_ethtool_stats;
- ops->get_strings = dsa_cpu_port_get_strings;
-}
-
static int dsa_slave_get_rxnfc(struct net_device *dev,
struct ethtool_rxnfc *nfc, u32 *rule_locs)
{
--
2.14.1
^ permalink raw reply related
* [PATCH net-next 2/4] net: dsa: setup master ethtool unconditionally
From: Vivien Didelot @ 2017-09-19 15:56 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
Andrew Lunn, Vivien Didelot
In-Reply-To: <20170919155700.14474-1-vivien.didelot@savoirfairelinux.com>
When a DSA switch tree is meant to be applied, it already has a CPU
port. Thus remove the condition of dst->cpu_dp.
Moreover, the next lines access dst->cpu_dp unconditionally.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
net/dsa/dsa2.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index 873af0108e24..bd19304f862f 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -433,11 +433,9 @@ static int dsa_dst_apply(struct dsa_switch_tree *dst)
return err;
}
- if (dst->cpu_dp) {
- err = dsa_cpu_port_ethtool_setup(dst->cpu_dp);
- if (err)
- return err;
- }
+ err = dsa_cpu_port_ethtool_setup(dst->cpu_dp);
+ if (err)
+ return err;
/* If we use a tagging format that doesn't have an ethertype
* field, make sure that all packets from this point on get
@@ -474,10 +472,8 @@ static void dsa_dst_unapply(struct dsa_switch_tree *dst)
dsa_ds_unapply(dst, ds);
}
- if (dst->cpu_dp) {
- dsa_cpu_port_ethtool_restore(dst->cpu_dp);
- dst->cpu_dp = NULL;
- }
+ dsa_cpu_port_ethtool_restore(dst->cpu_dp);
+ dst->cpu_dp = NULL;
pr_info("DSA: tree %d unapplied\n", dst->tree);
dst->applied = false;
--
2.14.1
^ permalink raw reply related
* [PATCH net-next 1/4] net: dsa: remove copy of master ethtool_ops
From: Vivien Didelot @ 2017-09-19 15:56 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
Andrew Lunn, Vivien Didelot
In-Reply-To: <20170919155700.14474-1-vivien.didelot@savoirfairelinux.com>
There is no need to store a copy of the master ethtool ops, storing the
original pointer in DSA and the new one in the master netdev itself is
enough.
In the meantime, set orig_ethtool_ops to NULL when restoring the master
ethtool ops and check the presence of the master original ethtool ops as
well as its needed functions before calling them.
Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
include/net/dsa.h | 1 -
net/dsa/dsa.c | 8 ++++----
net/dsa/slave.c | 19 +++++++++++--------
3 files changed, 15 insertions(+), 13 deletions(-)
diff --git a/include/net/dsa.h b/include/net/dsa.h
index dd44d6ce1097..8dee216a5a9b 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -188,7 +188,6 @@ struct dsa_port {
/*
* Original copy of the master netdev ethtool_ops
*/
- struct ethtool_ops ethtool_ops;
const struct ethtool_ops *orig_ethtool_ops;
};
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 03c58b0eb082..abadf7b49236 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -124,11 +124,10 @@ int dsa_cpu_port_ethtool_setup(struct dsa_port *cpu_dp)
if (!cpu_ops)
return -ENOMEM;
- memcpy(&cpu_dp->ethtool_ops, master->ethtool_ops,
- sizeof(struct ethtool_ops));
cpu_dp->orig_ethtool_ops = master->ethtool_ops;
- memcpy(cpu_ops, &cpu_dp->ethtool_ops,
- sizeof(struct ethtool_ops));
+ if (cpu_dp->orig_ethtool_ops)
+ memcpy(cpu_ops, cpu_dp->orig_ethtool_ops, sizeof(*cpu_ops));
+
dsa_cpu_port_ethtool_init(cpu_ops);
master->ethtool_ops = cpu_ops;
@@ -138,6 +137,7 @@ int dsa_cpu_port_ethtool_setup(struct dsa_port *cpu_dp)
void dsa_cpu_port_ethtool_restore(struct dsa_port *cpu_dp)
{
cpu_dp->netdev->ethtool_ops = cpu_dp->orig_ethtool_ops;
+ cpu_dp->orig_ethtool_ops = NULL;
}
void dsa_cpu_dsa_destroy(struct dsa_port *port)
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 2afa99506f8b..2ff4f907d137 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -574,12 +574,13 @@ static void dsa_cpu_port_get_ethtool_stats(struct net_device *dev,
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_port *cpu_dp = dsa_get_cpu_port(dst);
struct dsa_switch *ds = cpu_dp->ds;
+ const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
s8 cpu_port = cpu_dp->index;
int count = 0;
- if (cpu_dp->ethtool_ops.get_sset_count) {
- count = cpu_dp->ethtool_ops.get_sset_count(dev, ETH_SS_STATS);
- cpu_dp->ethtool_ops.get_ethtool_stats(dev, stats, data);
+ if (ops && ops->get_sset_count && ops->get_ethtool_stats) {
+ count = ops->get_sset_count(dev, ETH_SS_STATS);
+ ops->get_ethtool_stats(dev, stats, data);
}
if (ds->ops->get_ethtool_stats)
@@ -591,10 +592,11 @@ static int dsa_cpu_port_get_sset_count(struct net_device *dev, int sset)
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_port *cpu_dp = dsa_get_cpu_port(dst);
struct dsa_switch *ds = cpu_dp->ds;
+ const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
int count = 0;
- if (cpu_dp->ethtool_ops.get_sset_count)
- count += cpu_dp->ethtool_ops.get_sset_count(dev, sset);
+ if (ops && ops->get_sset_count)
+ count += ops->get_sset_count(dev, sset);
if (sset == ETH_SS_STATS && ds->ops->get_sset_count)
count += ds->ops->get_sset_count(ds);
@@ -608,6 +610,7 @@ static void dsa_cpu_port_get_strings(struct net_device *dev,
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_port *cpu_dp = dsa_get_cpu_port(dst);
struct dsa_switch *ds = cpu_dp->ds;
+ const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
s8 cpu_port = cpu_dp->index;
int len = ETH_GSTRING_LEN;
int mcount = 0, count;
@@ -619,9 +622,9 @@ static void dsa_cpu_port_get_strings(struct net_device *dev,
/* We do not want to be NULL-terminated, since this is a prefix */
pfx[sizeof(pfx) - 1] = '_';
- if (cpu_dp->ethtool_ops.get_sset_count) {
- mcount = cpu_dp->ethtool_ops.get_sset_count(dev, ETH_SS_STATS);
- cpu_dp->ethtool_ops.get_strings(dev, stringset, data);
+ if (ops && ops->get_sset_count && ops->get_strings) {
+ mcount = ops->get_sset_count(dev, ETH_SS_STATS);
+ ops->get_strings(dev, stringset, data);
}
if (stringset == ETH_SS_STATS && ds->ops->get_strings) {
--
2.14.1
^ permalink raw reply related
* [PATCH net-next 0/4] net: dsa: move master ethtool code
From: Vivien Didelot @ 2017-09-19 15:56 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, kernel, David S. Miller, Florian Fainelli,
Andrew Lunn, Vivien Didelot
The DSA core overrides the master device's ethtool_ops structure so that
it can inject statistics and such of its dedicated switch CPU port.
This ethtool code is currently called on unnecessary conditions or
before the master interface and its switch CPU port get wired up.
This patchset fixes this.
Similarly to slave.c where the DSA slave net_device is the entry point
of the dsa_slave_* functions, this patchset also isolates the master's
ethtool code in a new master.c file, where the DSA master net_device is
the entry point of the dsa_master_* functions.
This is a first step towards better control of the master device and
support for multiple CPU ports.
Vivien Didelot (4):
net: dsa: remove copy of master ethtool_ops
net: dsa: setup master ethtool unconditionally
net: dsa: setup master ethtool after dsa_ptr
net: dsa: move master ethtool code
include/net/dsa.h | 1 -
net/dsa/Makefile | 2 +-
net/dsa/dsa.c | 28 -------------
net/dsa/dsa2.c | 18 ++++----
net/dsa/dsa_priv.h | 7 ++--
net/dsa/legacy.c | 10 ++---
net/dsa/master.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++
net/dsa/slave.c | 80 -----------------------------------
8 files changed, 136 insertions(+), 130 deletions(-)
create mode 100644 net/dsa/master.c
--
2.14.1
^ permalink raw reply
* Re: [PATCH net-next 1/3] bpf: Implement map_delete_elem for BPF_MAP_TYPE_LPM_TRIE
From: Craig Gallek @ 2017-09-19 15:08 UTC (permalink / raw)
To: Alexei Starovoitov; +Cc: Daniel Mack, Daniel Borkmann, David S . Miller, netdev
In-Reply-To: <3e537b56-d0f2-de9a-5bb1-f60fbfc11ca5@fb.com>
On Mon, Sep 18, 2017 at 6:53 PM, Alexei Starovoitov <ast@fb.com> wrote:
Thanks for the review! Please correct me if I'm wrong...
> On 9/18/17 12:30 PM, Craig Gallek wrote:
>>
>> From: Craig Gallek <kraig@google.com>
>>
>> This is a simple non-recursive delete operation. It prunes paths
>> of empty nodes in the tree, but it does not try to further compress
>> the tree as nodes are removed.
>>
>> Signed-off-by: Craig Gallek <kraig@google.com>
>> ---
>> kernel/bpf/lpm_trie.c | 80
>> +++++++++++++++++++++++++++++++++++++++++++++++++--
>> 1 file changed, 77 insertions(+), 3 deletions(-)
>>
>> diff --git a/kernel/bpf/lpm_trie.c b/kernel/bpf/lpm_trie.c
>> index 1b767844a76f..9d58a576b2ae 100644
>> --- a/kernel/bpf/lpm_trie.c
>> +++ b/kernel/bpf/lpm_trie.c
>> @@ -389,10 +389,84 @@ static int trie_update_elem(struct bpf_map *map,
>> return ret;
>> }
>>
>> -static int trie_delete_elem(struct bpf_map *map, void *key)
>> +/* Called from syscall or from eBPF program */
>> +static int trie_delete_elem(struct bpf_map *map, void *_key)
>> {
>> - /* TODO */
>> - return -ENOSYS;
>> + struct lpm_trie *trie = container_of(map, struct lpm_trie, map);
>> + struct bpf_lpm_trie_key *key = _key;
>> + struct lpm_trie_node __rcu **trim;
>> + struct lpm_trie_node *node;
>> + unsigned long irq_flags;
>> + unsigned int next_bit;
>> + size_t matchlen = 0;
>> + int ret = 0;
>> +
>> + if (key->prefixlen > trie->max_prefixlen)
>> + return -EINVAL;
>> +
>> + raw_spin_lock_irqsave(&trie->lock, irq_flags);
>> +
>> + /* Walk the tree looking for an exact key/length match and keeping
>> + * track of where we could begin trimming the tree. The
>> trim-point
>> + * is the sub-tree along the walk consisting of only single-child
>> + * intermediate nodes and ending at a leaf node that we want to
>> + * remove.
>> + */
>> + trim = &trie->root;
>> + node = rcu_dereference_protected(
>> + trie->root, lockdep_is_held(&trie->lock));
>> + while (node) {
>> + matchlen = longest_prefix_match(trie, node, key);
>> +
>> + if (node->prefixlen != matchlen ||
>> + node->prefixlen == key->prefixlen)
>> + break;
>
>
> curious why there is no need to do
> 'node->prefixlen == trie->max_prefixlen' in the above
> like update/lookup do?
I don't believe the node->prefixlen == trie->max_prefixlen check in
trie_update_elem is necessary. In order to get to this third clause,
it implies that the first two clauses evaluated false. Which happens
when we find an exact prefix match for the current node, but the
to-be-inserted key prefix is different. If the node we are comparing
against had a prefix of max_prefixlen, it would not be possible to
have both a full prefix match but different prefix lengths. This
assumes that there are no nodes in the tree with > max_prefixlen
prefixes, but that is handled earlier in the update function.
There's a similar (I believe) unnecessary max_prefixlen check in
trie_lookup_elem. The function should behave the same way without
that check, but at least in this case it's used as an early-out and
saves a few lines of execution.
>
>> +
>> + next_bit = extract_bit(key->data, node->prefixlen);
>> + /* If we hit a node that has more than one child or is a
>> valid
>> + * prefix itself, do not remove it. Reset the root of the
>> trim
>> + * path to its descendant on our path.
>> + */
>> + if (!(node->flags & LPM_TREE_NODE_FLAG_IM) ||
>> + (node->child[0] && node->child[1]))
>> + trim = &node->child[next_bit];
>> + node = rcu_dereference_protected(
>> + node->child[next_bit],
>> lockdep_is_held(&trie->lock));
>> + }
>> +
>> + if (!node || node->prefixlen != key->prefixlen ||
>> + (node->flags & LPM_TREE_NODE_FLAG_IM)) {
>> + ret = -ENOENT;
>> + goto out;
>> + }
>> +
>> + trie->n_entries--;
>> +
>> + /* If the node we are removing is not a leaf node, simply mark it
>> + * as intermediate and we are done.
>> + */
>> + if (rcu_access_pointer(node->child[0]) ||
>> + rcu_access_pointer(node->child[1])) {
>> + node->flags |= LPM_TREE_NODE_FLAG_IM;
>> + goto out;
>> + }
>> +
>> + /* trim should now point to the slot holding the start of a path
>> from
>> + * zero or more intermediate nodes to our leaf node for deletion.
>> + */
>> + while ((node = rcu_dereference_protected(
>> + *trim, lockdep_is_held(&trie->lock)))) {
>> + RCU_INIT_POINTER(*trim, NULL);
>> + trim = rcu_access_pointer(node->child[0]) ?
>> + &node->child[0] :
>> + &node->child[1];
>> + kfree_rcu(node, rcu);
>
>
> can it be that some of the nodes this loop walks have
> both child[0] and [1] ?
No, the loop above will push trim down the walk every time it
encounters a node with two children. The only other trim assignment
is the initial trim = &trie->root. But the only time we would skip
the assignment in the loop is if the node being removed is the root.
If the root had multiple children and is being removed, it would be
handled by the case that turns the node into an intermediate node
rather than walking the trim path freeing things.
^ permalink raw reply
* Re: [PATCH net-next 4/4] test_rhashtable: add test case for rhl_table interface
From: kbuild test robot @ 2017-09-19 14:59 UTC (permalink / raw)
To: Florian Westphal; +Cc: kbuild-all, netdev, Florian Westphal
In-Reply-To: <20170918210711.10202-5-fw@strlen.de>
[-- Attachment #1: Type: text/plain, Size: 6339 bytes --]
Hi Florian,
[auto build test WARNING on net-next/master]
url: https://github.com/0day-ci/linux/commits/Florian-Westphal/test_rhashtable-add-test-case-for-rhl-table/20170919-135550
config: x86_64-randconfig-a0-09192105 (attached as .config)
compiler: gcc-4.4 (Debian 4.4.7-8) 4.4.7
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All warnings (new ones prefixed by >>):
lib/test_rhashtable.c: In function 'test_rhltable':
>> lib/test_rhashtable.c:433: warning: the frame size of 2144 bytes is larger than 2048 bytes
vim +433 lib/test_rhashtable.c
254
255 static int __init test_rhltable(unsigned int entries)
256 {
257 struct test_obj_rhl *rhl_test_objects;
258 unsigned long *obj_in_table;
259 struct rhltable rhlt;
260 unsigned int i, j, k;
261 int ret, err;
262
263 if (entries == 0)
264 entries = 1;
265
266 rhl_test_objects = vzalloc(sizeof(*rhl_test_objects) * entries);
267 if (!rhl_test_objects)
268 return -ENOMEM;
269
270 ret = -ENOMEM;
271 obj_in_table = vzalloc(BITS_TO_LONGS(entries) * sizeof(unsigned long));
272 if (!obj_in_table)
273 goto out_free;
274
275 /* nulls_base not supported in rhlist interface */
276 test_rht_params.nulls_base = 0;
277 err = rhltable_init(&rhlt, &test_rht_params);
278 if (WARN_ON(err))
279 goto out_free;
280
281 k = prandom_u32();
282 ret = 0;
283 for (i = 0; i < entries; i++) {
284 rhl_test_objects[i].value.id = k;
285 err = rhltable_insert(&rhlt, &rhl_test_objects[i].list_node,
286 test_rht_params);
287 if (WARN(err, "error %d on element %d\n", err, i))
288 break;
289 if (err == 0)
290 set_bit(i, obj_in_table);
291 }
292
293 if (err)
294 ret = err;
295
296 pr_info("test %d add/delete pairs into rhlist\n", entries);
297 for (i = 0; i < entries; i++) {
298 struct rhlist_head *h, *pos;
299 struct test_obj_rhl *obj;
300 struct test_obj_val key = {
301 .id = k,
302 };
303 bool found;
304
305 rcu_read_lock();
306 h = rhltable_lookup(&rhlt, &key, test_rht_params);
307 if (WARN(!h, "key not found during iteration %d of %d", i, entries)) {
308 rcu_read_unlock();
309 break;
310 }
311
312 if (i) {
313 j = i - 1;
314 rhl_for_each_entry_rcu(obj, pos, h, list_node) {
315 if (WARN(pos == &rhl_test_objects[j].list_node, "old element found, should be gone"))
316 break;
317 }
318 }
319
320 cond_resched_rcu();
321
322 found = false;
323
324 rhl_for_each_entry_rcu(obj, pos, h, list_node) {
325 if (pos == &rhl_test_objects[i].list_node) {
326 found = true;
327 break;
328 }
329 }
330
331 rcu_read_unlock();
332
333 if (WARN(!found, "element %d not found", i))
334 break;
335
336 err = rhltable_remove(&rhlt, &rhl_test_objects[i].list_node, test_rht_params);
337 WARN(err, "rhltable_remove: err %d for iteration %d\n", err, i);
338 if (err == 0)
339 clear_bit(i, obj_in_table);
340 }
341
342 if (ret == 0 && err)
343 ret = err;
344
345 for (i = 0; i < entries; i++) {
346 WARN(test_bit(i, obj_in_table), "elem %d allegedly still present", i);
347
348 err = rhltable_insert(&rhlt, &rhl_test_objects[i].list_node,
349 test_rht_params);
350 if (WARN(err, "error %d on element %d\n", err, i))
351 break;
352 if (err == 0)
353 set_bit(i, obj_in_table);
354 }
355
356 pr_info("test %d random rhlist add/delete operations\n", entries);
357 for (j = 0; j < entries; j++) {
358 u32 i = prandom_u32_max(entries);
359 u32 prand = prandom_u32();
360
361 cond_resched();
362
363 if (prand == 0)
364 prand = prandom_u32();
365
366 if (prand & 1) {
367 prand >>= 1;
368 continue;
369 }
370
371 err = rhltable_remove(&rhlt, &rhl_test_objects[i].list_node, test_rht_params);
372 if (test_bit(i, obj_in_table)) {
373 clear_bit(i, obj_in_table);
374 if (WARN(err, "cannot remove element at slot %d", i))
375 continue;
376 } else {
377 if (WARN(err != -ENOENT, "removed non-existant element %d, error %d not %d",
378 i, err, -ENOENT))
379 continue;
380 }
381
382 if (prand & 1) {
383 prand >>= 1;
384 continue;
385 }
386
387 err = rhltable_insert(&rhlt, &rhl_test_objects[i].list_node, test_rht_params);
388 if (err == 0) {
389 if (WARN(test_and_set_bit(i, obj_in_table), "succeeded to insert same object %d", i))
390 continue;
391 } else {
392 if (WARN(!test_bit(i, obj_in_table), "failed to insert object %d", i))
393 continue;
394 }
395
396 if (prand & 1) {
397 prand >>= 1;
398 continue;
399 }
400
401 i = prandom_u32_max(entries);
402 if (test_bit(i, obj_in_table)) {
403 err = rhltable_remove(&rhlt, &rhl_test_objects[i].list_node, test_rht_params);
404 WARN(err, "cannot remove element at slot %d", i);
405 if (err == 0)
406 clear_bit(i, obj_in_table);
407 } else {
408 err = rhltable_insert(&rhlt, &rhl_test_objects[i].list_node, test_rht_params);
409 WARN(err, "failed to insert object %d", i);
410 if (err == 0)
411 set_bit(i, obj_in_table);
412 }
413 }
414
415 for (i = 0; i < entries; i++) {
416 cond_resched();
417 err = rhltable_remove(&rhlt, &rhl_test_objects[i].list_node, test_rht_params);
418 if (test_bit(i, obj_in_table)) {
419 if (WARN(err, "cannot remove element at slot %d", i))
420 continue;
421 } else {
422 if (WARN(err != -ENOENT, "removed non-existant element, error %d not %d",
423 err, -ENOENT))
424 continue;
425 }
426 }
427
428 rhltable_destroy(&rhlt);
429 out_free:
430 vfree(rhl_test_objects);
431 vfree(obj_in_table);
432 return ret;
> 433 }
434
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 25659 bytes --]
^ permalink raw reply
* Re: software interrupts close to 100 with 9000 tc filter entries
From: Marco Berizzi @ 2017-09-19 14:57 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev
In-Reply-To: <1505829713.29839.57.camel@edumazet-glaptop3.roam.corp.google.com>
> Eric Dumazet wrote:
>
> On Tue, 2017-09-19 at 15:28 +0200, Marco Berizzi wrote:
>
> > Hi Folks,
> >
> > I'm running linux 4.12.10 x86_64 on a Slackware 14.2 64bit
> > as a simple 4 NIC router. Network throughput processed by
> > this machine is less than 200Mbit/s
> > The cpu model is Intel(R) Xeon(R) CPU 5160 @ 3.00GHz with
> > 2GB ram.
> >
> > I need to blacklist about 9000 single ip addresses.
> > This is the relevant script to blacklist these ip addresses:
> >
> > tc qdisc add dev eth0 ingress
> > tc qdisc add dev eth1 ingress
> >
> > while read -r line
> > do
> > tc filter add dev eth0 parent ffff: protocol ip prio 50 u32 match ip src $line action drop
> > tc filter add dev eth1 parent ffff: protocol ip prio 50 u32 match ip src $line action drop
> > done < blacklisted_ip_addresses
> >
> > After loading these ip addresses, the si (software interrupts)
> > number shown by top is always close to 100
> > If I delete the ingress qdisc on both the device, the si
> > fall down to less than 5
> >
> > Running the same script with 'only' 700 ip addresses is
> > flawless.
> >
> > Kindly I would like to ask if am I doing anything in
> > a wrong way or if the hardware is too old for this kind
> > of setup.
> >
> > I have selected the tc filter setup instead of netfilter
> > one, because I was reading this from iproute2/doc/actions:
> >
> > A side effect is that we can now get stateless firewalling to work with tc..
> > Essentially this is now an alternative to iptables.
> > I wont go into details of my dislike for iptables at times, but.
> > scalability is one of the main issues; however, if you need stateful
> > classification - use netfilter (for now).
> >
> > Any response are welcome
> > TIA
>
> Processing a list of 700 rules per incoming packet is not wise.
>
> Alternatives :
>
> * netfilter with IPSET : This probably can be done with one lookup in a
> table. Probably easiest way to setup.
>
> * BPF filter (XDP or TC )
Thanks Eric for the quick response.
For better performance (latency time and network throughput) which is the better
solution? netfilter with ipset or BPF?
^ permalink raw reply
* [RFC 1/1] net/smc: add SMC rendezvous protocol
From: Ursula Braun @ 2017-09-19 14:55 UTC (permalink / raw)
To: netdev; +Cc: hwippel, raspl, davem, ubraun
The SMC protocol [1] uses a rendezvous protocol to negotiate SMC
capability between peers. The current Linux implementation does not use
this rendezvous protocol and, thus, is not compliant to RFC7609 and
incompatible with other SMC implementations like in zOS. This patch adds
support for the SMC rendezvous protocol.
Details:
The SMC rendezvous protocol relies on the use of a new TCP experimental
option. With this option, SMC capabilities are exchanged between the
peers during the TCP three way handshake.
The goal of this patch is to leave common TCP code unmodified. Thus,
it uses netfilter hooks to intercept TCP SYN and SYN/ACK packets. For
outgoing packets originating from SMC sockets, the experimental option
is added. For inbound packets destined for SMC sockets, the experimental
option is checked.
Another goal was to minimize the performance impact on non-SMC traffic
(when SMC is enabled). The netfilter hooks used for SMC client
connections are active only during TCP connection establishment.
The netfilter hooks used for SMC servers are active as long as there are
listening SMC sockets.
When the hooks are active, the following additional operations are
performed on incoming and outgoing packets:
(1) call SMC netfilter hook (all IPv4 packets)
(2) check if TCP SYN or SYN/ACK packet (all IPv4 packets)
(3) check if packet goes to/comes from SMC socket (SYN & SYN/ACK
packets only)
(4) check/add SMC experimental option (SMC sockets' SYN & SYN/ACK
packets only)
References:
[1] SMC-R Informational RFC: http://www.rfc-editor.org/info/rfc7609
Signed-off-by: Hans Wippel <hwippel@linux.net.ibm.com>
Signed-off-by: Ursula Braun <ubraun@linux.vnet.ibm.com>
---
net/smc/Makefile | 2 +-
net/smc/af_smc.c | 66 ++++++-
net/smc/smc.h | 10 +-
net/smc/smc_rv.c | 542 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
net/smc/smc_rv.h | 31 ++++
5 files changed, 644 insertions(+), 7 deletions(-)
create mode 100644 net/smc/smc_rv.c
create mode 100644 net/smc/smc_rv.h
diff --git a/net/smc/Makefile b/net/smc/Makefile
index 188104654b54..2155a7eff41d 100644
--- a/net/smc/Makefile
+++ b/net/smc/Makefile
@@ -1,4 +1,4 @@
obj-$(CONFIG_SMC) += smc.o
obj-$(CONFIG_SMC_DIAG) += smc_diag.o
smc-y := af_smc.o smc_pnet.o smc_ib.o smc_clc.o smc_core.o smc_wr.o smc_llc.o
-smc-y += smc_cdc.o smc_tx.o smc_rx.o smc_close.o
+smc-y += smc_cdc.o smc_tx.o smc_rx.o smc_close.o smc_rv.o
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 8c6d24b2995d..6c280bbcd2fe 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -34,6 +34,7 @@
#include <net/smc.h>
#include "smc.h"
+#include "smc_rv.h"
#include "smc_clc.h"
#include "smc_llc.h"
#include "smc_cdc.h"
@@ -109,6 +110,7 @@ static int smc_release(struct socket *sock)
{
struct sock *sk = sock->sk;
struct smc_sock *smc;
+ int old_state;
int rc = 0;
if (!sk)
@@ -123,6 +125,7 @@ static int smc_release(struct socket *sock)
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
else
lock_sock(sk);
+ old_state = sk->sk_state;
if (smc->use_fallback) {
sk->sk_state = SMC_CLOSED;
@@ -132,6 +135,10 @@ static int smc_release(struct socket *sock)
sock_set_flag(sk, SOCK_DEAD);
sk->sk_shutdown |= SHUTDOWN_MASK;
}
+ if (old_state == SMC_LISTEN) {
+ smc_rv_nf_unregister_hook(sock_net(sk), &smc_nfho_serv);
+ kfree(smc->listen_pends);
+ }
if (smc->clcsock) {
sock_release(smc->clcsock);
smc->clcsock = NULL;
@@ -178,6 +185,7 @@ static struct sock *smc_sock_alloc(struct net *net, struct socket *sock)
sk->sk_destruct = smc_destruct;
sk->sk_protocol = SMCPROTO_SMC;
smc = smc_sk(sk);
+ smc->use_fallback = true; /* default: not SMC-capable */
INIT_WORK(&smc->tcp_listen_work, smc_tcp_listen_work);
INIT_LIST_HEAD(&smc->accept_q);
spin_lock_init(&smc->accept_q_lock);
@@ -386,6 +394,10 @@ static int smc_connect_rdma(struct smc_sock *smc)
int rc = 0;
u8 ibport;
+ if (smc->use_fallback)
+ /* peer has not signalled SMC-capability */
+ goto out_connected;
+
/* IPSec connections opt out of SMC-R optimizations */
if (using_ipsec(smc)) {
reason_code = SMC_CLC_DECL_IPSEC;
@@ -496,7 +508,6 @@ static int smc_connect_rdma(struct smc_sock *smc)
smc_tx_init(smc);
out_connected:
- smc_copy_sock_settings_to_clc(smc);
if (smc->sk.sk_state == SMC_INIT)
smc->sk.sk_state = SMC_ACTIVE;
@@ -551,7 +562,11 @@ static int smc_connect(struct socket *sock, struct sockaddr *addr,
}
smc_copy_sock_settings_to_clc(smc);
+ smc_rv_nf_register_hook(sock_net(sk), &smc_nfho_clnt);
+
rc = kernel_connect(smc->clcsock, addr, alen, flags);
+ if (rc != -EINPROGRESS)
+ smc_rv_nf_unregister_hook(sock_net(sk), &smc_nfho_clnt);
if (rc)
goto out;
@@ -570,10 +585,12 @@ static int smc_connect(struct socket *sock, struct sockaddr *addr,
static int smc_clcsock_accept(struct smc_sock *lsmc, struct smc_sock **new_smc)
{
+ struct smc_listen_pending *pnd;
struct sock *sk = &lsmc->sk;
struct socket *new_clcsock;
struct sock *new_sk;
- int rc;
+ unsigned long flags;
+ int i, rc;
release_sock(&lsmc->sk);
new_sk = smc_sock_alloc(sock_net(sk), NULL);
@@ -609,6 +626,25 @@ static int smc_clcsock_accept(struct smc_sock *lsmc, struct smc_sock **new_smc)
}
(*new_smc)->clcsock = new_clcsock;
+
+ /* enable SMC-capability if an SMC-capable connecting socket is
+ * contained in listen_pends; invalidate this entry
+ */
+ spin_lock_irqsave(&lsmc->listen_pends_lock, flags);
+ for (i = 0; i < 2 * lsmc->sk.sk_max_ack_backlog; i++) {
+ pnd = lsmc->listen_pends + i;
+ if (pnd->used &&
+ pnd->addr == new_clcsock->sk->sk_daddr &&
+ pnd->port == new_clcsock->sk->sk_dport &&
+ jiffies_to_msecs(get_jiffies_64() - pnd->time) <=
+ SMC_LISTEN_PEND_VALID_TIME) {
+ (*new_smc)->use_fallback = false;
+ pnd->used = false;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&lsmc->listen_pends_lock, flags);
+
out:
return rc;
}
@@ -755,6 +791,10 @@ static void smc_listen_work(struct work_struct *work)
u8 prefix_len;
u8 ibport;
+ if (new_smc->use_fallback)
+ /* peer has not signalled SMC-capability */
+ goto out_connected;
+
/* do inband token exchange -
*wait for and receive SMC Proposal CLC message
*/
@@ -927,7 +967,6 @@ static void smc_tcp_listen_work(struct work_struct *work)
continue;
new_smc->listen_smc = lsmc;
- new_smc->use_fallback = false; /* assume rdma capability first*/
sock_hold(&lsmc->sk); /* sock_put in smc_listen_work */
INIT_WORK(&new_smc->smc_listen_work, smc_listen_work);
smc_copy_sock_settings_to_smc(new_smc);
@@ -952,16 +991,32 @@ static int smc_listen(struct socket *sock, int backlog)
if ((sk->sk_state != SMC_INIT) && (sk->sk_state != SMC_LISTEN))
goto out;
+ rc = -ENOMEM;
+ /* Addresses and ports of incoming SYN packets with experimental option
+ * SMC are saved, but TCP might decide to drop them. Thus more slots
+ * than the backlog value are allocated for pending connecting sockets
+ */
+ smc->listen_pends = kzalloc(
+ 2 * backlog * sizeof(struct smc_listen_pending),
+ GFP_KERNEL);
+ if (!smc->listen_pends)
+ goto out;
+ spin_lock_init(&smc->listen_pends_lock);
+
rc = 0;
if (sk->sk_state == SMC_LISTEN) {
sk->sk_max_ack_backlog = backlog;
goto out;
}
+
+ smc->use_fallback = false; /* listen sockets are SMC-capable */
/* some socket options are handled in core, so we could not apply
* them to the clc socket -- copy smc socket options to clc socket
*/
smc_copy_sock_settings_to_clc(smc);
+ smc_rv_nf_register_hook(sock_net(sk), &smc_nfho_serv);
+
rc = kernel_listen(smc->clcsock, backlog);
if (rc)
goto out;
@@ -1112,7 +1167,7 @@ static unsigned int smc_poll(struct file *file, struct socket *sock,
struct sock *sk = sock->sk;
unsigned int mask = 0;
struct smc_sock *smc;
- int rc;
+ int rc = 0;
smc = smc_sk(sock->sk);
if ((sk->sk_state == SMC_INIT) || smc->use_fallback) {
@@ -1121,6 +1176,7 @@ static unsigned int smc_poll(struct file *file, struct socket *sock,
/* if non-blocking connect finished ... */
lock_sock(sk);
if ((sk->sk_state == SMC_INIT) && (mask & POLLOUT)) {
+ smc_rv_nf_unregister_hook(sock_net(sk), &smc_nfho_clnt);
sk->sk_err = smc->clcsock->sk->sk_err;
if (sk->sk_err) {
mask |= POLLERR;
@@ -1346,7 +1402,6 @@ static int smc_create(struct net *net, struct socket *sock, int protocol,
/* create internal TCP socket for CLC handshake and fallback */
smc = smc_sk(sk);
- smc->use_fallback = false; /* assume rdma capability first */
rc = sock_create_kern(net, PF_INET, SOCK_STREAM,
IPPROTO_TCP, &smc->clcsock);
if (rc)
@@ -1368,6 +1423,7 @@ static int __init smc_init(void)
{
int rc;
+ smc_rv_init();
rc = smc_pnet_init();
if (rc)
return rc;
diff --git a/net/smc/smc.h b/net/smc/smc.h
index 6e44313e4467..48097ca7a7fe 100644
--- a/net/smc/smc.h
+++ b/net/smc/smc.h
@@ -167,6 +167,13 @@ struct smc_connection {
struct work_struct close_work; /* peer sent some closing */
};
+struct smc_listen_pending {
+ u64 time; /* time when entry was created*/
+ bool used; /* true if entry is in use */
+ __be32 addr; /* address of a listen socket */
+ __be16 port; /* port of a listen socket */
+};
+
struct smc_sock { /* smc sock container */
struct sock sk;
struct socket *clcsock; /* internal tcp socket */
@@ -175,6 +182,8 @@ struct smc_sock { /* smc sock container */
struct smc_sock *listen_smc; /* listen parent */
struct work_struct tcp_listen_work;/* handle tcp socket accepts */
struct work_struct smc_listen_work;/* prepare new accept socket */
+ struct smc_listen_pending *listen_pends;/* listen pending SYNs */
+ spinlock_t listen_pends_lock; /* protects listen_pends */
struct list_head accept_q; /* sockets to be accepted */
spinlock_t accept_q_lock; /* protects accept_q */
struct delayed_work sock_put_work; /* final socket freeing */
@@ -271,5 +280,4 @@ int smc_conn_create(struct smc_sock *smc, __be32 peer_in_addr,
struct smc_clc_msg_local *lcl, int srv_first_contact);
struct sock *smc_accept_dequeue(struct sock *parent, struct socket *new_sock);
void smc_close_non_accepted(struct sock *sk);
-
#endif /* __SMC_H */
diff --git a/net/smc/smc_rv.c b/net/smc/smc_rv.c
new file mode 100644
index 000000000000..ae51e4120d7e
--- /dev/null
+++ b/net/smc/smc_rv.c
@@ -0,0 +1,542 @@
+/*
+ * Shared Memory Communications over RDMA (SMC-R) and RoCE
+ *
+ * SMC Rendezvous to determine SMC-capability of the peer
+ *
+ * Copyright IBM Corp. 2017
+ *
+ * Author(s): Hans Wippel <hwippel@linux.vnet.ibm.com>
+ * Ursula Braun <ubraun@linux.vnet.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/tcp.h>
+
+#include "smc.h"
+#include "smc_rv.h"
+
+#define TCPOLEN_SMC 8
+#define TCPOLEN_SMC_BASE 6
+#define TCPOLEN_SMC_ALIGNED 2
+
+static const char TCPOPT_SMC_MAGIC[4] = {'\xe2', '\xd4', '\xc3', '\xd9'};
+
+/* in TCP header, replace EOL option and remaining header bytes with NOPs */
+static bool smc_rv_replace_eol_option(struct sk_buff *skb)
+{
+ struct tcphdr *tcph = tcp_hdr(skb);
+ int opt_bytes = tcp_optlen(skb);
+ unsigned char *buf;
+ int i = 0;
+
+ buf = (unsigned char *)(tcph + 1);
+ /* Parse TCP options. Based on tcp_parse_options in tcp_input.c */
+ while (i < opt_bytes) {
+ switch (buf[i]) {
+ /* one byte options */
+ case TCPOPT_EOL:
+ /* replace remaining bytes with NOPs */
+ while (i < opt_bytes) {
+ buf[i] = TCPOPT_NOP;
+ i++;
+ }
+ return true;
+ case TCPOPT_NOP:
+ i++;
+ continue;
+ default:
+ /* multi-byte options */
+ if (buf[i + 1] < 2 || i + buf[i + 1] > opt_bytes)
+ return false; /* bad option */
+ i += buf[i + 1];
+ continue;
+ }
+ }
+ return true;
+}
+
+/* check if TCP header contains SMC option */
+static bool smc_rv_has_smc_option(struct sk_buff *skb)
+{
+ struct tcphdr *tcph = tcp_hdr(skb);
+ int opt_bytes = tcp_optlen(skb);
+ unsigned char *buf;
+ int i = 0;
+
+ buf = (unsigned char *)(tcph + 1);
+ /* Parse TCP options. Based on tcp_parse_options in tcp_input.c */
+ while (i < opt_bytes) {
+ switch (buf[i]) {
+ /* one byte options */
+ case TCPOPT_EOL:
+ return 0;
+ case TCPOPT_NOP:
+ i++;
+ continue;
+ default:
+ /* multi-byte options */
+ if (buf[i + 1] < 2)
+ return 0; /* bad option */
+ /* check for SMC rendezvous option */
+ if (buf[i] == TCPOPT_EXP &&
+ buf[i + 1] == TCPOLEN_SMC_BASE &&
+ (opt_bytes - i >= TCPOLEN_SMC_BASE) &&
+ !memcmp(&buf[i + 2], TCPOPT_SMC_MAGIC,
+ sizeof(TCPOPT_SMC_MAGIC)))
+ return true;
+ i += buf[i + 1];
+ continue;
+ }
+ }
+
+ return false;
+}
+
+/* Add SMC option to TCP header. Note: This assumes that there are no data after
+ * the TCP header.
+ */
+static int smc_rv_add_smc_option(struct sk_buff *skb)
+{
+ unsigned char smc_opt[] = {TCPOPT_NOP, TCPOPT_NOP,
+ TCPOPT_EXP, TCPOLEN_SMC_BASE,
+ TCPOPT_SMC_MAGIC[0], TCPOPT_SMC_MAGIC[1],
+ TCPOPT_SMC_MAGIC[2], TCPOPT_SMC_MAGIC[3]};
+ struct tcphdr *tcph = tcp_hdr(skb);
+ struct iphdr *iph = ip_hdr(skb);
+ int tcplen = 0;
+
+ if (skb_tailroom(skb) < TCPOLEN_SMC)
+ return -EFAULT;
+
+ if (((tcph->doff << 2) - sizeof(*tcph) + TCPOLEN_SMC) >
+ MAX_TCP_OPTION_SPACE)
+ return -EFAULT;
+
+ if (smc_rv_has_smc_option(skb))
+ return -EFAULT;
+
+ if (!smc_rv_replace_eol_option(skb))
+ return -EFAULT;
+
+ iph->tot_len = cpu_to_be16(be16_to_cpu(iph->tot_len) + TCPOLEN_SMC);
+ iph->check = 0;
+ iph->check = ip_fast_csum(iph, iph->ihl);
+ skb_put_data(skb, smc_opt, TCPOLEN_SMC);
+ tcph->doff += TCPOLEN_SMC_ALIGNED;
+ tcplen = (skb->len - ip_hdrlen(skb));
+ tcph->check = 0;
+ tcph->check = tcp_v4_check(tcplen, iph->saddr, iph->daddr,
+ csum_partial(tcph, tcplen, 0));
+ skb->ip_summed = CHECKSUM_NONE;
+ return 0;
+}
+
+/* return an smc socket with certain source and destination */
+static struct smc_sock *smc_rv_lookup_connecting_smc(struct net *net,
+ __be32 dest_addr,
+ __be16 dest_port,
+ __be32 source_addr,
+ __be16 source_port)
+{
+ struct smc_sock *smc = NULL;
+ struct hlist_head *head;
+ struct socket *clcsock;
+ struct sock *sk;
+
+ read_lock(&smc_proto.h.smc_hash->lock);
+ head = &smc_proto.h.smc_hash->ht;
+
+ if (hlist_empty(head))
+ goto out;
+
+ sk_for_each(sk, head) {
+ if (!net_eq(sock_net(sk), net))
+ continue;
+ if (sk->sk_state != SMC_INIT)
+ continue;
+ clcsock = smc_sk(sk)->clcsock;
+ if (!clcsock)
+ continue;
+ if (source_port != htons(clcsock->sk->sk_num))
+ continue;
+ if (source_addr != clcsock->sk->sk_rcv_saddr)
+ continue;
+ if (dest_port != clcsock->sk->sk_dport)
+ continue;
+ if (dest_addr == clcsock->sk->sk_daddr) {
+ smc = smc_sk(sk);
+ break;
+ }
+ }
+
+out:
+ read_unlock(&smc_proto.h.smc_hash->lock);
+ return smc;
+}
+
+/* for netfilter smc_rv_hook_out_clnt (outgoing SYN):
+ * check if there exists a connecting smc socket with certain source and
+ * destination
+ */
+static bool smc_rv_exists_connecting_smc(struct net *net,
+ __be32 dest_addr,
+ __be16 dest_port,
+ __be32 source_addr,
+ __be16 source_port)
+{
+ return (smc_rv_lookup_connecting_smc(net, dest_addr, dest_port,
+ source_addr, source_port) ?
+ true : false);
+}
+
+/* for netfilter smc_rv_hook_in_clnt (incoming SYN ACK):
+ * enable SMC-capability for the corresponding socket
+ */
+static void smc_rv_accepting_smc_peer(struct net *net,
+ __be32 dest_addr,
+ __be16 dest_port,
+ __be32 source_addr,
+ __be16 source_port)
+{
+ struct smc_sock *smc;
+
+ smc = smc_rv_lookup_connecting_smc(net, dest_addr, dest_port,
+ source_addr, source_port);
+ if (smc)
+ /* connection is SMC-capable */
+ smc->use_fallback = false;
+}
+
+/* return an smc socket listening on a certain port */
+static struct smc_sock *smc_rv_lookup_listen_socket(struct net *net,
+ __be32 listen_addr,
+ __be16 listen_port)
+{
+ struct smc_sock *smc = NULL;
+ struct hlist_head *head;
+ struct socket *clcsock;
+ struct sock *sk;
+
+ read_lock(&smc_proto.h.smc_hash->lock);
+ head = &smc_proto.h.smc_hash->ht;
+
+ if (hlist_empty(head))
+ goto out;
+
+ sk_for_each(sk, head) {
+ if (!net_eq(sock_net(sk), net))
+ continue;
+ if (sk->sk_state != SMC_LISTEN)
+ continue;
+ clcsock = smc_sk(sk)->clcsock;
+ if (listen_port != htons(clcsock->sk->sk_num))
+ continue;
+ if (!listen_addr || !clcsock->sk->sk_rcv_saddr ||
+ listen_addr == clcsock->sk->sk_rcv_saddr) {
+ smc = smc_sk(sk);
+ break;
+ }
+ }
+
+out:
+ read_unlock(&smc_proto.h.smc_hash->lock);
+ return smc;
+}
+
+/* for netfilter smc_rv_hook_in_serv (incoming SYN):
+ * save addr and port of connecting smc peer
+ */
+static void smc_rv_connecting_smc_peer(struct net *net,
+ __be32 listen_addr,
+ __be16 listen_port,
+ __be32 peer_addr,
+ __be16 peer_port)
+{
+ struct smc_listen_pending *pnd;
+ struct smc_sock *lsmc;
+ unsigned long flags;
+ int i;
+
+ lsmc = smc_rv_lookup_listen_socket(net, listen_addr, listen_port);
+ if (!lsmc)
+ return;
+
+ spin_lock_irqsave(&lsmc->listen_pends_lock, flags);
+ for (i = 0; i < 2 * lsmc->sk.sk_max_ack_backlog; i++) {
+ pnd = lsmc->listen_pends + i;
+ /* either use an unused entry or reuse an outdated entry */
+ if (!pnd->used ||
+ jiffies_to_msecs(get_jiffies_64() - pnd->time) >
+ SMC_LISTEN_PEND_VALID_TIME) {
+ pnd->used = true;
+ pnd->addr = peer_addr;
+ pnd->port = peer_port;
+ pnd->time = get_jiffies_64();
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&lsmc->listen_pends_lock, flags);
+}
+
+/* for netfilter smc_rv_hook_out_serv (outgoing SYN/ACK):
+ * remove listen_pends entry of connecting smc peer in case of a problem
+ */
+static void smc_rv_remove_smc_peer(struct net *net,
+ __be32 listen_addr,
+ __be16 listen_port,
+ __be32 peer_addr,
+ __be16 peer_port)
+{
+ struct smc_listen_pending *pnd;
+ struct smc_sock *lsmc;
+ unsigned long flags;
+ int i;
+
+ lsmc = smc_rv_lookup_listen_socket(net, listen_addr, listen_port);
+ if (!lsmc)
+ return;
+
+ spin_lock_irqsave(&lsmc->listen_pends_lock, flags);
+ for (i = 0; i < 2 * lsmc->sk.sk_max_ack_backlog; i++) {
+ pnd = lsmc->listen_pends + i;
+ if (pnd->used &&
+ pnd->addr == peer_addr &&
+ pnd->port == peer_port &&
+ jiffies_to_msecs(get_jiffies_64() - pnd->time) <=
+ SMC_LISTEN_PEND_VALID_TIME) {
+ pnd->used = false;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&lsmc->listen_pends_lock, flags);
+}
+
+/* for netfilter smc_rv_hook_out_serv (outgoing SYN ACK):
+ * check if there has been a connecting smc peer
+ */
+static bool smc_rv_exists_connecting_smc_peer(struct net *net,
+ __be32 listen_addr,
+ __be16 listen_port,
+ __be32 peer_addr,
+ __be16 peer_port)
+{
+ struct smc_listen_pending *pnd;
+ struct smc_sock *lsmc;
+ unsigned long flags;
+ int i;
+
+ lsmc = smc_rv_lookup_listen_socket(net, listen_addr, listen_port);
+ if (!lsmc)
+ return false;
+
+ spin_lock_irqsave(&lsmc->listen_pends_lock, flags);
+ for (i = 0; i < 2 * lsmc->sk.sk_max_ack_backlog; i++) {
+ pnd = lsmc->listen_pends + i;
+ if (pnd->used &&
+ pnd->addr == peer_addr &&
+ pnd->port == peer_port &&
+ jiffies_to_msecs(get_jiffies_64() - pnd->time) <=
+ SMC_LISTEN_PEND_VALID_TIME) {
+ spin_unlock_irqrestore(&lsmc->listen_pends_lock, flags);
+ return true;
+ }
+ }
+ spin_unlock_irqrestore(&lsmc->listen_pends_lock, flags);
+ return false;
+}
+
+/* Netfilter hooks */
+
+/* netfilter hook for incoming packets (client) */
+static unsigned int smc_rv_hook_in_clnt(void *priv, struct sk_buff *skb,
+ const struct nf_hook_state *state)
+{
+ struct tcphdr *tcph = tcp_hdr(skb);
+ struct iphdr *iph;
+
+ if (skb_headlen(skb) - sizeof(*iph) < sizeof(*tcph))
+ return NF_ACCEPT;
+
+ iph = ip_hdr(skb);
+ if (iph->protocol != IPPROTO_TCP)
+ return NF_ACCEPT;
+
+ /* Local SMC client, incoming SYN,ACK from server
+ * check if there really is a local SMC client
+ * and tell the client connection if the server is SMC capable
+ */
+ if (tcph->syn == 1 && tcph->ack == 1) {
+ /* check for experimental option */
+ if (!smc_rv_has_smc_option(skb))
+ return NF_ACCEPT;
+ /* add info about server SMC capability */
+ smc_rv_accepting_smc_peer(state->net, iph->saddr, tcph->source,
+ iph->daddr, tcph->dest);
+ }
+ return NF_ACCEPT;
+}
+
+/* netfilter hook for incoming packets (server) */
+static unsigned int smc_rv_hook_in_serv(void *priv, struct sk_buff *skb,
+ const struct nf_hook_state *state)
+{
+ struct tcphdr *tcph = tcp_hdr(skb);
+ struct iphdr *iph;
+
+ if (skb_headlen(skb) - sizeof(*iph) < sizeof(*tcph))
+ return NF_ACCEPT;
+
+ iph = ip_hdr(skb);
+ if (iph->protocol != IPPROTO_TCP)
+ return NF_ACCEPT;
+
+ /* Local SMC Server, incoming SYN request from client
+ * check if there is a local SMC server
+ * and tell the server if there is a new SMC capable client
+ */
+ if (tcph->syn == 1 && tcph->ack == 0) {
+ /* check for experimental option */
+ if (!smc_rv_has_smc_option(skb))
+ return NF_ACCEPT;
+ /* add info about new client SMC capability */
+ smc_rv_connecting_smc_peer(state->net, iph->daddr, tcph->dest,
+ iph->saddr, tcph->source);
+ }
+ return NF_ACCEPT;
+}
+
+/* netfilter hook for outgoing packets (client) */
+static unsigned int smc_rv_hook_out_clnt(void *priv, struct sk_buff *skb,
+ const struct nf_hook_state *state)
+{
+ struct tcphdr *tcph = tcp_hdr(skb);
+ struct iphdr *iph;
+
+ if (skb_headlen(skb) - sizeof(*iph) < sizeof(*tcph))
+ return NF_ACCEPT;
+
+ iph = ip_hdr(skb);
+ if (iph->protocol != IPPROTO_TCP)
+ return NF_ACCEPT;
+
+ /* Local SMC client, outgoing SYN request to server
+ * add TCP experimental option if there really is a local SMC client
+ */
+ if (tcph->syn == 1 && tcph->ack == 0) {
+ /* check for local SMC client */
+ if (!smc_rv_exists_connecting_smc(state->net,
+ iph->daddr, tcph->dest,
+ iph->saddr, tcph->source))
+ return NF_ACCEPT;
+ /* add experimental option */
+ smc_rv_add_smc_option(skb);
+ }
+ return NF_ACCEPT;
+}
+
+/* netfilter hook for outgoing packets (server) */
+static unsigned int smc_rv_hook_out_serv(void *priv, struct sk_buff *skb,
+ const struct nf_hook_state *state)
+{
+ struct tcphdr *tcph = tcp_hdr(skb);
+ struct iphdr *iph;
+
+ if (skb_headlen(skb) - sizeof(*iph) < sizeof(*tcph))
+ return NF_ACCEPT;
+
+ iph = ip_hdr(skb);
+ if (iph->protocol != IPPROTO_TCP)
+ return NF_ACCEPT;
+
+ /* Local SMC server, outgoing SYN,ACK to client
+ * add TCP experimental option if there really is a local SMC server
+ */
+ if (tcph->syn == 1 && tcph->ack == 1) {
+ /* check if client's SYN contained the experimental option */
+ if (!smc_rv_exists_connecting_smc_peer(state->net,
+ iph->saddr, tcph->source,
+ iph->daddr, tcph->dest))
+ return NF_ACCEPT;
+ /* add experimental option */
+ if (smc_rv_add_smc_option(skb) < 0)
+ smc_rv_remove_smc_peer(state->net,
+ iph->saddr, tcph->source,
+ iph->daddr, tcph->dest);
+ }
+ return NF_ACCEPT;
+}
+
+static struct nf_hook_ops smc_nfho_ops_clnt[] = {
+ {
+ .hook = smc_rv_hook_in_clnt,
+ .hooknum = NF_INET_PRE_ROUTING,
+ .pf = PF_INET,
+ .priority = NF_IP_PRI_FIRST,
+ },
+ {
+ .hook = smc_rv_hook_out_clnt,
+ .hooknum = NF_INET_POST_ROUTING,
+ .pf = PF_INET,
+ .priority = NF_IP_PRI_FIRST,
+ },
+};
+
+static struct nf_hook_ops smc_nfho_ops_serv[] = {
+ {
+ .hook = smc_rv_hook_in_serv,
+ .hooknum = NF_INET_PRE_ROUTING,
+ .pf = PF_INET,
+ .priority = NF_IP_PRI_FIRST,
+ },
+ {
+ .hook = smc_rv_hook_out_serv,
+ .hooknum = NF_INET_POST_ROUTING,
+ .pf = PF_INET,
+ .priority = NF_IP_PRI_FIRST,
+ },
+};
+
+struct smc_nf_hook smc_nfho_clnt = {
+ .refcount = 0,
+ .hook = &smc_nfho_ops_clnt[0],
+};
+
+struct smc_nf_hook smc_nfho_serv = {
+ .refcount = 0,
+ .hook = &smc_nfho_ops_serv[0],
+};
+
+int smc_rv_nf_register_hook(struct net *net, struct smc_nf_hook *nfho)
+{
+ int rc = 0;
+
+ mutex_lock(&nfho->nf_hook_mutex);
+ if (!(nfho->refcount++)) {
+ rc = nf_register_net_hooks(net, nfho->hook, 2);
+ if (rc)
+ nfho->refcount--;
+ }
+ mutex_unlock(&nfho->nf_hook_mutex);
+ return rc;
+}
+
+void smc_rv_nf_unregister_hook(struct net *net, struct smc_nf_hook *nfho)
+{
+ mutex_lock(&nfho->nf_hook_mutex);
+ if (!(--nfho->refcount))
+ nf_unregister_net_hooks(net, nfho->hook, 2);
+ mutex_unlock(&nfho->nf_hook_mutex);
+}
+
+void __init smc_rv_init(void)
+{
+ mutex_init(&smc_nfho_clnt.nf_hook_mutex);
+ mutex_init(&smc_nfho_serv.nf_hook_mutex);
+}
diff --git a/net/smc/smc_rv.h b/net/smc/smc_rv.h
new file mode 100644
index 000000000000..d0aa9bc98a46
--- /dev/null
+++ b/net/smc/smc_rv.h
@@ -0,0 +1,31 @@
+/*
+ * Shared Memory Communications over RDMA (SMC-R) and RoCE
+ *
+ * Definitions for SMC Rendezvous - SMC capability checking
+ *
+ * Copyright IBM Corp. 2017
+ *
+ * Author(s): Hans Wippel <hwippel@linux.vnet.ibm.com>
+ * Ursula Braun <ubraun@linux.vnet.ibm.com>
+ */
+
+#ifndef _SMC_RV_H
+#define _SMC_RV_H
+
+#include <linux/netfilter.h>
+
+#define SMC_LISTEN_PEND_VALID_TIME (600 * HZ)
+
+struct smc_nf_hook {
+ struct mutex nf_hook_mutex; /* serialize nf register ops */
+ int refcount;
+ struct nf_hook_ops *hook;
+};
+
+extern struct smc_nf_hook smc_nfho_clnt;
+extern struct smc_nf_hook smc_nfho_serv;
+
+int smc_rv_nf_register_hook(struct net *net, struct smc_nf_hook *nfho);
+void smc_rv_nf_unregister_hook(struct net *net, struct smc_nf_hook *nfho);
+void smc_rv_init(void) __init;
+#endif
--
2.13.5
^ permalink raw reply related
* Re: [PATCH net-next v2 12/12] net: dsa: bcm_sf2: Utilize b53_{enable,disable}_port
From: Vivien Didelot @ 2017-09-19 14:45 UTC (permalink / raw)
To: Florian Fainelli, netdev; +Cc: andrew, davem, Florian Fainelli
In-Reply-To: <20170919021947.8971-13-f.fainelli@gmail.com>
Florian Fainelli <f.fainelli@gmail.com> writes:
> Export b53_{enable,disable}_port and use these two functions in
> bcm_sf2_port_setup and bcm_sf2_port_disable. The generic functions
> cannot be used without wrapping because we need to manage additional
> switch integration details (PHY, Broadcom tag etc.).
>
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Reviewed-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
^ permalink raw reply
* Re: [RFC net-next v2] bridge lwtunnel, VPLS & NVGRE
From: Amine Kherbouche @ 2017-09-19 14:46 UTC (permalink / raw)
To: David Lamparter, netdev, bridge; +Cc: roopa, stephen
In-Reply-To: <6a538120-1941-7e81-c942-e97adeff2e3d@6wind.com>
Hi David,
What's next ? do you plan to send a v3 or should I do it ?
On 09/11/2017 10:02 AM, Amine Kherbouche wrote:
> Hi David,
>
> Do you plan to send a v3?
>
> On 21/08/2017 18:15, David Lamparter wrote:
>> Hi all,
>>
>>
>> this is an update on the earlier "[RFC net-next] VPLS support". Note
>> I've changed the subject lines on some of the patches to better reflect
>> what they really do (tbh the earlier subject lines were crap.)
>>
>> As previously, iproute2 / FRR patches are at:
>> - https://github.com/eqvinox/vpls-iproute2
>> - https://github.com/opensourcerouting/frr/commits/vpls
>> while this patchset is also available at:
>> - https://github.com/eqvinox/vpls-linux-kernel
>> (but please be aware that I'm amending and rebasing commits)
^ permalink raw reply
* Re: [PATCH net-next v2 11/12] net: dsa: bcm_sf2: Use SF2_NUM_EGRESS_QUEUES for CFP
From: Vivien Didelot @ 2017-09-19 14:42 UTC (permalink / raw)
To: Florian Fainelli, netdev; +Cc: andrew, davem, Florian Fainelli
In-Reply-To: <20170919021947.8971-12-f.fainelli@gmail.com>
Florian Fainelli <f.fainelli@gmail.com> writes:
> The magic number 8 in 3 locations in bcm_sf2_cfp.c actually designates the
> number of switch port egress queues, so use that define instead of open-coding
> it.
>
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Reviewed-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
^ permalink raw reply
* Re: [PATCH net-next v2 10/12] net: dsa: b53: Export b53_imp_vlan_setup()
From: Vivien Didelot @ 2017-09-19 14:41 UTC (permalink / raw)
To: Florian Fainelli, netdev; +Cc: andrew, davem, Florian Fainelli
In-Reply-To: <20170919021947.8971-11-f.fainelli@gmail.com>
Florian Fainelli <f.fainelli@gmail.com> writes:
> bcm_sf2 and b53 do exactly the same thing, so share that piece.
>
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Reviewed-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
^ permalink raw reply
* Re: [PATCH RFC V1 net-next 0/6] Time based packet transmission
From: Miroslav Lichvar @ 2017-09-19 14:43 UTC (permalink / raw)
To: Richard Cochran
Cc: netdev, Andre Guedes, Henrik Austad, linux-kernel,
Jesus Sanchez-Palencia, intel-wired-lan, John Stultz,
Thomas Gleixner, Anna-Maria Gleixner, David Miller
In-Reply-To: <cover.1505719061.git.rcochran@linutronix.de>
On Mon, Sep 18, 2017 at 09:41:15AM +0200, Richard Cochran wrote:
> This series is an early RFC that introduces a new socket option
> allowing time based transmission of packets. This option will be
> useful in implementing various real time protocols over Ethernet,
> including but not limited to P802.1Qbv, which is currently finding
> its way into 802.1Q.
If I understand it correctly, this also allows us to make a PTP/NTP
"one-step" clock with HW that doesn't support it directly.
> * Open questions about SO_TXTIME semantics
>
> - What should the kernel do if the dialed Tx time is in the past?
> Should the packet be sent ASAP, or should we throw an error?
Dropping the packet with an error would make more sense to me.
> - What should the timescale be for the dialed Tx time? Should the
> kernel select UTC when using the SW Qdisc and the HW time
> otherwise? Or should the socket option include a clockid_t?
I think for applications that don't (want to) bind their socket to a
specific interface it would be useful if the cmsg specified clockid_t
or maybe if_index. If the packet would be sent using a different
PHC/interface, it should be dropped.
> | | plain preempt_rt | so_txtime | txtime @ 250 us |
> |---------+------------------+---------------+-----------------|
> | min: | +1.940800e+04 | +4.720000e+02 | +4.720000e+02 |
> | max: | +7.556000e+04 | +5.680000e+02 | +5.760000e+02 |
> | pk-pk: | +5.615200e+04 | +9.600000e+01 | +1.040000e+02 |
> | mean: | +3.292776e+04 | +5.072274e+02 | +5.073602e+02 |
> | stddev: | +6.514709e+03 | +1.310849e+01 | +1.507144e+01 |
> | count: | 600000 | 600000 | 2400000 |
>
> Using so_txtime, the peak to peak jitter is about 100 nanoseconds,
Nice!
--
Miroslav Lichvar
^ permalink raw reply
* Re: [PATCH net-next v2 09/12] net: dsa: b53: Wire-up EEE
From: Vivien Didelot @ 2017-09-19 14:37 UTC (permalink / raw)
To: Florian Fainelli, netdev; +Cc: andrew, davem, Florian Fainelli
In-Reply-To: <20170919021947.8971-10-f.fainelli@gmail.com>
Florian Fainelli <f.fainelli@gmail.com> writes:
> Add support for enabling and disabling EEE, as well as re-negotiating it in
> .adjust_link() and in .port_enable().
>
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Reviewed-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
^ permalink raw reply
* Re: [PATCH net-next v2 08/12] net: dsa: b53: Move EEE functions to b53
From: Vivien Didelot @ 2017-09-19 14:34 UTC (permalink / raw)
To: Florian Fainelli, netdev; +Cc: andrew, davem, Florian Fainelli
In-Reply-To: <20170919021947.8971-9-f.fainelli@gmail.com>
Florian Fainelli <f.fainelli@gmail.com> writes:
> Move the bcm_sf2 EEE-related functions to the b53 driver because this is shared
> code amongst Gigabit capable switch, only 5325 and 5365 are too old to support
> that.
>
> Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Reviewed-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
^ permalink raw reply
* RE: [PATCH net-next 05/12] net: dsa: b53: Use a macro to define I/O operations
From: Florian Fainelli @ 2017-09-19 14:29 UTC (permalink / raw)
To: Vivien Didelot, David Laight, netdev@vger.kernel.org
Cc: davem@davemloft.net, andrew@lunn.ch
In-Reply-To: <87tvzy93ew.fsf@weeman.i-did-not-set--mail-host-address--so-tickle-me>
On September 19, 2017 7:19:35 AM PDT, Vivien Didelot <vivien.didelot@savoirfairelinux.com> wrote:
>Hi David,
>
>David Laight <David.Laight@ACULAB.COM> writes:
>
>> From: Florian Fainelli
>>> Sent: 18 September 2017 22:41
>>> Instead of repeating the same pattern: acquire mutex, read/write,
>release
>>> mutex, define a macro: b53_build_op() which takes the type
>(read|write), I/O
>>> size, and value (scalar or pointer). This helps with fixing bugs
>that could
>>> exit (e.g: missing barrier, lock etc.).
>> ....
>>> +#define b53_build_op(type, op_size, val_type) \
>>> +static inline int b53_##type##op_size(struct b53_device *dev, u8
>page, \
>>> + u8 reg, val_type val) \
>>> +{ \
>>> + int ret; \
>>> + \
>>> + mutex_lock(&dev->reg_mutex); \
>>> + ret = dev->ops->type##op_size(dev, page, reg, val); \
>>> + mutex_unlock(&dev->reg_mutex); \
>>> + \
>>> + return ret; \
>>> }
>>
>> Why separate the 'type' and 'op_size' arguments since they
>> are always pasted together?
>
>For read/write48, the value type is u64.
The way I read David's comment is that instead of calling the macro with read, 48, just combine that in a single argument: read48. I don't have a preference about that and can respin eventually.
--
Florian
^ permalink raw reply
* RE: [PATCH net-next 05/12] net: dsa: b53: Use a macro to define I/O operations
From: Vivien Didelot @ 2017-09-19 14:19 UTC (permalink / raw)
To: David Laight, 'Florian Fainelli', netdev@vger.kernel.org
Cc: davem@davemloft.net, andrew@lunn.ch
In-Reply-To: <063D6719AE5E284EB5DD2968C1650D6DD007A003@AcuExch.aculab.com>
Hi David,
David Laight <David.Laight@ACULAB.COM> writes:
> From: Florian Fainelli
>> Sent: 18 September 2017 22:41
>> Instead of repeating the same pattern: acquire mutex, read/write, release
>> mutex, define a macro: b53_build_op() which takes the type (read|write), I/O
>> size, and value (scalar or pointer). This helps with fixing bugs that could
>> exit (e.g: missing barrier, lock etc.).
> ....
>> +#define b53_build_op(type, op_size, val_type) \
>> +static inline int b53_##type##op_size(struct b53_device *dev, u8 page, \
>> + u8 reg, val_type val) \
>> +{ \
>> + int ret; \
>> + \
>> + mutex_lock(&dev->reg_mutex); \
>> + ret = dev->ops->type##op_size(dev, page, reg, val); \
>> + mutex_unlock(&dev->reg_mutex); \
>> + \
>> + return ret; \
>> }
>
> Why separate the 'type' and 'op_size' arguments since they
> are always pasted together?
For read/write48, the value type is u64.
Thanks,
Vivien
^ permalink raw reply
* RE: [PATCH net 0/7] Bug fixes for the HNS3 Ethernet Driver for Hip08 SoC
From: Salil Mehta @ 2017-09-19 14:12 UTC (permalink / raw)
To: Leon Romanovsky
Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org,
Zhuangyuzeng (Yisen), lipeng (Y),
mehta.salil.lnk-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Linuxarm
In-Reply-To: <20170919035900.GI5788-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
Hi Leon,
> -----Original Message-----
> From: Leon Romanovsky [mailto:leon-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org]
> Sent: Tuesday, September 19, 2017 4:59 AM
> To: Salil Mehta
> Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org; Zhuangyuzeng (Yisen); lipeng (Y);
> mehta.salil.lnk-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org; netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; linux-
> kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org; Linuxarm
> Subject: Re: [PATCH net 0/7] Bug fixes for the HNS3 Ethernet Driver for
> Hip08 SoC
>
> On Tue, Sep 19, 2017 at 02:06:21AM +0100, Salil Mehta wrote:
> > This patch set presents some bug fixes for the HNS3 Ethernet driver,
> identified
> > during internal testing & stabilization efforts.
> >
> > This patch series is meant for Linux 4.14 kernel.
> >
> > Lipeng (6):
> > net: hns3: get phy addr from NCL_config
> > net: hns3: fix the command used to unmap ring from vector
> > net: hns3: Fix ring and vector map command
> > net: hns3: fix a bug of set mac address
> > net: hns3: set default vlan id to PF
> > net: hns3: Fixes the premature exit of loop when matching clients
> >
> > Salil Mehta (1):
> > net: hns3: fixes the ether address copy with more appropriate API
>
> 1. The fixes patches should have Fixes line and not all of them have
> (I didn't look all patches).
> 2. Please decide on one style: fixes vs. Fixes, fix vs. Fix in the
> titles
> 3. Subject should be descriptive and usable, I don't know if it applies
> to the "fix a bug of set mac address" patch.
Yes, missed these. Will fix them. Thanks!
Salil
>
> Thanks
>
> >
> > drivers/net/ethernet/hisilicon/hns3/hnae3.c | 43 +++++-------
> ----------
> > .../net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h | 8 +++-
> > .../ethernet/hisilicon/hns3/hns3pf/hclge_main.c | 20 ++++++++--
> > .../net/ethernet/hisilicon/hns3/hns3pf/hns3_enet.c | 7 ++--
> > 4 files changed, 35 insertions(+), 43 deletions(-)
> >
> > --
> > 2.11.0
> >
> >
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* RE: [PATCH net-next 5/5] tls: Add generic NIC offload infrastructure.
From: Boris Pismenny @ 2017-09-19 14:02 UTC (permalink / raw)
To: Hannes Frederic Sowa, Ilya Lesokhin
Cc: netdev@vger.kernel.org, davem@davemloft.net, davejwatson@fb.com,
tom@herbertland.com, Aviad Yehezkel, Liran Liss
In-Reply-To: <87wp4vt4aa.fsf@stressinduktion.org>
Hello,
Hannes Frederic Sowa <hannes@stressinduktion.org> writes:
> Hello,
>
> Ilya Lesokhin <ilyal@mellanox.com> writes:
>
> > Hannes Frederic Sowa <hannes@stressinduktion.org> writes:
> >
> >> The user should be aware of that they can't migrate the socket to
> >> another interface if they got hw offloaded. This is not the case for
> software offload.
> >> Thus I think the user has to opt in and it shouldn't be a heuristic
> >> until we can switch back to sw offload path.
> >>
> >> Maybe change flowi_oif to sk_bound_dev_if and somwhow lock it against
> >> further changes if hw tls is in use?
> >>
> >
> > I'm not sure I follow.
> > We do set sk->sk_bound_dev_if to prevent further changes.
> >
> > Do you recommend we enable TLS offload only if SO_BINDTODEVICE
> > was previously used on that socket?
> > and prevent even users with CAP_NET_RAW from unbinding it?
> >
> > I would rather avoid requiring CAP_NET_RAW to use TLS offload.
> > But admittedly I'm not sure setting sk->sk_bound_dev_if without
> > CAP_NET_RAW like we do is legit either.
> >
> > Finally, the reason we made HW offload the default is that the user
> > can use sudo ethtool -K enp0s4 tls-hw-tx-offload off to opt out of HW
> > offload and we currently don't have anything equivalent for opting out of
> SW KTLS.
>
> IMHO the decision if a TCP flow should be bounded to hw and thus never
> push traffic to another interface should a decision the administrator and the
> application should opt in. You might have your management application
> which is accessible over multiple interfaces and your production application
> which might want to use hw offloaded tls. Thus I don't think only a single
> ethtool knob will do it.
IMO the configuration knob should be at the kTLS level and not at the
HW vs. SW level. The management application shouldn't be using kTLS.
I'd like to view TLS offload similarly to LSO. The default is opt-in if
possible, and the Kernel decides that based on device capabilities.
>
> I agree that SO_BINDTODEVICE is bad for this use case. First, the
> CAP_NET_RAW limitation seems annoying and we don't want to enforce TLS
> apps to have this capability. Second, the user space application doesn't care
> which interface it should talk to (maybe?) but leave the routing decision to
> the kernel and just opt in to TLS. SO_BINDTODEVICE doesn't allow this.
>
> sk_bound_dev_if can be rebound later with CAP_NET_RAW privileges, will
> this be a problem?
Yes it is a problem and we have some ideas for a software fallback that should
catch this.
Is the software fallback a prerequisite for kTLS offload in Kernel?
>
> Have you thought how the user space will configure the various offloading
> features (sw, hw, none)? Will it in e.g. OpenSSL be part of the Cipher Spec or
> will there be new functions around SSL_CTX to do so?
>
> Maybe an enhancement of the TLS_TX setsockopt with a boolean for hw
> offload is a solution?
Yes, we think that OpenSSL should first configure whether it complies with
kTLS support. Next, we thought of using an environment variable to control
kTLS globally in OpenSSL as follows:
1. only software kTLS
2. only hardware kTLS - no fallback to software.
3. Try to use hardware kTLS and if it isn't supported fallback to software kTLS.
The above is something we plan for the future, assuming that kTLS wouldn't fit for
all use-cases. What do you think?
If you'd like to have more fine-grained control of kTLS, e.g. per socket,
then the application would need to be modified to configure that,
which is something we try to avoid.
>
> Another question:
>
> How is the dependency management done between socket layer and driver
> layer? It seems a bit cyclic but judging from this code you don't hold
> references to the device (dev_hold) (which is good, you don't want to have
> users creating refs to devices). OTOH you somehow need to match sockets
> from the device layer up to the socket. Will those be reference counted or
> does that work without?
Not sure I follow your question.
We use the socket from the device layer through the SKB that carries it,
so I think it should work without.
We don't attempt to perform a socket lookup or anything of this sort.
^ permalink raw reply
* Re: software interrupts close to 100 with 9000 tc filter entries
From: Eric Dumazet @ 2017-09-19 14:01 UTC (permalink / raw)
To: Marco Berizzi; +Cc: netdev
In-Reply-To: <1627070802.486441.1505827738125@mail.libero.it>
On Tue, 2017-09-19 at 15:28 +0200, Marco Berizzi wrote:
> Hi Folks,
>
> I'm running linux 4.12.10 x86_64 on a Slackware 14.2 64bit
> as a simple 4 NIC router. Network throughput processed by
> this machine is less than 200Mbit/s
> The cpu model is Intel(R) Xeon(R) CPU 5160 @ 3.00GHz with
> 2GB ram.
>
> I need to blacklist about 9000 single ip addresses.
> This is the relevant script to blacklist these ip addresses:
>
> tc qdisc add dev eth0 ingress
> tc qdisc add dev eth1 ingress
>
> while read -r line
> do
> tc filter add dev eth0 parent ffff: protocol ip prio 50 u32 match ip src $line action drop
> tc filter add dev eth1 parent ffff: protocol ip prio 50 u32 match ip src $line action drop
> done < blacklisted_ip_addresses
>
> After loading these ip addresses, the si (software interrupts)
> number shown by top is always close to 100
> If I delete the ingress qdisc on both the device, the si
> fall down to less than 5
>
> Running the same script with 'only' 700 ip addresses is
> flawless.
>
> Kindly I would like to ask if am I doing anything in
> a wrong way or if the hardware is too old for this kind
> of setup.
>
> I have selected the tc filter setup instead of netfilter
> one, because I was reading this from iproute2/doc/actions:
>
> A side effect is that we can now get stateless firewalling to work with tc..
> Essentially this is now an alternative to iptables.
> I wont go into details of my dislike for iptables at times, but.
> scalability is one of the main issues; however, if you need stateful
> classification - use netfilter (for now).
>
> Any response are welcome
> TIA
Processing a list of 700 rules per incoming packet is not wise.
Alternatives :
- netfilter with IPSET : This probably can be done with one lookup in a
table. Probably easiest way to setup.
- BPF filter (XDP or TC )
^ permalink raw reply
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