* Re: [PATCH] net: dsa: add missing phy address offset
From: Andrew Lunn @ 2019-02-21 13:10 UTC (permalink / raw)
To: Marcel Reichmuth
Cc: Florian Fainelli, linux-kernel@vger.kernel.org,
netdev@vger.kernel.org, vivien.didelot@gmail.com,
davem@davemloft.net
In-Reply-To: <20190221075333.t7vikxznp3l6ello@debian>
> Thank you very much for your hints. Yes that works indeed too. I
> just assumed it was intended to work automatically with the
> built-in phys as it does with the other switches I am using.
Hi Marcel
The basic assumption is there is a one to one mapping of port number
to PHY address. All the other Marvell switch have this mapping.
Since the needed flexibility exists to support this, and Marvell has
not repeated this odd design, i decided not to do anything about it in
code.
Andrew
^ permalink raw reply
* [PATCH] drivers: net: phy: mdio-mux: Add support for Generic Mux controls
From: Pankaj Bansal @ 2019-02-21 13:00 UTC (permalink / raw)
To: Leo Li, Peter Rosin, Andrew Lunn, Florian Fainelli,
Heiner Kallweit
Cc: netdev@vger.kernel.org, Pankaj Bansal
Add support for Generic Mux controls, when Mdio mux node is a consumer
of mux produced by some other device.
Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
---
drivers/net/phy/Kconfig | 1 +
drivers/net/phy/mdio-mux.c | 81 ++++++++++++++++++++++++++++++++++++
2 files changed, 82 insertions(+)
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 3d187cd50eb0..e0e6b2b33d6d 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -47,6 +47,7 @@ config MDIO_BITBANG
config MDIO_BUS_MUX
tristate
depends on OF_MDIO
+ select MULTIPLEXER
help
This module provides a driver framework for MDIO bus
multiplexers which connect one of several child MDIO busses
diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c
index 0a86f1e4c02f..c49e4ae9c174 100644
--- a/drivers/net/phy/mdio-mux.c
+++ b/drivers/net/phy/mdio-mux.c
@@ -11,6 +11,7 @@
#include <linux/of_mdio.h>
#include <linux/device.h>
#include <linux/module.h>
+#include <linux/mux/consumer.h>
#include <linux/phy.h>
#define DRV_DESCRIPTION "MDIO bus multiplexer driver"
@@ -35,6 +36,11 @@ struct mdio_mux_child_bus {
int bus_number;
};
+struct mdio_mux_state {
+ struct mux_control *muxc;
+ void *mux_handle;
+};
+
/*
* The parent bus' lock is used to order access to the switch_fn.
*/
@@ -208,6 +214,81 @@ void mdio_mux_uninit(void *mux_handle)
}
EXPORT_SYMBOL_GPL(mdio_mux_uninit);
+static int mdio_mux_switch_fn(int current_child, int desired_child, void *data)
+{
+ struct platform_device *pdev;
+ struct mdio_mux_state *s;
+ int ret = 0;
+
+ pdev = (struct platform_device *)data;
+ s = (struct mdio_mux_state *)platform_get_drvdata(pdev);
+ if (current_child ^ desired_child) {
+ if (current_child != -1)
+ ret = mux_control_deselect(s->muxc);
+ if (ret)
+ return ret;
+
+ ret = mux_control_select(s->muxc, desired_child);
+ if (!ret)
+ dev_dbg(&pdev->dev, "%s %d -> %d\n", __func__,
+ current_child, desired_child);
+ }
+
+ return ret;
+}
+
+static int mdio_mux_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mdio_mux_state *s;
+ int ret = 0;
+
+ s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
+
+ s->muxc = devm_mux_control_get(dev, NULL);
+ if (IS_ERR(s->muxc)) {
+ ret = PTR_ERR(s->muxc);
+ if (ret != -EPROBE_DEFER)
+ dev_err(&pdev->dev, "Failed to get mux: %d\n", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, s);
+
+ ret = mdio_mux_init(&pdev->dev, pdev->dev.of_node, mdio_mux_switch_fn,
+ &s->mux_handle, pdev, NULL);
+
+ return ret;
+}
+
+static int mdio_mux_remove(struct platform_device *pdev)
+{
+ struct mdio_mux_state *s = platform_get_drvdata(pdev);
+
+ mdio_mux_uninit(s->mux_handle);
+
+ return 0;
+}
+
+static const struct of_device_id mdio_mux_match[] = {
+ { .compatible = "mdio-mux", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mdio_mux_match);
+
+static struct platform_driver mdio_mux_driver = {
+ .driver = {
+ .name = "mdio-mux",
+ .of_match_table = mdio_mux_match,
+ },
+ .probe = mdio_mux_probe,
+ .remove = mdio_mux_remove,
+};
+
+module_platform_driver(mdio_mux_driver);
+
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_AUTHOR("David Daney");
MODULE_LICENSE("GPL");
--
2.17.1
^ permalink raw reply related
* [PATCH] dt-bindings: Add bindings for mdio mux consumers
From: Pankaj Bansal @ 2019-02-21 12:59 UTC (permalink / raw)
To: Leo Li, Peter Rosin, Andrew Lunn, Florian Fainelli,
Heiner Kallweit, Rob Herring, Mark Rutland
Cc: devicetree@vger.kernel.org, netdev@vger.kernel.org, Pankaj Bansal
When we use the bindings defined in Documentation/devicetree/bindings/mux
to define mdio mux in producer and consumer terms, it results in two
devices. one is mux producer and other is mux consumer.
Add the bindings needed for Mdio mux consumer devices.
Signed-off-by: Pankaj Bansal <pankaj.bansal@nxp.com>
---
.../devicetree/bindings/net/mdio-mux.txt | 73 ++++++++++++++++++
1 file changed, 73 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/mdio-mux.txt b/Documentation/devicetree/bindings/net/mdio-mux.txt
index f58571f36570..bd198d1c6f10 100644
--- a/Documentation/devicetree/bindings/net/mdio-mux.txt
+++ b/Documentation/devicetree/bindings/net/mdio-mux.txt
@@ -18,8 +18,16 @@ Required properties for child nodes:
- #size-cells = <0>;
- reg : The sub-bus number.
+Required properties when Mdio mux node is consumer of a separate mux producer
+node.
+- compatible : should be "mmio-mux"
+- mux-controls : mux controller node to use for operating the mux
+- mdio-parent-bus : phandle to the parent MDIO bus.
+for more information please refer Documentation/devicetree/bindings/mux/
+
Example :
+The mux Producer and consumer nodes are same.
/* The parent MDIO bus. */
smi1: mdio@1180000001900 {
@@ -127,3 +135,68 @@ Example :
};
};
};
+
+Example 2:
+In below example the Mux producer and consumer are separate nodes.
+
+&i2c0 {
+ fpga@66 { // fpga connected to i2c
+ compatible = "fsl,lx2160aqds-fpga", "fsl,fpga-qixis-i2c",
+ "simple-mfd";
+ reg = <0x66>;
+
+ mux: mux-controller { // Mux Producer
+ compatible = "reg-mux";
+ #mux-control-cells = <1>;
+ mux-reg-masks = <0x54 0xf8>, /* 0: reg 0x54, bits 7:3 */
+ <0x54 0x07>; /* 1: reg 0x54, bits 2:0 */
+ };
+ };
+};
+
+mdio-mux-1 { // Mux consumer
+ compatible = "mdio-mux";
+ mux-controls = <&mux 0>;
+ mdio-parent-bus = <&emdio1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mdio@0 {
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mdio@40 {
+ reg = <0x40>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ ..
+ ..
+};
+
+mdio-mux-2 { // Mux consumer
+ compatible = "mdio-mux";
+ mux-controls = <&mux 1>;
+ mdio-parent-bus = <&emdio2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mdio@0 {
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ mdio@1 {
+ reg = <0x1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ ..
+ ..
+};
+
--
2.17.1
^ permalink raw reply related
* Re: [PATCH bpf-next v2] bpf, seccomp: fix false positive preemption splat for cbpf->ebpf progs
From: Jann Horn @ 2019-02-21 12:56 UTC (permalink / raw)
To: Daniel Borkmann
Cc: Kees Cook, Alexei Starovoitov, Andy Lutomirski,
Alexei Starovoitov, Network Development
In-Reply-To: <f5231b6f-cc97-f3ea-3262-edea973f21e2@iogearbox.net>
On Thu, Feb 21, 2019 at 9:53 AM Daniel Borkmann <daniel@iogearbox.net> wrote:
> On 02/21/2019 06:31 AM, Kees Cook wrote:
> > On Wed, Feb 20, 2019 at 8:03 PM Alexei Starovoitov
> > <alexei.starovoitov@gmail.com> wrote:
> >>
> >> On Wed, Feb 20, 2019 at 3:59 PM Alexei Starovoitov
> >> <alexei.starovoitov@gmail.com> wrote:
> >>>
> >>> On Thu, Feb 21, 2019 at 12:01:35AM +0100, Daniel Borkmann wrote:
> >>>> In 568f196756ad ("bpf: check that BPF programs run with preemption disabled")
> >>>> a check was added for BPF_PROG_RUN() that for every invocation preemption is
> >>>> disabled to not break eBPF assumptions (e.g. per-cpu map). Of course this does
> >>>> not count for seccomp because only cBPF -> eBPF is loaded here and it does
> >>>> not make use of any functionality that would require this assertion. Fix this
> >>>> false positive by adding and using SECCOMP_RUN() variant that does not have
> >>>> the cant_sleep(); check.
> >>>>
> >>>> Fixes: 568f196756ad ("bpf: check that BPF programs run with preemption disabled")
> >>>> Reported-by: syzbot+8bf19ee2aa580de7a2a7@syzkaller.appspotmail.com
> >>>> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
> >>>> Acked-by: Kees Cook <keescook@chromium.org>
> >>>
> >>> Applied, Thanks
> >>
> >> Actually I think it's a wrong approach to go long term.
> >> I'm thinking to revert it.
> >> I think it's better to disable preemption for duration of
> >> seccomp cbpf prog.
> >> It's short and there is really no reason for it to be preemptible.
> >> When seccomp switches to ebpf we'll have this weird inconsistency.
> >> Let's just disable preemption for seccomp as well.
> >
> > A lot of changes will be needed for seccomp ebpf -- not the least of
> > which is convincing me there is a use-case. ;)
> >
> > But the main issue is that I'm not a huge fan of dropping two
> > barriers() across syscall entry. That seems pretty heavy-duty for
> > something that is literally not needed right now.
>
> Yeah, I think it's okay to add once actually technically needed. Last
> time I looked, if I recall correctly, at least Chrome installs some
> heavy duty seccomp programs that go close to prog limit.
Half of that is probably because that seccomp BPF code is so
inefficient, though.
This snippet shows that those programs constantly recheck the high
halves of arguments:
014e if args[1].high == 0x00000000: [true +3, false +0]
0153 if args[1].low == 0x00000003: [true +135, false +0] -> ret
ALLOW (syscalls: fcntl)
0155 if args[1].high == 0x00000000: [true +3, false +0]
015a if args[1].low == 0x00000001: [true +128, false +0] -> ret
ALLOW (syscalls: fcntl)
015c if args[1].high == 0x00000000: [true +3, false +0]
0161 if args[1].low == 0x00000002: [true +121, false +0] -> ret
ALLOW (syscalls: fcntl)
0163 if args[1].high == 0x00000000: [true +3, false +0]
0168 if args[1].low == 0x00000006: [true +114, false +0] ->
ret ALLOW (syscalls: fcntl)
016a if args[1].high == 0x00000000: [true +3, false +0]
016f if args[1].low == 0x00000007: [true +107, false +0] ->
ret ALLOW (syscalls: fcntl)
0171 if args[1].high == 0x00000000: [true +3, false +0]
0176 if args[1].low == 0x00000005: [true +100, false +0]
-> ret ALLOW (syscalls: fcntl)
0178 if args[1].high == 0x00000000: [true +3, false +0]
017d if args[1].low == 0x00000000: [true +93, false +0]
-> ret ALLOW (syscalls: fcntl)
017f if args[1].high == 0x00000000: [true +3, false +0]
0184 if args[1].low == 0x00000406: [true +86, false
+0] -> ret ALLOW (syscalls: fcntl)
0186 if args[1].high == 0x00000000: [true +3, false +0]
018b if args[1].low != 0x00000004: [true +80, false
+0] -> ret TRAP
018d if args[2].high != 0x00000000: [true +78, false
+0] -> ret TRAP
018f if args[2].low COMMON-BITS 0xffe363fc: [true
+76, false +75] -> ret TRAP
01db ret ALLOW (syscalls: fcntl)
Some of the generated code is pointless because all reachable code
from that point on has the same outcome (the last "ret ALLOW" in the
following sample is unreachable because they've already checked that
the high bit of the low half is set, so the low half can't be 3):
00c9 if args[0].low == 0x00000005: [true +16, false +0] ->
ret ALLOW (syscalls: clock_gettime, clock_getres)
00cb if args[0].high == 0x00000000: [true +3, false +0]
00d0 if args[0].low == 0x00000003: [true +9, false +0] ->
ret ALLOW (syscalls: clock_gettime, clock_getres)
01dc ret TRAP
00cc if args[0].high != 0xffffffff: [true +8, false +0] -> ret TRAP
00ce if args[0].low COMMON-BITS 0x80000000: [true +0, false +6]
00d0 if args[0].low == 0x00000003: [true +9, false +0] ->
ret ALLOW (syscalls: clock_gettime, clock_getres)
01dc ret TRAP
01d7 ret TRAP
^ permalink raw reply
* Re: [PATCH net-next 1/2] devlink: Rename devlink health attributes
From: Jiri Pirko @ 2019-02-21 12:31 UTC (permalink / raw)
To: Eran Ben Elisha; +Cc: netdev, David S. Miller, Jiri Pirko, Aya Levin
In-Reply-To: <1550751122-2788-2-git-send-email-eranbe@mellanox.com>
Thu, Feb 21, 2019 at 01:12:01PM CET, eranbe@mellanox.com wrote:
>From: Aya Levin <ayal@mellanox.com>
>
>Rename devlink health attributes for better reflect the attributes use.
>Add COUNT prefix on error counter attribute and recovery counter
>attribute.
>
>Fixes: 7afe335a8bed ("devlink: Add health get command")
>Signed-off-by: Aya Levin <ayal@mellanox.com>
>Signed-off-by: Eran Ben Elisha <eranbe@mellanox.com>
>Acked-by: Jiri Pirko <jiri@mellanox.com>
>---
> include/uapi/linux/devlink.h | 4 ++--
> net/core/devlink.c | 4 ++--
> 2 files changed, 4 insertions(+), 4 deletions(-)
>
>diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
>index 53de8802a000..5bb4ea67d84f 100644
>--- a/include/uapi/linux/devlink.h
>+++ b/include/uapi/linux/devlink.h
>@@ -323,8 +323,8 @@ enum devlink_attr {
> DEVLINK_ATTR_HEALTH_REPORTER, /* nested */
> DEVLINK_ATTR_HEALTH_REPORTER_NAME, /* string */
> DEVLINK_ATTR_HEALTH_REPORTER_STATE, /* u8 */
>- DEVLINK_ATTR_HEALTH_REPORTER_ERR, /* u64 */
>- DEVLINK_ATTR_HEALTH_REPORTER_RECOVER, /* u64 */
>+ DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT, /* u64 */
>+ DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT, /* u64 */
Just note, this is still in net-next only, so it is okay to change it.
> DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS, /* u64 */
> DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD, /* u64 */
> DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER, /* u8 */
>diff --git a/net/core/devlink.c b/net/core/devlink.c
>index 04d98550c78c..5135997ecbe7 100644
>--- a/net/core/devlink.c
>+++ b/net/core/devlink.c
>@@ -4650,10 +4650,10 @@ devlink_nl_health_reporter_fill(struct sk_buff *msg,
> if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
> reporter->health_state))
> goto reporter_nest_cancel;
>- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR,
>+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
> reporter->error_count, DEVLINK_ATTR_PAD))
> goto reporter_nest_cancel;
>- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER,
>+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
> reporter->recovery_count, DEVLINK_ATTR_PAD))
> goto reporter_nest_cancel;
> if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
>--
>2.17.1
>
^ permalink raw reply
* [PATCH net-next v2 7/7] net/mlx5e: Trust kernel regarding transport offset
From: Maxim Mikityanskiy @ 2019-02-21 12:40 UTC (permalink / raw)
To: David S. Miller, Saeed Mahameed, Willem de Bruijn, Jason Wang,
Eric Dumazet
Cc: netdev@vger.kernel.org, Eran Ben Elisha, Tariq Toukan,
Maxim Mikityanskiy
In-Reply-To: <20190221123908.7196-1-maximmi@mellanox.com>
After AF_PACKET is fixed to calculate the transport header offset
correctly, trust the value set by the kernel. If the offset wasn't set,
it means there is no transport header in the packet.
Signed-off-by: Maxim Mikityanskiy <maximmi@mellanox.com>
Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index 6ca834702306..e7aae45a01f8 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -148,12 +148,8 @@ static inline int mlx5e_skb_l2_header_offset(struct sk_buff *skb)
static inline int mlx5e_skb_l3_header_offset(struct sk_buff *skb)
{
- struct flow_keys keys;
-
if (skb_transport_header_was_set(skb))
return skb_transport_offset(skb);
- else if (skb_flow_dissect_flow_keys(skb, &keys, 0))
- return keys.control.thoff;
else
return mlx5e_skb_l2_header_offset(skb);
}
--
2.19.1
^ permalink raw reply related
* [PATCH net-next v2 6/7] net/mlx5e: Remove the wrong assumption about transport offset
From: Maxim Mikityanskiy @ 2019-02-21 12:40 UTC (permalink / raw)
To: David S. Miller, Saeed Mahameed, Willem de Bruijn, Jason Wang,
Eric Dumazet
Cc: netdev@vger.kernel.org, Eran Ben Elisha, Tariq Toukan,
Maxim Mikityanskiy
In-Reply-To: <20190221123908.7196-1-maximmi@mellanox.com>
skb_transport_offset() == 0 is not a special value. The only special
value is when skb->transport_header is ~0U, and it's checked by
skb_transport_header_was_set().
Signed-off-by: Maxim Mikityanskiy <maximmi@mellanox.com>
Reviewed-by: Saeed Mahameed <saeedm@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 11 ++---------
1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index c1334a8ac8f3..6ca834702306 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -172,15 +172,8 @@ static inline u16 mlx5e_calc_min_inline(enum mlx5_inline_modes mode,
hlen += VLAN_HLEN;
break;
case MLX5_INLINE_MODE_IP:
- /* When transport header is set to zero, it means no transport
- * header. When transport header is set to 0xff's, it means
- * transport header wasn't set.
- */
- if (skb_transport_offset(skb)) {
- hlen = mlx5e_skb_l3_header_offset(skb);
- break;
- }
- /* fall through */
+ hlen = mlx5e_skb_l3_header_offset(skb);
+ break;
case MLX5_INLINE_MODE_L2:
default:
hlen = mlx5e_skb_l2_header_offset(skb);
--
2.19.1
^ permalink raw reply related
* [PATCH net-next v2 5/7] net/packet: Remove redundant skb->protocol set
From: Maxim Mikityanskiy @ 2019-02-21 12:40 UTC (permalink / raw)
To: David S. Miller, Saeed Mahameed, Willem de Bruijn, Jason Wang,
Eric Dumazet
Cc: netdev@vger.kernel.org, Eran Ben Elisha, Tariq Toukan,
Maxim Mikityanskiy
In-Reply-To: <20190221123908.7196-1-maximmi@mellanox.com>
c72219b75f introduced tpacket_set_protocol that parses the Ethernet L2
header and sets skb->protocol if it's unset. It is no longer needed
since the introduction of packet_parse_headers. In case of SOCK_RAW and
unset skb->protocol, packet_parse_headers asks the driver to tell the
protocol number, and it's implemented for all Ethernet devices. As the
old function supported only Ethernet, no functionality is lost.
Signed-off-by: Maxim Mikityanskiy <maximmi@mellanox.com>
---
net/packet/af_packet.c | 11 -----------
1 file changed, 11 deletions(-)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index cac4c1a3f807..8376bc1c1508 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -2413,15 +2413,6 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
sock_wfree(skb);
}
-static void tpacket_set_protocol(const struct net_device *dev,
- struct sk_buff *skb)
-{
- if (dev->type == ARPHRD_ETHER) {
- skb_reset_mac_header(skb);
- skb->protocol = eth_hdr(skb)->h_proto;
- }
-}
-
static int __packet_snd_vnet_parse(struct virtio_net_hdr *vnet_hdr, size_t len)
{
if ((vnet_hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
@@ -2492,8 +2483,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
return err;
if (!dev_validate_header(dev, skb->data, hdrlen))
return -EINVAL;
- if (!skb->protocol)
- tpacket_set_protocol(dev, skb);
data += hdrlen;
to_write -= hdrlen;
--
2.19.1
^ permalink raw reply related
* [PATCH net-next v2 4/7] net/packet: Ask driver for protocol if not provided by user
From: Maxim Mikityanskiy @ 2019-02-21 12:40 UTC (permalink / raw)
To: David S. Miller, Saeed Mahameed, Willem de Bruijn, Jason Wang,
Eric Dumazet
Cc: netdev@vger.kernel.org, Eran Ben Elisha, Tariq Toukan,
Maxim Mikityanskiy
In-Reply-To: <20190221123908.7196-1-maximmi@mellanox.com>
If a socket was created with socket(AF_PACKET, SOCK_RAW, 0), the
protocol number is unavailable. Try to ask the driver to extract it from
the L2 header in order for skb_try_probe_transport_header to succeed.
Signed-off-by: Maxim Mikityanskiy <maximmi@mellanox.com>
---
net/packet/af_packet.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 6afd6369d19e..cac4c1a3f807 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1850,6 +1850,15 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,
return 0;
}
+static void packet_parse_headers(struct sk_buff *skb, struct socket *sock)
+{
+ if (!skb->protocol && sock->type == SOCK_RAW) {
+ skb_reset_mac_header(skb);
+ skb->protocol = dev_parse_header_protocol(skb);
+ }
+
+ skb_probe_transport_header(skb);
+}
/*
* Output a raw packet to a device layer. This bypasses all the other
@@ -1970,7 +1979,7 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
if (unlikely(extra_len == 4))
skb->no_fcs = 1;
- skb_probe_transport_header(skb);
+ packet_parse_headers(skb, sock);
dev_queue_xmit(skb);
rcu_read_unlock();
@@ -2519,7 +2528,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
len = ((to_write > len_max) ? len_max : to_write);
}
- skb_probe_transport_header(skb);
+ packet_parse_headers(skb, sock);
return tp_len;
}
@@ -2925,7 +2934,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
virtio_net_hdr_set_proto(skb, &vnet_hdr);
}
- skb_probe_transport_header(skb);
+ packet_parse_headers(skb, sock);
if (unlikely(extra_len == 4))
skb->no_fcs = 1;
--
2.19.1
^ permalink raw reply related
* [PATCH net-next v2 1/7] net: Don't set transport offset to invalid value
From: Maxim Mikityanskiy @ 2019-02-21 12:39 UTC (permalink / raw)
To: David S. Miller, Saeed Mahameed, Willem de Bruijn, Jason Wang,
Eric Dumazet
Cc: netdev@vger.kernel.org, Eran Ben Elisha, Tariq Toukan,
Maxim Mikityanskiy
In-Reply-To: <20190221123908.7196-1-maximmi@mellanox.com>
If the socket was created with socket(AF_PACKET, SOCK_RAW, 0),
skb->protocol will be unset, __skb_flow_dissect() will fail, and
skb_probe_transport_header() will fall back to the offset_hint, making
the resulting skb_transport_offset incorrect.
If, however, there is no transport header in the packet,
transport_header shouldn't be set to an arbitrary value.
Fix it by leaving the transport offset unset if it couldn't be found, to
be explicit rather than to fill it with some wrong value. It changes the
behavior, but if some code relied on the old behavior, it would be
broken anyway, as the old one is incorrect.
Signed-off-by: Maxim Mikityanskiy <maximmi@mellanox.com>
---
drivers/net/tap.c | 4 ++--
drivers/net/tun.c | 4 ++--
drivers/net/xen-netback/netback.c | 15 ++++++++++++---
include/linux/skbuff.h | 5 +----
include/linux/virtio_net.h | 2 +-
net/packet/af_packet.c | 6 +++---
6 files changed, 21 insertions(+), 15 deletions(-)
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index c0b52e48f0e6..2ea9b4976f4a 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -712,7 +712,7 @@ static ssize_t tap_get_user(struct tap_queue *q, void *msg_control,
goto err_kfree;
}
- skb_probe_transport_header(skb, ETH_HLEN);
+ skb_probe_transport_header(skb);
/* Move network header to the right position for VLAN tagged packets */
if ((skb->protocol == htons(ETH_P_8021Q) ||
@@ -1187,7 +1187,7 @@ static int tap_get_user_xdp(struct tap_queue *q, struct xdp_buff *xdp)
tap = rcu_dereference(q->tap);
if (tap) {
skb->dev = tap->dev;
- skb_probe_transport_header(skb, ETH_HLEN);
+ skb_probe_transport_header(skb);
dev_queue_xmit(skb);
} else {
kfree_skb(skb);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index fed298c0cb39..80bff1b4ec17 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1929,7 +1929,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
}
skb_reset_network_header(skb);
- skb_probe_transport_header(skb, 0);
+ skb_probe_transport_header(skb);
if (skb_xdp) {
struct bpf_prog *xdp_prog;
@@ -2482,7 +2482,7 @@ static int tun_xdp_one(struct tun_struct *tun,
skb->protocol = eth_type_trans(skb, tun->dev);
skb_reset_network_header(skb);
- skb_probe_transport_header(skb, 0);
+ skb_probe_transport_header(skb);
if (skb_xdp) {
err = do_xdp_generic(xdp_prog, skb);
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 80aae3a32c2a..c801a832851c 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -1169,15 +1169,24 @@ static int xenvif_tx_submit(struct xenvif_queue *queue)
continue;
}
- skb_probe_transport_header(skb, 0);
+ skb_probe_transport_header(skb);
/* If the packet is GSO then we will have just set up the
* transport header offset in checksum_setup so it's now
* straightforward to calculate gso_segs.
*/
if (skb_is_gso(skb)) {
- int mss = skb_shinfo(skb)->gso_size;
- int hdrlen = skb_transport_header(skb) -
+ int mss, hdrlen;
+
+ /* GSO implies having the L4 header. */
+ WARN_ON_ONCE(!skb_transport_header_was_set(skb));
+ if (unlikely(!skb_transport_header_was_set(skb))) {
+ kfree_skb(skb);
+ continue;
+ }
+
+ mss = skb_shinfo(skb)->gso_size;
+ hdrlen = skb_transport_header(skb) -
skb_mac_header(skb) +
tcp_hdrlen(skb);
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 2069fb90a559..27beb549ffbe 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2429,8 +2429,7 @@ static inline void skb_pop_mac_header(struct sk_buff *skb)
skb->mac_header = skb->network_header;
}
-static inline void skb_probe_transport_header(struct sk_buff *skb,
- const int offset_hint)
+static inline void skb_probe_transport_header(struct sk_buff *skb)
{
struct flow_keys_basic keys;
@@ -2439,8 +2438,6 @@ static inline void skb_probe_transport_header(struct sk_buff *skb,
if (skb_flow_dissect_flow_keys_basic(skb, &keys, NULL, 0, 0, 0, 0))
skb_set_transport_header(skb, keys.control.thoff);
- else if (offset_hint >= 0)
- skb_set_transport_header(skb, offset_hint);
}
static inline void skb_mac_header_rebuild(struct sk_buff *skb)
diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index 71f2394abbf7..6728bf581e98 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -62,7 +62,7 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
* probe and drop if does not match one of the above types.
*/
if (gso_type) {
- skb_probe_transport_header(skb, -1);
+ skb_probe_transport_header(skb);
if (!skb_transport_header_was_set(skb))
return -EINVAL;
}
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 1cd1d83a4be0..6afd6369d19e 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1970,7 +1970,7 @@ static int packet_sendmsg_spkt(struct socket *sock, struct msghdr *msg,
if (unlikely(extra_len == 4))
skb->no_fcs = 1;
- skb_probe_transport_header(skb, 0);
+ skb_probe_transport_header(skb);
dev_queue_xmit(skb);
rcu_read_unlock();
@@ -2519,7 +2519,7 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
len = ((to_write > len_max) ? len_max : to_write);
}
- skb_probe_transport_header(skb, 0);
+ skb_probe_transport_header(skb);
return tp_len;
}
@@ -2925,7 +2925,7 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
virtio_net_hdr_set_proto(skb, &vnet_hdr);
}
- skb_probe_transport_header(skb, reserve);
+ skb_probe_transport_header(skb);
if (unlikely(extra_len == 4))
skb->no_fcs = 1;
--
2.19.1
^ permalink raw reply related
* [PATCH net-next v2 3/7] net/ethernet: Add parse_protocol header_ops support
From: Maxim Mikityanskiy @ 2019-02-21 12:39 UTC (permalink / raw)
To: David S. Miller, Saeed Mahameed, Willem de Bruijn, Jason Wang,
Eric Dumazet
Cc: netdev@vger.kernel.org, Eran Ben Elisha, Tariq Toukan,
Maxim Mikityanskiy
In-Reply-To: <20190221123908.7196-1-maximmi@mellanox.com>
The previous commit introduced parse_protocol callback which should
extract the protocol number from the L2 header. Make all Ethernet
devices support it.
Signed-off-by: Maxim Mikityanskiy <maximmi@mellanox.com>
---
include/linux/etherdevice.h | 1 +
net/ethernet/eth.c | 13 +++++++++++++
2 files changed, 14 insertions(+)
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index 2c0af7b00715..e2f3b21cd72a 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -44,6 +44,7 @@ int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh,
__be16 type);
void eth_header_cache_update(struct hh_cache *hh, const struct net_device *dev,
const unsigned char *haddr);
+__be16 eth_header_parse_protocol(const struct sk_buff *skb);
int eth_prepare_mac_addr_change(struct net_device *dev, void *p);
void eth_commit_mac_addr_change(struct net_device *dev, void *p);
int eth_mac_addr(struct net_device *dev, void *p);
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 4c520110b04f..f7a3d7a171c7 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -264,6 +264,18 @@ void eth_header_cache_update(struct hh_cache *hh,
}
EXPORT_SYMBOL(eth_header_cache_update);
+/**
+ * eth_header_parser_protocol - extract protocol from L2 header
+ * @skb: packet to extract protocol from
+ */
+__be16 eth_header_parse_protocol(const struct sk_buff *skb)
+{
+ const struct ethhdr *eth = eth_hdr(skb);
+
+ return eth->h_proto;
+}
+EXPORT_SYMBOL(eth_header_parse_protocol);
+
/**
* eth_prepare_mac_addr_change - prepare for mac change
* @dev: network device
@@ -346,6 +358,7 @@ const struct header_ops eth_header_ops ____cacheline_aligned = {
.parse = eth_header_parse,
.cache = eth_header_cache,
.cache_update = eth_header_cache_update,
+ .parse_protocol = eth_header_parse_protocol,
};
/**
--
2.19.1
^ permalink raw reply related
* [PATCH net-next v2 2/7] net: Introduce parse_protocol header_ops callback
From: Maxim Mikityanskiy @ 2019-02-21 12:39 UTC (permalink / raw)
To: David S. Miller, Saeed Mahameed, Willem de Bruijn, Jason Wang,
Eric Dumazet
Cc: netdev@vger.kernel.org, Eran Ben Elisha, Tariq Toukan,
Maxim Mikityanskiy
In-Reply-To: <20190221123908.7196-1-maximmi@mellanox.com>
Introduce a new optional header_ops callback called parse_protocol and a
wrapper function dev_parse_header_protocol, similar to dev_parse_header.
The new callback's purpose is to extract the protocol number from the L2
header, the format of which is known to the driver, but not to the upper
layers of the stack.
Signed-off-by: Maxim Mikityanskiy <maximmi@mellanox.com>
---
include/linux/netdevice.h | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index aab4d9f6613d..6997f62cb6a0 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -274,6 +274,7 @@ struct header_ops {
const struct net_device *dev,
const unsigned char *haddr);
bool (*validate)(const char *ll_header, unsigned int len);
+ __be16 (*parse_protocol)(const struct sk_buff *skb);
};
/* These flag bits are private to the generic network queueing
@@ -2939,6 +2940,15 @@ static inline int dev_parse_header(const struct sk_buff *skb,
return dev->header_ops->parse(skb, haddr);
}
+static inline __be16 dev_parse_header_protocol(const struct sk_buff *skb)
+{
+ const struct net_device *dev = skb->dev;
+
+ if (!dev->header_ops || !dev->header_ops->parse_protocol)
+ return 0;
+ return dev->header_ops->parse_protocol(skb);
+}
+
/* ll_header must have at least hard_header_len allocated */
static inline bool dev_validate_header(const struct net_device *dev,
char *ll_header, int len)
--
2.19.1
^ permalink raw reply related
* [PATCH net-next v2 0/7] AF_PACKET transport_offset fix
From: Maxim Mikityanskiy @ 2019-02-21 12:39 UTC (permalink / raw)
To: David S. Miller, Saeed Mahameed, Willem de Bruijn, Jason Wang,
Eric Dumazet
Cc: netdev@vger.kernel.org, Eran Ben Elisha, Tariq Toukan,
Maxim Mikityanskiy
This patch series contains the implementation of the RFC that was posted
on this mailing list previously:
https://www.spinics.net/lists/netdev/msg541709.html
It fixes having incorrect skb->transport_header values in cases when
dissect fails. Having correct values set by the kernel fixes mlx5
operation and allows to remove some unnecessary code flows in mlx5.
v2 changes:
- Rebase against the fresh net-next.
- Don't return bool from skb_probe_transport_header (and don't rename
the function).
- WARN_ON_ONCE and error path in case of GSO without the L4 header.
Maxim Mikityanskiy (7):
net: Don't set transport offset to invalid value
net: Introduce parse_protocol header_ops callback
net/ethernet: Add parse_protocol header_ops support
net/packet: Ask driver for protocol if not provided by user
net/packet: Remove redundant skb->protocol set
net/mlx5e: Remove the wrong assumption about transport offset
net/mlx5e: Trust kernel regarding transport offset
.../net/ethernet/mellanox/mlx5/core/en_tx.c | 15 ++---------
drivers/net/tap.c | 4 +--
drivers/net/tun.c | 4 +--
drivers/net/xen-netback/netback.c | 15 ++++++++---
include/linux/etherdevice.h | 1 +
include/linux/netdevice.h | 10 +++++++
include/linux/skbuff.h | 5 +---
include/linux/virtio_net.h | 2 +-
net/ethernet/eth.c | 13 ++++++++++
net/packet/af_packet.c | 26 +++++++++----------
10 files changed, 56 insertions(+), 39 deletions(-)
--
2.19.1
^ permalink raw reply
* [PATCH][next] rsi: fix missing null pointer check from a failed ieee80211_probereq_get call
From: Colin King @ 2019-02-21 12:35 UTC (permalink / raw)
To: Amitkumar Karwar, Siva Rebbagondla, Kalle Valo, David S . Miller,
linux-wireless, netdev
Cc: kernel-janitors, linux-kernel
From: Colin Ian King <colin.king@canonical.com>
The call to ieee80211_probereq_get can return NULL if a skb allocation
fails, so add a null pointer check and free an earlier skb on the error
exit return path.
Fixes: 7fdcb8e12660 ("rsi: add support for hardware scan offload")
Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
drivers/net/wireless/rsi/rsi_91x_mgmt.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
index 8c17842ac507..844f2fac298f 100644
--- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c
+++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c
@@ -1726,6 +1726,10 @@ int rsi_send_bgscan_probe_req(struct rsi_common *common,
probereq_skb = ieee80211_probereq_get(common->priv->hw, vif->addr, ssid,
ssid_len, scan_req->ie_len);
+ if (!probereq_skb) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
memcpy(&skb->data[frame_len], probereq_skb->data, probereq_skb->len);
--
2.20.1
^ permalink raw reply related
* Re: [PATCH mlx5-next] net/mlx5: Separate ODP capabilities
From: Leon Romanovsky @ 2019-02-21 12:21 UTC (permalink / raw)
To: Doug Ledford, Jason Gunthorpe
Cc: Moni Shoua, RDMA mailing list, Saeed Mahameed, linux-netdev
In-Reply-To: <20190221121003.GB17501@mtr-leonro.mtl.com>
[-- Attachment #1: Type: text/plain, Size: 1000 bytes --]
On Thu, Feb 21, 2019 at 12:10:06PM +0000, Leon Romanovsky wrote:
> On Tue, Feb 19, 2019 at 03:06:37PM +0200, Leon Romanovsky wrote:
> > From: Moni Shoua <monis@mellanox.com>
> >
> > ODP support for XRC transport is not enabled by default in FW,
> > so we need separate ODP checks to enable/disable it.
> >
> > While that, rewrite the set of ODP SRQ support capabilities in way
> > that tests each field separately for clearness, which is not needed
> > for current FW, but better to have it separated.
> >
> > Signed-off-by: Moni Shoua <monis@mellanox.com>
> > Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
> > ---
> > .../net/ethernet/mellanox/mlx5/core/main.c | 29 ++++++++++---------
> > 1 file changed, 15 insertions(+), 14 deletions(-)
> >
>
> Thanks, applied to mlx5-next
> f1463b9f1a97 net/mlx5: Separate ODP capabilities
>
> Doug, Jason,
>
> Can you please merge this branch into rdma-next as a preparation
> to pull request?
Sorry, it was a mistake, I dropped it.
>
> Thanks
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* [PATCH net-next 1/2] devlink: Rename devlink health attributes
From: Eran Ben Elisha @ 2019-02-21 12:12 UTC (permalink / raw)
To: netdev, David S. Miller; +Cc: Jiri Pirko, Aya Levin, Eran Ben Elisha
In-Reply-To: <1550751122-2788-1-git-send-email-eranbe@mellanox.com>
From: Aya Levin <ayal@mellanox.com>
Rename devlink health attributes for better reflect the attributes use.
Add COUNT prefix on error counter attribute and recovery counter
attribute.
Fixes: 7afe335a8bed ("devlink: Add health get command")
Signed-off-by: Aya Levin <ayal@mellanox.com>
Signed-off-by: Eran Ben Elisha <eranbe@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
---
include/uapi/linux/devlink.h | 4 ++--
net/core/devlink.c | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 53de8802a000..5bb4ea67d84f 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -323,8 +323,8 @@ enum devlink_attr {
DEVLINK_ATTR_HEALTH_REPORTER, /* nested */
DEVLINK_ATTR_HEALTH_REPORTER_NAME, /* string */
DEVLINK_ATTR_HEALTH_REPORTER_STATE, /* u8 */
- DEVLINK_ATTR_HEALTH_REPORTER_ERR, /* u64 */
- DEVLINK_ATTR_HEALTH_REPORTER_RECOVER, /* u64 */
+ DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT, /* u64 */
+ DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT, /* u64 */
DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS, /* u64 */
DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD, /* u64 */
DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER, /* u8 */
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 04d98550c78c..5135997ecbe7 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -4650,10 +4650,10 @@ devlink_nl_health_reporter_fill(struct sk_buff *msg,
if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_STATE,
reporter->health_state))
goto reporter_nest_cancel;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR,
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT,
reporter->error_count, DEVLINK_ATTR_PAD))
goto reporter_nest_cancel;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER,
+ if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
reporter->recovery_count, DEVLINK_ATTR_PAD))
goto reporter_nest_cancel;
if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
--
2.17.1
^ permalink raw reply related
* [PATCH net-next 2/2] devlink: Modify reply of DEVLINK_CMD_HEALTH_REPORTER_GET
From: Eran Ben Elisha @ 2019-02-21 12:12 UTC (permalink / raw)
To: netdev, David S. Miller; +Cc: Jiri Pirko, Aya Levin, Eran Ben Elisha
In-Reply-To: <1550751122-2788-1-git-send-email-eranbe@mellanox.com>
From: Aya Levin <ayal@mellanox.com>
Avoid sending attributes related to recovery:
DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD and
DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER in reply to
DEVLINK_CMD_HEALTH_REPORTER_GET for a reporter which didn't register a
recover operation.
These parameters can't be configured on a reporter that did not provide
a recover operation, thus not needed to return them.
Fixes: 7afe335a8bed ("devlink: Add health get command")
Signed-off-by: Aya Levin <ayal@mellanox.com>
Signed-off-by: Eran Ben Elisha <eranbe@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
---
net/core/devlink.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/net/core/devlink.c b/net/core/devlink.c
index 5135997ecbe7..4f31ddc883e7 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -4656,11 +4656,13 @@ devlink_nl_health_reporter_fill(struct sk_buff *msg,
if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT,
reporter->recovery_count, DEVLINK_ATTR_PAD))
goto reporter_nest_cancel;
- if (nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
+ if (reporter->ops->recover &&
+ nla_put_u64_64bit(msg, DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
reporter->graceful_period,
DEVLINK_ATTR_PAD))
goto reporter_nest_cancel;
- if (nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
+ if (reporter->ops->recover &&
+ nla_put_u8(msg, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
reporter->auto_recover))
goto reporter_nest_cancel;
if (reporter->dump_fmsg &&
--
2.17.1
^ permalink raw reply related
* [PATCH net-next 0/2] Devlink health fixes series
From: Eran Ben Elisha @ 2019-02-21 12:12 UTC (permalink / raw)
To: netdev, David S. Miller; +Cc: Jiri Pirko, Aya Levin, Eran Ben Elisha
This series includes two small fixes from Aya for the devlink health
infrastructure introduced earlier in this window.
First patch rename some UAPI attributes to better reflect their use.
Second patch reduces the amount of data passed from the devlink to the
netlink layer upon get reporter command, in case of no-recovery reporter.
Aya Levin (2):
devlink: Rename devlink health attributes
devlink: Modify reply of DEVLINK_CMD_HEALTH_REPORTER_GET
include/uapi/linux/devlink.h | 4 ++--
net/core/devlink.c | 10 ++++++----
2 files changed, 8 insertions(+), 6 deletions(-)
--
2.17.1
^ permalink raw reply
* Re: [PATCH mlx5-next] net/mlx5: Separate ODP capabilities
From: Leon Romanovsky @ 2019-02-21 12:10 UTC (permalink / raw)
To: Doug Ledford, Jason Gunthorpe
Cc: Moni Shoua, RDMA mailing list, Saeed Mahameed, linux-netdev
In-Reply-To: <20190219130638.21981-1-leon@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 844 bytes --]
On Tue, Feb 19, 2019 at 03:06:37PM +0200, Leon Romanovsky wrote:
> From: Moni Shoua <monis@mellanox.com>
>
> ODP support for XRC transport is not enabled by default in FW,
> so we need separate ODP checks to enable/disable it.
>
> While that, rewrite the set of ODP SRQ support capabilities in way
> that tests each field separately for clearness, which is not needed
> for current FW, but better to have it separated.
>
> Signed-off-by: Moni Shoua <monis@mellanox.com>
> Signed-off-by: Leon Romanovsky <leonro@mellanox.com>
> ---
> .../net/ethernet/mellanox/mlx5/core/main.c | 29 ++++++++++---------
> 1 file changed, 15 insertions(+), 14 deletions(-)
>
Thanks, applied to mlx5-next
f1463b9f1a97 net/mlx5: Separate ODP capabilities
Doug, Jason,
Can you please merge this branch into rdma-next as a preparation
to pull request?
Thanks
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]
^ permalink raw reply
* [PATCH] ip_tunnel: Add ip tunnel tunnel_info dst_cache in ip_tunnel_xmit
From: wenxu @ 2019-02-21 12:08 UTC (permalink / raw)
To: netdev, davem
From: wenxu <wenxu@ucloud.cn>
ip l add dev tun type gretap key 1000
Non-tunnel-dst ip tunnel device can send packet through lwtunnel.
This patch provide the tun_info dst cache support for this mode
Signed-off-by: wenxu <wenxu@ucloud.cn>
---
net/ipv4/ip_tunnel.c | 25 ++++++++++++++++++++-----
1 file changed, 20 insertions(+), 5 deletions(-)
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 893f013..874ad58 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -662,6 +662,9 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
unsigned int max_headroom; /* The extra header space needed */
__be32 dst;
bool connected;
+ bool use_cache = false;
+ bool md = false;
+ struct ip_tunnel_info *tun_info;
inner_iph = (const struct iphdr *)skb_inner_network_header(skb);
connected = (tunnel->parms.iph.daddr != 0);
@@ -671,7 +674,6 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
dst = tnl_params->daddr;
if (dst == 0) {
/* NBMA tunnel */
- struct ip_tunnel_info *tun_info;
if (!skb_dst(skb)) {
dev->stats.tx_fifo_errors++;
@@ -681,8 +683,11 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
tun_info = skb_tunnel_info(skb);
if (tun_info && (tun_info->mode & IP_TUNNEL_INFO_TX) &&
ip_tunnel_info_af(tun_info) == AF_INET &&
- tun_info->key.u.ipv4.dst)
+ tun_info->key.u.ipv4.dst) {
dst = tun_info->key.u.ipv4.dst;
+ md = true;
+ connected = true;
+ }
else if (skb->protocol == htons(ETH_P_IP)) {
rt = skb_rtable(skb);
dst = rt_nexthop(rt, inner_iph->daddr);
@@ -721,7 +726,8 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
else
goto tx_error;
- connected = false;
+ if (!md)
+ connected = false;
}
tos = tnl_params->tos;
@@ -743,8 +749,14 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0)
goto tx_error;
- rt = connected ? dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr) :
+ if (connected && md) {
+ use_cache = ip_tunnel_dst_cache_usable(skb, tun_info);
+ if (use_cache)
+ rt = dst_cache_get_ip4(&tun_info->dst_cache, &fl4.saddr);
+ } else {
+ rt = connected ? dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr) :
NULL;
+ }
if (!rt) {
rt = ip_route_output_key(tunnel->net, &fl4);
@@ -753,7 +765,10 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
dev->stats.tx_carrier_errors++;
goto tx_error;
}
- if (connected)
+ if (use_cache)
+ dst_cache_set_ip4(&tun_info->dst_cache, &rt->dst,
+ fl4.saddr);
+ else if (!md && connected)
dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst,
fl4.saddr);
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH bpf] Revert "xsk: simplify AF_XDP socket teardown"
From: Björn Töpel @ 2019-02-21 12:07 UTC (permalink / raw)
To: ast, daniel, netdev
Cc: Björn Töpel, magnus.karlsson, magnus.karlsson
From: Björn Töpel <bjorn.topel@intel.com>
This reverts commit e2ce3674883ecba2605370404208c9d4a07ae1c3.
It turns out that the sock destructor xsk_destruct was needed after
all. The cleanup simplification broke the skb transmit cleanup path,
due to that the umem was prematurely destroyed.
The umem cannot be destroyed until all outstanding skbs are freed,
which means that we cannot remove the umem until the sk_destruct has
been called.
Signed-off-by: Björn Töpel <bjorn.topel@intel.com>
---
net/xdp/xsk.c | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/net/xdp/xsk.c b/net/xdp/xsk.c
index 45f3b528dc09..85e4fe4f18cc 100644
--- a/net/xdp/xsk.c
+++ b/net/xdp/xsk.c
@@ -366,7 +366,6 @@ static int xsk_release(struct socket *sock)
xskq_destroy(xs->rx);
xskq_destroy(xs->tx);
- xdp_put_umem(xs->umem);
sock_orphan(sk);
sock->sk = NULL;
@@ -718,6 +717,18 @@ static const struct proto_ops xsk_proto_ops = {
.sendpage = sock_no_sendpage,
};
+static void xsk_destruct(struct sock *sk)
+{
+ struct xdp_sock *xs = xdp_sk(sk);
+
+ if (!sock_flag(sk, SOCK_DEAD))
+ return;
+
+ xdp_put_umem(xs->umem);
+
+ sk_refcnt_debug_dec(sk);
+}
+
static int xsk_create(struct net *net, struct socket *sock, int protocol,
int kern)
{
@@ -744,6 +755,9 @@ static int xsk_create(struct net *net, struct socket *sock, int protocol,
sk->sk_family = PF_XDP;
+ sk->sk_destruct = xsk_destruct;
+ sk_refcnt_debug_inc(sk);
+
sock_set_flag(sk, SOCK_RCU_FREE);
xs = xdp_sk(sk);
--
2.19.1
^ permalink raw reply related
* [PATCH net-next 4/6] net/smc: add smcd support to the pnet table
From: Ursula Braun @ 2019-02-21 12:01 UTC (permalink / raw)
To: davem
Cc: netdev, linux-s390, schwidefsky, heiko.carstens, raspl, kgraul,
ubraun
In-Reply-To: <20190221120103.10866-1-ubraun@linux.ibm.com>
From: Hans Wippel <hwippel@linux.ibm.com>
Currently, users can only set pnetids for netdevs and ib devices in the
pnet table. This patch adds support for smcd devices to the pnet table.
Signed-off-by: Hans Wippel <hwippel@linux.ibm.com>
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
---
include/net/smc.h | 1 +
net/smc/smc_pnet.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 81 insertions(+), 7 deletions(-)
diff --git a/include/net/smc.h b/include/net/smc.h
index 9ef49f8b1002..bd9c0fb3b577 100644
--- a/include/net/smc.h
+++ b/include/net/smc.h
@@ -74,6 +74,7 @@ struct smcd_dev {
struct list_head vlan;
struct workqueue_struct *event_wq;
u8 pnetid[SMC_MAX_PNETID_LEN];
+ bool pnetid_by_user;
};
struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name,
diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c
index 327bf2afe820..5497a8b44287 100644
--- a/net/smc/smc_pnet.c
+++ b/net/smc/smc_pnet.c
@@ -66,6 +66,7 @@ static struct smc_pnettable {
* @ndev: pointer to network device.
* @smcibdev: Pointer to IB device.
* @ib_port: Port of IB device.
+ * @smcd_dev: Pointer to smcd device.
*/
struct smc_user_pnetentry {
struct list_head list;
@@ -73,6 +74,7 @@ struct smc_user_pnetentry {
struct net_device *ndev;
struct smc_ib_device *smcibdev;
u8 ib_port;
+ struct smcd_dev *smcd_dev;
};
/* pnet entry stored in pnet table */
@@ -103,6 +105,7 @@ static int smc_pnet_remove_by_pnetid(char *pnet_name)
{
struct smc_pnetentry *pnetelem, *tmp_pe;
struct smc_ib_device *ibdev;
+ struct smcd_dev *smcd_dev;
int rc = -ENOENT;
int ibport;
@@ -135,6 +138,18 @@ static int smc_pnet_remove_by_pnetid(char *pnet_name)
}
}
spin_unlock(&smc_ib_devices.lock);
+ /* remove smcd devices */
+ spin_lock(&smcd_dev_list.lock);
+ list_for_each_entry(smcd_dev, &smcd_dev_list.list, list) {
+ if (smcd_dev->pnetid_by_user &&
+ (!pnet_name ||
+ smc_pnet_match(pnet_name, smcd_dev->pnetid))) {
+ memset(smcd_dev->pnetid, 0, SMC_MAX_PNETID_LEN);
+ smcd_dev->pnetid_by_user = false;
+ rc = 0;
+ }
+ }
+ spin_unlock(&smcd_dev_list.lock);
return rc;
}
@@ -168,6 +183,7 @@ static int smc_pnet_enter(struct smc_user_pnetentry *new_pnetelem)
u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
struct smc_pnetentry *tmp_pnetelem;
struct smc_pnetentry *pnetelem;
+ bool new_smcddev = false;
struct net_device *ndev;
bool new_netdev = true;
bool new_ibdev = false;
@@ -185,9 +201,21 @@ static int smc_pnet_enter(struct smc_user_pnetentry *new_pnetelem)
}
spin_unlock(&smc_ib_devices.lock);
}
+ if (new_pnetelem->smcd_dev) {
+ struct smcd_dev *smcd_dev = new_pnetelem->smcd_dev;
+
+ spin_lock(&smcd_dev_list.lock);
+ if (smc_pnet_match(smcd_dev->pnetid, pnet_null)) {
+ memcpy(smcd_dev->pnetid, new_pnetelem->pnet_name,
+ SMC_MAX_PNETID_LEN);
+ smcd_dev->pnetid_by_user = true;
+ new_smcddev = true;
+ }
+ spin_unlock(&smcd_dev_list.lock);
+ }
if (!new_pnetelem->ndev)
- return new_ibdev ? 0 : -EEXIST;
+ return (new_ibdev || new_smcddev) ? 0 : -EEXIST;
/* check if (base) netdev already has a pnetid. If there is one, we do
* not want to add a pnet table entry
@@ -195,7 +223,7 @@ static int smc_pnet_enter(struct smc_user_pnetentry *new_pnetelem)
ndev = pnet_find_base_ndev(new_pnetelem->ndev);
if (!smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
ndev_pnetid))
- return new_ibdev ? 0 : -EEXIST;
+ return (new_ibdev || new_smcddev) ? 0 : -EEXIST;
/* add a new netdev entry to the pnet table if there isn't one */
tmp_pnetelem = kzalloc(sizeof(*pnetelem), GFP_KERNEL);
@@ -219,7 +247,7 @@ static int smc_pnet_enter(struct smc_user_pnetentry *new_pnetelem)
kfree(tmp_pnetelem);
}
- return (new_netdev || new_ibdev) ? 0 : -EEXIST;
+ return (new_netdev || new_ibdev || new_smcddev) ? 0 : -EEXIST;
}
/* The limit for pnetid is 16 characters.
@@ -267,6 +295,23 @@ static struct smc_ib_device *smc_pnet_find_ib(char *ib_name)
return ibdev;
}
+/* Find an smcd device by a given name. The device might not exist. */
+static struct smcd_dev *smc_pnet_find_smcd(char *smcd_name)
+{
+ struct smcd_dev *smcd_dev;
+
+ spin_lock(&smcd_dev_list.lock);
+ list_for_each_entry(smcd_dev, &smcd_dev_list.list, list) {
+ if (!strncmp(dev_name(&smcd_dev->dev), smcd_name,
+ IB_DEVICE_NAME_MAX - 1))
+ goto out;
+ }
+ smcd_dev = NULL;
+out:
+ spin_unlock(&smcd_dev_list.lock);
+ return smcd_dev;
+}
+
/* Parse the supplied netlink attributes and fill a pnetentry structure.
* For ethernet and infiniband device names verify that the devices exist.
*/
@@ -300,7 +345,8 @@ static int smc_pnet_fill_entry(struct net *net,
ibname = (char *)nla_data(tb[SMC_PNETID_IBNAME]);
ibname = strim(ibname);
pnetelem->smcibdev = smc_pnet_find_ib(ibname);
- if (!pnetelem->smcibdev)
+ pnetelem->smcd_dev = smc_pnet_find_smcd(ibname);
+ if (!pnetelem->smcibdev && !pnetelem->smcd_dev)
goto error;
if (pnetelem->smcibdev) {
if (!tb[SMC_PNETID_IBPORT])
@@ -339,6 +385,11 @@ static int smc_pnet_set_nla(struct sk_buff *msg,
pnetelem->smcibdev->ibdev->name) ||
nla_put_u8(msg, SMC_PNETID_IBPORT, pnetelem->ib_port))
return -1;
+ } else if (pnetelem->smcd_dev) {
+ if (nla_put_string(msg, SMC_PNETID_IBNAME,
+ dev_name(&pnetelem->smcd_dev->dev)) ||
+ nla_put_u8(msg, SMC_PNETID_IBPORT, 1))
+ return -1;
} else {
if (nla_put_string(msg, SMC_PNETID_IBNAME, "n/a") ||
nla_put_u8(msg, SMC_PNETID_IBPORT, 0xff))
@@ -400,6 +451,7 @@ static int _smc_pnet_dump(struct sk_buff *skb, u32 portid, u32 seq, u8 *pnetid,
struct smc_user_pnetentry tmp_entry;
struct smc_pnetentry *pnetelem;
struct smc_ib_device *ibdev;
+ struct smcd_dev *smcd_dev;
int idx = 0;
int ibport;
@@ -450,6 +502,27 @@ static int _smc_pnet_dump(struct sk_buff *skb, u32 portid, u32 seq, u8 *pnetid,
}
spin_unlock(&smc_ib_devices.lock);
+ /* dump smcd devices */
+ spin_lock(&smcd_dev_list.lock);
+ list_for_each_entry(smcd_dev, &smcd_dev_list.list, list) {
+ if (smcd_dev->pnetid_by_user) {
+ if (pnetid && !smc_pnet_match(smcd_dev->pnetid, pnetid))
+ continue;
+ if (idx++ < start_idx)
+ continue;
+ memset(&tmp_entry, 0, sizeof(tmp_entry));
+ memcpy(&tmp_entry.pnet_name, smcd_dev->pnetid,
+ SMC_MAX_PNETID_LEN);
+ tmp_entry.smcd_dev = smcd_dev;
+ if (smc_pnet_dumpinfo(skb, portid, seq, NLM_F_MULTI,
+ &tmp_entry)) {
+ --idx;
+ break;
+ }
+ }
+ }
+ spin_unlock(&smcd_dev_list.lock);
+
return idx;
}
@@ -666,12 +739,13 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev,
ndev = pnet_find_base_ndev(ndev);
if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
- ndev_pnetid))
+ ndev_pnetid) &&
+ smc_pnet_find_ndev_pnetid_by_table(ndev, ndev_pnetid))
return; /* pnetid could not be determined */
spin_lock(&smcd_dev_list.lock);
list_for_each_entry(ismdev, &smcd_dev_list.list, list) {
- if (!memcmp(ismdev->pnetid, ndev_pnetid, SMC_MAX_PNETID_LEN)) {
+ if (smc_pnet_match(ismdev->pnetid, ndev_pnetid)) {
*smcismdev = ismdev;
break;
}
@@ -715,7 +789,6 @@ void smc_pnet_find_ism_resource(struct sock *sk, struct smcd_dev **smcismdev)
if (!dst->dev)
goto out_rel;
- /* if possible, lookup via hardware-defined pnetid */
smc_pnet_find_ism_by_pnetid(dst->dev, smcismdev);
out_rel:
--
2.16.4
^ permalink raw reply related
* [PATCH net-next 6/6] net/smc: allow PCI IDs as ib device names in the pnet table
From: Ursula Braun @ 2019-02-21 12:01 UTC (permalink / raw)
To: davem
Cc: netdev, linux-s390, schwidefsky, heiko.carstens, raspl, kgraul,
ubraun
In-Reply-To: <20190221120103.10866-1-ubraun@linux.ibm.com>
From: Hans Wippel <hwippel@linux.ibm.com>
SMC-D devices are identified by their PCI IDs in the pnet table. In
order to make usage of the pnet table more consistent for users, this
patch adds this form of identification for ib devices as well.
Signed-off-by: Hans Wippel <hwippel@linux.ibm.com>
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
---
net/smc/smc_pnet.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c
index 878f5c085444..25dfbe343e26 100644
--- a/net/smc/smc_pnet.c
+++ b/net/smc/smc_pnet.c
@@ -293,7 +293,9 @@ static struct smc_ib_device *smc_pnet_find_ib(char *ib_name)
spin_lock(&smc_ib_devices.lock);
list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
if (!strncmp(ibdev->ibdev->name, ib_name,
- sizeof(ibdev->ibdev->name))) {
+ sizeof(ibdev->ibdev->name)) ||
+ !strncmp(dev_name(ibdev->ibdev->dev.parent), ib_name,
+ IB_DEVICE_NAME_MAX - 1)) {
goto out;
}
}
@@ -394,7 +396,7 @@ static int smc_pnet_set_nla(struct sk_buff *msg,
}
if (pnetelem->smcibdev) {
if (nla_put_string(msg, SMC_PNETID_IBNAME,
- pnetelem->smcibdev->ibdev->name) ||
+ dev_name(pnetelem->smcibdev->ibdev->dev.parent)) ||
nla_put_u8(msg, SMC_PNETID_IBPORT, pnetelem->ib_port))
return -1;
} else if (pnetelem->smcd_dev) {
--
2.16.4
^ permalink raw reply related
* [PATCH net-next 3/6] net/smc: rework pnet table
From: Ursula Braun @ 2019-02-21 12:01 UTC (permalink / raw)
To: davem
Cc: netdev, linux-s390, schwidefsky, heiko.carstens, raspl, kgraul,
ubraun
In-Reply-To: <20190221120103.10866-1-ubraun@linux.ibm.com>
From: Hans Wippel <hwippel@linux.ibm.com>
If a device does not have a pnetid, users can set a temporary pnetid for
said device in the pnet table. This patch reworks the pnet table to make
it more flexible. Multiple entries with the same pnetid but differing
devices are now allowed. Additionally, the netlink interface now sends
each mapping from pnetid to device separately to the user while
maintaining the message format existing applications might expect. Also,
the SMC data structure for ib devices already has a pnetid attribute.
So, it is used to store the user defined pnetids. As a result, the pnet
table entries are only used for netdevs.
Signed-off-by: Hans Wippel <hwippel@linux.ibm.com>
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
---
net/smc/smc_ib.c | 1 -
net/smc/smc_ib.h | 2 +
net/smc/smc_pnet.c | 439 ++++++++++++++++++++++++++++++-----------------------
net/smc/smc_pnet.h | 1 -
4 files changed, 249 insertions(+), 194 deletions(-)
diff --git a/net/smc/smc_ib.c b/net/smc/smc_ib.c
index 0b244be24fe0..53f429c04843 100644
--- a/net/smc/smc_ib.c
+++ b/net/smc/smc_ib.c
@@ -564,7 +564,6 @@ static void smc_ib_remove_dev(struct ib_device *ibdev, void *client_data)
spin_lock(&smc_ib_devices.lock);
list_del_init(&smcibdev->list); /* remove from smc_ib_devices */
spin_unlock(&smc_ib_devices.lock);
- smc_pnet_remove_by_ibdev(smcibdev);
smc_ib_cleanup_per_ibdev(smcibdev);
ib_unregister_event_handler(&smcibdev->event_handler);
kfree(smcibdev);
diff --git a/net/smc/smc_ib.h b/net/smc/smc_ib.h
index bac7fd65a4c0..da60ab9e8d70 100644
--- a/net/smc/smc_ib.h
+++ b/net/smc/smc_ib.h
@@ -42,6 +42,8 @@ struct smc_ib_device { /* ib-device infos for smc */
/* mac address per port*/
u8 pnetid[SMC_MAX_PORTS][SMC_MAX_PNETID_LEN];
/* pnetid per port */
+ bool pnetid_by_user[SMC_MAX_PORTS];
+ /* pnetid defined by user? */
u8 initialized : 1; /* ib dev CQ, evthdl done */
struct work_struct port_event_work;
unsigned long port_event_mask;
diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c
index 632c3109dee5..327bf2afe820 100644
--- a/net/smc/smc_pnet.c
+++ b/net/smc/smc_pnet.c
@@ -24,6 +24,10 @@
#include "smc_ib.h"
#include "smc_ism.h"
+#define SMC_ASCII_BLANK 32
+
+static struct net_device *pnet_find_base_ndev(struct net_device *ndev);
+
static struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = {
[SMC_PNETID_NAME] = {
.type = NLA_NUL_STRING,
@@ -56,13 +60,14 @@ static struct smc_pnettable {
};
/**
- * struct smc_pnetentry - pnet identifier name entry
+ * struct smc_user_pnetentry - pnet identifier name entry for/from user
* @list: List node.
* @pnet_name: Pnet identifier name
* @ndev: pointer to network device.
* @smcibdev: Pointer to IB device.
+ * @ib_port: Port of IB device.
*/
-struct smc_pnetentry {
+struct smc_user_pnetentry {
struct list_head list;
char pnet_name[SMC_MAX_PNETID_LEN + 1];
struct net_device *ndev;
@@ -70,33 +75,26 @@ struct smc_pnetentry {
u8 ib_port;
};
-/* Check if two RDMA device entries are identical. Use device name and port
- * number for comparison.
- */
-static bool smc_pnet_same_ibname(struct smc_pnetentry *pnetelem, char *ibname,
- u8 ibport)
-{
- return pnetelem->ib_port == ibport &&
- !strncmp(pnetelem->smcibdev->ibdev->name, ibname,
- sizeof(pnetelem->smcibdev->ibdev->name));
-}
+/* pnet entry stored in pnet table */
+struct smc_pnetentry {
+ struct list_head list;
+ char pnet_name[SMC_MAX_PNETID_LEN + 1];
+ struct net_device *ndev;
+};
-/* Find a pnetid in the pnet table.
- */
-static struct smc_pnetentry *smc_pnet_find_pnetid(char *pnet_name)
+/* Check if two given pnetids match */
+static bool smc_pnet_match(u8 *pnetid1, u8 *pnetid2)
{
- struct smc_pnetentry *pnetelem, *found_pnetelem = NULL;
+ int i;
- read_lock(&smc_pnettable.lock);
- list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
- if (!strncmp(pnetelem->pnet_name, pnet_name,
- sizeof(pnetelem->pnet_name))) {
- found_pnetelem = pnetelem;
+ for (i = 0; i < SMC_MAX_PNETID_LEN; i++) {
+ if ((pnetid1[i] == 0 || pnetid1[i] == SMC_ASCII_BLANK) &&
+ (pnetid2[i] == 0 || pnetid2[i] == SMC_ASCII_BLANK))
break;
- }
+ if (pnetid1[i] != pnetid2[i])
+ return false;
}
- read_unlock(&smc_pnettable.lock);
- return found_pnetelem;
+ return true;
}
/* Remove a pnetid from the pnet table.
@@ -104,21 +102,39 @@ static struct smc_pnetentry *smc_pnet_find_pnetid(char *pnet_name)
static int smc_pnet_remove_by_pnetid(char *pnet_name)
{
struct smc_pnetentry *pnetelem, *tmp_pe;
+ struct smc_ib_device *ibdev;
int rc = -ENOENT;
+ int ibport;
+ /* remove netdevices */
write_lock(&smc_pnettable.lock);
list_for_each_entry_safe(pnetelem, tmp_pe, &smc_pnettable.pnetlist,
list) {
- if (!strncmp(pnetelem->pnet_name, pnet_name,
- sizeof(pnetelem->pnet_name))) {
+ if (!pnet_name ||
+ smc_pnet_match(pnetelem->pnet_name, pnet_name)) {
list_del(&pnetelem->list);
dev_put(pnetelem->ndev);
kfree(pnetelem);
rc = 0;
- break;
}
}
write_unlock(&smc_pnettable.lock);
+ /* remove ib devices */
+ spin_lock(&smc_ib_devices.lock);
+ list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
+ for (ibport = 0; ibport < SMC_MAX_PORTS; ibport++) {
+ if (ibdev->pnetid_by_user[ibport] &&
+ (!pnet_name ||
+ smc_pnet_match(pnet_name,
+ ibdev->pnetid[ibport]))) {
+ memset(ibdev->pnetid[ibport], 0,
+ SMC_MAX_PNETID_LEN);
+ ibdev->pnetid_by_user[ibport] = false;
+ rc = 0;
+ }
+ }
+ }
+ spin_unlock(&smc_ib_devices.lock);
return rc;
}
@@ -144,53 +160,66 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev)
return rc;
}
-/* Remove a pnet entry mentioning a given ib device from the pnet table.
+/* Append a pnetid to the end of the pnet table if not already on this list.
*/
-int smc_pnet_remove_by_ibdev(struct smc_ib_device *ibdev)
+static int smc_pnet_enter(struct smc_user_pnetentry *new_pnetelem)
{
- struct smc_pnetentry *pnetelem, *tmp_pe;
- int rc = -ENOENT;
-
- write_lock(&smc_pnettable.lock);
- list_for_each_entry_safe(pnetelem, tmp_pe, &smc_pnettable.pnetlist,
- list) {
- if (pnetelem->smcibdev == ibdev) {
- list_del(&pnetelem->list);
- dev_put(pnetelem->ndev);
- kfree(pnetelem);
- rc = 0;
- break;
+ u8 pnet_null[SMC_MAX_PNETID_LEN] = {0};
+ u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
+ struct smc_pnetentry *tmp_pnetelem;
+ struct smc_pnetentry *pnetelem;
+ struct net_device *ndev;
+ bool new_netdev = true;
+ bool new_ibdev = false;
+
+ if (new_pnetelem->smcibdev) {
+ struct smc_ib_device *ib_dev = new_pnetelem->smcibdev;
+ int ib_port = new_pnetelem->ib_port;
+
+ spin_lock(&smc_ib_devices.lock);
+ if (smc_pnet_match(ib_dev->pnetid[ib_port - 1], pnet_null)) {
+ memcpy(ib_dev->pnetid[ib_port - 1],
+ new_pnetelem->pnet_name, SMC_MAX_PNETID_LEN);
+ ib_dev->pnetid_by_user[ib_port - 1] = true;
+ new_ibdev = true;
}
+ spin_unlock(&smc_ib_devices.lock);
}
- write_unlock(&smc_pnettable.lock);
- return rc;
-}
-/* Append a pnetid to the end of the pnet table if not already on this list.
- */
-static int smc_pnet_enter(struct smc_pnetentry *new_pnetelem)
-{
- struct smc_pnetentry *pnetelem;
- int rc = -EEXIST;
+ if (!new_pnetelem->ndev)
+ return new_ibdev ? 0 : -EEXIST;
+
+ /* check if (base) netdev already has a pnetid. If there is one, we do
+ * not want to add a pnet table entry
+ */
+ ndev = pnet_find_base_ndev(new_pnetelem->ndev);
+ if (!smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
+ ndev_pnetid))
+ return new_ibdev ? 0 : -EEXIST;
+
+ /* add a new netdev entry to the pnet table if there isn't one */
+ tmp_pnetelem = kzalloc(sizeof(*pnetelem), GFP_KERNEL);
+ if (!tmp_pnetelem)
+ return -ENOMEM;
+ memcpy(tmp_pnetelem->pnet_name, new_pnetelem->pnet_name,
+ SMC_MAX_PNETID_LEN);
+ tmp_pnetelem->ndev = new_pnetelem->ndev;
write_lock(&smc_pnettable.lock);
list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
- if (!strncmp(pnetelem->pnet_name, new_pnetelem->pnet_name,
- sizeof(new_pnetelem->pnet_name)) ||
- !strncmp(pnetelem->ndev->name, new_pnetelem->ndev->name,
- sizeof(new_pnetelem->ndev->name)) ||
- smc_pnet_same_ibname(pnetelem,
- new_pnetelem->smcibdev->ibdev->name,
- new_pnetelem->ib_port)) {
- dev_put(pnetelem->ndev);
- goto found;
- }
+ if (pnetelem->ndev == new_pnetelem->ndev)
+ new_netdev = false;
}
- list_add_tail(&new_pnetelem->list, &smc_pnettable.pnetlist);
- rc = 0;
-found:
- write_unlock(&smc_pnettable.lock);
- return rc;
+ if (new_netdev) {
+ dev_hold(tmp_pnetelem->ndev);
+ list_add_tail(&tmp_pnetelem->list, &smc_pnettable.pnetlist);
+ write_unlock(&smc_pnettable.lock);
+ } else {
+ write_unlock(&smc_pnettable.lock);
+ kfree(tmp_pnetelem);
+ }
+
+ return (new_netdev || new_ibdev) ? 0 : -EEXIST;
}
/* The limit for pnetid is 16 characters.
@@ -241,7 +270,8 @@ static struct smc_ib_device *smc_pnet_find_ib(char *ib_name)
/* Parse the supplied netlink attributes and fill a pnetentry structure.
* For ethernet and infiniband device names verify that the devices exist.
*/
-static int smc_pnet_fill_entry(struct net *net, struct smc_pnetentry *pnetelem,
+static int smc_pnet_fill_entry(struct net *net,
+ struct smc_user_pnetentry *pnetelem,
struct nlattr *tb[])
{
char *string, *ibname;
@@ -258,30 +288,29 @@ static int smc_pnet_fill_entry(struct net *net, struct smc_pnetentry *pnetelem,
goto error;
rc = -EINVAL;
- if (!tb[SMC_PNETID_ETHNAME])
- goto error;
- rc = -ENOENT;
- string = (char *)nla_data(tb[SMC_PNETID_ETHNAME]);
- pnetelem->ndev = dev_get_by_name(net, string);
- if (!pnetelem->ndev)
- goto error;
-
- rc = -EINVAL;
- if (!tb[SMC_PNETID_IBNAME])
- goto error;
- rc = -ENOENT;
- ibname = (char *)nla_data(tb[SMC_PNETID_IBNAME]);
- ibname = strim(ibname);
- pnetelem->smcibdev = smc_pnet_find_ib(ibname);
- if (!pnetelem->smcibdev)
- goto error;
+ if (tb[SMC_PNETID_ETHNAME]) {
+ string = (char *)nla_data(tb[SMC_PNETID_ETHNAME]);
+ pnetelem->ndev = dev_get_by_name(net, string);
+ if (!pnetelem->ndev)
+ goto error;
+ }
rc = -EINVAL;
- if (!tb[SMC_PNETID_IBPORT])
- goto error;
- pnetelem->ib_port = nla_get_u8(tb[SMC_PNETID_IBPORT]);
- if (pnetelem->ib_port < 1 || pnetelem->ib_port > SMC_MAX_PORTS)
- goto error;
+ if (tb[SMC_PNETID_IBNAME]) {
+ ibname = (char *)nla_data(tb[SMC_PNETID_IBNAME]);
+ ibname = strim(ibname);
+ pnetelem->smcibdev = smc_pnet_find_ib(ibname);
+ if (!pnetelem->smcibdev)
+ goto error;
+ if (pnetelem->smcibdev) {
+ if (!tb[SMC_PNETID_IBPORT])
+ goto error;
+ pnetelem->ib_port = nla_get_u8(tb[SMC_PNETID_IBPORT]);
+ if (pnetelem->ib_port < 1 ||
+ pnetelem->ib_port > SMC_MAX_PORTS)
+ goto error;
+ }
+ }
return 0;
@@ -292,71 +321,44 @@ static int smc_pnet_fill_entry(struct net *net, struct smc_pnetentry *pnetelem,
}
/* Convert an smc_pnetentry to a netlink attribute sequence */
-static int smc_pnet_set_nla(struct sk_buff *msg, struct smc_pnetentry *pnetelem)
+static int smc_pnet_set_nla(struct sk_buff *msg,
+ struct smc_user_pnetentry *pnetelem)
{
- if (nla_put_string(msg, SMC_PNETID_NAME, pnetelem->pnet_name) ||
- nla_put_string(msg, SMC_PNETID_ETHNAME, pnetelem->ndev->name) ||
- nla_put_string(msg, SMC_PNETID_IBNAME,
- pnetelem->smcibdev->ibdev->name) ||
- nla_put_u8(msg, SMC_PNETID_IBPORT, pnetelem->ib_port))
+ if (nla_put_string(msg, SMC_PNETID_NAME, pnetelem->pnet_name))
return -1;
- return 0;
-}
-
-/* Retrieve one PNETID entry */
-static int smc_pnet_get(struct sk_buff *skb, struct genl_info *info)
-{
- struct smc_pnetentry *pnetelem;
- struct sk_buff *msg;
- void *hdr;
- int rc;
-
- if (!info->attrs[SMC_PNETID_NAME])
- return -EINVAL;
- pnetelem = smc_pnet_find_pnetid(
- (char *)nla_data(info->attrs[SMC_PNETID_NAME]));
- if (!pnetelem)
- return -ENOENT;
- msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
- if (!msg)
- return -ENOMEM;
-
- hdr = genlmsg_put(msg, info->snd_portid, info->snd_seq,
- &smc_pnet_nl_family, 0, SMC_PNETID_GET);
- if (!hdr) {
- rc = -EMSGSIZE;
- goto err_out;
+ if (pnetelem->ndev) {
+ if (nla_put_string(msg, SMC_PNETID_ETHNAME,
+ pnetelem->ndev->name))
+ return -1;
+ } else {
+ if (nla_put_string(msg, SMC_PNETID_ETHNAME, "n/a"))
+ return -1;
}
-
- if (smc_pnet_set_nla(msg, pnetelem)) {
- rc = -ENOBUFS;
- goto err_out;
+ if (pnetelem->smcibdev) {
+ if (nla_put_string(msg, SMC_PNETID_IBNAME,
+ pnetelem->smcibdev->ibdev->name) ||
+ nla_put_u8(msg, SMC_PNETID_IBPORT, pnetelem->ib_port))
+ return -1;
+ } else {
+ if (nla_put_string(msg, SMC_PNETID_IBNAME, "n/a") ||
+ nla_put_u8(msg, SMC_PNETID_IBPORT, 0xff))
+ return -1;
}
- genlmsg_end(msg, hdr);
- return genlmsg_reply(msg, info);
-
-err_out:
- nlmsg_free(msg);
- return rc;
+ return 0;
}
static int smc_pnet_add(struct sk_buff *skb, struct genl_info *info)
{
struct net *net = genl_info_net(info);
- struct smc_pnetentry *pnetelem;
+ struct smc_user_pnetentry pnetelem;
int rc;
- pnetelem = kzalloc(sizeof(*pnetelem), GFP_KERNEL);
- if (!pnetelem)
- return -ENOMEM;
- rc = smc_pnet_fill_entry(net, pnetelem, info->attrs);
+ rc = smc_pnet_fill_entry(net, &pnetelem, info->attrs);
if (!rc)
- rc = smc_pnet_enter(pnetelem);
- if (rc) {
- kfree(pnetelem);
- return rc;
- }
+ rc = smc_pnet_enter(&pnetelem);
+ if (pnetelem.ndev)
+ dev_put(pnetelem.ndev);
return rc;
}
@@ -376,7 +378,7 @@ static int smc_pnet_dump_start(struct netlink_callback *cb)
static int smc_pnet_dumpinfo(struct sk_buff *skb,
u32 portid, u32 seq, u32 flags,
- struct smc_pnetentry *pnetelem)
+ struct smc_user_pnetentry *pnetelem)
{
void *hdr;
@@ -392,42 +394,107 @@ static int smc_pnet_dumpinfo(struct sk_buff *skb,
return 0;
}
-static int smc_pnet_dump(struct sk_buff *skb, struct netlink_callback *cb)
+static int _smc_pnet_dump(struct sk_buff *skb, u32 portid, u32 seq, u8 *pnetid,
+ int start_idx)
{
+ struct smc_user_pnetentry tmp_entry;
struct smc_pnetentry *pnetelem;
+ struct smc_ib_device *ibdev;
int idx = 0;
+ int ibport;
+ /* dump netdevices */
read_lock(&smc_pnettable.lock);
list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
- if (idx++ < cb->args[0])
+ if (pnetid && !smc_pnet_match(pnetelem->pnet_name, pnetid))
+ continue;
+ if (idx++ < start_idx)
continue;
- if (smc_pnet_dumpinfo(skb, NETLINK_CB(cb->skb).portid,
- cb->nlh->nlmsg_seq, NLM_F_MULTI,
- pnetelem)) {
+ memset(&tmp_entry, 0, sizeof(tmp_entry));
+ memcpy(&tmp_entry.pnet_name, pnetelem->pnet_name,
+ SMC_MAX_PNETID_LEN);
+ tmp_entry.ndev = pnetelem->ndev;
+ if (smc_pnet_dumpinfo(skb, portid, seq, NLM_F_MULTI,
+ &tmp_entry)) {
--idx;
break;
}
}
- cb->args[0] = idx;
read_unlock(&smc_pnettable.lock);
+
+ /* dump ib devices */
+ spin_lock(&smc_ib_devices.lock);
+ list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
+ for (ibport = 0; ibport < SMC_MAX_PORTS; ibport++) {
+ if (ibdev->pnetid_by_user[ibport]) {
+ if (pnetid &&
+ !smc_pnet_match(ibdev->pnetid[ibport],
+ pnetid))
+ continue;
+ if (idx++ < start_idx)
+ continue;
+ memset(&tmp_entry, 0, sizeof(tmp_entry));
+ memcpy(&tmp_entry.pnet_name,
+ ibdev->pnetid[ibport],
+ SMC_MAX_PNETID_LEN);
+ tmp_entry.smcibdev = ibdev;
+ tmp_entry.ib_port = ibport + 1;
+ if (smc_pnet_dumpinfo(skb, portid, seq,
+ NLM_F_MULTI,
+ &tmp_entry)) {
+ --idx;
+ break;
+ }
+ }
+ }
+ }
+ spin_unlock(&smc_ib_devices.lock);
+
+ return idx;
+}
+
+static int smc_pnet_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ int idx;
+
+ idx = _smc_pnet_dump(skb, NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq, NULL, cb->args[0]);
+
+ cb->args[0] = idx;
return skb->len;
}
+/* Retrieve one PNETID entry */
+static int smc_pnet_get(struct sk_buff *skb, struct genl_info *info)
+{
+ struct sk_buff *msg;
+ void *hdr;
+
+ if (!info->attrs[SMC_PNETID_NAME])
+ return -EINVAL;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ _smc_pnet_dump(msg, info->snd_portid, info->snd_seq,
+ nla_data(info->attrs[SMC_PNETID_NAME]), 0);
+
+ /* finish multi part message and send it */
+ hdr = nlmsg_put(msg, info->snd_portid, info->snd_seq, NLMSG_DONE, 0,
+ NLM_F_MULTI);
+ if (!hdr) {
+ nlmsg_free(msg);
+ return -EMSGSIZE;
+ }
+ return genlmsg_reply(msg, info);
+}
+
/* Remove and delete all pnetids from pnet table.
*/
static int smc_pnet_flush(struct sk_buff *skb, struct genl_info *info)
{
- struct smc_pnetentry *pnetelem, *tmp_pe;
-
- write_lock(&smc_pnettable.lock);
- list_for_each_entry_safe(pnetelem, tmp_pe, &smc_pnettable.pnetlist,
- list) {
- list_del(&pnetelem->list);
- dev_put(pnetelem->ndev);
- kfree(pnetelem);
- }
- write_unlock(&smc_pnettable.lock);
- return 0;
+ return smc_pnet_remove_by_pnetid(NULL);
}
/* SMC_PNETID generic netlink operation definition */
@@ -534,6 +601,25 @@ static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
return ndev;
}
+static int smc_pnet_find_ndev_pnetid_by_table(struct net_device *netdev,
+ u8 *pnetid)
+{
+ struct smc_pnetentry *pnetelem;
+ int rc = -ENOENT;
+
+ read_lock(&smc_pnettable.lock);
+ list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
+ if (netdev == pnetelem->ndev) {
+ /* get pnetid of netdev device */
+ memcpy(pnetid, pnetelem->pnet_name, SMC_MAX_PNETID_LEN);
+ rc = 0;
+ break;
+ }
+ }
+ read_unlock(&smc_pnettable.lock);
+ return rc;
+}
+
/* Determine the corresponding IB device port based on the hardware PNETID.
* Searching stops at the first matching active IB device port with vlan_id
* configured.
@@ -549,7 +635,8 @@ static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev,
ndev = pnet_find_base_ndev(ndev);
if (smc_pnetid_by_dev_port(ndev->dev.parent, ndev->dev_port,
- ndev_pnetid))
+ ndev_pnetid) &&
+ smc_pnet_find_ndev_pnetid_by_table(ndev, ndev_pnetid))
return; /* pnetid could not be determined */
spin_lock(&smc_ib_devices.lock);
@@ -557,8 +644,7 @@ static void smc_pnet_find_roce_by_pnetid(struct net_device *ndev,
for (i = 1; i <= SMC_MAX_PORTS; i++) {
if (!rdma_is_port_valid(ibdev->ibdev, i))
continue;
- if (!memcmp(ibdev->pnetid[i - 1], ndev_pnetid,
- SMC_MAX_PNETID_LEN) &&
+ if (smc_pnet_match(ibdev->pnetid[i - 1], ndev_pnetid) &&
smc_ib_port_active(ibdev, i) &&
!smc_ib_determine_gid(ibdev, i, vlan_id, gid,
NULL)) {
@@ -593,31 +679,6 @@ static void smc_pnet_find_ism_by_pnetid(struct net_device *ndev,
spin_unlock(&smcd_dev_list.lock);
}
-/* Lookup of coupled ib_device via SMC pnet table */
-static void smc_pnet_find_roce_by_table(struct net_device *netdev,
- struct smc_ib_device **smcibdev,
- u8 *ibport, unsigned short vlan_id,
- u8 gid[])
-{
- struct smc_pnetentry *pnetelem;
-
- read_lock(&smc_pnettable.lock);
- list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
- if (netdev == pnetelem->ndev) {
- if (smc_ib_port_active(pnetelem->smcibdev,
- pnetelem->ib_port) &&
- !smc_ib_determine_gid(pnetelem->smcibdev,
- pnetelem->ib_port, vlan_id,
- gid, NULL)) {
- *smcibdev = pnetelem->smcibdev;
- *ibport = pnetelem->ib_port;
- }
- break;
- }
- }
- read_unlock(&smc_pnettable.lock);
-}
-
/* PNET table analysis for a given sock:
* determine ib_device and port belonging to used internal TCP socket
* ethernet interface.
@@ -636,13 +697,7 @@ void smc_pnet_find_roce_resource(struct sock *sk,
if (!dst->dev)
goto out_rel;
- /* if possible, lookup via hardware-defined pnetid */
smc_pnet_find_roce_by_pnetid(dst->dev, smcibdev, ibport, vlan_id, gid);
- if (*smcibdev)
- goto out_rel;
-
- /* lookup via SMC PNET table */
- smc_pnet_find_roce_by_table(dst->dev, smcibdev, ibport, vlan_id, gid);
out_rel:
dst_release(dst);
diff --git a/net/smc/smc_pnet.h b/net/smc/smc_pnet.h
index 8ff777636e32..37044e4ee50f 100644
--- a/net/smc/smc_pnet.h
+++ b/net/smc/smc_pnet.h
@@ -31,7 +31,6 @@ static inline int smc_pnetid_by_dev_port(struct device *dev,
int smc_pnet_init(void) __init;
void smc_pnet_exit(void);
-int smc_pnet_remove_by_ibdev(struct smc_ib_device *ibdev);
void smc_pnet_find_roce_resource(struct sock *sk,
struct smc_ib_device **smcibdev, u8 *ibport,
unsigned short vlan_id, u8 gid[]);
--
2.16.4
^ permalink raw reply related
* [PATCH net-next 5/6] net/smc: add pnet table namespace support
From: Ursula Braun @ 2019-02-21 12:01 UTC (permalink / raw)
To: davem
Cc: netdev, linux-s390, schwidefsky, heiko.carstens, raspl, kgraul,
ubraun
In-Reply-To: <20190221120103.10866-1-ubraun@linux.ibm.com>
From: Hans Wippel <hwippel@linux.ibm.com>
This patch adds namespace support to the pnet table code. Each network
namespace gets its own pnet table. Infiniband and smcd device pnetids
can only be modified in the initial namespace. In other namespaces they
can still be used as if they were set by the underlying hardware.
Signed-off-by: Hans Wippel <hwippel@linux.ibm.com>
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
---
net/smc/af_smc.c | 28 ++++++++++
net/smc/smc_netns.h | 20 ++++++++
net/smc/smc_pnet.c | 145 ++++++++++++++++++++++++++++++++++++----------------
net/smc/smc_pnet.h | 12 +++++
4 files changed, 162 insertions(+), 43 deletions(-)
create mode 100644 net/smc/smc_netns.h
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 46fa9f3016cc..77ef53596d18 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -30,6 +30,10 @@
#include <net/smc.h>
#include <asm/ioctls.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+#include "smc_netns.h"
+
#include "smc.h"
#include "smc_clc.h"
#include "smc_llc.h"
@@ -1966,10 +1970,33 @@ static const struct net_proto_family smc_sock_family_ops = {
.create = smc_create,
};
+unsigned int smc_net_id;
+
+static __net_init int smc_net_init(struct net *net)
+{
+ return smc_pnet_net_init(net);
+}
+
+static void __net_exit smc_net_exit(struct net *net)
+{
+ smc_pnet_net_exit(net);
+}
+
+static struct pernet_operations smc_net_ops = {
+ .init = smc_net_init,
+ .exit = smc_net_exit,
+ .id = &smc_net_id,
+ .size = sizeof(struct smc_net),
+};
+
static int __init smc_init(void)
{
int rc;
+ rc = register_pernet_subsys(&smc_net_ops);
+ if (rc)
+ return rc;
+
rc = smc_pnet_init();
if (rc)
return rc;
@@ -2035,6 +2062,7 @@ static void __exit smc_exit(void)
proto_unregister(&smc_proto6);
proto_unregister(&smc_proto);
smc_pnet_exit();
+ unregister_pernet_subsys(&smc_net_ops);
}
module_init(smc_init);
diff --git a/net/smc/smc_netns.h b/net/smc/smc_netns.h
new file mode 100644
index 000000000000..e7a8fc4ae02f
--- /dev/null
+++ b/net/smc/smc_netns.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Shared Memory Communications
+ *
+ * Network namespace definitions.
+ *
+ * Copyright IBM Corp. 2018
+ */
+
+#ifndef SMC_NETNS_H
+#define SMC_NETNS_H
+
+#include "smc_pnet.h"
+
+extern unsigned int smc_net_id;
+
+/* per-network namespace private data */
+struct smc_net {
+ struct smc_pnettable pnettable;
+};
+#endif
diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c
index 5497a8b44287..878f5c085444 100644
--- a/net/smc/smc_pnet.c
+++ b/net/smc/smc_pnet.c
@@ -20,6 +20,9 @@
#include <rdma/ib_verbs.h>
+#include <net/netns/generic.h>
+#include "smc_netns.h"
+
#include "smc_pnet.h"
#include "smc_ib.h"
#include "smc_ism.h"
@@ -46,19 +49,6 @@ static struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = {
static struct genl_family smc_pnet_nl_family;
-/**
- * struct smc_pnettable - SMC PNET table anchor
- * @lock: Lock for list action
- * @pnetlist: List of PNETIDs
- */
-static struct smc_pnettable {
- rwlock_t lock;
- struct list_head pnetlist;
-} smc_pnettable = {
- .pnetlist = LIST_HEAD_INIT(smc_pnettable.pnetlist),
- .lock = __RW_LOCK_UNLOCKED(smc_pnettable.lock)
-};
-
/**
* struct smc_user_pnetentry - pnet identifier name entry for/from user
* @list: List node.
@@ -101,17 +91,23 @@ static bool smc_pnet_match(u8 *pnetid1, u8 *pnetid2)
/* Remove a pnetid from the pnet table.
*/
-static int smc_pnet_remove_by_pnetid(char *pnet_name)
+static int smc_pnet_remove_by_pnetid(struct net *net, char *pnet_name)
{
struct smc_pnetentry *pnetelem, *tmp_pe;
+ struct smc_pnettable *pnettable;
struct smc_ib_device *ibdev;
struct smcd_dev *smcd_dev;
+ struct smc_net *sn;
int rc = -ENOENT;
int ibport;
+ /* get pnettable for namespace */
+ sn = net_generic(net, smc_net_id);
+ pnettable = &sn->pnettable;
+
/* remove netdevices */
- write_lock(&smc_pnettable.lock);
- list_for_each_entry_safe(pnetelem, tmp_pe, &smc_pnettable.pnetlist,
+ write_lock(&pnettable->lock);
+ list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist,
list) {
if (!pnet_name ||
smc_pnet_match(pnetelem->pnet_name, pnet_name)) {
@@ -121,7 +117,12 @@ static int smc_pnet_remove_by_pnetid(char *pnet_name)
rc = 0;
}
}
- write_unlock(&smc_pnettable.lock);
+ write_unlock(&pnettable->lock);
+
+ /* if this is not the initial namespace, stop here */
+ if (net != &init_net)
+ return rc;
+
/* remove ib devices */
spin_lock(&smc_ib_devices.lock);
list_for_each_entry(ibdev, &smc_ib_devices.list, list) {
@@ -158,11 +159,17 @@ static int smc_pnet_remove_by_pnetid(char *pnet_name)
static int smc_pnet_remove_by_ndev(struct net_device *ndev)
{
struct smc_pnetentry *pnetelem, *tmp_pe;
+ struct smc_pnettable *pnettable;
+ struct net *net = dev_net(ndev);
+ struct smc_net *sn;
int rc = -ENOENT;
- write_lock(&smc_pnettable.lock);
- list_for_each_entry_safe(pnetelem, tmp_pe, &smc_pnettable.pnetlist,
- list) {
+ /* get pnettable for namespace */
+ sn = net_generic(net, smc_net_id);
+ pnettable = &sn->pnettable;
+
+ write_lock(&pnettable->lock);
+ list_for_each_entry_safe(pnetelem, tmp_pe, &pnettable->pnetlist, list) {
if (pnetelem->ndev == ndev) {
list_del(&pnetelem->list);
dev_put(pnetelem->ndev);
@@ -171,13 +178,14 @@ static int smc_pnet_remove_by_ndev(struct net_device *ndev)
break;
}
}
- write_unlock(&smc_pnettable.lock);
+ write_unlock(&pnettable->lock);
return rc;
}
/* Append a pnetid to the end of the pnet table if not already on this list.
*/
-static int smc_pnet_enter(struct smc_user_pnetentry *new_pnetelem)
+static int smc_pnet_enter(struct smc_pnettable *pnettable,
+ struct smc_user_pnetentry *new_pnetelem)
{
u8 pnet_null[SMC_MAX_PNETID_LEN] = {0};
u8 ndev_pnetid[SMC_MAX_PNETID_LEN];
@@ -233,17 +241,17 @@ static int smc_pnet_enter(struct smc_user_pnetentry *new_pnetelem)
SMC_MAX_PNETID_LEN);
tmp_pnetelem->ndev = new_pnetelem->ndev;
- write_lock(&smc_pnettable.lock);
- list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
+ write_lock(&pnettable->lock);
+ list_for_each_entry(pnetelem, &pnettable->pnetlist, list) {
if (pnetelem->ndev == new_pnetelem->ndev)
new_netdev = false;
}
if (new_netdev) {
dev_hold(tmp_pnetelem->ndev);
- list_add_tail(&tmp_pnetelem->list, &smc_pnettable.pnetlist);
- write_unlock(&smc_pnettable.lock);
+ list_add_tail(&tmp_pnetelem->list, &pnettable->pnetlist);
+ write_unlock(&pnettable->lock);
} else {
- write_unlock(&smc_pnettable.lock);
+ write_unlock(&pnettable->lock);
kfree(tmp_pnetelem);
}
@@ -340,6 +348,10 @@ static int smc_pnet_fill_entry(struct net *net,
goto error;
}
+ /* if this is not the initial namespace, stop here */
+ if (net != &init_net)
+ return 0;
+
rc = -EINVAL;
if (tb[SMC_PNETID_IBNAME]) {
ibname = (char *)nla_data(tb[SMC_PNETID_IBNAME]);
@@ -403,11 +415,17 @@ static int smc_pnet_add(struct sk_buff *skb, struct genl_info *info)
{
struct net *net = genl_info_net(info);
struct smc_user_pnetentry pnetelem;
+ struct smc_pnettable *pnettable;
+ struct smc_net *sn;
int rc;
+ /* get pnettable for namespace */
+ sn = net_generic(net, smc_net_id);
+ pnettable = &sn->pnettable;
+
rc = smc_pnet_fill_entry(net, &pnetelem, info->attrs);
if (!rc)
- rc = smc_pnet_enter(&pnetelem);
+ rc = smc_pnet_enter(pnettable, &pnetelem);
if (pnetelem.ndev)
dev_put(pnetelem.ndev);
return rc;
@@ -415,9 +433,11 @@ static int smc_pnet_add(struct sk_buff *skb, struct genl_info *info)
static int smc_pnet_del(struct sk_buff *skb, struct genl_info *info)
{
+ struct net *net = genl_info_net(info);
+
if (!info->attrs[SMC_PNETID_NAME])
return -EINVAL;
- return smc_pnet_remove_by_pnetid(
+ return smc_pnet_remove_by_pnetid(net,
(char *)nla_data(info->attrs[SMC_PNETID_NAME]));
}
@@ -445,19 +465,25 @@ static int smc_pnet_dumpinfo(struct sk_buff *skb,
return 0;
}
-static int _smc_pnet_dump(struct sk_buff *skb, u32 portid, u32 seq, u8 *pnetid,
- int start_idx)
+static int _smc_pnet_dump(struct net *net, struct sk_buff *skb, u32 portid,
+ u32 seq, u8 *pnetid, int start_idx)
{
struct smc_user_pnetentry tmp_entry;
+ struct smc_pnettable *pnettable;
struct smc_pnetentry *pnetelem;
struct smc_ib_device *ibdev;
struct smcd_dev *smcd_dev;
+ struct smc_net *sn;
int idx = 0;
int ibport;
+ /* get pnettable for namespace */
+ sn = net_generic(net, smc_net_id);
+ pnettable = &sn->pnettable;
+
/* dump netdevices */
- read_lock(&smc_pnettable.lock);
- list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
+ read_lock(&pnettable->lock);
+ list_for_each_entry(pnetelem, &pnettable->pnetlist, list) {
if (pnetid && !smc_pnet_match(pnetelem->pnet_name, pnetid))
continue;
if (idx++ < start_idx)
@@ -472,7 +498,11 @@ static int _smc_pnet_dump(struct sk_buff *skb, u32 portid, u32 seq, u8 *pnetid,
break;
}
}
- read_unlock(&smc_pnettable.lock);
+ read_unlock(&pnettable->lock);
+
+ /* if this is not the initial namespace, stop here */
+ if (net != &init_net)
+ return idx;
/* dump ib devices */
spin_lock(&smc_ib_devices.lock);
@@ -528,9 +558,10 @@ static int _smc_pnet_dump(struct sk_buff *skb, u32 portid, u32 seq, u8 *pnetid,
static int smc_pnet_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
+ struct net *net = sock_net(skb->sk);
int idx;
- idx = _smc_pnet_dump(skb, NETLINK_CB(cb->skb).portid,
+ idx = _smc_pnet_dump(net, skb, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NULL, cb->args[0]);
cb->args[0] = idx;
@@ -540,6 +571,7 @@ static int smc_pnet_dump(struct sk_buff *skb, struct netlink_callback *cb)
/* Retrieve one PNETID entry */
static int smc_pnet_get(struct sk_buff *skb, struct genl_info *info)
{
+ struct net *net = genl_info_net(info);
struct sk_buff *msg;
void *hdr;
@@ -550,7 +582,7 @@ static int smc_pnet_get(struct sk_buff *skb, struct genl_info *info)
if (!msg)
return -ENOMEM;
- _smc_pnet_dump(msg, info->snd_portid, info->snd_seq,
+ _smc_pnet_dump(net, msg, info->snd_portid, info->snd_seq,
nla_data(info->attrs[SMC_PNETID_NAME]), 0);
/* finish multi part message and send it */
@@ -567,7 +599,9 @@ static int smc_pnet_get(struct sk_buff *skb, struct genl_info *info)
*/
static int smc_pnet_flush(struct sk_buff *skb, struct genl_info *info)
{
- return smc_pnet_remove_by_pnetid(NULL);
+ struct net *net = genl_info_net(info);
+
+ return smc_pnet_remove_by_pnetid(net, NULL);
}
/* SMC_PNETID generic netlink operation definition */
@@ -631,6 +665,18 @@ static struct notifier_block smc_netdev_notifier = {
.notifier_call = smc_pnet_netdev_event
};
+/* init network namespace */
+int smc_pnet_net_init(struct net *net)
+{
+ struct smc_net *sn = net_generic(net, smc_net_id);
+ struct smc_pnettable *pnettable = &sn->pnettable;
+
+ INIT_LIST_HEAD(&pnettable->pnetlist);
+ rwlock_init(&pnettable->lock);
+
+ return 0;
+}
+
int __init smc_pnet_init(void)
{
int rc;
@@ -644,9 +690,15 @@ int __init smc_pnet_init(void)
return rc;
}
+/* exit network namespace */
+void smc_pnet_net_exit(struct net *net)
+{
+ /* flush pnet table */
+ smc_pnet_remove_by_pnetid(net, NULL);
+}
+
void smc_pnet_exit(void)
{
- smc_pnet_flush(NULL, NULL);
unregister_netdevice_notifier(&smc_netdev_notifier);
genl_unregister_family(&smc_pnet_nl_family);
}
@@ -674,22 +726,29 @@ static struct net_device *pnet_find_base_ndev(struct net_device *ndev)
return ndev;
}
-static int smc_pnet_find_ndev_pnetid_by_table(struct net_device *netdev,
+static int smc_pnet_find_ndev_pnetid_by_table(struct net_device *ndev,
u8 *pnetid)
{
+ struct smc_pnettable *pnettable;
+ struct net *net = dev_net(ndev);
struct smc_pnetentry *pnetelem;
+ struct smc_net *sn;
int rc = -ENOENT;
- read_lock(&smc_pnettable.lock);
- list_for_each_entry(pnetelem, &smc_pnettable.pnetlist, list) {
- if (netdev == pnetelem->ndev) {
+ /* get pnettable for namespace */
+ sn = net_generic(net, smc_net_id);
+ pnettable = &sn->pnettable;
+
+ read_lock(&pnettable->lock);
+ list_for_each_entry(pnetelem, &pnettable->pnetlist, list) {
+ if (ndev == pnetelem->ndev) {
/* get pnetid of netdev device */
memcpy(pnetid, pnetelem->pnet_name, SMC_MAX_PNETID_LEN);
rc = 0;
break;
}
}
- read_unlock(&smc_pnettable.lock);
+ read_unlock(&pnettable->lock);
return rc;
}
diff --git a/net/smc/smc_pnet.h b/net/smc/smc_pnet.h
index 37044e4ee50f..5eac42fb45d0 100644
--- a/net/smc/smc_pnet.h
+++ b/net/smc/smc_pnet.h
@@ -19,6 +19,16 @@
struct smc_ib_device;
struct smcd_dev;
+/**
+ * struct smc_pnettable - SMC PNET table anchor
+ * @lock: Lock for list action
+ * @pnetlist: List of PNETIDs
+ */
+struct smc_pnettable {
+ rwlock_t lock;
+ struct list_head pnetlist;
+};
+
static inline int smc_pnetid_by_dev_port(struct device *dev,
unsigned short port, u8 *pnetid)
{
@@ -30,7 +40,9 @@ static inline int smc_pnetid_by_dev_port(struct device *dev,
}
int smc_pnet_init(void) __init;
+int smc_pnet_net_init(struct net *net);
void smc_pnet_exit(void);
+void smc_pnet_net_exit(struct net *net);
void smc_pnet_find_roce_resource(struct sock *sk,
struct smc_ib_device **smcibdev, u8 *ibport,
unsigned short vlan_id, u8 gid[]);
--
2.16.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox