* Re: [PATCH net] net: validate untrusted gso packets without csum offload
From: Willem de Bruijn @ 2019-02-18 19:12 UTC (permalink / raw)
To: Network Development
Cc: David Miller, Eric Dumazet, Jason Wang, Maxim Mikityanskiy,
Willem de Bruijn, syzbot
In-Reply-To: <20190215171547.247018-1-willemdebruijn.kernel@gmail.com>
On Fri, Feb 15, 2019 at 12:15 PM Willem de Bruijn
<willemdebruijn.kernel@gmail.com> wrote:
>
> From: Willem de Bruijn <willemb@google.com>
>
> Syzkaller again found a path to a kernel crash through bad gso input.
> By building an excessively large packet to cause an skb field to wrap.
>
> If VIRTIO_NET_HDR_F_NEEDS_CSUM was set this would have been dropped in
> skb_partial_csum_set.
>
> GSO packets that do not set checksum offload are suspicious and rare.
> Most callers of virtio_net_hdr_to_skb already pass them to
> skb_probe_transport_header.
>
> Move that test forward, change it to detect parse failure and drop
> packets on failure as those cleary are not one of the legitimate
> VIRTIO_NET_HDR_GSO types.
>
> Fixes: bfd5f4a3d605 ("packet: Add GSO/csum offload support.")
> Fixes: f43798c27684 ("tun: Allow GSO using virtio_net_hdr")
> Reported-by: syzbot <syzkaller@googlegroups.com>
> Signed-off-by: Willem de Bruijn <willemb@google.com>
This causes false positive drops on virtio-net and tun for these
packets with gso without csum_off. And on pf_packet with proto 0.
This happens because skb->protocol is set in these callers after
the call to virtio_net_hdr_to_skb. And the flow dissector relies on
this to start dissection, not the link layer header (if present).
Moving this logic forward is too much churn for net, especially since
eth_type_header pulls the header, requiring additional changes to
adjust csum_start.
virtio_net_hdr_set_proto() aims to fix this by deriving skb->protocol
from the gso_type. But unfortunately for UDP it unconditionally
selects ipv4, which will cause drops for UDP over ipv6.
For net I plan to just ignore the error for these callers that do not
set skb->protocol.
- if (!skb_transport_header_was_set(skb))
+ if (!skb_transport_header_was_set(skb) && skb->protocol)
Possibly with an extension of tpacket_set_protocol to also cover
packet_snd, so that that cannot evade it on purpose. Other callers can
wait till net-next.
>
> ---
>
> This captures a variety of bad gso packets, but to tighten further:
>
> - drop SKB_GSO_DODGY packets with ipip/sit/.. , which cannot be legal.
> by ipip_gso_segment wrappers around inet_gso_segment
> expands on 121d57af308d ("gso: validate gso_type in GSO handlers")
>
> - limit the number of ipv6 exthdrs allowed from dodgy sources.
> not sure where to draw the line. but not at 64K ;)
This already exists, in the form of skb_flow_dissect_allowed
> - validate the network and transport protocol returned in
> skb_probe_transport_header against the VIRTIO_NET_HDR_GSO type
>
> - probe all dodgy GSO packets, also those that set checksum offload.
> this will have a performance impact, discussed previously in
> http://patchwork.ozlabs.org/patch/861874/
> but it would have blocked this latest bug as well
>
> All but the last one seem pretty uncontroversial to me. If no one
> objects I plan to send those to net-next.
>
> ---
> include/linux/skbuff.h | 2 +-
> include/linux/virtio_net.h | 9 +++++++++
> 2 files changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
> index 95d25b010a25..4c1c82a5678c 100644
> --- a/include/linux/skbuff.h
> +++ b/include/linux/skbuff.h
> @@ -2434,7 +2434,7 @@ 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
> + else if (offset_hint >= 0)
> skb_set_transport_header(skb, offset_hint);
> }
>
> diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
> index cb462f9ab7dd..71f2394abbf7 100644
> --- a/include/linux/virtio_net.h
> +++ b/include/linux/virtio_net.h
> @@ -57,6 +57,15 @@ static inline int virtio_net_hdr_to_skb(struct sk_buff *skb,
>
> if (!skb_partial_csum_set(skb, start, off))
> return -EINVAL;
> + } else {
> + /* gso packets without NEEDS_CSUM do not set transport_offset.
> + * probe and drop if does not match one of the above types.
> + */
> + if (gso_type) {
> + skb_probe_transport_header(skb, -1);
> + if (!skb_transport_header_was_set(skb))
> + return -EINVAL;
> + }
> }
>
> if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
> --
> 2.21.0.rc0.258.g878e2cd30e-goog
>
^ permalink raw reply
* Re: [BUG] [FIX] net: dsa: oops in br_vlan_enabled
From: Florian Fainelli @ 2019-02-18 19:09 UTC (permalink / raw)
To: Frank Wunderlich; +Cc: netdev, Andrew Lunn, Vivien Didelot
In-Reply-To: <trinity-d285d34c-7cf1-47bc-a86e-ab4e59a194b1-1550509887417@3c-app-gmx-bs58>
On February 18, 2019 9:11:27 AM PST, Frank Wunderlich <frank-w@public-files.de> wrote:
>Hi,
>
>tried your Patch but crashes the same way:
Yes the lower_dev targeted by switched does point to the DSA slave network device, but we really don't have dp->bridge_dev assigned since the physical DSA port was not enslaved in the bridge. Will follow up with a correct version late today.
>
>[ 107.416972] [<bf0fde88>] (br_vlan_enabled [bridge]) from
>[<bf14e234>] (dsa_po
>rt_vlan_add+0x60/0xbc [dsa_core])
>
>[ 107.426939] [<bf14e234>] (dsa_port_vlan_add [dsa_core]) from
>[<bf14eba4>] (ds
>a_slave_port_obj_add+0x64/0x68 [dsa_core])
>
>[ 107.437666] [<bf14eba4>] (dsa_slave_port_obj_add [dsa_core]) from
>[<c0b4e684>
>] (__switchdev_port_obj_add+0x50/0xc4)
>
>[ 107.448029] [<c0b4e684>] (__switchdev_port_obj_add) from
>[<c0b4e6d4>] (__swit
>chdev_port_obj_add+0xa0/0xc4)
>
>[ 107.457612] [<c0b4e6d4>] (__switchdev_port_obj_add) from
>[<c0b4e758>] (switch
>dev_port_obj_add_now+0x60/0x130)
>
>[ 107.467453] [<c0b4e758>] (switchdev_port_obj_add_now) from
>[<c0b4eb94>] (swit
>chdev_port_obj_add+0x44/0x190)
>
>[ 107.477181] [<c0b4eb94>] (switchdev_port_obj_add) from [<bf1013d0>]
>(br_switc
>hdev_port_vlan_add+0x60/0x7c [bridge])
>
>[ 107.487644] [<bf1013d0>] (br_switchdev_port_vlan_add [bridge]) from
>[<bf0ff25
>0>] (__vlan_add+0xb0/0x620 [bridge])
>
>regards Frank
>
>
>> Gesendet: Montag, 18. Februar 2019 um 00:20 Uhr
>> Von: "Florian Fainelli" <f.fainelli@gmail.com>
>> An: "Frank Wunderlich" <frank-w@public-files.de>,
>netdev@vger.kernel.org, "Andrew Lunn" <andrew@lunn.ch>, "Vivien
>Didelot" <vivien.didelot@gmail.com>
>> Betreff: Re: [BUG] [FIX] net: dsa: oops in br_vlan_enabled
>>
>>
>>
>> On 2/17/2019 9:13 AM, Florian Fainelli wrote:
>> > Hi Frank,
>> >
>> > On 2/16/2019 8:22 AM, Frank Wunderlich wrote:
>> >> Hi,
>> >>
>> >> i've found an oops in 4.19.23/10, seems to be fixed anyhow in 5.0
>(also works in 4.14.101)
>> >>
>> >> root@bpi-r2:~# ip link add link lan0 name lan0.5 type vlan id 5
>> >> root@bpi-r2:~# ip addr add 192.168.5.200/24 brd 192.168.5.255 dev
>lan0.5
>> >> root@bpi-r2:~# ip link set dev lan0 up
>> >> root@bpi-r2:~# ip link set dev lan0.5 up
>> >
>> > So that these steps don't involve a bridge, and because we don't
>(yet)
>> > implment ndo_vlan_rx_{add,kill}_vid() netdevice_ops, there is no
>VLAN
>> > programming, it's all software
>> >
>> >>
>> >> 12: lan0.5@lan0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500
>qdisc noqueue state LOWERLAYERDOWN group default qlen 1000
>> >> link/ether 02:02:02:02:02:02 brd ff:ff:ff:ff:ff:ff
>> >> inet 192.168.5.200/24 brd 192.168.5.255 scope global lan0.5
>> >> valid_lft forever preferred_lft forever
>> >>
>> >> root@bpi-r2:~# brctl addbr bridge_name
>> >> root@bpi-r2:~# brctl addif bridge_name lan0.5
>> >
>> > Unless you changed the bridge to have VLAN filtering/awareness
>with:
>> >
>> > echo 1 > /sys/class/net/bridge_name/bridge/vlan_filtering
>> >
>> > There will be no VLAN configuration/objects pushed to DSA since
>commit
>> > 2ea7a679ca2abd251c1ec03f20508619707e1749 ("net: dsa: Don't add
>vlans
>> > when vlan filtering is disabled") so I am not sure how you got into
>that
>> > situation because prior to pushing a VLAN object, the port must be
>part
>> > of a bridge, so the steps typically look like:
>> >
>> > - port_bridge_join which assigns dp->bridge_dev
>> > - port_vlan_add
>> >
>> > Does your 4.19.23 kernel somehow change how VLAN objects are pushed
>down
>> > the switch driver?
>> >
>> >> [ 352.057128] bridge_name: port 1(lan0.5) entered blocking state
>> >> [ 352.063065] bridge_name: port 1(lan0.5) entered disabled state
>> >> [ 352.069181] device lan0.5 entered promiscuous mode
>> >> [ 352.074018] device lan0 entered promiscuous mode
>> >> [ 352.078906] Unable to handle kernel NULL pointer dereference at
>virtual address 00000558
>> >> ...
>> >> [ 352.493085] [<bf0fde88>] (br_vlan_enabled [bridge]) from
>[<bf12c234>] (dsa_port_vlan_add+0x60/0xbc [dsa_core])
>> >> [ 352.503050] [<bf12c234>] (dsa_port_vlan_add [dsa_core]) from
>[<bf12cb64>] (dsa_slave_port_obj_add+0x4c/0x50 [dsa_core])
>> >> [ 352.513776] [<bf12cb64>] (dsa_slave_port_obj_add [dsa_core])
>from [<c0b4e2d4>] (__switchdev_port_obj_add+0x50/0xc4)
>> >> [ 352.524138] [<c0b4e2d4>] (__switchdev_port_obj_add) from
>[<c0b4e324>] (__switchdev_port_obj_add+0xa0/0xc4)
>> >> [ 352.533721] [<c0b4e324>] (__switchdev_port_obj_add) from
>[<c0b4e3a8>] (switchdev_port_obj_add_now+0x60/0x130)
>> >> [ 352.543562] [<c0b4e3a8>] (switchdev_port_obj_add_now) from
>[<c0b4e7e4>] (switchdev_port_obj_add+0x44/0x190)
>> >> [ 352.553284] [<c0b4e7e4>] (switchdev_port_obj_add) from
>[<bf1013d0>] (br_switchdev_port_vlan_add+0x60/0x7c [bridge])
>> >> [ 352.563733] [<bf1013d0>] (br_switchdev_port_vlan_add [bridge])
>from [<bf0ff250>] (__vlan_add+0xb0/0x620 [bridge])
>> >> [ 352.574007] [<bf0ff250>] (__vlan_add [bridge]) from
>[<bf0ffd04>] (nbp_vlan_add+0xc4/0x150 [bridge])
>> >> [ 352.583073] [<bf0ffd04>] (nbp_vlan_add [bridge]) from
>[<bf0ffec4>] (nbp_vlan_init+0x134/0x164 [bridge])
>> >> [ 352.592482] [<bf0ffec4>] (nbp_vlan_init [bridge]) from
>[<bf0edd4c>] (br_add_if+0x40c/0x5fc [bridge])
>> >> [ 352.601632] [<bf0edd4c>] (br_add_if [bridge]) from [<bf0eeb14>]
>(add_del_if+0x6c/0x80 [bridge])
>> >> [ 352.610351] [<bf0eeb14>] (add_del_if [bridge]) from
>[<bf0ef5b0>] (br_dev_ioctl+0x7c/0x9c [bridge])
>> >> [ 352.619290] [<bf0ef5b0>] (br_dev_ioctl [bridge]) from
>[<c09583d4>] (dev_ifsioc+0x184/0x324)
>> >> [ 352.627582] [<c09583d4>] (dev_ifsioc) from [<c09589e8>]
>(dev_ioctl+0x32c/0x5cc)
>> >> [ 352.634837] [<c09589e8>] (dev_ioctl) from [<c090913c>]
>(sock_ioctl+0x3bc/0x580)
>> >>
>> >>
>> >> since my 4.19.23 kernel is modified a bit i tried with 4.19.10
>without my net modifications and it is still reproducable with steps
>above (create a vlan on dsa-user-port and then use it in a bridge)
>> >>
>> >> i fixed it with these changes:
>>
>> Your fix is undoing the commit from Andrew I just referenced, so it
>is
>> definitively not the right fix because it will push VLAN objects down
>to
>> a non-VLAN aware bridge, not that this is really a problem, but it
>> should not be happening anyway.
>>
>> The problem appears to be the following though: you are enslaving a
>VLAN
>> device, which does not have switchdev_ops, so we recurse into the
>lower
>> device, which is the DSA network device, which does have
>switchdev_ops
>> defined. Once we are there we check the orig_dev against being a
>bridge
>> master network device, but we are not checking that it's a VLAN
>device
>> so we end-up assuming it is a DSA network device, we de-reference
>> garbage by checking br_vlan_enabled(dp->bridge_dev) because there is
>> simply no such data structure associated with the VLAN device.
>>
>> The attached patch should help.
>>
>> This is no longer a problem in newer kernels because the switchdev
>> operations use a notifier which checks the target network device to
>be DSA.
>> --
>> Florian
>>
--
Florian
^ permalink raw reply
* Re: [PATCH net-next 01/12] net: sched: flower: don't check for rtnl on head dereference
From: Cong Wang @ 2019-02-18 19:08 UTC (permalink / raw)
To: Vlad Buslov
Cc: Linux Kernel Network Developers, Jamal Hadi Salim, Jiri Pirko,
David Miller
In-Reply-To: <20190214074712.17846-2-vladbu@mellanox.com>
On Wed, Feb 13, 2019 at 11:47 PM Vlad Buslov <vladbu@mellanox.com> wrote:
>
> Flower classifier only changes root pointer during init and destroy. Cls
> API implements reference counting for tcf_proto, so there is no danger of
> concurrent access to tp when it is being destroyed, even without protection
> provided by rtnl lock.
How about atomicity? Refcnt doesn't guarantee atomicity, how do
you make sure two concurrent modifications are atomic?
>
> Implement new function fl_head_dereference() to dereference tp->root
> without checking for rtnl lock. Use it in all flower function that obtain
> head pointer instead of rtnl_dereference().
>
So what lock protects RCU writers after this patch?
^ permalink raw reply
* Re: [PATCH 1/2] wireless: mt76: call hweight8() instead of __sw_hweight8()
From: Kalle Valo @ 2019-02-18 19:06 UTC (permalink / raw)
To: Masahiro Yamada
Cc: Ingo Molnar, Thomas Gleixner, Borislav Petkov, H . Peter Anvin,
x86, linux-wireless, Christoph Hellwig, David S. Miller, netdev,
linux-kernel, Lorenzo Bianconi, linux-mediatek, linux-arm-kernel,
Felix Fietkau, Matthias Brugger
In-Reply-To: <877edxt1f1.fsf@kamboji.qca.qualcomm.com>
Kalle Valo <kvalo@codeaurora.org> writes:
> Masahiro Yamada <yamada.masahiro@socionext.com> writes:
>
>> __sw_hweight8() is just internal implementation.
>>
>> Drivers should use the common API, hweight8().
>>
>> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
>
> Acked-by: Kalle Valo <kvalo@codeaurora.org>
>
>> This patch should go to x86 tree along with 2/2.
>>
>> Otherwise, all{yes,mod}config of x86 would be broken.
>>
>> This patch is trivial enough.
>> I want ACK from the net/wireless maintainer
>> so that this can go in via x86 tree.
>
> Sounds good to me, feel free to push via the x86 tree.
Actually, can you wait a bit? Felix just reminded me that we have a
similar patch pending from Ben Hutchings:
https://patchwork.kernel.org/patch/10808203/
And it seems there are two instances of __sw_hweight8, at least in my
wireless-drivers-next tree:
drivers/net/wireless/mediatek/mt76/mac80211.c: int i, nstream = __sw_hweight8(dev->antenna_mask);
drivers/net/wireless/mediatek/mt76/mac80211.c: int n_chains = __sw_hweight8(dev->antenna_mask);
So we need to think what to do.
--
Kalle Valo
^ permalink raw reply
* Yet another approach for implementing connection tracking offload
From: Yossi Kuperman @ 2019-02-18 19:00 UTC (permalink / raw)
To: Guy Shattah, Aaron Conole, John Hurley, Simon Horman,
Justin Pettit, Gregory Rose, Eelco Chaudron, Flavio Leitner,
Florian Westphal, Jiri Pirko, Rashid Khan, Sushil Kulkarni,
Andy Gospodarek, Roi Dayan, Yossi Kuperman, Or Gerlitz,
Rony Efraim, davem@davemloft.net, Marcelo Leitner, Paul Blakey
Cc: netdev@vger.kernel.org
Hello All,
Following is a description of yet another possible approach to implement connection tracking offload. We would like to hear your opinion. There is the “native” way of implementing such an offload by mirroring the software tables to hardware. This way seems straightforward and simple, but real life is much more complicated than that. Alternatively, we can merge the data-path flows (separated by recirc_id) and offload a single flow to hardware.
The general idea is quite simple. When OVS-daemon configures TC with a filter that recirculate, the driver merely pretends to offload it and return success. Upon packet arrival (in software) we let it traverse TC as usual, except for now we notify the driver on each successful match. By doing this, the driver has all the necessary information to merge the participating flows---including connection tracking 5-tuple---into one equivalent flow. We do such a merge and offload only if the connection is established. Note: the same mechanism to communicate a 5-tuple to the driver can be used to notify on a filter match.
It is the driver responsibility to build and maintain the list of filters a (specific) packet hit along the TC walk. Once we reach the last filter (a terminating one, e.g., forward) the driver posts a work on a dedicated work-queue. In this work-queue context, we merge the participating filters and create a new filter that is logically equal (match + actions). The merge itself is not complicated as it might seems—TC does all the heavy lifting, this is not a random list of filters. At this point, we configure the hardware with one filter, either we have a match and the packet is handled by the hardware, or we don’t and the packet goes to software unmodified.
Going along this path we must tackle two things: 1) counters and 2) TC filter deletion. 1) We must maintain TC counters as the user expect. Each merged filter holds a list of filters it is derived from, parents. Once an update is available for a merged filter counter, the driver must update the corresponding parents appropriately. 2) Upon TC filer deletion it is mandatory to remove all the derived (merged) filters from the hardware as consequence.
Pros & Cons
Pros: 1) Circumvent the complexity involved with continuation in software where the hardware left off. 2) Simplifies the hardware pipeline with only one filter and might improve the overall performance.
Cons: 1) Only applicable to OVS-oriented filters, will not support priorities and overlapping filters. 2) Merger logic might consume CPU cycles which might impact the rate of filters we can offload. However, this overhead is believed to be negligible, if implemented carefully. 3) Requires TC/flower to notify the driver on each filter match (that is the only change needed above the driver).
Both approaches share the same software model, most of the code above the driver is shared. This approach can be considered temporary until the hardware will mature.
What do you think about this approach?
If something is not clear please let me know and I will do my best to clarify.
Cheers,
Kuperman
^ permalink raw reply
* Re: [PATCH net-next v4 17/17] net: sched: unlock rules update API
From: Cong Wang @ 2019-02-18 18:56 UTC (permalink / raw)
To: Vlad Buslov
Cc: Linux Kernel Network Developers, Jamal Hadi Salim, Jiri Pirko,
David Miller, Alexei Starovoitov, Daniel Borkmann
In-Reply-To: <20190211085548.7190-18-vladbu@mellanox.com>
On Mon, Feb 11, 2019 at 12:56 AM Vlad Buslov <vladbu@mellanox.com> wrote:
>
> Register netlink protocol handlers for message types RTM_NEWTFILTER,
> RTM_DELTFILTER, RTM_GETTFILTER as unlocked. Set rtnl_held variable that
> tracks rtnl mutex state to be false by default.
>
> Introduce tcf_proto_is_unlocked() helper that is used to check
> tcf_proto_ops->flag to determine if ops can be called without taking rtnl
> lock. Manually lookup Qdisc, class and block in rule update handlers.
> Verify that both Qdisc ops and proto ops are unlocked before using any of
> their callbacks, and obtain rtnl lock otherwise.
So if you end goal is to completely get rid of RTNL from tc filter and
action control path, why this change is needed?
I was expecting you to break down the RTNL lock down to each
block/filter chain, which should be done in this patchset. So again,
why do we still need RTNL for some cases?
Please state the reasoning in your changelog, rather than just
describing what your code does.
Thanks.
^ permalink raw reply
* Re: TC stats / hw offload question
From: Edward Cree @ 2019-02-18 18:56 UTC (permalink / raw)
To: Jamal Hadi Salim, netdev
Cc: Jiri Pirko, Cong Wang, Or Gerlitz, Andy Gospodarek, PJ Waskiewicz,
Anjali Singhai Jain, Jakub Kicinski
In-Reply-To: <702dd5b7-c6ed-b669-8270-d44f5ff4fb30@mojatatu.com>
On 14/02/19 12:39, Jamal Hadi Salim wrote:
> On 2019-02-11 6:44 a.m., Edward Cree wrote:
>> My end goal is to implement TC offload in some hw we're designing
>> here at Solarflare. So I'm trying to determine what hardware is
>> expected/required to do.
>> It might be possible to design our new hw so that we can attach a
>> counter to every action, if that's what TC wants.
>
> It makes sense to have a counter on every action - even if it is
> for debugging purposes. The two most basic actions are "drop" or
> "accept". In TC speak the default action is "classid x:y" which
> typically is to select a queue or give the flow some identity
Perhaps I was insufficiently clear; we're only looking at the switching
side of things (e.g. OVS offload) right now; we don't yet have a plan
for 'delivery' filters (I imagine we'll probably initially port over
our ethtool ntuple filter handling from ef10, though we may end up
going down the TC route there).
So I think at the moment 'classid' isn't relevant (?)
> Note, your counters should also be shareable; example, count all
> the drops in one counter across multiple flows as in the following
> case where counter index 1 is used.
>
> tc flower match foo action drop index 1
> tc flower match bar action drop index 1
[...]
> allow them to specify
> the counter index (assuming you architecture has an indexed table
> of counters).
Our architecture allocates objects (including counters) and returns
opaque handles to them, so we'd need a software table to connect
counter index to FW counter ID.
Also, sharing counters in hw causes extra work for the driver code
that keeps track of which encap actions are getting hit (so it can
keep the neighbour entries alive). Maybe summing the shared
counters in sw is easier than that, I'm not sure (or maybe encap
action counters should just be kept separate from the counters we
report to TC).
TBH I'm coming to the conclusion that what we should do for the first
version of our driver is just to create a counter per rule and report
it against the first action (only), and for now ignore the index (or
maybe require it to be set to some distinguished value, like 0, to
mean 'allocate', so that as a future extension we can support
shareable counters).
-Ed
^ permalink raw reply
* Re: [PATCH net-next v4 07/17] net: sched: protect filter_chain list with filter_chain_lock mutex
From: Cong Wang @ 2019-02-18 18:31 UTC (permalink / raw)
To: Vlad Buslov
Cc: Linux Kernel Network Developers, Jamal Hadi Salim, Jiri Pirko,
David Miller, Alexei Starovoitov, Daniel Borkmann
In-Reply-To: <vbfk1hxqrxr.fsf@mellanox.com>
On Mon, Feb 18, 2019 at 3:06 AM Vlad Buslov <vladbu@mellanox.com> wrote:
>
> On Fri 15 Feb 2019 at 22:35, Cong Wang <xiyou.wangcong@gmail.com> wrote:
> > On Mon, Feb 11, 2019 at 12:56 AM Vlad Buslov <vladbu@mellanox.com> wrote:
> >> +#ifdef CONFIG_PROVE_LOCKING
> >> +static inline bool lockdep_tcf_chain_is_locked(struct tcf_chain *chain)
> >> +{
> >> + return lockdep_is_held(&chain->filter_chain_lock);
> >> +}
> >> +#else
> >> +static inline bool lockdep_tcf_chain_is_locked(struct tcf_block *chain)
> >> +{
> >> + return true;
> >> +}
> >> +#endif /* #ifdef CONFIG_PROVE_LOCKING */
> >> +
> >> +#define tcf_chain_dereference(p, chain) \
> >> + rcu_dereference_protected(p, lockdep_tcf_chain_is_locked(chain))
> >
> >
> > Are you sure you need this #ifdef CONFIG_PROVE_LOCKING?
> > rcu_dereference_protected() should already test CONFIG_PROVE_RCU.
> >
> > Ditto for tcf_proto_dereference().
>
> I implemented these macro same way as rtnl_dereference() is implemented,
> which they are intended to substitute.
>
> After removing them I get following compilation error with
> CONFIG_PROVE_LOCKING disabled:
This is pretty odd, because net/core/neighbour.c uses it without
any #ifdef CONFIG_PROVE_LOCKING, for instance:
192 neigh = rcu_dereference_protected(n->next,
193
lockdep_is_held(&tbl->lock));
194 rcu_assign_pointer(*np, neigh);
195 neigh_mark_dead(n);
196 retval = true;
So how does this compile when CONFIG_PROVE_LOCKING
is disabled? :-/
^ permalink raw reply
* Re: [PATCH net-next v4 05/17] net: sched: traverse chains in block with tcf_get_next_chain()
From: Cong Wang @ 2019-02-18 18:26 UTC (permalink / raw)
To: Vlad Buslov
Cc: Linux Kernel Network Developers, Jamal Hadi Salim, Jiri Pirko,
David Miller, Alexei Starovoitov, Daniel Borkmann
In-Reply-To: <vbflg2dqukb.fsf@mellanox.com>
On Mon, Feb 18, 2019 at 2:07 AM Vlad Buslov <vladbu@mellanox.com> wrote:
>
> Hi Cong,
>
> Thanks for reviewing!
>
> On Fri 15 Feb 2019 at 22:21, Cong Wang <xiyou.wangcong@gmail.com> wrote:
> > (Sorry for joining this late.)
> >
> > On Mon, Feb 11, 2019 at 12:56 AM Vlad Buslov <vladbu@mellanox.com> wrote:
> >> @@ -2432,7 +2474,11 @@ static int tc_dump_chain(struct sk_buff *skb, struct netlink_callback *cb)
> >> index_start = cb->args[0];
> >> index = 0;
> >>
> >> - list_for_each_entry(chain, &block->chain_list, list) {
> >> + for (chain = __tcf_get_next_chain(block, NULL);
> >> + chain;
> >> + chain_prev = chain,
> >> + chain = __tcf_get_next_chain(block, chain),
> >> + tcf_chain_put(chain_prev)) {
> >
> > Why do you want to take the block->lock in each iteration
> > of the loop rather than taking once for the whole loop?
>
> This loop calls classifier ops callback in tc_chain_fill_node(). I don't
> call any classifier ops callbacks while holding block or chain lock in
> this change because the goal is to achieve fine-grained locking for data
> structures used by filter update path. Locking per-block or per-chain is
> much coarser than taking reference counters to parent structures and
> allowing classifiers to implement their own locking.
That is the problem, when we have N filter chains in a block, you
lock and unlock mutex N times... And what __tcf_get_next_chain()
does is basically just retrieving the next entry in the list, so the
overhead of mutex is likely more than the list operation itself in
contention situation.
Now I can see why you complained about mutex before, it is
how you use it, not actually its own problem. :)
>
> In this case call to ops->tmplt_dump() is probably quite fast and its
> execution time doesn't depend on number of filters on the classifier, so
> releasing block->lock on each iteration doesn't provide much benefit, if
> at all. However, it is easier for me to reason about locking correctness
> in this refactoring by following a simple rule that no locks (besides
> rtnl mutex) can be held when calling classifier ops callbacks.
Well, for me, a hierarchy locking is always simple when you take
them in the right order, that is locking the larger-scope lock first
and then smaller-scope one.
The way you use the locking here is actually harder for me to
review, because it is hard to valid its atomicity when you unlock
the larger scope lock and re-take the smaller scope lock. You
use refcnt to ensure it will not go way, but that is still far from
guarantee of the atomicity.
For example, tp->ops->change() which changes an existing
filter, I don't see you lock either block->lock or
chain->filter_chain_lock when calling it. How does it even work?
Thanks.
^ permalink raw reply
* [RFC PATCH net-next v3 00/21] ethtool netlink interface, part 1
From: Michal Kubecek @ 2019-02-18 18:21 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
Note: this is marked as RFC because it's rather late in the cycle; the plan
is to make a regular submission (with changes based on review) once
net-next reopens after the 5.1 merge window. The full (work in progress)
series, together with the (userspace) ethtool counterpart can be found at
https://github.com/mkubecek/ethnl
This is first part of alternative userspace interface for ethtool. The aim
is to address some long known issues with the ioctl interface, mainly lack
of extensibility, raciness, limited error reporting and absence of
notifications.
The interface uses generic netlink family "ethtool"; it provides multicast
group "monitor" which is used for notifications. Documentation for the
interface is in Documentation/networking/ethtool-netlink.txt
Basic concepts:
- the goal is to provide all features of ioctl interface but allow
easier future extensions; at some point, it should be possible to have
full ethtool functionality without using the ioctl interface
- inextensibility of ioctl interface resulted in way too many commands,
many of them obsoleted by newer ones; reduce the number by ignoring the
obsolete commands and grouping some together
- for "set" type commands, allows passing only the attributes to be
changed; therefore we don't need a get-modify-set cycle (which is
inherently racy), userspace can simply say what it wants to change
- provide notifications to multicast group "monitor" like rtnetlink does,
i.e. in the form of messages close to replies to "get" requests
- allow dump requests to get some information about all network devices
providing it
- be less dependent on ethtool and kernel being in sync; allow e.g. saying
"ethtool -s eth0 advertise foo off" without ethtool knowing what "foo"
means; it's kernel's job to know what mode "xyz" is and if it exists and
is supported
Main changes between RFC v2 and RFC v3:
- do not allow building as a module (no netdev notifiers needed)
- drop some obsolete fields
- add permanent hw address, timestamping and private flags support
- rework bitset handling to get rid of variable length arrays
- notify monitor on device renames
- restructure GET_SETTINGS/SET_SETTINGS messages
- split too long patches and submit only first part of the series
Main changes between RFC v1 and RFC v2:
- support dumps for all "get" requests
- provide notifications for changes related to supported request types
- support getting string sets (both global and per device)
- support getting/setting device features
- get rid of family specific header, everything passed as attributes
- split netlink code into multiple files in net/ethtool/ directory
ToDo / open questions:
- some features provided by ethtool would rather belong to devlink (and
some are already superseded by devlink); however, only few drivers
provide devlink interface at the moment and as recent discussion on
flashing revealed, we cannot rely on devlink's presence
- while the netlink interface allows easy future extensions, ethtool_ops
interface does not; some settings could be implemented using tunables and
accessed via relevant netlink messages (as well as tunables) from
userspace but in the long term, something better will be needed
- currently, all communication with drivers via ethtool_ops is done
under RTNL as this is what ioctl interface does and likely many
ethtool_ops handlers rely on that; if we are going to rework ethtool_ops
in the future ("phase two"), it would be nice to get rid of it
- ethtool_ops should pass extack pointer to allow drivers more meaningful
error reporting; it's not clear, however, how to pass information about
offending attribute
- notifications are sent whenever a change is done via netlink API or
ioctl API and for netdev features also whenever they are updated using
netdev_change_features(); it would be desirable to notify also about
link state and negotiation result (speed/duplex and partner link
modes) but it would be more tricky
Michal Kubecek (21):
netlink: introduce nla_put_bitfield32()
ethtool: move to its own directory
ethtool: introduce ethtool netlink interface
ethtool: helper functions for netlink interface
ethtool: netlink bitset handling
ethtool: support for netlink notifications
ethtool: implement EVENT notifications
ethtool: generic handlers for GET requests
ethtool: move string arrays into common file
ethtool: provide string sets with GET_STRSET request
ethtool: provide driver/device information in GET_INFO request
ethtool: provide permanent hardware address in GET_INFO request
ethtool: provide timestamping information in GET_INFO request
ethtool: provide link mode names as a string set
ethtool: provide link settings and link modes in GET_SETTINGS request
ethtool: provide WoL information in GET_SETTINGS request
ethtool: provide message level in GET_SETTINGS request
ethtool: provide link state in GET_SETTINGS request
ethtool: provide device features in GET_SETTINGS request
ethtool: provide private flags in GET_SETTINGS request
ethtool: send netlink notifications about setting changes
Documentation/networking/ethtool-netlink.txt | 441 +++++++++++++
include/linux/ethtool_netlink.h | 17 +
include/linux/netdevice.h | 14 +
include/net/netlink.h | 15 +
include/uapi/linux/ethtool.h | 10 +
include/uapi/linux/ethtool_netlink.h | 265 ++++++++
include/uapi/linux/net_tstamp.h | 13 +
net/Kconfig | 8 +
net/Makefile | 2 +-
net/core/Makefile | 2 +-
net/ethtool/Makefile | 7 +
net/ethtool/bitset.c | 572 +++++++++++++++++
net/ethtool/bitset.h | 40 ++
net/ethtool/common.c | 227 +++++++
net/ethtool/common.h | 29 +
net/ethtool/info.c | 332 ++++++++++
net/{core/ethtool.c => ethtool/ioctl.c} | 244 ++-----
net/ethtool/netlink.c | 634 +++++++++++++++++++
net/ethtool/netlink.h | 252 ++++++++
net/ethtool/settings.c | 559 ++++++++++++++++
net/ethtool/strset.c | 461 ++++++++++++++
21 files changed, 3937 insertions(+), 207 deletions(-)
create mode 100644 Documentation/networking/ethtool-netlink.txt
create mode 100644 include/linux/ethtool_netlink.h
create mode 100644 include/uapi/linux/ethtool_netlink.h
create mode 100644 net/ethtool/Makefile
create mode 100644 net/ethtool/bitset.c
create mode 100644 net/ethtool/bitset.h
create mode 100644 net/ethtool/common.c
create mode 100644 net/ethtool/common.h
create mode 100644 net/ethtool/info.c
rename net/{core/ethtool.c => ethtool/ioctl.c} (91%)
create mode 100644 net/ethtool/netlink.c
create mode 100644 net/ethtool/netlink.h
create mode 100644 net/ethtool/settings.c
create mode 100644 net/ethtool/strset.c
--
2.20.1
^ permalink raw reply
* [RFC PATCH net-next v3 01/21] netlink: introduce nla_put_bitfield32()
From: Michal Kubecek @ 2019-02-18 18:21 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
Similar to other data types, this helper puts NLA_BITFIELD32 attribute into
a netlink message. It takes separate value and selector arguments, if there
is a struct nla_bitfield32 already, one can use nla_put().
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
include/net/netlink.h | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/include/net/netlink.h b/include/net/netlink.h
index 23f27b0b3cef..bc0497076bec 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -1211,6 +1211,21 @@ static inline int nla_put_in6_addr(struct sk_buff *skb, int attrtype,
return nla_put(skb, attrtype, sizeof(*addr), addr);
}
+/**
+ * nla_put_bitfield32 - Add a bitfield32 value/selector attribute to
+ * a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @value: 32-bit value bitmap
+ * @selector: 32-bit selector bitmap
+ */
+static inline int nla_put_bitfield32(struct sk_buff *skb, int attrtype,
+ u32 value, u32 selector)
+{
+ struct nla_bitfield32 tmp = { .value = value, .selector = selector };
+
+ return nla_put(skb, attrtype, sizeof(tmp), &tmp);
+}
+
/**
* nla_get_u32 - return payload of u32 attribute
* @nla: u32 netlink attribute
--
2.20.1
^ permalink raw reply related
* [RFC PATCH net-next v3 08/21] ethtool: generic handlers for GET requests
From: Michal Kubecek @ 2019-02-18 18:22 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
Some parts of processing GET type requests and related notifications are
independent of a command. Provide universal functions so that only four
callbacks need to be defined for each command type:
parse_request() - parse incoming message
prepare_data() - retrieve data from driver or NIC
reply_size() - estimate reply message size
fill_reply() - compose reply message
These callback are defined in an instance of struct get_request_ops.
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
net/ethtool/netlink.c | 286 ++++++++++++++++++++++++++++++++++++++++++
net/ethtool/netlink.h | 84 +++++++++++++
2 files changed, 370 insertions(+)
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index ee3424cd1f90..8cdb6f52cb4a 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -84,6 +84,41 @@ int ethnl_fill_dev(struct sk_buff *msg, struct net_device *dev, u16 attrtype)
return ret;
}
+/* GET request helpers */
+
+const struct get_request_ops *get_requests[__ETHNL_CMD_CNT] = {
+};
+
+static struct common_req_info *alloc_get_data(const struct get_request_ops *ops)
+{
+ struct common_req_info *req_info = kmalloc(ops->data_size, GFP_KERNEL);
+
+ if (!req_info)
+ return NULL;
+ memset(req_info, '\0', ops->repdata_offset);
+ req_info->reply_data =
+ (struct common_reply_data *)((char *)req_info +
+ ops->repdata_offset);
+ return req_info;
+}
+
+static void free_get_data(const struct get_request_ops *ops,
+ struct common_req_info *req_info)
+{
+ if (ops->cleanup)
+ ops->cleanup(req_info);
+ kfree(req_info);
+}
+
+static void init_reply_data(const struct common_req_info *req_info,
+ const struct get_request_ops *ops,
+ struct net_device *dev)
+{
+ memset(req_info->reply_data, '\0',
+ ops->data_size - ops->repdata_offset);
+ req_info->reply_data->dev = dev;
+}
+
/* create skb for a reply and fill device identification
* payload: payload length (without netlink and genetlink header)
* dev: device the reply is about (may be null)
@@ -124,6 +159,257 @@ struct sk_buff *ethnl_reply_init(size_t payload, struct net_device *dev, u8 cmd,
return NULL;
}
+int ethnl_get_doit(struct sk_buff *skb, struct genl_info *info)
+{
+ const u8 cmd = info->genlhdr->cmd;
+ struct common_req_info *req_info;
+ const struct get_request_ops *ops;
+ struct sk_buff *rskb;
+ void *reply_payload;
+ int reply_len;
+ int ret;
+
+ ops = get_requests[cmd];
+ if (WARN_ONCE(!ops, "cmd %u has no get_request_ops\n", cmd))
+ return -EOPNOTSUPP;
+ req_info = alloc_get_data(ops);
+ if (!req_info)
+ return -ENOMEM;
+ ret = ops->parse_request(req_info, skb, info, info->nlhdr);
+ if (!ops->allow_nodev_do && !req_info->dev) {
+ ETHNL_SET_ERRMSG(info, "device not specified in do request");
+ ret = -EINVAL;
+ }
+ if (ret < 0)
+ goto err_dev;
+ init_reply_data(req_info, ops, req_info->dev);
+
+ rtnl_lock();
+ ret = ops->prepare_data(req_info, info);
+ if (ret < 0)
+ goto err_rtnl;
+ reply_len = ops->reply_size(req_info);
+ if (ret < 0)
+ goto err_rtnl;
+ ret = -ENOMEM;
+ rskb = ethnl_reply_init(reply_len, req_info->dev, ops->reply_cmd,
+ ops->dev_attrtype, info, &reply_payload);
+ if (!rskb)
+ goto err_rtnl;
+ ret = ops->fill_reply(rskb, req_info);
+ if (ret < 0)
+ goto err;
+ rtnl_unlock();
+
+ genlmsg_end(rskb, reply_payload);
+ if (req_info->dev)
+ dev_put(req_info->dev);
+ free_get_data(ops, req_info);
+ return genlmsg_reply(rskb, info);
+
+err:
+ WARN_ONCE(ret == -EMSGSIZE,
+ "calculated message payload length (%d) not sufficient\n",
+ reply_len);
+ nlmsg_free(rskb);
+ free_get_data(ops, req_info);
+err_rtnl:
+ rtnl_unlock();
+err_dev:
+ if (req_info->dev)
+ dev_put(req_info->dev);
+ return ret;
+}
+
+static int ethnl_get_dump_one(struct sk_buff *skb,
+ struct net_device *dev,
+ const struct get_request_ops *ops,
+ struct common_req_info *req_info)
+{
+ int ret;
+
+ init_reply_data(req_info, ops, dev);
+ rtnl_lock();
+ ret = ops->prepare_data(req_info, NULL);
+ if (ret < 0)
+ return ret;
+ ret = ethnl_fill_dev(skb, dev, ops->dev_attrtype);
+ if (ret < 0)
+ return ret;
+ ret = ops->fill_reply(skb, req_info);
+ rtnl_unlock();
+
+ req_info->reply_data->dev = NULL;
+ return ret;
+}
+
+/* generic ->dumpit() handler; device iteration copied from rtnl_dump_ifinfo()
+ * cb->args[0]: pointer to struct get_request_ops
+ * cb->args[1]: pointer to request data
+ * cb->args[2]: iteration position - hashbucket
+ * cb->args[3]: iteration position - ifindex
+ */
+int ethnl_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
+{
+ struct net *net = sock_net(skb->sk);
+ struct common_req_info *req_info;
+ const struct get_request_ops *ops;
+ int h, s_h, idx = 0, s_idx;
+ struct hlist_head *head;
+ struct net_device *dev;
+ int ret = 0;
+ void *ehdr;
+
+ ops = (const struct get_request_ops *)cb->args[0];
+ req_info = (struct common_req_info *)cb->args[1];
+ s_h = cb->args[2];
+ s_idx = cb->args[3];
+
+ for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
+ idx = 0;
+ head = &net->dev_index_head[h];
+ hlist_for_each_entry(dev, head, index_hlist) {
+ if (idx < s_idx)
+ goto cont;
+ ehdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
+ cb->nlh->nlmsg_seq,
+ ðtool_genl_family, 0,
+ ops->reply_cmd);
+ ret = ethnl_get_dump_one(skb, dev, ops, req_info);
+ if (ret < 0) {
+ genlmsg_cancel(skb, ehdr);
+ if (ret == -EOPNOTSUPP)
+ goto cont;
+ if (likely(skb->len))
+ goto out;
+ goto out_err;
+ }
+ genlmsg_end(skb, ehdr);
+cont:
+ idx++;
+ }
+ }
+out:
+ ret = skb->len;
+out_err:
+ cb->args[2] = h;
+ cb->args[3] = idx;
+ cb->seq = net->dev_base_seq;
+ nl_dump_check_consistent(cb, nlmsg_hdr(skb));
+
+ return ret;
+}
+
+/* generic ->start() handler for GET requests */
+static int ethnl_get_start(struct netlink_callback *cb)
+{
+ struct common_req_info *req_info;
+ const struct get_request_ops *ops;
+ struct genlmsghdr *ghdr;
+ int ret;
+
+ ghdr = nlmsg_data(cb->nlh);
+ ops = get_requests[ghdr->cmd];
+ if (WARN_ONCE(!ops, "cmd %u has no get_request_ops\n", ghdr->cmd))
+ return -EOPNOTSUPP;
+ req_info = alloc_get_data(ops);
+ if (!req_info)
+ return -ENOMEM;
+
+ ret = ops->parse_request(req_info, cb->skb, NULL, cb->nlh);
+ if (req_info->dev) {
+ /* We ignore device specification in dump requests but as the
+ * same parser as for non-dump (doit) requests is used, it
+ * would take reference to the device if it finds one
+ */
+ dev_put(req_info->dev);
+ req_info->dev = NULL;
+ }
+ if (ret < 0)
+ return ret;
+
+ cb->args[0] = (long)ops;
+ cb->args[1] = (long)req_info;
+ cb->args[2] = 0;
+ cb->args[3] = 0;
+
+ return 0;
+}
+
+/* generic ->done() handler for GET requests */
+static int ethnl_get_done(struct netlink_callback *cb)
+{
+ free_get_data((const struct get_request_ops *)cb->args[0],
+ (struct common_req_info *)cb->args[1]);
+
+ return 0;
+}
+
+/* generic notification handler */
+static void ethnl_std_notify(struct net_device *dev,
+ struct netlink_ext_ack *extack, unsigned int cmd,
+ u32 req_mask, const void *data)
+{
+ struct common_req_info *req_info;
+ const struct get_request_ops *ops;
+ struct sk_buff *skb;
+ void *reply_payload;
+ int reply_len;
+ int ret;
+
+ ops = get_requests[cmd - 1];
+ if (WARN_ONCE(!ops, "cmd %u has no get_request_ops\n", cmd - 1))
+ return;
+ /* when ethnl_std_notify() is used as notify handler, command id of
+ * corresponding GET request must be one less than cmd argument passed
+ * to ethnl_std_notify()
+ */
+ if (WARN_ONCE(ops->reply_cmd != cmd,
+ "reply_cmd for %u is %u, expected %u\n", cmd - 1,
+ ops->reply_cmd, cmd))
+ return;
+
+ req_info = alloc_get_data(ops);
+ if (!req_info)
+ return;
+ req_info->dev = dev;
+ req_info->req_mask = req_mask;
+ req_info->compact = true;
+
+ init_reply_data(req_info, ops, dev);
+ ret = ops->prepare_data(req_info, NULL);
+ if (ret < 0)
+ goto err_data;
+ reply_len = ops->reply_size(req_info);
+ if (reply_len < 0)
+ goto err_data;
+ skb = genlmsg_new(reply_len, GFP_KERNEL);
+ if (!skb)
+ goto err_data;
+ reply_payload = genlmsg_put(skb, 0, ++ethnl_bcast_seq,
+ ðtool_genl_family, 0, ops->reply_cmd);
+ if (!reply_payload)
+ goto err_skb;
+
+ ret = ethnl_fill_dev(skb, dev, ops->dev_attrtype);
+ if (ret < 0)
+ goto err_skb;
+ ret = ops->fill_reply(skb, req_info);
+ if (ret < 0)
+ goto err_skb;
+ free_get_data(ops, req_info);
+ genlmsg_end(skb, reply_payload);
+
+ genlmsg_multicast(ðtool_genl_family, skb, 0, ETHNL_MCGRP_MONITOR,
+ GFP_KERNEL);
+ return;
+
+err_skb:
+ nlmsg_free(skb);
+err_data:
+ free_get_data(ops, req_info);
+}
+
/* notifications */
typedef void (*ethnl_notify_handler_t)(struct net_device *dev,
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 78385baeaec0..7141ec71a6d3 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -155,4 +155,88 @@ static inline unsigned int dev_ident_size(void)
nla_total_size(IFNAMSIZ));
}
+/* GET request handling */
+
+struct common_reply_data;
+
+/* Structure holding data for unified processing a GET request consists of two
+ * parts: request info and reply data. Request info starts at offset 0 with
+ * embedded struct common_req_info, is usually filled by ->parse_request()
+ * and is common for all reply messages to one request. Reply data start with
+ * embedded struct common_reply_data and contain data specific to a reply
+ * message (usually one per device for dump requests); this part is filled by
+ * ->prepare_data()
+ *
+ * @reply_data: pointer to corresponding struct common_reply_data
+ * @dev: requested device; may be null (dumps), if not, reference is held
+ * @req_mask: bit mask of parts of information requested
+ * @compact: use compact format for bitsets
+ */
+struct common_req_info {
+ struct common_reply_data *reply_data;
+ struct net_device *dev;
+ u32 req_mask;
+ bool compact;
+};
+
+/* @dev: device for current reply message
+ * @info_mask: subset of req_mask (without information which is not available)
+ */
+struct common_reply_data {
+ struct net_device *dev;
+ u32 info_mask;
+};
+
+static inline int ethnl_before_ops(struct net_device *dev)
+{
+ if (dev && dev->ethtool_ops->begin)
+ return dev->ethtool_ops->begin(dev);
+ else
+ return 0;
+}
+
+static inline void ethnl_after_ops(struct net_device *dev)
+{
+ if (dev && dev->ethtool_ops->complete)
+ dev->ethtool_ops->complete(dev);
+}
+
+/* parameters and callbacks for unified handling of GET requests
+ * @request_cmd: command id for request (GET)
+ * @reply_cmd: command id for reply (SET)
+ * @dev_attr: attr type for device specification
+ * @data_size: total length of data structure
+ * @repdata_offset: offset of "reply data" part (struct common_reply_data)
+ * @allow_nodev_do: do not fail if device is not specified for non-dump request
+ * @parse_request: parse request message and fill request info; request info
+ * is zero initialized on entry except reply_data pointer (which is set)
+ * @prepare_data: retrieve data needed to compose a reply message; reply data
+ * is zero initialized on entry except @dev
+ * @reply_size: return size of reply message payload without device
+ * specification; reported size may be slightly bigger than actual reply
+ * but must not be smaller
+ * @fill_reply: fill reply message payload
+ * @cleanup: (optional) called when data are no longer needed; use e.g. to free
+ * any additional data allocated in prepare_data() which are not part
+ * of the main structure
+ */
+struct get_request_ops {
+ u8 request_cmd;
+ u8 reply_cmd;
+ u16 dev_attrtype;
+ unsigned int data_size;
+ unsigned int repdata_offset;
+ bool allow_nodev_do;
+
+ int (*parse_request)(struct common_req_info *req_info,
+ struct sk_buff *skb, struct genl_info *info,
+ const struct nlmsghdr *nlhdr);
+ int (*prepare_data)(struct common_req_info *req_info,
+ struct genl_info *info);
+ int (*reply_size)(const struct common_req_info *req_info);
+ int (*fill_reply)(struct sk_buff *skb,
+ const struct common_req_info *req_info);
+ void (*cleanup)(struct common_req_info *req_info);
+};
+
#endif /* _NET_ETHTOOL_NETLINK_H */
--
2.20.1
^ permalink raw reply related
* [RFC PATCH net-next v3 09/21] ethtool: move string arrays into common file
From: Michal Kubecek @ 2019-02-18 18:22 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
Introduce file net/ethtool/common.c for code shared by ioctl and netlink
ethtool interface. Move name tables of features, RSS hash functions,
tunables and PHY tunables into this file.
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
net/ethtool/Makefile | 2 +-
net/ethtool/common.c | 83 ++++++++++++++++++++++++++++++++++++++++++++
net/ethtool/common.h | 17 +++++++++
net/ethtool/ioctl.c | 82 ++-----------------------------------------
4 files changed, 103 insertions(+), 81 deletions(-)
create mode 100644 net/ethtool/common.c
create mode 100644 net/ethtool/common.h
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
index 482fdb9380fa..11782306593b 100644
--- a/net/ethtool/Makefile
+++ b/net/ethtool/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-obj-y += ioctl.o
+obj-y += ioctl.o common.o
obj-$(CONFIG_ETHTOOL_NETLINK) += ethtool_nl.o
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
new file mode 100644
index 000000000000..73f721a1c557
--- /dev/null
+++ b/net/ethtool/common.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+
+#include "common.h"
+
+const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
+ [NETIF_F_SG_BIT] = "tx-scatter-gather",
+ [NETIF_F_IP_CSUM_BIT] = "tx-checksum-ipv4",
+ [NETIF_F_HW_CSUM_BIT] = "tx-checksum-ip-generic",
+ [NETIF_F_IPV6_CSUM_BIT] = "tx-checksum-ipv6",
+ [NETIF_F_HIGHDMA_BIT] = "highdma",
+ [NETIF_F_FRAGLIST_BIT] = "tx-scatter-gather-fraglist",
+ [NETIF_F_HW_VLAN_CTAG_TX_BIT] = "tx-vlan-hw-insert",
+
+ [NETIF_F_HW_VLAN_CTAG_RX_BIT] = "rx-vlan-hw-parse",
+ [NETIF_F_HW_VLAN_CTAG_FILTER_BIT] = "rx-vlan-filter",
+ [NETIF_F_HW_VLAN_STAG_TX_BIT] = "tx-vlan-stag-hw-insert",
+ [NETIF_F_HW_VLAN_STAG_RX_BIT] = "rx-vlan-stag-hw-parse",
+ [NETIF_F_HW_VLAN_STAG_FILTER_BIT] = "rx-vlan-stag-filter",
+ [NETIF_F_VLAN_CHALLENGED_BIT] = "vlan-challenged",
+ [NETIF_F_GSO_BIT] = "tx-generic-segmentation",
+ [NETIF_F_LLTX_BIT] = "tx-lockless",
+ [NETIF_F_NETNS_LOCAL_BIT] = "netns-local",
+ [NETIF_F_GRO_BIT] = "rx-gro",
+ [NETIF_F_GRO_HW_BIT] = "rx-gro-hw",
+ [NETIF_F_LRO_BIT] = "rx-lro",
+
+ [NETIF_F_TSO_BIT] = "tx-tcp-segmentation",
+ [NETIF_F_GSO_ROBUST_BIT] = "tx-gso-robust",
+ [NETIF_F_TSO_ECN_BIT] = "tx-tcp-ecn-segmentation",
+ [NETIF_F_TSO_MANGLEID_BIT] = "tx-tcp-mangleid-segmentation",
+ [NETIF_F_TSO6_BIT] = "tx-tcp6-segmentation",
+ [NETIF_F_FSO_BIT] = "tx-fcoe-segmentation",
+ [NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation",
+ [NETIF_F_GSO_GRE_CSUM_BIT] = "tx-gre-csum-segmentation",
+ [NETIF_F_GSO_IPXIP4_BIT] = "tx-ipxip4-segmentation",
+ [NETIF_F_GSO_IPXIP6_BIT] = "tx-ipxip6-segmentation",
+ [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation",
+ [NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT] = "tx-udp_tnl-csum-segmentation",
+ [NETIF_F_GSO_PARTIAL_BIT] = "tx-gso-partial",
+ [NETIF_F_GSO_SCTP_BIT] = "tx-sctp-segmentation",
+ [NETIF_F_GSO_ESP_BIT] = "tx-esp-segmentation",
+ [NETIF_F_GSO_UDP_L4_BIT] = "tx-udp-segmentation",
+
+ [NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc",
+ [NETIF_F_SCTP_CRC_BIT] = "tx-checksum-sctp",
+ [NETIF_F_FCOE_MTU_BIT] = "fcoe-mtu",
+ [NETIF_F_NTUPLE_BIT] = "rx-ntuple-filter",
+ [NETIF_F_RXHASH_BIT] = "rx-hashing",
+ [NETIF_F_RXCSUM_BIT] = "rx-checksum",
+ [NETIF_F_NOCACHE_COPY_BIT] = "tx-nocache-copy",
+ [NETIF_F_LOOPBACK_BIT] = "loopback",
+ [NETIF_F_RXFCS_BIT] = "rx-fcs",
+ [NETIF_F_RXALL_BIT] = "rx-all",
+ [NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload",
+ [NETIF_F_HW_TC_BIT] = "hw-tc-offload",
+ [NETIF_F_HW_ESP_BIT] = "esp-hw-offload",
+ [NETIF_F_HW_ESP_TX_CSUM_BIT] = "esp-tx-csum-hw-offload",
+ [NETIF_F_RX_UDP_TUNNEL_PORT_BIT] = "rx-udp_tunnel-port-offload",
+ [NETIF_F_HW_TLS_RECORD_BIT] = "tls-hw-record",
+ [NETIF_F_HW_TLS_TX_BIT] = "tls-hw-tx-offload",
+ [NETIF_F_HW_TLS_RX_BIT] = "tls-hw-rx-offload",
+};
+
+const char
+rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN] = {
+ [ETH_RSS_HASH_TOP_BIT] = "toeplitz",
+ [ETH_RSS_HASH_XOR_BIT] = "xor",
+ [ETH_RSS_HASH_CRC32_BIT] = "crc32",
+};
+
+const char
+tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
+ [ETHTOOL_ID_UNSPEC] = "Unspec",
+ [ETHTOOL_RX_COPYBREAK] = "rx-copybreak",
+ [ETHTOOL_TX_COPYBREAK] = "tx-copybreak",
+ [ETHTOOL_PFC_PREVENTION_TOUT] = "pfc-prevention-tout",
+};
+
+const char
+phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
+ [ETHTOOL_ID_UNSPEC] = "Unspec",
+ [ETHTOOL_PHY_DOWNSHIFT] = "phy-downshift",
+};
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
new file mode 100644
index 000000000000..41b2efc1e4e1
--- /dev/null
+++ b/net/ethtool/common.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+
+#ifndef _ETHTOOL_COMMON_H
+#define _ETHTOOL_COMMON_H
+
+#include <linux/ethtool.h>
+
+extern const char
+netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN];
+extern const char
+rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN];
+extern const char
+tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN];
+extern const char
+phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
+
+#endif /* _ETHTOOL_COMMON_H */
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 1320e8dce559..71a1643adb2b 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -31,6 +31,8 @@
#include <net/xdp_sock.h>
#include <net/flow_offload.h>
+#include "common.h"
+
/*
* Some useful ethtool_ops methods that're device independent.
* If we find that all drivers want to do the same thing here,
@@ -58,86 +60,6 @@ EXPORT_SYMBOL(ethtool_op_get_ts_info);
#define ETHTOOL_DEV_FEATURE_WORDS ((NETDEV_FEATURE_COUNT + 31) / 32)
-static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
- [NETIF_F_SG_BIT] = "tx-scatter-gather",
- [NETIF_F_IP_CSUM_BIT] = "tx-checksum-ipv4",
- [NETIF_F_HW_CSUM_BIT] = "tx-checksum-ip-generic",
- [NETIF_F_IPV6_CSUM_BIT] = "tx-checksum-ipv6",
- [NETIF_F_HIGHDMA_BIT] = "highdma",
- [NETIF_F_FRAGLIST_BIT] = "tx-scatter-gather-fraglist",
- [NETIF_F_HW_VLAN_CTAG_TX_BIT] = "tx-vlan-hw-insert",
-
- [NETIF_F_HW_VLAN_CTAG_RX_BIT] = "rx-vlan-hw-parse",
- [NETIF_F_HW_VLAN_CTAG_FILTER_BIT] = "rx-vlan-filter",
- [NETIF_F_HW_VLAN_STAG_TX_BIT] = "tx-vlan-stag-hw-insert",
- [NETIF_F_HW_VLAN_STAG_RX_BIT] = "rx-vlan-stag-hw-parse",
- [NETIF_F_HW_VLAN_STAG_FILTER_BIT] = "rx-vlan-stag-filter",
- [NETIF_F_VLAN_CHALLENGED_BIT] = "vlan-challenged",
- [NETIF_F_GSO_BIT] = "tx-generic-segmentation",
- [NETIF_F_LLTX_BIT] = "tx-lockless",
- [NETIF_F_NETNS_LOCAL_BIT] = "netns-local",
- [NETIF_F_GRO_BIT] = "rx-gro",
- [NETIF_F_GRO_HW_BIT] = "rx-gro-hw",
- [NETIF_F_LRO_BIT] = "rx-lro",
-
- [NETIF_F_TSO_BIT] = "tx-tcp-segmentation",
- [NETIF_F_GSO_ROBUST_BIT] = "tx-gso-robust",
- [NETIF_F_TSO_ECN_BIT] = "tx-tcp-ecn-segmentation",
- [NETIF_F_TSO_MANGLEID_BIT] = "tx-tcp-mangleid-segmentation",
- [NETIF_F_TSO6_BIT] = "tx-tcp6-segmentation",
- [NETIF_F_FSO_BIT] = "tx-fcoe-segmentation",
- [NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation",
- [NETIF_F_GSO_GRE_CSUM_BIT] = "tx-gre-csum-segmentation",
- [NETIF_F_GSO_IPXIP4_BIT] = "tx-ipxip4-segmentation",
- [NETIF_F_GSO_IPXIP6_BIT] = "tx-ipxip6-segmentation",
- [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation",
- [NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT] = "tx-udp_tnl-csum-segmentation",
- [NETIF_F_GSO_PARTIAL_BIT] = "tx-gso-partial",
- [NETIF_F_GSO_SCTP_BIT] = "tx-sctp-segmentation",
- [NETIF_F_GSO_ESP_BIT] = "tx-esp-segmentation",
- [NETIF_F_GSO_UDP_L4_BIT] = "tx-udp-segmentation",
-
- [NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc",
- [NETIF_F_SCTP_CRC_BIT] = "tx-checksum-sctp",
- [NETIF_F_FCOE_MTU_BIT] = "fcoe-mtu",
- [NETIF_F_NTUPLE_BIT] = "rx-ntuple-filter",
- [NETIF_F_RXHASH_BIT] = "rx-hashing",
- [NETIF_F_RXCSUM_BIT] = "rx-checksum",
- [NETIF_F_NOCACHE_COPY_BIT] = "tx-nocache-copy",
- [NETIF_F_LOOPBACK_BIT] = "loopback",
- [NETIF_F_RXFCS_BIT] = "rx-fcs",
- [NETIF_F_RXALL_BIT] = "rx-all",
- [NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload",
- [NETIF_F_HW_TC_BIT] = "hw-tc-offload",
- [NETIF_F_HW_ESP_BIT] = "esp-hw-offload",
- [NETIF_F_HW_ESP_TX_CSUM_BIT] = "esp-tx-csum-hw-offload",
- [NETIF_F_RX_UDP_TUNNEL_PORT_BIT] = "rx-udp_tunnel-port-offload",
- [NETIF_F_HW_TLS_RECORD_BIT] = "tls-hw-record",
- [NETIF_F_HW_TLS_TX_BIT] = "tls-hw-tx-offload",
- [NETIF_F_HW_TLS_RX_BIT] = "tls-hw-rx-offload",
-};
-
-static const char
-rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN] = {
- [ETH_RSS_HASH_TOP_BIT] = "toeplitz",
- [ETH_RSS_HASH_XOR_BIT] = "xor",
- [ETH_RSS_HASH_CRC32_BIT] = "crc32",
-};
-
-static const char
-tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
- [ETHTOOL_ID_UNSPEC] = "Unspec",
- [ETHTOOL_RX_COPYBREAK] = "rx-copybreak",
- [ETHTOOL_TX_COPYBREAK] = "tx-copybreak",
- [ETHTOOL_PFC_PREVENTION_TOUT] = "pfc-prevention-tout",
-};
-
-static const char
-phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
- [ETHTOOL_ID_UNSPEC] = "Unspec",
- [ETHTOOL_PHY_DOWNSHIFT] = "phy-downshift",
-};
-
static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
{
struct ethtool_gfeatures cmd = {
--
2.20.1
^ permalink raw reply related
* [RFC PATCH net-next v3 14/21] ethtool: provide link mode names as a string set
From: Michal Kubecek @ 2019-02-18 18:22 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
Add table of ethernet link mode names and make it available as a string set
to userspace GET_STRSET requests.
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
include/uapi/linux/ethtool.h | 2 ++
net/ethtool/netlink.c | 58 ++++++++++++++++++++++++++++++++++++
net/ethtool/netlink.h | 1 +
net/ethtool/strset.c | 6 ++++
4 files changed, 67 insertions(+)
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 1b58637d3a4d..ba96a691bfd4 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -566,6 +566,7 @@ struct ethtool_pauseparam {
* @ETH_SS_TSTAMP_SOF: timestamping flag names
* @ETH_SS_TSTAMP_TX_TYPE: timestamping Tx type names
* @ETH_SS_TSTAMP_RX_FILTER: timestamping Rx filter names
+ * @ETH_SS_LINK_MODES: link mode names
*/
enum ethtool_stringset {
ETH_SS_TEST = 0,
@@ -580,6 +581,7 @@ enum ethtool_stringset {
ETH_SS_TSTAMP_SOF,
ETH_SS_TSTAMP_TX_TYPE,
ETH_SS_TSTAMP_RX_FILTER,
+ ETH_SS_LINK_MODES,
ETH_SS_COUNT
};
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index e27dec427414..1ff6696ad716 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -6,6 +6,61 @@
u32 ethnl_bcast_seq;
+const char *const link_mode_names[] = {
+ [ETHTOOL_LINK_MODE_10baseT_Half_BIT] = "10baseT/Half",
+ [ETHTOOL_LINK_MODE_10baseT_Full_BIT] = "10baseT/Full",
+ [ETHTOOL_LINK_MODE_100baseT_Half_BIT] = "100baseT/Half",
+ [ETHTOOL_LINK_MODE_100baseT_Full_BIT] = "100baseT/Full",
+ [ETHTOOL_LINK_MODE_1000baseT_Half_BIT] = "1000baseT/Half",
+ [ETHTOOL_LINK_MODE_1000baseT_Full_BIT] = "1000baseT/Full",
+ [ETHTOOL_LINK_MODE_Autoneg_BIT] = "Autoneg",
+ [ETHTOOL_LINK_MODE_TP_BIT] = "TP",
+ [ETHTOOL_LINK_MODE_AUI_BIT] = "AUI",
+ [ETHTOOL_LINK_MODE_MII_BIT] = "MII",
+ [ETHTOOL_LINK_MODE_FIBRE_BIT] = "FIBRE",
+ [ETHTOOL_LINK_MODE_BNC_BIT] = "BNC",
+ [ETHTOOL_LINK_MODE_10000baseT_Full_BIT] = "10000baseT/Full",
+ [ETHTOOL_LINK_MODE_Pause_BIT] = "Pause",
+ [ETHTOOL_LINK_MODE_Asym_Pause_BIT] = "Asym_Pause",
+ [ETHTOOL_LINK_MODE_2500baseX_Full_BIT] = "2500baseX/Full",
+ [ETHTOOL_LINK_MODE_Backplane_BIT] = "Backplane",
+ [ETHTOOL_LINK_MODE_1000baseKX_Full_BIT] = "1000baseKX/Full",
+ [ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT] = "10000baseKX4/Full",
+ [ETHTOOL_LINK_MODE_10000baseKR_Full_BIT] = "10000baseKR/Full",
+ [ETHTOOL_LINK_MODE_10000baseR_FEC_BIT] = "10000baseR/FEC",
+ [ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT] = "20000baseMLD2/Full",
+ [ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT] = "20000baseKR2/Full",
+ [ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT] = "40000baseKR4/Full",
+ [ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT] = "40000baseCR4/Full",
+ [ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT] = "40000baseSR4/Full",
+ [ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT] = "40000baseLR4/Full",
+ [ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT] = "56000baseKR4/Full",
+ [ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT] = "56000baseCR4/Full",
+ [ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT] = "56000baseSR4/Full",
+ [ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT] = "56000baseLR4/Full",
+ [ETHTOOL_LINK_MODE_25000baseCR_Full_BIT] = "25000baseCR/Full",
+ [ETHTOOL_LINK_MODE_25000baseKR_Full_BIT] = "25000baseKR/Full",
+ [ETHTOOL_LINK_MODE_25000baseSR_Full_BIT] = "25000baseSR/Full",
+ [ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT] = "50000baseCR2/Full",
+ [ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT] = "50000baseKR2/Full",
+ [ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT] = "100000baseKR4/Full",
+ [ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT] = "100000baseSR4/Full",
+ [ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT] = "100000baseCR4/Full",
+ [ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT] = "100000baseLR4/ER4_Full",
+ [ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT] = "50000baseSR2/Full",
+ [ETHTOOL_LINK_MODE_1000baseX_Full_BIT] = "1000baseX/Full",
+ [ETHTOOL_LINK_MODE_10000baseCR_Full_BIT] = "10000baseCR/Full",
+ [ETHTOOL_LINK_MODE_10000baseSR_Full_BIT] = "10000baseSR/Full",
+ [ETHTOOL_LINK_MODE_10000baseLR_Full_BIT] = "10000baseLR/Full",
+ [ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT] = "10000baseLRM/Full",
+ [ETHTOOL_LINK_MODE_10000baseER_Full_BIT] = "10000baseER/Full",
+ [ETHTOOL_LINK_MODE_2500baseT_Full_BIT] = "2500baseT/Full",
+ [ETHTOOL_LINK_MODE_5000baseT_Full_BIT] = "5000baseT/Full",
+ [ETHTOOL_LINK_MODE_FEC_NONE_BIT] = "None",
+ [ETHTOOL_LINK_MODE_FEC_RS_BIT] = "RS",
+ [ETHTOOL_LINK_MODE_FEC_BASER_BIT] = "BASER",
+};
+
static const struct nla_policy dev_policy[ETHA_DEV_MAX + 1] = {
[ETHA_DEV_UNSPEC] = { .type = NLA_REJECT },
[ETHA_DEV_INDEX] = { .type = NLA_U32 },
@@ -541,6 +596,9 @@ static int __init ethnl_init(void)
{
int ret;
+ BUILD_BUG_ON(ARRAY_SIZE(link_mode_names) <
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+
ret = genl_register_family(ðtool_genl_family);
if (ret < 0)
panic("ethtool: could not register genetlink family\n");
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 82a4c1f398d8..800ea57ab0de 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -23,6 +23,7 @@ extern struct genl_family ethtool_genl_family;
extern const char *const so_timestamping_labels[];
extern const char *const tstamp_tx_type_labels[];
extern const char *const tstamp_rx_filter_labels[];
+extern const char *const link_mode_names[];
struct net_device *ethnl_dev_get(struct genl_info *info, struct nlattr *nest);
int ethnl_fill_dev(struct sk_buff *msg, struct net_device *dev, u16 attrtype);
diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c
index 5c74498d9c72..dd87d7db8b61 100644
--- a/net/ethtool/strset.c
+++ b/net/ethtool/strset.c
@@ -85,6 +85,12 @@ static const struct strset_info info_template[] = {
.count = __HWTSTAMP_FILTER_COUNT,
.data = { .simple = tstamp_rx_filter_labels },
},
+ [ETH_SS_LINK_MODES] = {
+ .type = ETH_SS_TYPE_SIMPLE,
+ .per_dev = false,
+ .count = __ETHTOOL_LINK_MODE_MASK_NBITS,
+ .data = { .simple = link_mode_names },
+ },
};
struct strset_data {
--
2.20.1
^ permalink raw reply related
* [RFC PATCH net-next v3 16/21] ethtool: provide WoL information in GET_SETTINGS request
From: Michal Kubecek @ 2019-02-18 18:22 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
Add information about supported and enabled wake on LAN modes into the
GET_SETTINGS reply when ETH_SETTINGS_IM_WOLINFO flag is set in the request.
The GET_SETTINGS request can be still sent by unprivileged users but in
such case the SecureOn password (if any) is not included in the reply.
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
Documentation/networking/ethtool-netlink.txt | 13 ++++-
include/uapi/linux/ethtool_netlink.h | 13 ++++-
net/ethtool/common.c | 10 ++++
net/ethtool/common.h | 1 +
net/ethtool/ioctl.c | 8 +--
net/ethtool/settings.c | 61 ++++++++++++++++++++
6 files changed, 100 insertions(+), 6 deletions(-)
diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 0ea7d89c6052..913df35cb762 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -283,6 +283,7 @@ Info mask bits meaning:
ETH_SETTINGS_IM_LINKINFO link_ksettings except link modes
ETH_SETTINGS_IM_LINKMODES link modes from link_ksettings
+ ETH_SETTINGS_IM_WOLINFO struct ethtool_wolinfo
Response contents:
@@ -298,12 +299,22 @@ Response contents:
ETHA_LINKINFO_TRANSCEIVER (u8) transceiver
ETHA_SETTINGS_LINK_MODES (bitset) device link modes
ETHA_SETTINGS_PEER_MODES (bitset) link partner link modes
+ ETHA_SETTINGS_WOL (nested) wake on LAN settings
+ ETHA_WOL_MODES (bitfield32) wake on LAN modes
+ ETHA_WOL_SOPASS (binary) SecureOn(tm) password
Most of the attributes and their values have the same meaning as matching
members of the corresponding ioctl structures. For ETHA_SETTINGS_LINK_MODES,
value represents advertised modes and mask represents supported modes.
ETHA_SETTINGS_PEER_MODES in the reply is a bit list.
+For ETHA_WOL_MODES, selector reports wake on LAN modes supported by the
+device and value enabled modes.
+
+GET_SETTINGS request is allowed for unprivileged user but ETHA_SETTINGS_SOPASS
+is only provided by kernel in response to privileged (netns CAP_NET_ADMIN)
+requests.
+
GET_SETTINGS requests allow dumps and messages in the same format as response
to them are broadcasted as notifications on change of these settings using
netlink or ioctl ethtool interface.
@@ -322,7 +333,7 @@ ETHTOOL_GSET ETHNL_CMD_GET_SETTINGS
ETHTOOL_SSET n/a
ETHTOOL_GDRVINFO ETHNL_CMD_GET_INFO
ETHTOOL_GREGS n/a
-ETHTOOL_GWOL n/a
+ETHTOOL_GWOL ETHNL_CMD_GET_SETTINGS
ETHTOOL_SWOL n/a
ETHTOOL_GMSGLVL n/a
ETHTOOL_SMSGLVL n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 4e1fa4a06aac..ce9d6b48f814 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -201,6 +201,7 @@ enum {
ETHA_SETTINGS_LINK_INFO, /* nested */
ETHA_SETTINGS_LINK_MODES, /* bitset */
ETHA_SETTINGS_PEER_MODES, /* bitset */
+ ETHA_SETTINGS_WOL, /* nested */
__ETHA_SETTINGS_CNT,
ETHA_SETTINGS_MAX = (__ETHA_SETTINGS_CNT - 1)
@@ -208,8 +209,9 @@ enum {
#define ETH_SETTINGS_IM_LINKINFO 0x01
#define ETH_SETTINGS_IM_LINKMODES 0x02
+#define ETH_SETTINGS_IM_WOLINFO 0x04
-#define ETH_SETTINGS_IM_ALL 0x03
+#define ETH_SETTINGS_IM_ALL 0x07
enum {
ETHA_LINKINFO_UNSPEC,
@@ -226,6 +228,15 @@ enum {
ETHA_LINKINFO_MAX = (__ETHA_LINKINFO_CNT - 1)
};
+enum {
+ ETHA_WOL_UNSPEC,
+ ETHA_WOL_MODES, /* bitfield32 */
+ ETHA_WOL_SOPASS, /* binary */
+
+ __ETHA_WOL_CNT,
+ ETHA_WOL_MAX = (__ETHA_WOL_CNT - 1)
+};
+
/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 3316e9e403c9..9fba57f554dd 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -207,3 +207,13 @@ convert_legacy_settings_to_link_ksettings(
= legacy_settings->eth_tp_mdix_ctrl;
return retval;
}
+
+int __ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ if (!dev->ethtool_ops->get_wol)
+ return -EOPNOTSUPP;
+
+ dev->ethtool_ops->get_wol(dev, wol);
+
+ return 0;
+}
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index 7a3e0b10e69a..ed3f1ca54660 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -17,6 +17,7 @@ phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info);
+int __ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol);
bool convert_legacy_settings_to_link_ksettings(
struct ethtool_link_ksettings *link_ksettings,
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 5e878cf6f418..945eaf551a4c 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -1230,11 +1230,11 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr)
static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
{
struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
+ int rc;
- if (!dev->ethtool_ops->get_wol)
- return -EOPNOTSUPP;
-
- dev->ethtool_ops->get_wol(dev, &wol);
+ rc = __ethtool_get_wol(dev, &wol);
+ if (rc < 0)
+ return rc;
if (copy_to_user(useraddr, &wol, sizeof(wol)))
return -EFAULT;
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index 4f2858fe1a7d..d296625edb2b 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -6,11 +6,13 @@
struct settings_data {
struct common_req_info reqinfo_base;
+ bool privileged;
/* everything below here will be reset for each device in dumps */
struct common_reply_data repdata_base;
struct ethtool_link_ksettings ksettings;
struct ethtool_link_settings *lsettings;
+ struct ethtool_wolinfo wolinfo;
bool lpm_empty;
};
@@ -22,15 +24,20 @@ static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = {
[ETHA_SETTINGS_LINK_INFO] = { .type = NLA_REJECT },
[ETHA_SETTINGS_LINK_MODES] = { .type = NLA_REJECT },
[ETHA_SETTINGS_PEER_MODES] = { .type = NLA_REJECT },
+ [ETHA_SETTINGS_WOL] = { .type = NLA_REJECT },
};
static int parse_settings(struct common_req_info *req_info,
struct sk_buff *skb, struct genl_info *info,
const struct nlmsghdr *nlhdr)
{
+ struct settings_data *data =
+ container_of(req_info, struct settings_data, reqinfo_base);
struct nlattr *tb[ETHA_SETTINGS_MAX + 1];
int ret;
+ data->privileged = ethnl_is_privileged(skb);
+
ret = genlmsg_parse(nlhdr, ðtool_genl_family, tb,
ETHA_SETTINGS_MAX, get_settings_policy,
info ? info->extack : NULL);
@@ -68,6 +75,16 @@ static int ethnl_get_link_ksettings(struct genl_info *info,
return ret;
}
+static int ethnl_get_wol(struct genl_info *info, struct net_device *dev,
+ struct ethtool_wolinfo *wolinfo)
+{
+ int ret = __ethtool_get_wol(dev, wolinfo);
+
+ if (ret < 0)
+ ETHNL_SET_ERRMSG(info, "failed to retrieve wol info");
+ return ret;
+}
+
static int prepare_settings(struct common_req_info *req_info,
struct genl_info *info)
{
@@ -100,6 +117,11 @@ static int prepare_settings(struct common_req_info *req_info,
ethnl_bitmap_to_u32(data->ksettings.link_modes.lp_advertising,
__ETHTOOL_LINK_MODE_MASK_NWORDS);
}
+ if (req_mask & ETH_SETTINGS_IM_WOLINFO) {
+ ret = ethnl_get_wol(info, dev, &data->wolinfo);
+ if (ret < 0)
+ req_mask &= ~ETH_SETTINGS_IM_WOLINFO;
+ }
ethnl_after_ops(dev);
data->repdata_base.info_mask = req_mask;
@@ -147,6 +169,12 @@ static int link_modes_size(const struct ethtool_link_ksettings *ksettings,
return len;
}
+static int wol_size(void)
+{
+ return nla_total_size(nla_total_size(sizeof(struct nla_bitfield32)) +
+ nla_total_size(SOPASS_MAX));
+}
+
/* To keep things simple, reserve space for some attributes which may not
* be added to the message (e.g. ETHA_SETTINGS_SOPASS); therefore the length
* returned may be bigger than the actual length of the message sent
@@ -168,6 +196,8 @@ static int settings_size(const struct common_req_info *req_info)
return ret;
len += ret;
}
+ if (info_mask & ETH_SETTINGS_IM_WOLINFO)
+ len += wol_size();
return len;
}
@@ -227,6 +257,32 @@ static int fill_link_modes(struct sk_buff *skb,
return 0;
}
+static int fill_wolinfo(struct sk_buff *skb,
+ const struct ethtool_wolinfo *wolinfo, bool privileged)
+{
+ struct nlattr *nest = ethnl_nest_start(skb, ETHA_SETTINGS_WOL);
+
+ if (!nest)
+ return -EMSGSIZE;
+ if (nla_put_bitfield32(skb, ETHA_WOL_MODES, wolinfo->wolopts,
+ wolinfo->supported))
+ goto err;
+ /* ioctl() restricts read access to wolinfo but the actual
+ * reason is to hide sopass from unprivileged users; netlink
+ * can show wol modes without sopass
+ */
+ if (privileged &&
+ nla_put(skb, ETHA_WOL_SOPASS, sizeof(wolinfo->sopass),
+ wolinfo->sopass))
+ goto err;
+ nla_nest_end(skb, nest);
+ return 0;
+
+err:
+ nla_nest_cancel(skb, nest);
+ return -EMSGSIZE;
+}
+
static int fill_settings(struct sk_buff *skb,
const struct common_req_info *req_info)
{
@@ -247,6 +303,11 @@ static int fill_settings(struct sk_buff *skb,
if (ret < 0)
return ret;
}
+ if (info_mask & ETH_SETTINGS_IM_WOLINFO) {
+ ret = fill_wolinfo(skb, &data->wolinfo, data->privileged);
+ if (ret < 0)
+ return ret;
+ }
return 0;
}
--
2.20.1
^ permalink raw reply related
* [RFC PATCH net-next v3 17/21] ethtool: provide message level in GET_SETTINGS request
From: Michal Kubecek @ 2019-02-18 18:22 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
Add information about supported and enabled message levels to the
GET_SETTINGS reply when ETH_SETTINGS_IM_MSGLEVEL flag is set in the
request.
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
Documentation/networking/ethtool-netlink.txt | 7 ++++++-
include/linux/netdevice.h | 2 ++
include/uapi/linux/ethtool_netlink.h | 4 +++-
net/ethtool/settings.c | 16 ++++++++++++++++
4 files changed, 27 insertions(+), 2 deletions(-)
diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 913df35cb762..057eb3213cfe 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -284,6 +284,7 @@ Info mask bits meaning:
ETH_SETTINGS_IM_LINKINFO link_ksettings except link modes
ETH_SETTINGS_IM_LINKMODES link modes from link_ksettings
ETH_SETTINGS_IM_WOLINFO struct ethtool_wolinfo
+ ETH_SETTINGS_IM_MSGLEVEL msglevel
Response contents:
@@ -302,6 +303,7 @@ Response contents:
ETHA_SETTINGS_WOL (nested) wake on LAN settings
ETHA_WOL_MODES (bitfield32) wake on LAN modes
ETHA_WOL_SOPASS (binary) SecureOn(tm) password
+ ETHA_SETTINGS_MSGLEVEL (bitfield32) debug level
Most of the attributes and their values have the same meaning as matching
members of the corresponding ioctl structures. For ETHA_SETTINGS_LINK_MODES,
@@ -311,6 +313,9 @@ ETHA_SETTINGS_PEER_MODES in the reply is a bit list.
For ETHA_WOL_MODES, selector reports wake on LAN modes supported by the
device and value enabled modes.
+For ETHA_SETTINGS_MSGLEVEL, selector reports all flags supported by kernel and
+value flags enabled for the device.
+
GET_SETTINGS request is allowed for unprivileged user but ETHA_SETTINGS_SOPASS
is only provided by kernel in response to privileged (netns CAP_NET_ADMIN)
requests.
@@ -335,7 +340,7 @@ ETHTOOL_GDRVINFO ETHNL_CMD_GET_INFO
ETHTOOL_GREGS n/a
ETHTOOL_GWOL ETHNL_CMD_GET_SETTINGS
ETHTOOL_SWOL n/a
-ETHTOOL_GMSGLVL n/a
+ETHTOOL_GMSGLVL ETHNL_CMD_GET_SETTINGS
ETHTOOL_SMSGLVL n/a
ETHTOOL_NWAY_RST n/a
ETHTOOL_GLINK n/a
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 9a50a67f328f..a2ddfeb381bb 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3846,6 +3846,8 @@ enum {
NETIF_MSG_PKTDATA = 0x1000,
NETIF_MSG_HW = 0x2000,
NETIF_MSG_WOL = 0x4000,
+
+ NETIF_MSG_ALL = 0x7fff,
};
#define netif_msg_drv(p) ((p)->msg_enable & NETIF_MSG_DRV)
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index ce9d6b48f814..360e20a73f19 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -202,6 +202,7 @@ enum {
ETHA_SETTINGS_LINK_MODES, /* bitset */
ETHA_SETTINGS_PEER_MODES, /* bitset */
ETHA_SETTINGS_WOL, /* nested */
+ ETHA_SETTINGS_MSGLEVEL, /* bitfield32 */
__ETHA_SETTINGS_CNT,
ETHA_SETTINGS_MAX = (__ETHA_SETTINGS_CNT - 1)
@@ -210,8 +211,9 @@ enum {
#define ETH_SETTINGS_IM_LINKINFO 0x01
#define ETH_SETTINGS_IM_LINKMODES 0x02
#define ETH_SETTINGS_IM_WOLINFO 0x04
+#define ETH_SETTINGS_IM_MSGLEVEL 0x08
-#define ETH_SETTINGS_IM_ALL 0x07
+#define ETH_SETTINGS_IM_ALL 0x0f
enum {
ETHA_LINKINFO_UNSPEC,
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index d296625edb2b..58cd2d19a75d 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -13,6 +13,7 @@ struct settings_data {
struct ethtool_link_ksettings ksettings;
struct ethtool_link_settings *lsettings;
struct ethtool_wolinfo wolinfo;
+ u32 msglevel;
bool lpm_empty;
};
@@ -25,6 +26,7 @@ static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = {
[ETHA_SETTINGS_LINK_MODES] = { .type = NLA_REJECT },
[ETHA_SETTINGS_PEER_MODES] = { .type = NLA_REJECT },
[ETHA_SETTINGS_WOL] = { .type = NLA_REJECT },
+ [ETHA_SETTINGS_MSGLEVEL] = { .type = NLA_REJECT },
};
static int parse_settings(struct common_req_info *req_info,
@@ -91,6 +93,7 @@ static int prepare_settings(struct common_req_info *req_info,
struct settings_data *data =
container_of(req_info, struct settings_data, reqinfo_base);
struct net_device *dev = data->repdata_base.dev;
+ const struct ethtool_ops *eops = dev->ethtool_ops;
u32 req_mask = req_info->req_mask;
int ret;
@@ -122,6 +125,12 @@ static int prepare_settings(struct common_req_info *req_info,
if (ret < 0)
req_mask &= ~ETH_SETTINGS_IM_WOLINFO;
}
+ if (req_mask & ETH_SETTINGS_IM_MSGLEVEL) {
+ if (eops->get_msglevel)
+ data->msglevel = eops->get_msglevel(dev);
+ else
+ req_mask &= ~ETH_SETTINGS_IM_MSGLEVEL;
+ }
ethnl_after_ops(dev);
data->repdata_base.info_mask = req_mask;
@@ -198,6 +207,8 @@ static int settings_size(const struct common_req_info *req_info)
}
if (info_mask & ETH_SETTINGS_IM_WOLINFO)
len += wol_size();
+ if (info_mask & ETH_SETTINGS_IM_MSGLEVEL)
+ len += nla_total_size(sizeof(struct nla_bitfield32));
return len;
}
@@ -308,6 +319,11 @@ static int fill_settings(struct sk_buff *skb,
if (ret < 0)
return ret;
}
+ if (info_mask & ETH_SETTINGS_IM_MSGLEVEL) {
+ if (nla_put_bitfield32(skb, ETHA_SETTINGS_MSGLEVEL,
+ data->msglevel, NETIF_MSG_ALL))
+ return -EMSGSIZE;
+ }
return 0;
}
--
2.20.1
^ permalink raw reply related
* [RFC PATCH net-next v3 19/21] ethtool: provide device features in GET_SETTINGS request
From: Michal Kubecek @ 2019-02-18 18:23 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
Add information about network device features (as provided by
ETHTOOL_GFEATURES ioctl command) in GET_SETTINGS reply when
ETH_SETTINGS_IM_FEATURES flag is set in the request.
This request also provides information provided by ETHTOOL_GRXCSUM,
ETHTOOL_GTXCSUM, ETHTOOL_GSG, ETHTOOL_GTSO, ETHTOOL_GUFO, ETHTOOL_GGSO,
ETHTOOL_GFLAGS and ETHTOOL_GGRO ioctl commands.
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
Documentation/networking/ethtool-netlink.txt | 36 +++++--
include/uapi/linux/ethtool_netlink.h | 15 ++-
net/ethtool/common.h | 2 +
net/ethtool/ioctl.c | 2 -
net/ethtool/settings.c | 108 +++++++++++++++++++
5 files changed, 150 insertions(+), 13 deletions(-)
diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 538dad93009f..664c922a05eb 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -286,6 +286,7 @@ Info mask bits meaning:
ETH_SETTINGS_IM_WOLINFO struct ethtool_wolinfo
ETH_SETTINGS_IM_MSGLEVEL msglevel
ETH_SETTINGS_IM_LINK link state
+ ETH_SETTINGS_IM_FEATURES features
Response contents:
@@ -306,6 +307,11 @@ Response contents:
ETHA_WOL_SOPASS (binary) SecureOn(tm) password
ETHA_SETTINGS_MSGLEVEL (bitfield32) debug level
ETHA_SETTINGS_LINK (u8) link state
+ ETHA_SETTINGS_FEATURES (nested) device features
+ ETHA_FEATURES_HW (bitset) dev->hw_features
+ ETHA_FEATURES_WANTED (bitset) dev->wanted_features
+ ETHA_FEATURES_ACTIVE (bitset) dev->features
+ ETHA_FEATURES_NOCHANGE (bitset) NETIF_F_NEVER_CHANGE
Most of the attributes and their values have the same meaning as matching
members of the corresponding ioctl structures. For ETHA_SETTINGS_LINK_MODES,
@@ -318,13 +324,23 @@ device and value enabled modes.
For ETHA_SETTINGS_MSGLEVEL, selector reports all flags supported by kernel and
value flags enabled for the device.
+Bitmaps contained in ETHA_SETTINGS_FEATURES have the same meaning as bitmaps
+used in ioctl interference but attribute names are different (they are based
+on corresponding members of struct net_device). Legacy "flags" are not
+provided, if userspace needs them (most likely only ethtool for backward
+compatibility), it can calculate their values from related feature bits
+itself. ETHA_FEATURES_HW uses mask consisting of all features recognized by
+kernel (to provide all names when using verbose bitmap format), remaining
+three use mask equal to value (to save space).
+
GET_SETTINGS request is allowed for unprivileged user but ETHA_SETTINGS_SOPASS
is only provided by kernel in response to privileged (netns CAP_NET_ADMIN)
requests.
GET_SETTINGS requests allow dumps and messages in the same format as response
to them are broadcasted as notifications on change of these settings using
-netlink or ioctl ethtool interface.
+netlink or ioctl ethtool interface; feature notifications are also sent
+whenever netdev_update_features() or netdev_change_features() is called.
Request translation
@@ -354,30 +370,30 @@ ETHTOOL_GRINGPARAM n/a
ETHTOOL_SRINGPARAM n/a
ETHTOOL_GPAUSEPARAM n/a
ETHTOOL_SPAUSEPARAM n/a
-ETHTOOL_GRXCSUM n/a
+ETHTOOL_GRXCSUM ETHNL_CMD_GET_SETTINGS
ETHTOOL_SRXCSUM n/a
-ETHTOOL_GTXCSUM n/a
+ETHTOOL_GTXCSUM ETHNL_CMD_GET_SETTINGS
ETHTOOL_STXCSUM n/a
-ETHTOOL_GSG n/a
+ETHTOOL_GSG ETHNL_CMD_GET_SETTINGS
ETHTOOL_SSG n/a
ETHTOOL_TEST n/a
ETHTOOL_GSTRINGS ETHNL_CMD_GET_STRSET
ETHTOOL_PHYS_ID n/a
ETHTOOL_GSTATS n/a
-ETHTOOL_GTSO n/a
+ETHTOOL_GTSO ETHNL_CMD_GET_SETTINGS
ETHTOOL_STSO n/a
ETHTOOL_GPERMADDR ETHNL_CMD_GET_INFO
-ETHTOOL_GUFO n/a
+ETHTOOL_GUFO ETHNL_CMD_GET_SETTINGS
ETHTOOL_SUFO n/a
-ETHTOOL_GGSO n/a
+ETHTOOL_GGSO ETHNL_CMD_GET_SETTINGS
ETHTOOL_SGSO n/a
-ETHTOOL_GFLAGS n/a
+ETHTOOL_GFLAGS ETHNL_CMD_GET_SETTINGS
ETHTOOL_SFLAGS n/a
ETHTOOL_GPFLAGS n/a
ETHTOOL_SPFLAGS n/a
ETHTOOL_GRXFH n/a
ETHTOOL_SRXFH n/a
-ETHTOOL_GGRO n/a
+ETHTOOL_GGRO ETHNL_CMD_GET_SETTINGS
ETHTOOL_SGRO n/a
ETHTOOL_GRXRINGS n/a
ETHTOOL_GRXCLSRLCNT n/a
@@ -392,7 +408,7 @@ ETHTOOL_GRXNTUPLE n/a
ETHTOOL_GSSET_INFO ETHNL_CMD_GET_STRSET
ETHTOOL_GRXFHINDIR n/a
ETHTOOL_SRXFHINDIR n/a
-ETHTOOL_GFEATURES n/a
+ETHTOOL_GFEATURES ETHNL_CMD_GET_SETTINGS
ETHTOOL_SFEATURES n/a
ETHTOOL_GCHANNELS n/a
ETHTOOL_SCHANNELS n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 06e78d94cacc..154d7e6a59dd 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -204,6 +204,7 @@ enum {
ETHA_SETTINGS_WOL, /* nested */
ETHA_SETTINGS_MSGLEVEL, /* bitfield32 */
ETHA_SETTINGS_LINK, /* u8 */
+ ETHA_SETTINGS_FEATURES, /* nest - ETHA_FEATURES_* */
__ETHA_SETTINGS_CNT,
ETHA_SETTINGS_MAX = (__ETHA_SETTINGS_CNT - 1)
@@ -214,8 +215,20 @@ enum {
#define ETH_SETTINGS_IM_WOLINFO 0x04
#define ETH_SETTINGS_IM_MSGLEVEL 0x08
#define ETH_SETTINGS_IM_LINK 0x10
+#define ETH_SETTINGS_IM_FEATURES 0x20
-#define ETH_SETTINGS_IM_ALL 0x1f
+#define ETH_SETTINGS_IM_ALL 0x3f
+
+enum {
+ ETHA_FEATURES_UNSPEC,
+ ETHA_FEATURES_HW, /* bitset */
+ ETHA_FEATURES_WANTED, /* bitset */
+ ETHA_FEATURES_ACTIVE, /* bitset */
+ ETHA_FEATURES_NOCHANGE, /* bitset */
+
+ __ETHA_FEATURES_CNT,
+ ETHA_FEATURES_MAX = (__ETHA_FEATURES_CNT - 1)
+};
enum {
ETHA_LINKINFO_UNSPEC,
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index e5b5c5c2a4b9..cf0b81af2d9f 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -6,6 +6,8 @@
#include <linux/netdevice.h>
#include <linux/ethtool.h>
+#define ETHTOOL_DEV_FEATURE_WORDS ((NETDEV_FEATURE_COUNT + 31) / 32)
+
extern const char
netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN];
extern const char
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 63662a3fa2ae..6c3b492a88fe 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -58,8 +58,6 @@ EXPORT_SYMBOL(ethtool_op_get_ts_info);
/* Handlers for each ethtool command */
-#define ETHTOOL_DEV_FEATURE_WORDS ((NETDEV_FEATURE_COUNT + 31) / 32)
-
static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
{
struct ethtool_gfeatures cmd = {
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index 099300901c12..32ee273de879 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -16,6 +16,12 @@ struct settings_data {
u32 msglevel;
int link;
bool lpm_empty;
+ struct {
+ u32 hw[ETHTOOL_DEV_FEATURE_WORDS];
+ u32 wanted[ETHTOOL_DEV_FEATURE_WORDS];
+ u32 active[ETHTOOL_DEV_FEATURE_WORDS];
+ u32 nochange[ETHTOOL_DEV_FEATURE_WORDS];
+ } features;
};
static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = {
@@ -29,6 +35,7 @@ static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = {
[ETHA_SETTINGS_WOL] = { .type = NLA_REJECT },
[ETHA_SETTINGS_MSGLEVEL] = { .type = NLA_REJECT },
[ETHA_SETTINGS_LINK] = { .type = NLA_REJECT },
+ [ETHA_SETTINGS_FEATURES] = { .type = NLA_REJECT },
};
static int parse_settings(struct common_req_info *req_info,
@@ -89,6 +96,24 @@ static int ethnl_get_wol(struct genl_info *info, struct net_device *dev,
return ret;
}
+static void features_to_bitmap(u32 *dest, netdev_features_t src)
+{
+ unsigned int i;
+
+ for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; i++)
+ dest[i] = (u32)(src >> (32 * i));
+}
+
+static int ethnl_get_features(struct net_device *dev,
+ struct settings_data *data)
+{
+ features_to_bitmap(data->features.hw, dev->hw_features);
+ features_to_bitmap(data->features.wanted, dev->wanted_features);
+ features_to_bitmap(data->features.active, dev->features);
+ features_to_bitmap(data->features.nochange, NETIF_F_NEVER_CHANGE);
+ return 0;
+}
+
static int prepare_settings(struct common_req_info *req_info,
struct genl_info *info)
{
@@ -136,6 +161,8 @@ static int prepare_settings(struct common_req_info *req_info,
}
if (req_mask & ETH_SETTINGS_IM_LINK)
data->link = __ethtool_get_link(dev);
+ if (req_mask & ETH_SETTINGS_IM_FEATURES)
+ ethnl_get_features(dev, data);
ethnl_after_ops(dev);
data->repdata_base.info_mask = req_mask;
@@ -189,6 +216,38 @@ static int wol_size(void)
nla_total_size(SOPASS_MAX));
}
+static int features_size(const struct settings_data *data)
+{
+ unsigned int flags =
+ (data->reqinfo_base.compact ? ETHNL_BITSET_COMPACT : 0) |
+ ETHNL_BITSET_LEGACY_NAMES;
+ int len = 0, ret;
+
+ ret = ethnl_bitset32_size(NETDEV_FEATURE_COUNT, data->features.hw,
+ NULL, netdev_features_strings, flags);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ flags |= ETHNL_BITSET_LIST;
+ ret = ethnl_bitset32_size(NETDEV_FEATURE_COUNT, data->features.wanted,
+ NULL, netdev_features_strings, flags);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ ret = ethnl_bitset32_size(NETDEV_FEATURE_COUNT, data->features.active,
+ NULL, netdev_features_strings, flags);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ ret = ethnl_bitset32_size(NETDEV_FEATURE_COUNT, data->features.nochange,
+ NULL, netdev_features_strings, flags);
+ if (ret < 0)
+ return ret;
+ len += ret;
+
+ return len;
+}
+
/* To keep things simple, reserve space for some attributes which may not
* be added to the message (e.g. ETHA_SETTINGS_SOPASS); therefore the length
* returned may be bigger than the actual length of the message sent
@@ -216,6 +275,12 @@ static int settings_size(const struct common_req_info *req_info)
len += nla_total_size(sizeof(struct nla_bitfield32));
if (info_mask & ETH_SETTINGS_IM_LINK)
len += nla_total_size(sizeof(u32));
+ if (info_mask & ETH_SETTINGS_IM_FEATURES) {
+ ret = features_size(data);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ }
return len;
}
@@ -301,6 +366,44 @@ static int fill_wolinfo(struct sk_buff *skb,
return -EMSGSIZE;
}
+static int fill_features(struct sk_buff *skb, const struct settings_data *data)
+{
+ unsigned int flags =
+ (data->reqinfo_base.compact ? ETHNL_BITSET_COMPACT : 0) |
+ ETHNL_BITSET_LEGACY_NAMES;
+ struct nlattr *feat_attr;
+ int ret;
+
+ feat_attr = ethnl_nest_start(skb, ETHA_SETTINGS_FEATURES);
+ if (!feat_attr)
+ return -EMSGSIZE;
+
+ ret = ethnl_put_bitset32(skb, ETHA_FEATURES_HW, NETDEV_FEATURE_COUNT,
+ data->features.hw, NULL,
+ netdev_features_strings, flags);
+ if (ret < 0)
+ return ret;
+ flags |= ETHNL_BITSET_LIST;
+ ret = ethnl_put_bitset32(skb, ETHA_FEATURES_WANTED,
+ NETDEV_FEATURE_COUNT, data->features.wanted,
+ NULL, netdev_features_strings, flags);
+ if (ret < 0)
+ return ret;
+ ret = ethnl_put_bitset32(skb, ETHA_FEATURES_ACTIVE,
+ NETDEV_FEATURE_COUNT, data->features.active,
+ NULL, netdev_features_strings, flags);
+ if (ret < 0)
+ return ret;
+ ret = ethnl_put_bitset32(skb, ETHA_FEATURES_NOCHANGE,
+ NETDEV_FEATURE_COUNT, data->features.nochange,
+ NULL, netdev_features_strings, flags);
+ if (ret < 0)
+ return ret;
+
+ nla_nest_end(skb, feat_attr);
+ return 0;
+}
+
static int fill_settings(struct sk_buff *skb,
const struct common_req_info *req_info)
{
@@ -335,6 +438,11 @@ static int fill_settings(struct sk_buff *skb,
if (nla_put_u8(skb, ETHA_SETTINGS_LINK, data->link))
return -EMSGSIZE;
}
+ if (info_mask & ETH_SETTINGS_IM_FEATURES) {
+ ret = fill_features(skb, data);
+ if (ret < 0)
+ return ret;
+ }
return 0;
}
--
2.20.1
^ permalink raw reply related
* [RFC PATCH net-next v3 20/21] ethtool: provide private flags in GET_SETTINGS request
From: Michal Kubecek @ 2019-02-18 18:23 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
Add information about device private flags (as provided by
ETHTOOL_GPFLAGS ioctl command) in GET_SETTINGS reply when
ETH_SETTINGS_IM_PRIVFLAGS flag is set in the request.
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
Documentation/networking/ethtool-netlink.txt | 9 +-
include/uapi/linux/ethtool_netlink.h | 4 +-
net/ethtool/settings.c | 98 ++++++++++++++++++++
3 files changed, 109 insertions(+), 2 deletions(-)
diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 664c922a05eb..290008aaed0a 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -287,6 +287,7 @@ Info mask bits meaning:
ETH_SETTINGS_IM_MSGLEVEL msglevel
ETH_SETTINGS_IM_LINK link state
ETH_SETTINGS_IM_FEATURES features
+ ETH_SETTINGS_IM_PRIVFLAGS device private flags
Response contents:
@@ -312,6 +313,7 @@ Response contents:
ETHA_FEATURES_WANTED (bitset) dev->wanted_features
ETHA_FEATURES_ACTIVE (bitset) dev->features
ETHA_FEATURES_NOCHANGE (bitset) NETIF_F_NEVER_CHANGE
+ ETHA_SETTINGS_PRIV_FLAGS (bitset) device private flags
Most of the attributes and their values have the same meaning as matching
members of the corresponding ioctl structures. For ETHA_SETTINGS_LINK_MODES,
@@ -333,6 +335,11 @@ itself. ETHA_FEATURES_HW uses mask consisting of all features recognized by
kernel (to provide all names when using verbose bitmap format), remaining
three use mask equal to value (to save space).
+ETHA_SETTINGS_PRIV_FLAGS is a bitset with values of device private flags.
+These flags are defined by driver, their number and names (as well as meaning)
+are device dependent. For compact bitset format, names can be retrieved as
+ETH_SS_PRIV_FLAGS string set.
+
GET_SETTINGS request is allowed for unprivileged user but ETHA_SETTINGS_SOPASS
is only provided by kernel in response to privileged (netns CAP_NET_ADMIN)
requests.
@@ -389,7 +396,7 @@ ETHTOOL_GGSO ETHNL_CMD_GET_SETTINGS
ETHTOOL_SGSO n/a
ETHTOOL_GFLAGS ETHNL_CMD_GET_SETTINGS
ETHTOOL_SFLAGS n/a
-ETHTOOL_GPFLAGS n/a
+ETHTOOL_GPFLAGS ETHNL_CMD_GET_SETTINGS
ETHTOOL_SPFLAGS n/a
ETHTOOL_GRXFH n/a
ETHTOOL_SRXFH n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 154d7e6a59dd..afd61d36bcf8 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -205,6 +205,7 @@ enum {
ETHA_SETTINGS_MSGLEVEL, /* bitfield32 */
ETHA_SETTINGS_LINK, /* u8 */
ETHA_SETTINGS_FEATURES, /* nest - ETHA_FEATURES_* */
+ ETHA_SETTINGS_PRIV_FLAGS, /* nest - ETHA_BITSET_* */
__ETHA_SETTINGS_CNT,
ETHA_SETTINGS_MAX = (__ETHA_SETTINGS_CNT - 1)
@@ -216,8 +217,9 @@ enum {
#define ETH_SETTINGS_IM_MSGLEVEL 0x08
#define ETH_SETTINGS_IM_LINK 0x10
#define ETH_SETTINGS_IM_FEATURES 0x20
+#define ETH_SETTINGS_IM_PRIVFLAGS 0x40
-#define ETH_SETTINGS_IM_ALL 0x3f
+#define ETH_SETTINGS_IM_ALL 0x7f
enum {
ETHA_FEATURES_UNSPEC,
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index 32ee273de879..7f72f4250306 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -22,6 +22,9 @@ struct settings_data {
u32 active[ETHTOOL_DEV_FEATURE_WORDS];
u32 nochange[ETHTOOL_DEV_FEATURE_WORDS];
} features;
+ char (*priv_flag_names)[ETH_GSTRING_LEN];
+ u32 priv_flags;
+ unsigned int n_priv_flags;
};
static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = {
@@ -36,6 +39,7 @@ static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = {
[ETHA_SETTINGS_MSGLEVEL] = { .type = NLA_REJECT },
[ETHA_SETTINGS_LINK] = { .type = NLA_REJECT },
[ETHA_SETTINGS_FEATURES] = { .type = NLA_REJECT },
+ [ETHA_SETTINGS_PRIV_FLAGS] = { .type = NLA_REJECT },
};
static int parse_settings(struct common_req_info *req_info,
@@ -114,6 +118,58 @@ static int ethnl_get_features(struct net_device *dev,
return 0;
}
+static int get_priv_flags_info(struct net_device *dev, unsigned int *count,
+ void **names)
+{
+ const struct ethtool_ops *ops = dev->ethtool_ops;
+ int nflags;
+
+ if (!ops->get_priv_flags || !ops->get_sset_count || !ops->get_strings)
+ return -EOPNOTSUPP;
+ nflags = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
+ if (nflags < 0)
+ return nflags;
+
+ if (names) {
+ *names = kcalloc(nflags, ETH_GSTRING_LEN, GFP_KERNEL);
+ if (!*names)
+ return -ENOMEM;
+ ops->get_strings(dev, ETH_SS_PRIV_FLAGS, *names);
+ }
+
+ /* We can easily pass more than 32 private flags to userspace via
+ * netlink but we cannot get more with ethtool_ops::get_priv_flags().
+ * Note that we must not adjust nflags before allocating the space
+ * for flag names as the buffer must be large enough for all flags.
+ */
+ if (WARN_ONCE(nflags > 32,
+ "device %s reports more than 32 private flags (%d)\n",
+ netdev_name(dev), nflags))
+ nflags = 32;
+
+ *count = nflags;
+ return 0;
+}
+
+static int ethnl_get_priv_flags(struct genl_info *info,
+ struct settings_data *data)
+{
+ struct net_device *dev = data->repdata_base.dev;
+ const struct ethtool_ops *ops = dev->ethtool_ops;
+ unsigned int nflags;
+ void *names;
+ int ret;
+
+ ret = get_priv_flags_info(dev, &nflags, &names);
+ if (ret < 0)
+ return ret;
+
+ data->priv_flags = ops->get_priv_flags(dev);
+ data->priv_flag_names = names;
+ data->n_priv_flags = nflags;
+ return 0;
+}
+
static int prepare_settings(struct common_req_info *req_info,
struct genl_info *info)
{
@@ -163,6 +219,11 @@ static int prepare_settings(struct common_req_info *req_info,
data->link = __ethtool_get_link(dev);
if (req_mask & ETH_SETTINGS_IM_FEATURES)
ethnl_get_features(dev, data);
+ if (req_mask & ETH_SETTINGS_IM_PRIVFLAGS) {
+ ret = ethnl_get_priv_flags(info, data);
+ if (ret < 0)
+ req_mask &= ~ETH_SETTINGS_IM_PRIVFLAGS;
+ }
ethnl_after_ops(dev);
data->repdata_base.info_mask = req_mask;
@@ -281,6 +342,17 @@ static int settings_size(const struct common_req_info *req_info)
return ret;
len += ret;
}
+ if (info_mask & ETH_SETTINGS_IM_PRIVFLAGS) {
+ const unsigned int flags =
+ (compact ? ETHNL_BITSET_COMPACT : 0) |
+ ETHNL_BITSET_LEGACY_NAMES;
+
+ ret = ethnl_bitset32_size(data->n_priv_flags, &data->priv_flags,
+ NULL, data->priv_flag_names, flags);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ }
return len;
}
@@ -404,6 +476,18 @@ static int fill_features(struct sk_buff *skb, const struct settings_data *data)
return 0;
}
+static int fill_priv_flags(struct sk_buff *skb,
+ const struct settings_data *data)
+{
+ const unsigned int bitset_flags =
+ (data->reqinfo_base.compact ? ETHNL_BITSET_COMPACT : 0) |
+ ETHNL_BITSET_LEGACY_NAMES;
+
+ return ethnl_put_bitset32(skb, ETHA_SETTINGS_PRIV_FLAGS,
+ data->n_priv_flags, &data->priv_flags, NULL,
+ data->priv_flag_names, bitset_flags);
+}
+
static int fill_settings(struct sk_buff *skb,
const struct common_req_info *req_info)
{
@@ -443,10 +527,23 @@ static int fill_settings(struct sk_buff *skb,
if (ret < 0)
return ret;
}
+ if (info_mask & ETH_SETTINGS_IM_PRIVFLAGS) {
+ ret = fill_priv_flags(skb, data);
+ if (ret < 0)
+ return ret;
+ }
return 0;
}
+static void settings_cleanup(struct common_req_info *req_info)
+{
+ const struct settings_data *data =
+ container_of(req_info, struct settings_data, reqinfo_base);
+
+ kfree(data->priv_flag_names);
+}
+
const struct get_request_ops settings_request_ops = {
.request_cmd = ETHNL_CMD_GET_SETTINGS,
.reply_cmd = ETHNL_CMD_SET_SETTINGS,
@@ -458,4 +555,5 @@ const struct get_request_ops settings_request_ops = {
.prepare_data = prepare_settings,
.reply_size = settings_size,
.fill_reply = fill_settings,
+ .cleanup = settings_cleanup,
};
--
2.20.1
^ permalink raw reply related
* Re: [PATCH net-next 0/2] tracepoints in neighbor subsystem
From: Roopa Prabhu @ 2019-02-18 18:23 UTC (permalink / raw)
To: David Miller; +Cc: netdev, David Ahern
In-Reply-To: <20190217.103437.1509010953072073413.davem@davemloft.net>
On Sun, Feb 17, 2019 at 10:34 AM David Miller <davem@davemloft.net> wrote:
>
> From: Roopa Prabhu <roopa@cumulusnetworks.com>
> Date: Thu, 14 Feb 2019 09:15:09 -0800
>
> > From: Roopa Prabhu <roopa@cumulusnetworks.com>
> >
> > Roopa Prabhu (2):
> > trace: events: add a few neigh tracepoints
> > neigh: hook tracepoints in neigh update code
>
> Series applied, thanks.
>
> Maybe put some actual text in this intro posting next time, explaining
> what the series is doing, how it is doing it, and why?
>
Oops, My bad. I did have text here in my initial version and possibly
accidentally dropped it when re-generating the cover-letter multiple
times. And absolutely, will keep an eye out to make sure it is
complete next time on. Thanks.
Here are some examples of perf report outputs for neigh creates and
deletes (if anyone wants to review further).
As i type this i realized I missed the converting of new_state to
string. Will send a patch to fix it.
# create a neigh
$ip neigh add 45.0.1.100 dev vlan1001 lladdr 00:02:00:00:00:aa nud reachable
ip 3964 [000] 52484.852372: neigh:neigh_update: family 2
dev vlan1001 lladdr 000000000000 flags 00 nud_state 0x0 type 01 dead 0
refcnt 2 primary_key4 45.0.1.100 primary_key6 ::ffff:45.0.1.100
confirmed 4344992162 updated 4347152162 used 4347152162 new_lladdr
0002000000aa new_state 02 update_flags 80000005 pid 3964
ip 3964 [000] 52484.852446: neigh:neigh_update_done: family 2
dev vlan1001 lladdr 0002000000aa flags 00 nud_state reachable type 01
dead 0 refcnt 3 primary_key4 45.0.1.100 primary_key6 ::ffff:45.0.1.100
confirmed 4347152162 updated 4347152162 used 4347152162 err 0
# change of lladdr on existing neigh
$ip neigh replace 45.0.1.100 dev vlan1001 lladdr 00:02:00:00:00:bb nud reachable
ip 3965 [000] 52484.855838: neigh:neigh_update: family 2
dev vlan1001 lladdr 0002000000aa flags 00 nud_state reachable type 01
dead 0 refcnt 3 primary_key4 45.0.1.100 primary_key6 ::ffff:45.0.1.100
confirmed 4347152162 updated 4347152162 used 4347152162 new_lladdr
0002000000bb new_state 02 update_flags 80000005 pid 3965
ip 3965 [000] 52484.855883: neigh:neigh_update_done: family 2
dev vlan1001 lladdr 0002000000bb flags 00 nud_state reachable type 01
dead 0 refcnt 3 primary_key4 45.0.1.100 primary_key6 ::ffff:45.0.1.100
confirmed 4347152165 updated 4347152165 used 4347152162 err 0
# neigh delete, update comes in with NUD_FAILED
$ip neigh del 45.0.1.100 dev vlan1001
ip 3966 [000] 52484.859354: neigh:neigh_update: family 2
dev vlan1001 lladdr 0002000000bb flags 00 nud_state reachable type 01
dead 0 refcnt 3 primary_key4 45.0.1.100 primary_key6 ::ffff:45.0.1.100
confirmed 4347152165 updated 4347152165 used 4347152162 new_lladdr
00000000766c new_state 20 update_flags 80000001 pid 3966
ip 3966 [000] 52484.859397: neigh:neigh_update_done: family 2
dev vlan1001 lladdr 0002000000bb flags 00 nud_state failed type 01
dead 0 refcnt 2 primary_key4 45.0.1.100 primary_key6 ::ffff:45.0.1.100
confirmed 4347152165 updated 4347152165 used 4347152162 err 0
ip 3966 [000] 52484.859401: neigh:neigh_cleanup_and_release: family 2
dev vlan1001 lladdr 0002000000bb flags 00 nud_state failed type 01
dead 1 refcnt 1 primary_key4 45.0.1.100 primary_key6 ::ffff:45.0.1.100
confirmed 4347152165 updated 4347152165 used 4347152162 err 0
# readd neigh entry and allow it to age, this time
$ip neigh add 45.0.1.100 dev vlan1001 lladdr 00:02:00:00:00:aa nud reachable
ip 4165 [000] 52519.192502: neigh:neigh_update: family 2
dev vlan1001 lladdr 000000000000 flags 00 nud_state 0x0 type 01 dead 0
refcnt 2 primary_key4 45.0.1.100 primary_key6 ::ffff:45.0.1.100
confirmed 4345026502 updated 4347186502 used 4347186502 new_lladdr
0002000000aa new_state 02 update_flags 80000005 pid 4165
ip 4165 [000] 52519.192562: neigh:neigh_update_done: family 2
dev vlan1001 lladdr 0002000000aa flags 00 nud_state reachable type 01
dead 0 refcnt 3 primary_key4 45.0.1.100 primary_key6 ::ffff:45.0.1.100
confirmed 4347186502 updated 4347186502 used 4347186502 err 0
swapper 0 [000] 53220.306184: neigh:neigh_timer_handler:
family 2 dev vlan1001 lladdr 0002000000aa flags 00 nud_state reachable
type 01 dead 0 refcnt 3 primary_key4 45.0.1.100 primary_key6
::ffff:45.0.1.100 confirmed 4347186502 updated 4347186502 used
4347186502 err 0
swapper 0 [000] 53973.970238: neigh:neigh_timer_handler:
family 2 dev vlan1001 lladdr 0002000000aa flags 00 nud_state stale
type 01 dead 0 refcnt 2 primary_key4 45.0.1.100 primary_key6
::ffff:45.0.1.100 confirmed 4347186502 updated 4348641280 used
4347186502 err 0
ip 10268 [000] 65338.084401: neigh:neigh_cleanup_and_release: family 2
dev vlan1001 lladdr 0002000000aa flags 00 nud_state stale type 01 dead
1 refcnt 1 primary_key4 45.0.1.100 primary_key6 ::ffff:45.0.1.100
confirmed 4347186502 updated 4348641280 used 4347186502 err 0
^ permalink raw reply
* [RFC PATCH net-next v3 21/21] ethtool: send netlink notifications about setting changes
From: Michal Kubecek @ 2019-02-18 18:23 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
SET_SETTINGS notification message has the same format as response to
GET_SETTINGS request and is broadcasted on change of relevant fields. Info
mask can be used to limit the information passed to userspace.
Send the notification on changes performed via the legacy ioctl interface;
feature notifications are also sent whenever netdev_update_features() or
netdev_change_features() is called, even if the change was not performed
using the ethtool interface.
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
net/ethtool/ioctl.c | 24 ++++++++++++++++++++++--
net/ethtool/netlink.c | 12 ++++++++++++
2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 6c3b492a88fe..17ccca14f5c3 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -30,6 +30,7 @@
#include <net/devlink.h>
#include <net/xdp_sock.h>
#include <net/flow_offload.h>
+#include <linux/ethtool_netlink.h>
#include "common.h"
@@ -567,7 +568,12 @@ static int ethtool_set_link_ksettings(struct net_device *dev,
!= link_ksettings.base.link_mode_masks_nwords)
return -EINVAL;
- return dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
+ err = dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
+ if (err >= 0)
+ ethtool_notify(dev, NULL, ETHNL_CMD_SET_SETTINGS,
+ ETH_SETTINGS_IM_LINKINFO |
+ ETH_SETTINGS_IM_LINKMODES, NULL);
+ return err;
}
/* Query device for its ethtool_cmd settings.
@@ -616,6 +622,7 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
{
struct ethtool_link_ksettings link_ksettings;
struct ethtool_cmd cmd;
+ int ret;
ASSERT_RTNL();
@@ -628,7 +635,12 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
return -EINVAL;
link_ksettings.base.link_mode_masks_nwords =
__ETHTOOL_LINK_MODE_MASK_NU32;
- return dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
+ ret = dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
+ if (ret >= 0)
+ ethtool_notify(dev, NULL, ETHNL_CMD_SET_SETTINGS,
+ ETH_SETTINGS_IM_LINKINFO |
+ ETH_SETTINGS_IM_LINKMODES, NULL);
+ return ret;
}
static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
@@ -1255,6 +1267,8 @@ static int ethtool_set_wol(struct net_device *dev, char __user *useraddr)
return ret;
dev->wol_enabled = !!wol.wolopts;
+ ethtool_notify(dev, NULL, ETHNL_CMD_SET_SETTINGS,
+ ETH_SETTINGS_IM_WOLINFO, NULL);
return 0;
}
@@ -2453,6 +2467,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
case ETHTOOL_SMSGLVL:
rc = ethtool_set_value_void(dev, useraddr,
dev->ethtool_ops->set_msglevel);
+ if (rc >= 0)
+ ethtool_notify(dev, NULL, ETHNL_CMD_SET_SETTINGS,
+ ETH_SETTINGS_IM_MSGLEVEL, NULL);
break;
case ETHTOOL_GEEE:
rc = ethtool_get_eee(dev, useraddr);
@@ -2519,6 +2536,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
case ETHTOOL_SPFLAGS:
rc = ethtool_set_value(dev, useraddr,
dev->ethtool_ops->set_priv_flags);
+ if (rc == 0)
+ ethtool_notify(dev, NULL, ETHNL_CMD_SET_SETTINGS,
+ ETH_SETTINGS_IM_PRIVFLAGS, NULL);
break;
case ETHTOOL_GRXFH:
case ETHTOOL_GRXRINGS:
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 5166b0c28288..6f94aec6fa69 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -480,6 +480,7 @@ typedef void (*ethnl_notify_handler_t)(struct net_device *dev,
const void *data);
ethnl_notify_handler_t ethnl_notify_handlers[] = {
+ [ETHNL_CMD_SET_SETTINGS] = ethnl_std_notify,
};
void ethtool_notify(struct net_device *dev, struct netlink_ext_ack *extack,
@@ -534,6 +535,14 @@ static void ethnl_notify_devlist(struct netdev_notifier_info *info,
nlmsg_free(skb);
}
+static void ethnl_notify_features(struct netdev_notifier_info *info)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(info);
+
+ ethtool_notify(dev, NULL, ETHNL_CMD_SET_SETTINGS,
+ ETH_SETTINGS_IM_FEATURES, NULL);
+}
+
static int ethnl_netdev_event(struct notifier_block *this, unsigned long event,
void *ptr)
{
@@ -548,6 +557,9 @@ static int ethnl_netdev_event(struct notifier_block *this, unsigned long event,
ethnl_notify_devlist(ptr, ETHA_EVENT_RENAMEDEV,
ETHA_RENAMEDEV_DEV);
break;
+ case NETDEV_FEAT_CHANGE:
+ ethnl_notify_features(ptr);
+ break;
}
return NOTIFY_DONE;
--
2.20.1
^ permalink raw reply related
* [RFC PATCH net-next v3 18/21] ethtool: provide link state in GET_SETTINGS request
From: Michal Kubecek @ 2019-02-18 18:22 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
Add information about device link state (as provided by ETHTOOL_GLINK ioctl
command) into the GET_SETTINGS reply when ETH_SETTINGS_IM_LINK flag is set
in the request.
Note: we cannot use NLA_FLAG for link state as we need three states: off,
on and unknown.
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
Documentation/networking/ethtool-netlink.txt | 4 +++-
include/uapi/linux/ethtool_netlink.h | 4 +++-
net/ethtool/common.c | 8 ++++++++
net/ethtool/common.h | 1 +
net/ethtool/ioctl.c | 8 ++++----
net/ethtool/settings.c | 11 +++++++++++
6 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 057eb3213cfe..538dad93009f 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -285,6 +285,7 @@ Info mask bits meaning:
ETH_SETTINGS_IM_LINKMODES link modes from link_ksettings
ETH_SETTINGS_IM_WOLINFO struct ethtool_wolinfo
ETH_SETTINGS_IM_MSGLEVEL msglevel
+ ETH_SETTINGS_IM_LINK link state
Response contents:
@@ -304,6 +305,7 @@ Response contents:
ETHA_WOL_MODES (bitfield32) wake on LAN modes
ETHA_WOL_SOPASS (binary) SecureOn(tm) password
ETHA_SETTINGS_MSGLEVEL (bitfield32) debug level
+ ETHA_SETTINGS_LINK (u8) link state
Most of the attributes and their values have the same meaning as matching
members of the corresponding ioctl structures. For ETHA_SETTINGS_LINK_MODES,
@@ -343,7 +345,7 @@ ETHTOOL_SWOL n/a
ETHTOOL_GMSGLVL ETHNL_CMD_GET_SETTINGS
ETHTOOL_SMSGLVL n/a
ETHTOOL_NWAY_RST n/a
-ETHTOOL_GLINK n/a
+ETHTOOL_GLINK ETHNL_CMD_GET_SETTINGS
ETHTOOL_GEEPROM n/a
ETHTOOL_SEEPROM n/a
ETHTOOL_GCOALESCE n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 360e20a73f19..06e78d94cacc 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -203,6 +203,7 @@ enum {
ETHA_SETTINGS_PEER_MODES, /* bitset */
ETHA_SETTINGS_WOL, /* nested */
ETHA_SETTINGS_MSGLEVEL, /* bitfield32 */
+ ETHA_SETTINGS_LINK, /* u8 */
__ETHA_SETTINGS_CNT,
ETHA_SETTINGS_MAX = (__ETHA_SETTINGS_CNT - 1)
@@ -212,8 +213,9 @@ enum {
#define ETH_SETTINGS_IM_LINKMODES 0x02
#define ETH_SETTINGS_IM_WOLINFO 0x04
#define ETH_SETTINGS_IM_MSGLEVEL 0x08
+#define ETH_SETTINGS_IM_LINK 0x10
-#define ETH_SETTINGS_IM_ALL 0x0f
+#define ETH_SETTINGS_IM_ALL 0x1f
enum {
ETHA_LINKINFO_UNSPEC,
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 9fba57f554dd..a188f07bcb4c 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -217,3 +217,11 @@ int __ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return 0;
}
+
+int __ethtool_get_link(struct net_device *dev)
+{
+ if (!dev->ethtool_ops->get_link)
+ return -EOPNOTSUPP;
+
+ return netif_running(dev) && dev->ethtool_ops->get_link(dev);
+}
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index ed3f1ca54660..e5b5c5c2a4b9 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -18,6 +18,7 @@ phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info);
int __ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol);
+int __ethtool_get_link(struct net_device *dev);
bool convert_legacy_settings_to_link_ksettings(
struct ethtool_link_ksettings *link_ksettings,
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 945eaf551a4c..63662a3fa2ae 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -1306,12 +1306,12 @@ static int ethtool_nway_reset(struct net_device *dev)
static int ethtool_get_link(struct net_device *dev, char __user *useraddr)
{
struct ethtool_value edata = { .cmd = ETHTOOL_GLINK };
+ int link = __ethtool_get_link(dev);
- if (!dev->ethtool_ops->get_link)
- return -EOPNOTSUPP;
-
- edata.data = netif_running(dev) && dev->ethtool_ops->get_link(dev);
+ if (link < 0)
+ return link;
+ edata.data = link;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
return 0;
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
index 58cd2d19a75d..099300901c12 100644
--- a/net/ethtool/settings.c
+++ b/net/ethtool/settings.c
@@ -14,6 +14,7 @@ struct settings_data {
struct ethtool_link_settings *lsettings;
struct ethtool_wolinfo wolinfo;
u32 msglevel;
+ int link;
bool lpm_empty;
};
@@ -27,6 +28,7 @@ static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = {
[ETHA_SETTINGS_PEER_MODES] = { .type = NLA_REJECT },
[ETHA_SETTINGS_WOL] = { .type = NLA_REJECT },
[ETHA_SETTINGS_MSGLEVEL] = { .type = NLA_REJECT },
+ [ETHA_SETTINGS_LINK] = { .type = NLA_REJECT },
};
static int parse_settings(struct common_req_info *req_info,
@@ -99,6 +101,7 @@ static int prepare_settings(struct common_req_info *req_info,
data->lsettings = &data->ksettings.base;
data->lpm_empty = true;
+ data->link = -EOPNOTSUPP;
ret = ethnl_before_ops(dev);
if (ret < 0)
@@ -131,6 +134,8 @@ static int prepare_settings(struct common_req_info *req_info,
else
req_mask &= ~ETH_SETTINGS_IM_MSGLEVEL;
}
+ if (req_mask & ETH_SETTINGS_IM_LINK)
+ data->link = __ethtool_get_link(dev);
ethnl_after_ops(dev);
data->repdata_base.info_mask = req_mask;
@@ -209,6 +214,8 @@ static int settings_size(const struct common_req_info *req_info)
len += wol_size();
if (info_mask & ETH_SETTINGS_IM_MSGLEVEL)
len += nla_total_size(sizeof(struct nla_bitfield32));
+ if (info_mask & ETH_SETTINGS_IM_LINK)
+ len += nla_total_size(sizeof(u32));
return len;
}
@@ -324,6 +331,10 @@ static int fill_settings(struct sk_buff *skb,
data->msglevel, NETIF_MSG_ALL))
return -EMSGSIZE;
}
+ if (info_mask & ETH_SETTINGS_IM_LINK && data->link >= 0) {
+ if (nla_put_u8(skb, ETHA_SETTINGS_LINK, data->link))
+ return -EMSGSIZE;
+ }
return 0;
}
--
2.20.1
^ permalink raw reply related
* [RFC PATCH net-next v3 15/21] ethtool: provide link settings and link modes in GET_SETTINGS request
From: Michal Kubecek @ 2019-02-18 18:22 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
Implement GET_SETTINGS netlink request to get link settings and link mode
information provided by ETHTOOL_GLINKSETTINGS ioctl command.
The information is divided into two parts: supported, advertised and peer
advertised link modes when ETH_SETTINGS_IM_LINKMODES flag is set in the
request and other settings when ETH_SETTINGS_IM_LINKINFO is set.
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
Documentation/networking/ethtool-netlink.txt | 49 +++-
include/linux/ethtool_netlink.h | 3 +
include/uapi/linux/ethtool_netlink.h | 37 +++
net/ethtool/Makefile | 2 +-
net/ethtool/common.c | 48 ++++
net/ethtool/common.h | 4 +
net/ethtool/ioctl.c | 48 ----
net/ethtool/netlink.c | 9 +
net/ethtool/settings.c | 265 +++++++++++++++++++
9 files changed, 414 insertions(+), 51 deletions(-)
create mode 100644 net/ethtool/settings.c
diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index c6c7475340e2..0ea7d89c6052 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -130,6 +130,8 @@ List of message types
ETHNL_CMD_SET_STRSET response only
ETHNL_CMD_GET_INFO
ETHNL_CMD_SET_INFO response only
+ ETHNL_CMD_GET_SETTINGS
+ ETHNL_CMD_SET_SETTINGS response only (for now)
All constants use ETHNL_CMD_ prefix, usually followed by "GET", "SET" or "ACT"
to indicate the type.
@@ -264,6 +266,49 @@ if no PHC is associated, the attribute is not present.
GET_INFO requests allow dumps.
+GET_SETTINGS
+------------
+
+GET_SETTINGS request retrieves information provided by ETHTOOL_GLINKSETTINGS,
+ETHTOOL_GWOL, ETHTOOL_GMSGLVL and ETHTOOL_GLINK ioctl requests. The request
+doesn't use any attributes.
+
+Request attributes:
+
+ ETHA_SETTINGS_DEV (nested) device identification
+ ETHA_SETTINGS_INFOMASK (u32) info mask
+ ETHA_SETTINGS_COMPACT (flag) request compact bitsets
+
+Info mask bits meaning:
+
+ ETH_SETTINGS_IM_LINKINFO link_ksettings except link modes
+ ETH_SETTINGS_IM_LINKMODES link modes from link_ksettings
+
+Response contents:
+
+ ETHA_SETTINGS_DEV (nested) device identification
+ ETHA_SETTINGS_LINK_INFO (nested) link settings
+ ETHA_LINKINFO_SPEED (u32) link speed (Mb/s)
+ ETHA_LINKINFO_DUPLEX (u8) duplex mode
+ ETHA_LINKINFO_PORT (u8) physical port
+ ETHA_LINKINFO_PHYADDR (u8) MDIO address of phy
+ ETHA_LINKINFO_AUTONEG (u8) autoneotiation status
+ ETHA_LINKINFO_TP_MDIX (u8) MDI(-X) status
+ ETHA_LINKINFO_TP_MDIX_CTRL (u8) MDI(-X) control
+ ETHA_LINKINFO_TRANSCEIVER (u8) transceiver
+ ETHA_SETTINGS_LINK_MODES (bitset) device link modes
+ ETHA_SETTINGS_PEER_MODES (bitset) link partner link modes
+
+Most of the attributes and their values have the same meaning as matching
+members of the corresponding ioctl structures. For ETHA_SETTINGS_LINK_MODES,
+value represents advertised modes and mask represents supported modes.
+ETHA_SETTINGS_PEER_MODES in the reply is a bit list.
+
+GET_SETTINGS requests allow dumps and messages in the same format as response
+to them are broadcasted as notifications on change of these settings using
+netlink or ioctl ethtool interface.
+
+
Request translation
-------------------
@@ -273,7 +318,7 @@ have their netlink replacement yet.
ioctl command netlink command
---------------------------------------------------------------------
-ETHTOOL_GSET n/a
+ETHTOOL_GSET ETHNL_CMD_GET_SETTINGS
ETHTOOL_SSET n/a
ETHTOOL_GDRVINFO ETHNL_CMD_GET_INFO
ETHTOOL_GREGS n/a
@@ -347,7 +392,7 @@ ETHTOOL_GTUNABLE n/a
ETHTOOL_STUNABLE n/a
ETHTOOL_GPHYSTATS n/a
ETHTOOL_PERQUEUE n/a
-ETHTOOL_GLINKSETTINGS n/a
+ETHTOOL_GLINKSETTINGS ETHNL_CMD_GET_SETTINGS
ETHTOOL_SLINKSETTINGS n/a
ETHTOOL_PHY_GTUNABLE n/a
ETHTOOL_PHY_STUNABLE n/a
diff --git a/include/linux/ethtool_netlink.h b/include/linux/ethtool_netlink.h
index 2a15e64a16f3..e770e6e9acca 100644
--- a/include/linux/ethtool_netlink.h
+++ b/include/linux/ethtool_netlink.h
@@ -7,6 +7,9 @@
#include <linux/ethtool.h>
#include <linux/netdevice.h>
+#define __ETHTOOL_LINK_MODE_MASK_NWORDS \
+ DIV_ROUND_UP(__ETHTOOL_LINK_MODE_MASK_NBITS, 32)
+
enum ethtool_multicast_groups {
ETHNL_MCGRP_MONITOR,
};
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 8ab2b7454e81..4e1fa4a06aac 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -12,6 +12,8 @@ enum {
ETHNL_CMD_SET_STRSET, /* only for reply */
ETHNL_CMD_GET_INFO,
ETHNL_CMD_SET_INFO, /* only for reply */
+ ETHNL_CMD_GET_SETTINGS,
+ ETHNL_CMD_SET_SETTINGS,
__ETHNL_CMD_CNT,
ETHNL_CMD_MAX = (__ETHNL_CMD_CNT - 1)
@@ -189,6 +191,41 @@ enum {
ETHA_TSINFO_MAX = (__ETHA_TSINFO_CNT - 1)
};
+/* GET_SETTINGS / SET_SETTINGS */
+
+enum {
+ ETHA_SETTINGS_UNSPEC,
+ ETHA_SETTINGS_DEV, /* nest - ETHA_DEV_* */
+ ETHA_SETTINGS_INFOMASK, /* u32 */
+ ETHA_SETTINGS_COMPACT, /* flag */
+ ETHA_SETTINGS_LINK_INFO, /* nested */
+ ETHA_SETTINGS_LINK_MODES, /* bitset */
+ ETHA_SETTINGS_PEER_MODES, /* bitset */
+
+ __ETHA_SETTINGS_CNT,
+ ETHA_SETTINGS_MAX = (__ETHA_SETTINGS_CNT - 1)
+};
+
+#define ETH_SETTINGS_IM_LINKINFO 0x01
+#define ETH_SETTINGS_IM_LINKMODES 0x02
+
+#define ETH_SETTINGS_IM_ALL 0x03
+
+enum {
+ ETHA_LINKINFO_UNSPEC,
+ ETHA_LINKINFO_SPEED, /* u32 */
+ ETHA_LINKINFO_DUPLEX, /* u8 */
+ ETHA_LINKINFO_PORT, /* u8 */
+ ETHA_LINKINFO_PHYADDR, /* u8 */
+ ETHA_LINKINFO_AUTONEG, /* u8 */
+ ETHA_LINKINFO_TP_MDIX, /* u8 */
+ ETHA_LINKINFO_TP_MDIX_CTRL, /* u8 */
+ ETHA_LINKINFO_TRANSCEIVER, /* u8 */
+
+ __ETHA_LINKINFO_CNT,
+ ETHA_LINKINFO_MAX = (__ETHA_LINKINFO_CNT - 1)
+};
+
/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
index 96d41dc45d4f..6a7a182e1568 100644
--- a/net/ethtool/Makefile
+++ b/net/ethtool/Makefile
@@ -4,4 +4,4 @@ obj-y += ioctl.o common.o
obj-$(CONFIG_ETHTOOL_NETLINK) += ethtool_nl.o
-ethtool_nl-y := netlink.o bitset.o strset.o info.o
+ethtool_nl-y := netlink.o bitset.o strset.o info.o settings.o
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 4616816861cc..3316e9e403c9 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -159,3 +159,51 @@ int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
return err;
}
+
+/* return false if legacy contained non-0 deprecated fields
+ * maxtxpkt/maxrxpkt. rest of ksettings always updated
+ */
+bool
+convert_legacy_settings_to_link_ksettings(
+ struct ethtool_link_ksettings *link_ksettings,
+ const struct ethtool_cmd *legacy_settings)
+{
+ bool retval = true;
+
+ memset(link_ksettings, 0, sizeof(*link_ksettings));
+
+ /* This is used to tell users that driver is still using these
+ * deprecated legacy fields, and they should not use
+ * %ETHTOOL_GLINKSETTINGS/%ETHTOOL_SLINKSETTINGS
+ */
+ if (legacy_settings->maxtxpkt ||
+ legacy_settings->maxrxpkt)
+ retval = false;
+
+ ethtool_convert_legacy_u32_to_link_mode(
+ link_ksettings->link_modes.supported,
+ legacy_settings->supported);
+ ethtool_convert_legacy_u32_to_link_mode(
+ link_ksettings->link_modes.advertising,
+ legacy_settings->advertising);
+ ethtool_convert_legacy_u32_to_link_mode(
+ link_ksettings->link_modes.lp_advertising,
+ legacy_settings->lp_advertising);
+ link_ksettings->base.speed
+ = ethtool_cmd_speed(legacy_settings);
+ link_ksettings->base.duplex
+ = legacy_settings->duplex;
+ link_ksettings->base.port
+ = legacy_settings->port;
+ link_ksettings->base.phy_address
+ = legacy_settings->phy_address;
+ link_ksettings->base.autoneg
+ = legacy_settings->autoneg;
+ link_ksettings->base.mdio_support
+ = legacy_settings->mdio_support;
+ link_ksettings->base.eth_tp_mdix
+ = legacy_settings->eth_tp_mdix;
+ link_ksettings->base.eth_tp_mdix_ctrl
+ = legacy_settings->eth_tp_mdix_ctrl;
+ return retval;
+}
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index 02cbee79da35..7a3e0b10e69a 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -18,4 +18,8 @@ phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info);
+bool convert_legacy_settings_to_link_ksettings(
+ struct ethtool_link_ksettings *link_ksettings,
+ const struct ethtool_cmd *legacy_settings);
+
#endif /* _ETHTOOL_COMMON_H */
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 0837849156d3..5e878cf6f418 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -356,54 +356,6 @@ bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32,
}
EXPORT_SYMBOL(ethtool_convert_link_mode_to_legacy_u32);
-/* return false if legacy contained non-0 deprecated fields
- * maxtxpkt/maxrxpkt. rest of ksettings always updated
- */
-static bool
-convert_legacy_settings_to_link_ksettings(
- struct ethtool_link_ksettings *link_ksettings,
- const struct ethtool_cmd *legacy_settings)
-{
- bool retval = true;
-
- memset(link_ksettings, 0, sizeof(*link_ksettings));
-
- /* This is used to tell users that driver is still using these
- * deprecated legacy fields, and they should not use
- * %ETHTOOL_GLINKSETTINGS/%ETHTOOL_SLINKSETTINGS
- */
- if (legacy_settings->maxtxpkt ||
- legacy_settings->maxrxpkt)
- retval = false;
-
- ethtool_convert_legacy_u32_to_link_mode(
- link_ksettings->link_modes.supported,
- legacy_settings->supported);
- ethtool_convert_legacy_u32_to_link_mode(
- link_ksettings->link_modes.advertising,
- legacy_settings->advertising);
- ethtool_convert_legacy_u32_to_link_mode(
- link_ksettings->link_modes.lp_advertising,
- legacy_settings->lp_advertising);
- link_ksettings->base.speed
- = ethtool_cmd_speed(legacy_settings);
- link_ksettings->base.duplex
- = legacy_settings->duplex;
- link_ksettings->base.port
- = legacy_settings->port;
- link_ksettings->base.phy_address
- = legacy_settings->phy_address;
- link_ksettings->base.autoneg
- = legacy_settings->autoneg;
- link_ksettings->base.mdio_support
- = legacy_settings->mdio_support;
- link_ksettings->base.eth_tp_mdix
- = legacy_settings->eth_tp_mdix;
- link_ksettings->base.eth_tp_mdix_ctrl
- = legacy_settings->eth_tp_mdix_ctrl;
- return retval;
-}
-
/* return false if ksettings link modes had higher bits
* set. legacy_settings always updated (best effort)
*/
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 1ff6696ad716..5166b0c28288 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -143,10 +143,12 @@ int ethnl_fill_dev(struct sk_buff *msg, struct net_device *dev, u16 attrtype)
extern const struct get_request_ops strset_request_ops;
extern const struct get_request_ops info_request_ops;
+extern const struct get_request_ops settings_request_ops;
const struct get_request_ops *get_requests[__ETHNL_CMD_CNT] = {
[ETHNL_CMD_GET_STRSET] = &strset_request_ops,
[ETHNL_CMD_GET_INFO] = &info_request_ops,
+ [ETHNL_CMD_GET_SETTINGS] = &settings_request_ops,
};
static struct common_req_info *alloc_get_data(const struct get_request_ops *ops)
@@ -572,6 +574,13 @@ static const struct genl_ops ethtool_genl_ops[] = {
.dumpit = ethnl_get_dumpit,
.done = ethnl_get_done,
},
+ {
+ .cmd = ETHNL_CMD_GET_SETTINGS,
+ .doit = ethnl_get_doit,
+ .start = ethnl_get_start,
+ .dumpit = ethnl_get_dumpit,
+ .done = ethnl_get_done,
+ },
};
static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
diff --git a/net/ethtool/settings.c b/net/ethtool/settings.c
new file mode 100644
index 000000000000..4f2858fe1a7d
--- /dev/null
+++ b/net/ethtool/settings.c
@@ -0,0 +1,265 @@
+// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+
+#include "netlink.h"
+#include "common.h"
+#include "bitset.h"
+
+struct settings_data {
+ struct common_req_info reqinfo_base;
+
+ /* everything below here will be reset for each device in dumps */
+ struct common_reply_data repdata_base;
+ struct ethtool_link_ksettings ksettings;
+ struct ethtool_link_settings *lsettings;
+ bool lpm_empty;
+};
+
+static const struct nla_policy get_settings_policy[ETHA_SETTINGS_MAX + 1] = {
+ [ETHA_SETTINGS_UNSPEC] = { .type = NLA_REJECT },
+ [ETHA_SETTINGS_DEV] = { .type = NLA_NESTED },
+ [ETHA_SETTINGS_INFOMASK] = { .type = NLA_U32 },
+ [ETHA_SETTINGS_COMPACT] = { .type = NLA_FLAG },
+ [ETHA_SETTINGS_LINK_INFO] = { .type = NLA_REJECT },
+ [ETHA_SETTINGS_LINK_MODES] = { .type = NLA_REJECT },
+ [ETHA_SETTINGS_PEER_MODES] = { .type = NLA_REJECT },
+};
+
+static int parse_settings(struct common_req_info *req_info,
+ struct sk_buff *skb, struct genl_info *info,
+ const struct nlmsghdr *nlhdr)
+{
+ struct nlattr *tb[ETHA_SETTINGS_MAX + 1];
+ int ret;
+
+ ret = genlmsg_parse(nlhdr, ðtool_genl_family, tb,
+ ETHA_SETTINGS_MAX, get_settings_policy,
+ info ? info->extack : NULL);
+ if (ret < 0)
+ return ret;
+
+ if (tb[ETHA_SETTINGS_DEV]) {
+ req_info->dev = ethnl_dev_get(info, tb[ETHA_SETTINGS_DEV]);
+ if (IS_ERR(req_info->dev)) {
+ ret = PTR_ERR(req_info->dev);
+ req_info->dev = NULL;
+ return ret;
+ }
+ }
+ if (tb[ETHA_SETTINGS_INFOMASK])
+ req_info->req_mask = nla_get_u32(tb[ETHA_SETTINGS_INFOMASK]);
+ if (tb[ETHA_SETTINGS_COMPACT])
+ req_info->compact = true;
+ if (req_info->req_mask == 0)
+ req_info->req_mask = ETH_SETTINGS_IM_ALL;
+
+ return 0;
+}
+
+static int ethnl_get_link_ksettings(struct genl_info *info,
+ struct net_device *dev,
+ struct ethtool_link_ksettings *ksettings)
+{
+ int ret;
+
+ ret = __ethtool_get_link_ksettings(dev, ksettings);
+
+ if (ret < 0)
+ ETHNL_SET_ERRMSG(info, "failed to retrieve link settings");
+ return ret;
+}
+
+static int prepare_settings(struct common_req_info *req_info,
+ struct genl_info *info)
+{
+ struct settings_data *data =
+ container_of(req_info, struct settings_data, reqinfo_base);
+ struct net_device *dev = data->repdata_base.dev;
+ u32 req_mask = req_info->req_mask;
+ int ret;
+
+ data->lsettings = &data->ksettings.base;
+ data->lpm_empty = true;
+
+ ret = ethnl_before_ops(dev);
+ if (ret < 0)
+ return ret;
+ if (req_mask & (ETH_SETTINGS_IM_LINKINFO | ETH_SETTINGS_IM_LINKMODES)) {
+ ret = ethnl_get_link_ksettings(info, dev, &data->ksettings);
+ if (ret < 0)
+ req_mask &= ~(ETH_SETTINGS_IM_LINKINFO |
+ ETH_SETTINGS_IM_LINKMODES);
+ }
+ if (req_mask & ETH_SETTINGS_IM_LINKMODES) {
+ data->lpm_empty =
+ bitmap_empty(data->ksettings.link_modes.lp_advertising,
+ __ETHTOOL_LINK_MODE_MASK_NBITS);
+ ethnl_bitmap_to_u32(data->ksettings.link_modes.supported,
+ __ETHTOOL_LINK_MODE_MASK_NWORDS);
+ ethnl_bitmap_to_u32(data->ksettings.link_modes.advertising,
+ __ETHTOOL_LINK_MODE_MASK_NWORDS);
+ ethnl_bitmap_to_u32(data->ksettings.link_modes.lp_advertising,
+ __ETHTOOL_LINK_MODE_MASK_NWORDS);
+ }
+ ethnl_after_ops(dev);
+
+ data->repdata_base.info_mask = req_mask;
+ if (req_info->req_mask & ~req_mask)
+ warn_partial_info(info);
+ return 0;
+}
+
+static int link_info_size(void)
+{
+ int len = 0;
+
+ /* speed */
+ len += nla_total_size(sizeof(u32));
+ /* duplex, autoneg, port, phyaddr, mdix, mdixctrl, transcvr */
+ len += 7 * nla_total_size(sizeof(u8));
+ /* mdio_support */
+ len += nla_total_size(sizeof(struct nla_bitfield32));
+
+ /* nest */
+ return nla_total_size(len);
+}
+
+static int link_modes_size(const struct ethtool_link_ksettings *ksettings,
+ bool compact)
+{
+ unsigned int flags = compact ? ETHNL_BITSET_COMPACT : 0;
+ u32 *supported = (u32 *)ksettings->link_modes.supported;
+ u32 *advertising = (u32 *)ksettings->link_modes.advertising;
+ u32 *lp_advertising = (u32 *)ksettings->link_modes.lp_advertising;
+ int len = 0, ret;
+
+ ret = ethnl_bitset32_size(__ETHTOOL_LINK_MODE_MASK_NBITS, advertising,
+ supported, link_mode_names, flags);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ ret = ethnl_bitset32_size(__ETHTOOL_LINK_MODE_MASK_NBITS,
+ lp_advertising, NULL, link_mode_names,
+ flags & ETHNL_BITSET_LIST);
+ if (ret < 0)
+ return ret;
+ len += ret;
+
+ return len;
+}
+
+/* To keep things simple, reserve space for some attributes which may not
+ * be added to the message (e.g. ETHA_SETTINGS_SOPASS); therefore the length
+ * returned may be bigger than the actual length of the message sent
+ */
+static int settings_size(const struct common_req_info *req_info)
+{
+ struct settings_data *data =
+ container_of(req_info, struct settings_data, reqinfo_base);
+ u32 info_mask = data->repdata_base.info_mask;
+ bool compact = req_info->compact;
+ int len = 0, ret;
+
+ len += dev_ident_size();
+ if (info_mask & ETH_SETTINGS_IM_LINKINFO)
+ len += link_info_size();
+ if (info_mask & ETH_SETTINGS_IM_LINKMODES) {
+ ret = link_modes_size(&data->ksettings, compact);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ }
+
+ return len;
+}
+
+static int fill_link_info(struct sk_buff *skb,
+ const struct ethtool_link_settings *lsettings)
+{
+ struct nlattr *nest = ethnl_nest_start(skb, ETHA_SETTINGS_LINK_INFO);
+
+ if (!nest)
+ return -EMSGSIZE;
+ if (nla_put_u32(skb, ETHA_LINKINFO_SPEED, lsettings->speed) ||
+ nla_put_u8(skb, ETHA_LINKINFO_DUPLEX, lsettings->duplex) ||
+ nla_put_u8(skb, ETHA_LINKINFO_PORT, lsettings->port) ||
+ nla_put_u8(skb, ETHA_LINKINFO_PHYADDR,
+ lsettings->phy_address) ||
+ nla_put_u8(skb, ETHA_LINKINFO_AUTONEG,
+ lsettings->autoneg) ||
+ nla_put_u8(skb, ETHA_LINKINFO_TP_MDIX,
+ lsettings->eth_tp_mdix) ||
+ nla_put_u8(skb, ETHA_LINKINFO_TP_MDIX_CTRL,
+ lsettings->eth_tp_mdix_ctrl) ||
+ nla_put_u8(skb, ETHA_LINKINFO_TRANSCEIVER,
+ lsettings->transceiver)) {
+ nla_nest_cancel(skb, nest);
+ return -EMSGSIZE;
+ }
+
+ nla_nest_end(skb, nest);
+ return 0;
+}
+
+static int fill_link_modes(struct sk_buff *skb,
+ const struct ethtool_link_ksettings *ksettings,
+ bool lpm_empty, bool compact)
+{
+ const u32 *supported = (const u32 *)ksettings->link_modes.supported;
+ const u32 *advertising = (const u32 *)ksettings->link_modes.advertising;
+ const u32 *lp_adv = (const u32 *)ksettings->link_modes.lp_advertising;
+ const unsigned int flags = compact ? ETHNL_BITSET_COMPACT : 0;
+ int ret;
+
+ ret = ethnl_put_bitset32(skb, ETHA_SETTINGS_LINK_MODES,
+ __ETHTOOL_LINK_MODE_MASK_NBITS, advertising,
+ supported, link_mode_names, flags);
+ if (ret < 0)
+ return ret;
+ if (!lpm_empty) {
+ ret = ethnl_put_bitset32(skb, ETHA_SETTINGS_PEER_MODES,
+ __ETHTOOL_LINK_MODE_MASK_NBITS,
+ lp_adv, NULL, link_mode_names,
+ flags | ETHNL_BITSET_LIST);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int fill_settings(struct sk_buff *skb,
+ const struct common_req_info *req_info)
+{
+ const struct settings_data *data =
+ container_of(req_info, struct settings_data, reqinfo_base);
+ u32 info_mask = data->repdata_base.info_mask;
+ bool compact = req_info->compact;
+ int ret;
+
+ if (info_mask & ETH_SETTINGS_IM_LINKINFO) {
+ ret = fill_link_info(skb, data->lsettings);
+ if (ret < 0)
+ return ret;
+ }
+ if (info_mask & ETH_SETTINGS_IM_LINKMODES) {
+ ret = fill_link_modes(skb, &data->ksettings, data->lpm_empty,
+ compact);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+const struct get_request_ops settings_request_ops = {
+ .request_cmd = ETHNL_CMD_GET_SETTINGS,
+ .reply_cmd = ETHNL_CMD_SET_SETTINGS,
+ .dev_attrtype = ETHA_SETTINGS_DEV,
+ .data_size = sizeof(struct settings_data),
+ .repdata_offset = offsetof(struct settings_data, repdata_base),
+
+ .parse_request = parse_settings,
+ .prepare_data = prepare_settings,
+ .reply_size = settings_size,
+ .fill_reply = fill_settings,
+};
--
2.20.1
^ permalink raw reply related
* [RFC PATCH net-next v3 13/21] ethtool: provide timestamping information in GET_INFO request
From: Michal Kubecek @ 2019-02-18 18:22 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
Add timestamping information as provided by ETHTOOL_GET_TS_INFO ioctl
command in GET_INFO reply if ETH_INFO_IM_TSINFO flag is set in the request.
Add constants for counts of HWTSTAMP_TX_* and HWTSTAM_FILTER_* constants
and provide symbolic names for timestamping related values so that they can
be retrieved in GET_STRSET and GET_INFO requests.
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
Documentation/networking/ethtool-netlink.txt | 10 +-
include/uapi/linux/ethtool.h | 6 +
include/uapi/linux/ethtool_netlink.h | 14 +-
include/uapi/linux/net_tstamp.h | 13 ++
net/ethtool/common.c | 24 ++++
net/ethtool/common.h | 2 +
net/ethtool/info.c | 138 +++++++++++++++++++
net/ethtool/ioctl.c | 20 +--
net/ethtool/netlink.h | 9 ++
net/ethtool/strset.c | 18 +++
10 files changed, 234 insertions(+), 20 deletions(-)
diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index 1e615e111262..c6c7475340e2 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -242,6 +242,11 @@ Kernel response contents:
ETHA_INFO_PERMADDR (nested)
ETHA_PERMADDR_ADDRESS (binary) permanent HW address
ETHA_PERMADDR_TYPE (u16) dev->type
+ ETHA_INFO_TSINFO (nested) timestamping information
+ ETHA_TSINFO_TIMESTAMPING (bitset) supported flags
+ ETHA_TSINFO_PHC_INDEX (u32) associated PHC
+ ETHA_TSINFO_TX_TYPES (bitset) Tx types
+ ETHA_TSINFO_RX_FILTERS (bitset) Rx filters
The meaning of DRVINFO attributes follows the corresponding fields of
ETHTOOL_GDRVINFO response. Second part with various counts and sizes is
@@ -253,6 +258,9 @@ There is no separate attribute for permanent address length as the length can
be determined from attribute length (nla_len()). ETHA_PERMADDR_TYPE provides
net_device::type value to give a hint about what kind of address device has.
+ETHA_TSINFO_PHC_INDEX can be unsigned as there is no need for special value;
+if no PHC is associated, the attribute is not present.
+
GET_INFO requests allow dumps.
@@ -328,7 +336,7 @@ ETHTOOL_SCHANNELS n/a
ETHTOOL_SET_DUMP n/a
ETHTOOL_GET_DUMP_FLAG n/a
ETHTOOL_GET_DUMP_DATA n/a
-ETHTOOL_GET_TS_INFO n/a
+ETHTOOL_GET_TS_INFO ETHNL_CMD_GET_INFO
ETHTOOL_GMODULEINFO n/a
ETHTOOL_GMODULEEEPROM n/a
ETHTOOL_GEEE n/a
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index 9ea278961d80..1b58637d3a4d 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -563,6 +563,9 @@ struct ethtool_pauseparam {
* @ETH_SS_RSS_HASH_FUNCS: RSS hush function names
* @ETH_SS_PHY_STATS: Statistic names, for use with %ETHTOOL_GPHYSTATS
* @ETH_SS_PHY_TUNABLES: PHY tunable names
+ * @ETH_SS_TSTAMP_SOF: timestamping flag names
+ * @ETH_SS_TSTAMP_TX_TYPE: timestamping Tx type names
+ * @ETH_SS_TSTAMP_RX_FILTER: timestamping Rx filter names
*/
enum ethtool_stringset {
ETH_SS_TEST = 0,
@@ -574,6 +577,9 @@ enum ethtool_stringset {
ETH_SS_TUNABLES,
ETH_SS_PHY_STATS,
ETH_SS_PHY_TUNABLES,
+ ETH_SS_TSTAMP_SOF,
+ ETH_SS_TSTAMP_TX_TYPE,
+ ETH_SS_TSTAMP_RX_FILTER,
ETH_SS_COUNT
};
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index fb756b6a8592..8ab2b7454e81 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -154,8 +154,9 @@ enum {
#define ETH_INFO_IM_DRVINFO 0x01
#define ETH_INFO_IM_PERMADDR 0x02
+#define ETH_INFO_IM_TSINFO 0x04
-#define ETH_INFO_IM_ALL 0x03
+#define ETH_INFO_IM_ALL 0x07
enum {
ETHA_DRVINFO_UNSPEC,
@@ -177,6 +178,17 @@ enum {
ETHA_PERMADDR_MAX = (__ETHA_PERMADDR_CNT - 1)
};
+enum {
+ ETHA_TSINFO_UNSPEC,
+ ETHA_TSINFO_TIMESTAMPING, /* bitset */
+ ETHA_TSINFO_PHC_INDEX, /* u32 */
+ ETHA_TSINFO_TX_TYPES, /* bitset */
+ ETHA_TSINFO_RX_FILTERS, /* bitset */
+
+ __ETHA_TSINFO_CNT,
+ ETHA_TSINFO_MAX = (__ETHA_TSINFO_CNT - 1)
+};
+
/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
diff --git a/include/uapi/linux/net_tstamp.h b/include/uapi/linux/net_tstamp.h
index e5b39721c6e4..e5b0472c4416 100644
--- a/include/uapi/linux/net_tstamp.h
+++ b/include/uapi/linux/net_tstamp.h
@@ -30,6 +30,9 @@ enum {
SOF_TIMESTAMPING_OPT_STATS = (1<<12),
SOF_TIMESTAMPING_OPT_PKTINFO = (1<<13),
SOF_TIMESTAMPING_OPT_TX_SWHW = (1<<14),
+ /* when adding a flag, please update so_timestamping_labels array
+ * in net/ethtool/info.c
+ */
SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_TX_SWHW,
SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) |
@@ -90,6 +93,11 @@ enum hwtstamp_tx_types {
* queue.
*/
HWTSTAMP_TX_ONESTEP_SYNC,
+ /* when adding a value, please update tstamp_tx_type_labels array
+ * in net/ethtool/info.c
+ */
+
+ HWTSTAMP_TX_LAST = HWTSTAMP_TX_ONESTEP_SYNC
};
/* possible values for hwtstamp_config->rx_filter */
@@ -132,6 +140,11 @@ enum hwtstamp_rx_filters {
/* NTP, UDP, all versions and packet modes */
HWTSTAMP_FILTER_NTP_ALL,
+ /* when adding a value, please update tstamp_rx_filter_labels array
+ * in net/ethtool/info.c
+ */
+
+ HWTSTAMP_FILTER_LAST = HWTSTAMP_FILTER_NTP_ALL
};
/* SCM_TIMESTAMPING_PKTINFO control message */
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index e0bd7c6c5874..4616816861cc 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
#include <linux/rtnetlink.h>
+#include <linux/phy.h>
+#include <linux/net_tstamp.h>
#include <net/devlink.h>
#include "common.h"
@@ -135,3 +137,25 @@ int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
return 0;
}
+
+int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
+{
+ const struct ethtool_ops *ops = dev->ethtool_ops;
+ struct phy_device *phydev = dev->phydev;
+ int err = 0;
+
+ memset(info, 0, sizeof(*info));
+ info->cmd = ETHTOOL_GET_TS_INFO;
+
+ if (phydev && phydev->drv && phydev->drv->ts_info) {
+ err = phydev->drv->ts_info(phydev, info);
+ } else if (ops->get_ts_info) {
+ err = ops->get_ts_info(dev, info);
+ } else {
+ info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
+ SOF_TIMESTAMPING_SOFTWARE;
+ info->phc_index = -1;
+ }
+
+ return err;
+}
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index e87e58b3a274..02cbee79da35 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -16,4 +16,6 @@ extern const char
phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
+int __ethtool_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info);
+
#endif /* _ETHTOOL_COMMON_H */
diff --git a/net/ethtool/info.c b/net/ethtool/info.c
index 05dbd87ebc41..838257db1d31 100644
--- a/net/ethtool/info.c
+++ b/net/ethtool/info.c
@@ -1,15 +1,61 @@
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+#include <linux/net_tstamp.h>
+
#include "netlink.h"
#include "common.h"
#include "bitset.h"
+const char *const so_timestamping_labels[] = {
+ "hardware-transmit", /* SOF_TIMESTAMPING_TX_HARDWARE */
+ "software-transmit", /* SOF_TIMESTAMPING_TX_SOFTWARE */
+ "hardware-receive", /* SOF_TIMESTAMPING_RX_HARDWARE */
+ "software-receive", /* SOF_TIMESTAMPING_RX_SOFTWARE */
+ "software-system-clock", /* SOF_TIMESTAMPING_SOFTWARE */
+ "hardware-legacy-clock", /* SOF_TIMESTAMPING_SYS_HARDWARE */
+ "hardware-raw-clock", /* SOF_TIMESTAMPING_RAW_HARDWARE */
+ "option-id", /* SOF_TIMESTAMPING_OPT_ID */
+ "sched-transmit", /* SOF_TIMESTAMPING_TX_SCHED */
+ "ack-transmit", /* SOF_TIMESTAMPING_TX_ACK */
+ "option-cmsg", /* SOF_TIMESTAMPING_OPT_CMSG */
+ "option-tsonly", /* SOF_TIMESTAMPING_OPT_TSONLY */
+ "option-stats", /* SOF_TIMESTAMPING_OPT_STATS */
+ "option-pktinfo", /* SOF_TIMESTAMPING_OPT_PKTINFO */
+ "option-tx-swhw", /* SOF_TIMESTAMPING_OPT_TX_SWHW */
+};
+
+const char *const tstamp_tx_type_labels[] = {
+ [HWTSTAMP_TX_OFF] = "off",
+ [HWTSTAMP_TX_ON] = "on",
+ [HWTSTAMP_TX_ONESTEP_SYNC] = "one-step-sync",
+};
+
+const char *const tstamp_rx_filter_labels[] = {
+ [HWTSTAMP_FILTER_NONE] = "none",
+ [HWTSTAMP_FILTER_ALL] = "all",
+ [HWTSTAMP_FILTER_SOME] = "some",
+ [HWTSTAMP_FILTER_PTP_V1_L4_EVENT] = "ptpv1-l4-event",
+ [HWTSTAMP_FILTER_PTP_V1_L4_SYNC] = "ptpv1-l4-sync",
+ [HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ] = "ptpv1-l4-delay-req",
+ [HWTSTAMP_FILTER_PTP_V2_L4_EVENT] = "ptpv2-l4-event",
+ [HWTSTAMP_FILTER_PTP_V2_L4_SYNC] = "ptpv2-l4-sync",
+ [HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ] = "ptpv2-l4-delay-req",
+ [HWTSTAMP_FILTER_PTP_V2_L2_EVENT] = "ptpv2-l2-event",
+ [HWTSTAMP_FILTER_PTP_V2_L2_SYNC] = "ptpv2-l2-sync",
+ [HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ] = "ptpv2-l2-delay-req",
+ [HWTSTAMP_FILTER_PTP_V2_EVENT] = "ptpv2-event",
+ [HWTSTAMP_FILTER_PTP_V2_SYNC] = "ptpv2-sync",
+ [HWTSTAMP_FILTER_PTP_V2_DELAY_REQ] = "ptpv2-delay-req",
+ [HWTSTAMP_FILTER_NTP_ALL] = "ntp-all",
+};
+
struct info_data {
struct common_req_info reqinfo_base;
/* everything below here will be reset for each device in dumps */
struct common_reply_data repdata_base;
struct ethtool_drvinfo drvinfo;
+ struct ethtool_ts_info tsinfo;
};
static const struct nla_policy get_info_policy[ETHA_INFO_MAX + 1] = {
@@ -19,6 +65,7 @@ static const struct nla_policy get_info_policy[ETHA_INFO_MAX + 1] = {
[ETHA_INFO_COMPACT] = { .type = NLA_FLAG },
[ETHA_INFO_DRVINFO] = { .type = NLA_REJECT },
[ETHA_INFO_PERMADDR] = { .type = NLA_REJECT },
+ [ETHA_INFO_TSINFO] = { .type = NLA_REJECT },
};
static int parse_info(struct common_req_info *req_info, struct sk_buff *skb,
@@ -67,6 +114,11 @@ static int prepare_info(struct common_req_info *req_info,
if (ret < 0)
req_mask &= ~ETH_INFO_IM_DRVINFO;
}
+ if (req_mask & ETH_INFO_IM_TSINFO) {
+ ret = __ethtool_get_ts_info(dev, &data->tsinfo);
+ if (ret < 0)
+ req_mask &= ~ETH_INFO_IM_TSINFO;
+ }
ethnl_after_ops(dev);
data->repdata_base.info_mask = req_mask;
@@ -97,6 +149,42 @@ static int permaddr_size(const struct net_device *dev)
return nla_total_size(len);
}
+static int tsinfo_size(const struct ethtool_ts_info *tsinfo, bool compact)
+{
+ const unsigned int flags = compact ? ETHNL_BITSET_COMPACT : 0;
+ int len = 0;
+ int ret;
+
+ /* if any of these exceeds 32, we need a different interface to talk to
+ * NIC drivers anyway
+ */
+ BUILD_BUG_ON(__SOF_TIMESTAMPING_COUNT > 32);
+ BUILD_BUG_ON(__HWTSTAMP_TX_COUNT > 32);
+ BUILD_BUG_ON(__HWTSTAMP_FILTER_COUNT > 32);
+
+ ret = ethnl_bitset32_size(__SOF_TIMESTAMPING_COUNT,
+ &tsinfo->so_timestamping, NULL,
+ so_timestamping_labels, flags);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ ret = ethnl_bitset32_size(__HWTSTAMP_TX_COUNT,
+ &tsinfo->tx_types, NULL,
+ tstamp_tx_type_labels, flags);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ ret = ethnl_bitset32_size(__HWTSTAMP_FILTER_COUNT,
+ &tsinfo->rx_filters, NULL,
+ tstamp_rx_filter_labels, flags);
+ if (ret < 0)
+ return ret;
+ len += ret;
+ len += nla_total_size(sizeof(u32));
+
+ return nla_total_size(len);
+}
+
static int info_size(const struct common_req_info *req_info)
{
const struct info_data *data =
@@ -110,6 +198,13 @@ static int info_size(const struct common_req_info *req_info)
len += drvinfo_size(&data->drvinfo);
if (info_mask & ETH_INFO_IM_PERMADDR)
len += permaddr_size(dev);
+ if (info_mask & ETH_INFO_IM_TSINFO) {
+ int ret = tsinfo_size(&data->tsinfo, req_info->compact);
+
+ if (ret < 0)
+ return ret;
+ len += ret;
+ }
return len;
}
@@ -158,6 +253,44 @@ static int fill_permaddr(struct sk_buff *skb, const struct net_device *dev)
return ret;
}
+static int fill_tsinfo(struct sk_buff *skb,
+ const struct ethtool_ts_info *tsinfo, bool compact)
+{
+ const unsigned int flags = compact ? ETHNL_BITSET_COMPACT : 0;
+ struct nlattr *nest = ethnl_nest_start(skb, ETHA_INFO_TSINFO);
+ int ret;
+
+ if (!nest)
+ return -EMSGSIZE;
+ ret = ethnl_put_bitset32(skb, ETHA_TSINFO_TIMESTAMPING,
+ __SOF_TIMESTAMPING_COUNT,
+ &tsinfo->so_timestamping, NULL,
+ so_timestamping_labels, flags);
+ if (ret < 0)
+ goto err;
+ ret = -EMSGSIZE;
+ if (tsinfo->phc_index >= 0 &&
+ nla_put_u32(skb, ETHA_TSINFO_PHC_INDEX, tsinfo->phc_index))
+ goto err;
+
+ ret = ethnl_put_bitset32(skb, ETHA_TSINFO_TX_TYPES, __HWTSTAMP_TX_COUNT,
+ &tsinfo->tx_types, NULL, tstamp_tx_type_labels,
+ flags);
+ if (ret < 0)
+ goto err;
+ ret = ethnl_put_bitset32(skb, ETHA_TSINFO_RX_FILTERS,
+ __HWTSTAMP_FILTER_COUNT, &tsinfo->rx_filters,
+ NULL, tstamp_rx_filter_labels, flags);
+ if (ret < 0)
+ goto err;
+
+ nla_nest_end(skb, nest);
+ return 0;
+err:
+ nla_nest_cancel(skb, nest);
+ return ret;
+}
+
static int fill_info(struct sk_buff *skb,
const struct common_req_info *req_info)
{
@@ -176,6 +309,11 @@ static int fill_info(struct sk_buff *skb,
if (ret < 0)
return ret;
}
+ if (info_mask & ETH_INFO_IM_TSINFO) {
+ ret = fill_tsinfo(skb, &data->tsinfo, req_info->compact);
+ if (ret < 0)
+ return ret;
+ }
return 0;
}
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index c883239001a4..0837849156d3 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -2034,28 +2034,12 @@ static int ethtool_get_dump_data(struct net_device *dev,
static int ethtool_get_ts_info(struct net_device *dev, void __user *useraddr)
{
- int err = 0;
+ int err;
struct ethtool_ts_info info;
- const struct ethtool_ops *ops = dev->ethtool_ops;
- struct phy_device *phydev = dev->phydev;
-
- memset(&info, 0, sizeof(info));
- info.cmd = ETHTOOL_GET_TS_INFO;
-
- if (phydev && phydev->drv && phydev->drv->ts_info) {
- err = phydev->drv->ts_info(phydev, &info);
- } else if (ops->get_ts_info) {
- err = ops->get_ts_info(dev, &info);
- } else {
- info.so_timestamping =
- SOF_TIMESTAMPING_RX_SOFTWARE |
- SOF_TIMESTAMPING_SOFTWARE;
- info.phc_index = -1;
- }
+ err = __ethtool_get_ts_info(dev, &info);
if (err)
return err;
-
if (copy_to_user(useraddr, &info, sizeof(info)))
err = -EFAULT;
diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h
index 7141ec71a6d3..82a4c1f398d8 100644
--- a/net/ethtool/netlink.h
+++ b/net/ethtool/netlink.h
@@ -7,14 +7,23 @@
#include <linux/netdevice.h>
#include <net/genetlink.h>
#include <net/sock.h>
+#include <linux/net_tstamp.h>
#define ETHNL_SET_ERRMSG(info, msg) \
do { if (info) GENL_SET_ERR_MSG(info, msg); } while (0)
+#define __SOF_TIMESTAMPING_COUNT (const_ilog2(SOF_TIMESTAMPING_LAST) + 1)
+#define __HWTSTAMP_TX_COUNT (HWTSTAMP_TX_LAST + 1)
+#define __HWTSTAMP_FILTER_COUNT (HWTSTAMP_FILTER_LAST + 1)
+
extern u32 ethnl_bcast_seq;
extern struct genl_family ethtool_genl_family;
+extern const char *const so_timestamping_labels[];
+extern const char *const tstamp_tx_type_labels[];
+extern const char *const tstamp_rx_filter_labels[];
+
struct net_device *ethnl_dev_get(struct genl_info *info, struct nlattr *nest);
int ethnl_fill_dev(struct sk_buff *msg, struct net_device *dev, u16 attrtype);
diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c
index a7d0ec2865fb..5c74498d9c72 100644
--- a/net/ethtool/strset.c
+++ b/net/ethtool/strset.c
@@ -67,6 +67,24 @@ static const struct strset_info info_template[] = {
.count = ARRAY_SIZE(phy_tunable_strings),
.data = { .legacy = phy_tunable_strings },
},
+ [ETH_SS_TSTAMP_SOF] = {
+ .type = ETH_SS_TYPE_SIMPLE,
+ .per_dev = false,
+ .count = __SOF_TIMESTAMPING_COUNT,
+ .data = { .simple = so_timestamping_labels },
+ },
+ [ETH_SS_TSTAMP_TX_TYPE] = {
+ .type = ETH_SS_TYPE_SIMPLE,
+ .per_dev = false,
+ .count = __HWTSTAMP_TX_COUNT,
+ .data = { .simple = tstamp_tx_type_labels },
+ },
+ [ETH_SS_TSTAMP_RX_FILTER] = {
+ .type = ETH_SS_TYPE_SIMPLE,
+ .per_dev = false,
+ .count = __HWTSTAMP_FILTER_COUNT,
+ .data = { .simple = tstamp_rx_filter_labels },
+ },
};
struct strset_data {
--
2.20.1
^ permalink raw reply related
* [RFC PATCH net-next v3 12/21] ethtool: provide permanent hardware address in GET_INFO request
From: Michal Kubecek @ 2019-02-18 18:22 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
Add information about permanent hadware address of a device (as provided by
ETHTOOL_GPERMADDR ioctl command) in GET_INFO reply if ETH_INFO_IM_PERMADDR
flag is set in the request.
There is no separate attribute for hardware address length as nla_len gives
this information. The reply also provides address type (net_device::type).
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
Documentation/networking/ethtool-netlink.txt | 9 ++++-
include/uapi/linux/ethtool_netlink.h | 12 +++++-
net/ethtool/info.c | 39 ++++++++++++++++++++
3 files changed, 58 insertions(+), 2 deletions(-)
diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index b6999a2167e8..1e615e111262 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -239,6 +239,9 @@ Kernel response contents:
ETHA_DRVINFO_FWVERSION (string) firmware version
ETHA_DRVINFO_BUSINFO (string) device bus address
ETHA_DRVINFO_EROM_VER (string) expansion ROM version
+ ETHA_INFO_PERMADDR (nested)
+ ETHA_PERMADDR_ADDRESS (binary) permanent HW address
+ ETHA_PERMADDR_TYPE (u16) dev->type
The meaning of DRVINFO attributes follows the corresponding fields of
ETHTOOL_GDRVINFO response. Second part with various counts and sizes is
@@ -246,6 +249,10 @@ omitted as these are not really needed (and if they are, they can be easily
found by different means). Driver version is also omitted as it is rather
misleading in most cases.
+There is no separate attribute for permanent address length as the length can
+be determined from attribute length (nla_len()). ETHA_PERMADDR_TYPE provides
+net_device::type value to give a hint about what kind of address device has.
+
GET_INFO requests allow dumps.
@@ -288,7 +295,7 @@ ETHTOOL_PHYS_ID n/a
ETHTOOL_GSTATS n/a
ETHTOOL_GTSO n/a
ETHTOOL_STSO n/a
-ETHTOOL_GPERMADDR n/a
+ETHTOOL_GPERMADDR ETHNL_CMD_GET_INFO
ETHTOOL_GUFO n/a
ETHTOOL_SUFO n/a
ETHTOOL_GGSO n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index fdae12b6c6b6..fb756b6a8592 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -153,8 +153,9 @@ enum {
};
#define ETH_INFO_IM_DRVINFO 0x01
+#define ETH_INFO_IM_PERMADDR 0x02
-#define ETH_INFO_IM_ALL 0x01
+#define ETH_INFO_IM_ALL 0x03
enum {
ETHA_DRVINFO_UNSPEC,
@@ -167,6 +168,15 @@ enum {
ETHA_DRVINFO_MAX = (__ETHA_DRVINFO_CNT - 1)
};
+enum {
+ ETHA_PERMADDR_UNSPEC,
+ ETHA_PERMADDR_ADDRESS, /* binary */
+ ETHA_PERMADDR_TYPE, /* u16 */
+
+ __ETHA_PERMADDR_CNT,
+ ETHA_PERMADDR_MAX = (__ETHA_PERMADDR_CNT - 1)
+};
+
/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/info.c b/net/ethtool/info.c
index 1a2e78d238e3..05dbd87ebc41 100644
--- a/net/ethtool/info.c
+++ b/net/ethtool/info.c
@@ -18,6 +18,7 @@ static const struct nla_policy get_info_policy[ETHA_INFO_MAX + 1] = {
[ETHA_INFO_INFOMASK] = { .type = NLA_U32 },
[ETHA_INFO_COMPACT] = { .type = NLA_FLAG },
[ETHA_INFO_DRVINFO] = { .type = NLA_REJECT },
+ [ETHA_INFO_PERMADDR] = { .type = NLA_REJECT },
};
static int parse_info(struct common_req_info *req_info, struct sk_buff *skb,
@@ -86,16 +87,29 @@ static int drvinfo_size(const struct ethtool_drvinfo *drvinfo)
return nla_total_size(len);
}
+static int permaddr_size(const struct net_device *dev)
+{
+ int len = 0;
+
+ len += nla_total_size(dev->addr_len);
+ len += nla_total_size(sizeof(u16));
+
+ return nla_total_size(len);
+}
+
static int info_size(const struct common_req_info *req_info)
{
const struct info_data *data =
container_of(req_info, struct info_data, reqinfo_base);
+ const struct net_device *dev = data->repdata_base.dev;
u32 info_mask = data->repdata_base.info_mask;
int len = 0;
len += dev_ident_size();
if (info_mask & ETH_INFO_IM_DRVINFO)
len += drvinfo_size(&data->drvinfo);
+ if (info_mask & ETH_INFO_IM_PERMADDR)
+ len += permaddr_size(dev);
return len;
}
@@ -124,6 +138,26 @@ static int fill_drvinfo(struct sk_buff *skb,
return ret;
}
+static int fill_permaddr(struct sk_buff *skb, const struct net_device *dev)
+{
+ struct nlattr *nest = ethnl_nest_start(skb, ETHA_INFO_PERMADDR);
+ int ret;
+
+ if (!nest)
+ return -EMSGSIZE;
+ ret = -EMSGSIZE;
+ if (nla_put(skb, ETHA_PERMADDR_ADDRESS, dev->addr_len, dev->perm_addr))
+ goto err;
+ if (nla_put_u16(skb, ETHA_PERMADDR_TYPE, dev->type))
+ goto err;
+
+ nla_nest_end(skb, nest);
+ return 0;
+err:
+ nla_nest_cancel(skb, nest);
+ return ret;
+}
+
static int fill_info(struct sk_buff *skb,
const struct common_req_info *req_info)
{
@@ -137,6 +171,11 @@ static int fill_info(struct sk_buff *skb,
if (ret < 0)
return ret;
}
+ if (info_mask & ETH_INFO_IM_PERMADDR) {
+ ret = fill_permaddr(skb, data->repdata_base.dev);
+ if (ret < 0)
+ return ret;
+ }
return 0;
}
--
2.20.1
^ permalink raw reply related
* [RFC PATCH net-next v3 11/21] ethtool: provide driver/device information in GET_INFO request
From: Michal Kubecek @ 2019-02-18 18:22 UTC (permalink / raw)
To: netdev; +Cc: David Miller, Andrew Lunn, Jakub Kicinski, Jiri Pirko,
linux-kernel
In-Reply-To: <cover.1550513384.git.mkubecek@suse.cz>
Implement GET_INFO request to get basic driver and device information as
provided by ETHTOOL_GDRVINFO ioct command. The information is read only so
that the corresponding SET_INFO message is only used in kernel replies.
Move most of ethtool_get_drvinfo() int common.c so that the code can be
shared by both ioctl and netlink interface.
Signed-off-by: Michal Kubecek <mkubecek@suse.cz>
---
Documentation/networking/ethtool-netlink.txt | 43 ++++-
include/uapi/linux/ethtool_netlink.h | 32 ++++
net/ethtool/Makefile | 2 +-
net/ethtool/common.c | 54 +++++++
net/ethtool/common.h | 2 +
net/ethtool/info.c | 155 +++++++++++++++++++
net/ethtool/ioctl.c | 52 +------
net/ethtool/netlink.c | 9 ++
8 files changed, 300 insertions(+), 49 deletions(-)
create mode 100644 net/ethtool/info.c
diff --git a/Documentation/networking/ethtool-netlink.txt b/Documentation/networking/ethtool-netlink.txt
index f0fe4f50db9f..b6999a2167e8 100644
--- a/Documentation/networking/ethtool-netlink.txt
+++ b/Documentation/networking/ethtool-netlink.txt
@@ -128,6 +128,8 @@ List of message types
ETHNL_CMD_EVENT notification only
ETHNL_CMD_GET_STRSET
ETHNL_CMD_SET_STRSET response only
+ ETHNL_CMD_GET_INFO
+ ETHNL_CMD_SET_INFO response only
All constants use ETHNL_CMD_ prefix, usually followed by "GET", "SET" or "ACT"
to indicate the type.
@@ -208,6 +210,45 @@ ETHA_STRSET_COUNTS tells kernel to only return string counts of the sets, not
the actual strings.
+GET_INFO
+--------
+
+GET_INFO requests information provided by ioctl commands ETHTOOL_GDRVINFO,
+ETHTOOL_GPERMADDR and ETHTOOL_GET_TS_INFO to provide basic device information.
+Common pattern is that all information is read only so that SET_INFO message
+exists but is only used by kernel for replies to GET_INFO requests. There is
+also no corresponding notification.
+
+Request contents:
+
+ ETHA_INFO_DEV (nested) device identification
+ ETHA_INFO_INFOMASK (u32) info mask
+ ETHA_INFO_COMPACT (flag) request compact bitsets
+
+Info mask bits meaning:
+
+ ETH_INFO_IM_DRVINFO driver info (GDRVINFO)
+ ETH_INFO_IM_PERMADDR permanent HW address (GPERMADDR)
+ ETH_INFO_IM_TSINFO timestamping info (GET_TS_INFO)
+
+Kernel response contents:
+
+ ETHA_INFO_DEV (nested) device identification
+ ETHA_INFO_DRVINFO (nested) driver information
+ ETHA_DRVINFO_DRIVER (string) driver name
+ ETHA_DRVINFO_FWVERSION (string) firmware version
+ ETHA_DRVINFO_BUSINFO (string) device bus address
+ ETHA_DRVINFO_EROM_VER (string) expansion ROM version
+
+The meaning of DRVINFO attributes follows the corresponding fields of
+ETHTOOL_GDRVINFO response. Second part with various counts and sizes is
+omitted as these are not really needed (and if they are, they can be easily
+found by different means). Driver version is also omitted as it is rather
+misleading in most cases.
+
+GET_INFO requests allow dumps.
+
+
Request translation
-------------------
@@ -219,7 +260,7 @@ ioctl command netlink command
---------------------------------------------------------------------
ETHTOOL_GSET n/a
ETHTOOL_SSET n/a
-ETHTOOL_GDRVINFO n/a
+ETHTOOL_GDRVINFO ETHNL_CMD_GET_INFO
ETHTOOL_GREGS n/a
ETHTOOL_GWOL n/a
ETHTOOL_SWOL n/a
diff --git a/include/uapi/linux/ethtool_netlink.h b/include/uapi/linux/ethtool_netlink.h
index 630b66732dc9..fdae12b6c6b6 100644
--- a/include/uapi/linux/ethtool_netlink.h
+++ b/include/uapi/linux/ethtool_netlink.h
@@ -10,6 +10,8 @@ enum {
ETHNL_CMD_EVENT, /* only for notifications */
ETHNL_CMD_GET_STRSET,
ETHNL_CMD_SET_STRSET, /* only for reply */
+ ETHNL_CMD_GET_INFO,
+ ETHNL_CMD_SET_INFO, /* only for reply */
__ETHNL_CMD_CNT,
ETHNL_CMD_MAX = (__ETHNL_CMD_CNT - 1)
@@ -135,6 +137,36 @@ enum {
ETHA_STRSET_MAX = (__ETHA_STRSET_CNT - 1)
};
+/* GET_INFO / SET_INFO */
+
+enum {
+ ETHA_INFO_UNSPEC,
+ ETHA_INFO_DEV, /* nest - ETHA_DEV_* */
+ ETHA_INFO_INFOMASK, /* u32 */
+ ETHA_INFO_COMPACT, /* flag */
+ ETHA_INFO_DRVINFO, /* nest - ETHA_DRVINFO_* */
+ ETHA_INFO_PERMADDR, /* nest - ETHA_PERMADDR_* */
+ ETHA_INFO_TSINFO, /* nest - ETHA_TSINFO_* */
+
+ __ETHA_INFO_CNT,
+ ETHA_INFO_MAX = (__ETHA_INFO_CNT - 1)
+};
+
+#define ETH_INFO_IM_DRVINFO 0x01
+
+#define ETH_INFO_IM_ALL 0x01
+
+enum {
+ ETHA_DRVINFO_UNSPEC,
+ ETHA_DRVINFO_DRIVER, /* string */
+ ETHA_DRVINFO_FWVERSION, /* string */
+ ETHA_DRVINFO_BUSINFO, /* string */
+ ETHA_DRVINFO_EROM_VER, /* string */
+
+ __ETHA_DRVINFO_CNT,
+ ETHA_DRVINFO_MAX = (__ETHA_DRVINFO_CNT - 1)
+};
+
/* generic netlink info */
#define ETHTOOL_GENL_NAME "ethtool"
#define ETHTOOL_GENL_VERSION 1
diff --git a/net/ethtool/Makefile b/net/ethtool/Makefile
index 11ceb00821b3..96d41dc45d4f 100644
--- a/net/ethtool/Makefile
+++ b/net/ethtool/Makefile
@@ -4,4 +4,4 @@ obj-y += ioctl.o common.o
obj-$(CONFIG_ETHTOOL_NETLINK) += ethtool_nl.o
-ethtool_nl-y := netlink.o bitset.o strset.o
+ethtool_nl-y := netlink.o bitset.o strset.o info.o
diff --git a/net/ethtool/common.c b/net/ethtool/common.c
index 73f721a1c557..e0bd7c6c5874 100644
--- a/net/ethtool/common.c
+++ b/net/ethtool/common.c
@@ -1,5 +1,7 @@
// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+#include <linux/rtnetlink.h>
+#include <net/devlink.h>
#include "common.h"
const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
@@ -81,3 +83,55 @@ phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
[ETHTOOL_ID_UNSPEC] = "Unspec",
[ETHTOOL_PHY_DOWNSHIFT] = "phy-downshift",
};
+
+int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+ const struct ethtool_ops *ops = dev->ethtool_ops;
+
+ memset(info, 0, sizeof(*info));
+ info->cmd = ETHTOOL_GDRVINFO;
+ if (ops->get_drvinfo) {
+ ops->get_drvinfo(dev, info);
+ } else if (dev->dev.parent && dev->dev.parent->driver) {
+ strlcpy(info->bus_info, dev_name(dev->dev.parent),
+ sizeof(info->bus_info));
+ strlcpy(info->driver, dev->dev.parent->driver->name,
+ sizeof(info->driver));
+ } else {
+ return -EOPNOTSUPP;
+ }
+
+ /* this method of obtaining string set info is deprecated;
+ * Use ETHTOOL_GSSET_INFO instead.
+ */
+ if (ops->get_sset_count) {
+ int rc;
+
+ rc = ops->get_sset_count(dev, ETH_SS_TEST);
+ if (rc >= 0)
+ info->testinfo_len = rc;
+ rc = ops->get_sset_count(dev, ETH_SS_STATS);
+ if (rc >= 0)
+ info->n_stats = rc;
+ rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
+ if (rc >= 0)
+ info->n_priv_flags = rc;
+ }
+ if (ops->get_regs_len) {
+ int ret = ops->get_regs_len(dev);
+
+ if (ret > 0)
+ info->regdump_len = ret;
+ }
+
+ if (ops->get_eeprom_len)
+ info->eedump_len = ops->get_eeprom_len(dev);
+
+ rtnl_unlock();
+ if (!info->fw_version[0])
+ devlink_compat_running_version(dev, info->fw_version,
+ sizeof(info->fw_version));
+ rtnl_lock();
+
+ return 0;
+}
diff --git a/net/ethtool/common.h b/net/ethtool/common.h
index 41b2efc1e4e1..e87e58b3a274 100644
--- a/net/ethtool/common.h
+++ b/net/ethtool/common.h
@@ -3,6 +3,7 @@
#ifndef _ETHTOOL_COMMON_H
#define _ETHTOOL_COMMON_H
+#include <linux/netdevice.h>
#include <linux/ethtool.h>
extern const char
@@ -14,4 +15,5 @@ tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN];
extern const char
phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN];
+int __ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
#endif /* _ETHTOOL_COMMON_H */
diff --git a/net/ethtool/info.c b/net/ethtool/info.c
new file mode 100644
index 000000000000..1a2e78d238e3
--- /dev/null
+++ b/net/ethtool/info.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+
+#include "netlink.h"
+#include "common.h"
+#include "bitset.h"
+
+struct info_data {
+ struct common_req_info reqinfo_base;
+
+ /* everything below here will be reset for each device in dumps */
+ struct common_reply_data repdata_base;
+ struct ethtool_drvinfo drvinfo;
+};
+
+static const struct nla_policy get_info_policy[ETHA_INFO_MAX + 1] = {
+ [ETHA_INFO_UNSPEC] = { .type = NLA_REJECT },
+ [ETHA_INFO_DEV] = { .type = NLA_NESTED },
+ [ETHA_INFO_INFOMASK] = { .type = NLA_U32 },
+ [ETHA_INFO_COMPACT] = { .type = NLA_FLAG },
+ [ETHA_INFO_DRVINFO] = { .type = NLA_REJECT },
+};
+
+static int parse_info(struct common_req_info *req_info, struct sk_buff *skb,
+ struct genl_info *info, const struct nlmsghdr *nlhdr)
+{
+ struct nlattr *tb[ETHA_INFO_MAX + 1];
+ int ret;
+
+ ret = genlmsg_parse(nlhdr, ðtool_genl_family, tb, ETHA_INFO_MAX,
+ get_info_policy, info ? info->extack : NULL);
+ if (ret < 0)
+ return ret;
+
+ if (tb[ETHA_INFO_DEV]) {
+ req_info->dev = ethnl_dev_get(info, tb[ETHA_INFO_DEV]);
+ if (IS_ERR(req_info->dev)) {
+ ret = PTR_ERR(req_info->dev);
+ req_info->dev = NULL;
+ return ret;
+ }
+ }
+ if (tb[ETHA_INFO_INFOMASK])
+ req_info->req_mask = nla_get_u32(tb[ETHA_INFO_INFOMASK]);
+ if (tb[ETHA_INFO_COMPACT])
+ req_info->compact = true;
+ if (req_info->req_mask == 0)
+ req_info->req_mask = ETH_INFO_IM_ALL;
+
+ return 0;
+}
+
+static int prepare_info(struct common_req_info *req_info,
+ struct genl_info *info)
+{
+ struct info_data *data =
+ container_of(req_info, struct info_data, reqinfo_base);
+ struct net_device *dev = data->repdata_base.dev;
+ u32 req_mask = req_info->req_mask & ETH_INFO_IM_ALL;
+ int ret;
+
+ ret = ethnl_before_ops(dev);
+ if (ret < 0)
+ return ret;
+ if (req_mask & ETH_INFO_IM_DRVINFO) {
+ ret = __ethtool_get_drvinfo(dev, &data->drvinfo);
+ if (ret < 0)
+ req_mask &= ~ETH_INFO_IM_DRVINFO;
+ }
+ ethnl_after_ops(dev);
+
+ data->repdata_base.info_mask = req_mask;
+ if (req_info->req_mask & ~req_mask)
+ warn_partial_info(info);
+ return 0;
+}
+
+static int drvinfo_size(const struct ethtool_drvinfo *drvinfo)
+{
+ int len = 0;
+
+ len += ethnl_str_ifne_size(drvinfo->driver);
+ len += ethnl_str_ifne_size(drvinfo->fw_version);
+ len += ethnl_str_ifne_size(drvinfo->bus_info);
+ len += ethnl_str_ifne_size(drvinfo->erom_version);
+
+ return nla_total_size(len);
+}
+
+static int info_size(const struct common_req_info *req_info)
+{
+ const struct info_data *data =
+ container_of(req_info, struct info_data, reqinfo_base);
+ u32 info_mask = data->repdata_base.info_mask;
+ int len = 0;
+
+ len += dev_ident_size();
+ if (info_mask & ETH_INFO_IM_DRVINFO)
+ len += drvinfo_size(&data->drvinfo);
+
+ return len;
+}
+
+static int fill_drvinfo(struct sk_buff *skb,
+ const struct ethtool_drvinfo *drvinfo)
+{
+ struct nlattr *nest = ethnl_nest_start(skb, ETHA_INFO_DRVINFO);
+ int ret;
+
+ if (!nest)
+ return -EMSGSIZE;
+ ret = -EMSGSIZE;
+ if (ethnl_put_str_ifne(skb, ETHA_DRVINFO_DRIVER, drvinfo->driver) ||
+ ethnl_put_str_ifne(skb, ETHA_DRVINFO_FWVERSION,
+ drvinfo->fw_version) ||
+ ethnl_put_str_ifne(skb, ETHA_DRVINFO_BUSINFO, drvinfo->bus_info) ||
+ ethnl_put_str_ifne(skb, ETHA_DRVINFO_EROM_VER,
+ drvinfo->erom_version))
+ goto err;
+
+ nla_nest_end(skb, nest);
+ return 0;
+err:
+ nla_nest_cancel(skb, nest);
+ return ret;
+}
+
+static int fill_info(struct sk_buff *skb,
+ const struct common_req_info *req_info)
+{
+ const struct info_data *data =
+ container_of(req_info, struct info_data, reqinfo_base);
+ u32 info_mask = data->repdata_base.info_mask;
+ int ret;
+
+ if (info_mask & ETH_INFO_IM_DRVINFO) {
+ ret = fill_drvinfo(skb, &data->drvinfo);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+const struct get_request_ops info_request_ops = {
+ .request_cmd = ETHNL_CMD_GET_INFO,
+ .reply_cmd = ETHNL_CMD_SET_INFO,
+ .dev_attrtype = ETHA_INFO_DEV,
+ .data_size = sizeof(struct info_data),
+ .repdata_offset = offsetof(struct info_data, repdata_base),
+
+ .parse_request = parse_info,
+ .prepare_data = prepare_info,
+ .reply_size = info_size,
+ .fill_reply = fill_info,
+};
diff --git a/net/ethtool/ioctl.c b/net/ethtool/ioctl.c
index 71a1643adb2b..c883239001a4 100644
--- a/net/ethtool/ioctl.c
+++ b/net/ethtool/ioctl.c
@@ -685,56 +685,14 @@ static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev,
void __user *useraddr)
{
struct ethtool_drvinfo info;
- const struct ethtool_ops *ops = dev->ethtool_ops;
-
- memset(&info, 0, sizeof(info));
- info.cmd = ETHTOOL_GDRVINFO;
- if (ops->get_drvinfo) {
- ops->get_drvinfo(dev, &info);
- } else if (dev->dev.parent && dev->dev.parent->driver) {
- strlcpy(info.bus_info, dev_name(dev->dev.parent),
- sizeof(info.bus_info));
- strlcpy(info.driver, dev->dev.parent->driver->name,
- sizeof(info.driver));
- } else {
- return -EOPNOTSUPP;
- }
-
- /*
- * this method of obtaining string set info is deprecated;
- * Use ETHTOOL_GSSET_INFO instead.
- */
- if (ops->get_sset_count) {
- int rc;
-
- rc = ops->get_sset_count(dev, ETH_SS_TEST);
- if (rc >= 0)
- info.testinfo_len = rc;
- rc = ops->get_sset_count(dev, ETH_SS_STATS);
- if (rc >= 0)
- info.n_stats = rc;
- rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
- if (rc >= 0)
- info.n_priv_flags = rc;
- }
- if (ops->get_regs_len) {
- int ret = ops->get_regs_len(dev);
-
- if (ret > 0)
- info.regdump_len = ret;
- }
-
- if (ops->get_eeprom_len)
- info.eedump_len = ops->get_eeprom_len(dev);
-
- rtnl_unlock();
- if (!info.fw_version[0])
- devlink_compat_running_version(dev, info.fw_version,
- sizeof(info.fw_version));
- rtnl_lock();
+ int rc;
+ rc = __ethtool_get_drvinfo(dev, &info);
+ if (rc < 0)
+ return rc;
if (copy_to_user(useraddr, &info, sizeof(info)))
return -EFAULT;
+
return 0;
}
diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c
index 082a9f2aa0a7..e27dec427414 100644
--- a/net/ethtool/netlink.c
+++ b/net/ethtool/netlink.c
@@ -87,9 +87,11 @@ int ethnl_fill_dev(struct sk_buff *msg, struct net_device *dev, u16 attrtype)
/* GET request helpers */
extern const struct get_request_ops strset_request_ops;
+extern const struct get_request_ops info_request_ops;
const struct get_request_ops *get_requests[__ETHNL_CMD_CNT] = {
[ETHNL_CMD_GET_STRSET] = &strset_request_ops,
+ [ETHNL_CMD_GET_INFO] = &info_request_ops,
};
static struct common_req_info *alloc_get_data(const struct get_request_ops *ops)
@@ -508,6 +510,13 @@ static const struct genl_ops ethtool_genl_ops[] = {
.dumpit = ethnl_get_dumpit,
.done = ethnl_get_done,
},
+ {
+ .cmd = ETHNL_CMD_GET_INFO,
+ .doit = ethnl_get_doit,
+ .start = ethnl_get_start,
+ .dumpit = ethnl_get_dumpit,
+ .done = ethnl_get_done,
+ },
};
static const struct genl_multicast_group ethtool_nl_mcgrps[] = {
--
2.20.1
^ 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