Netdev List
 help / color / mirror / Atom feed
* Re: [net-next, PATCH 3/3, v2] net: netsec: add XDP support
From: Ivan Khoronzhuk @ 2019-06-30 16:20 UTC (permalink / raw)
  To: Ilias Apalodimas
  Cc: netdev, jaswinder.singh, ard.biesheuvel, bjorn.topel,
	magnus.karlsson, brouer, daniel, ast, makita.toshiaki,
	jakub.kicinski, john.fastabend, davem, maciejromanfijalkowski
In-Reply-To: <1561785805-21647-4-git-send-email-ilias.apalodimas@linaro.org>

On Sat, Jun 29, 2019 at 08:23:25AM +0300, Ilias Apalodimas wrote:

[...]

>+
>+static int netsec_xdp(struct net_device *ndev, struct netdev_bpf *xdp)
>+{
>+	struct netsec_priv *priv = netdev_priv(ndev);
>+
>+	switch (xdp->command) {
>+	case XDP_SETUP_PROG:
>+		return netsec_xdp_setup(priv, xdp->prog, xdp->extack);
>+	case XDP_QUERY_PROG:
>+		xdp->prog_id = priv->xdp_prog ? priv->xdp_prog->aux->id : 0;
xdp_attachment family to save bpf flags?

>+		return 0;
>+	default:
>+		return -EINVAL;
>+	}
>+}
>+
> static const struct net_device_ops netsec_netdev_ops = {
> 	.ndo_init		= netsec_netdev_init,
> 	.ndo_uninit		= netsec_netdev_uninit,
>@@ -1537,6 +1842,8 @@ static const struct net_device_ops netsec_netdev_ops = {
> 	.ndo_set_mac_address    = eth_mac_addr,
> 	.ndo_validate_addr	= eth_validate_addr,
> 	.ndo_do_ioctl		= netsec_netdev_ioctl,
>+	.ndo_xdp_xmit		= netsec_xdp_xmit,
>+	.ndo_bpf		= netsec_xdp,
> };
>
> static int netsec_of_probe(struct platform_device *pdev,
>-- 
>2.20.1
>

-- 
Regards,
Ivan Khoronzhuk

^ permalink raw reply

* Re: r8169 not working on 5.2.0rc6 with GPD MicroPC
From: Karsten Wiborg @ 2019-06-30 16:03 UTC (permalink / raw)
  To: Andrew Lunn; +Cc: Heiner Kallweit, nic_swsd, romieu, netdev
In-Reply-To: <20190630145511.GA5330@lunn.ch>

[-- Attachment #1: Type: text/plain, Size: 845 bytes --]

Hi Andrew,

On 30/06/2019 16:55, Andrew Lunn wrote:
> Hi Karsten
> 
> What MAC address do you get with the vendor driver? Is it the same MAC
> address every time you reboot, or does it look random.
> 
> The BIOS is expected to program the MAC address into the hardware. It
> could be that the vendor driver is checking if the MAC address is
> valid, and if not, picking a random MAC address. The mainline driver
> does not do this.

I programmed a static DHCP-entry on my local DHCP-server so I would
notice if the MAC address changes. Just turned the computer back on and
received the intended IP address, so the MAC address seems to stay the
same with the vendor driver.

The vendor part of my MAC is 6e:69:73 which is interesting because
according to some Vendor-Lookup-pages the vendor is unknown.

Regards,
Karsten


[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 4156 bytes --]

^ permalink raw reply

* Re: r8169 not working on 5.2.0rc6 with GPD MicroPC
From: Andrew Lunn @ 2019-06-30 14:55 UTC (permalink / raw)
  To: Karsten Wiborg; +Cc: Heiner Kallweit, nic_swsd, romieu, netdev
In-Reply-To: <62684063-10d1-58ad-55ad-ff35b231e3b0@web.de>

On Sun, Jun 30, 2019 at 02:40:14PM +0200, Karsten Wiborg wrote:
> Hi Heiner,
> 
> On 30/06/2019 11:12, Heiner Kallweit wrote:
> > Indeed the MAC is missing:
> > [    2.839776] r8169 0000:02:00.0 eth0: RTL8168h/8111h,
> > 00:00:00:00:00:00, XID 541, IRQ 126
> >
> > This works with RTL8168h in other systems, so I'd say you should
> > check with the vendor. Maybe it's a BIOS issue.
> Tested some more. Found out that the Realtek-supplied r8168-8.046.00 is
> buggy (compilation bugged out, see one of my last mails). I just
> succeeded in compiling r8168-8.047.00, which ran straight out of the
> box. So the NIC is fine and not defect.
> 
> I do agree with you: I definitely would prefer an opensource driver but
> the r8169 simply didn't work.
> 
> In regard of my success with r8168-8.047.00, do you still think it might
> be a BIOS-issue?

Hi Karsten

What MAC address do you get with the vendor driver? Is it the same MAC
address every time you reboot, or does it look random.

The BIOS is expected to program the MAC address into the hardware. It
could be that the vendor driver is checking if the MAC address is
valid, and if not, picking a random MAC address. The mainline driver
does not do this.

       Andrew

^ permalink raw reply

* [PATCH] net: ethernet: broadcom: bcm63xx_enet: Remove unneeded memset
From: Hariprasad Kelam @ 2019-06-30 14:29 UTC (permalink / raw)
  To: David S. Miller, Florian Fainelli, bcm-kernel-feedback-list,
	Andrew Lunn, Greg Kroah-Hartman, Hariprasad Kelam, YueHaibing,
	Thomas Gleixner, Luis Chamberlain, netdev, linux-arm-kernel,
	linux-kernel

Remove unneeded memset as alloc_etherdev is using kvzalloc which uses
__GFP_ZERO flag

Signed-off-by: Hariprasad Kelam <hariprasad.kelam@gmail.com>
---
 drivers/net/ethernet/broadcom/bcm63xx_enet.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
index 85e6102..f2dd74c 100644
--- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c
@@ -2659,8 +2659,7 @@ static int bcm_enetsw_probe(struct platform_device *pdev)
 	if (!dev)
 		return -ENOMEM;
 	priv = netdev_priv(dev);
-	memset(priv, 0, sizeof(*priv));
-
+
 	/* initialize default and fetch platform data */
 	priv->enet_is_sw = true;
 	priv->irq_rx = irq_rx;
-- 
2.7.4


^ permalink raw reply related

* Re: r8169 not working on 5.2.0rc6 with GPD MicroPC
From: Karsten Wiborg @ 2019-06-30 12:40 UTC (permalink / raw)
  To: Heiner Kallweit, nic_swsd, romieu; +Cc: netdev
In-Reply-To: <b104dbf2-6adc-2eee-0a1a-505c013787c0@gmail.com>

Hi Heiner,

On 30/06/2019 11:12, Heiner Kallweit wrote:
> Indeed the MAC is missing:
> [    2.839776] r8169 0000:02:00.0 eth0: RTL8168h/8111h,
> 00:00:00:00:00:00, XID 541, IRQ 126
>
> This works with RTL8168h in other systems, so I'd say you should
> check with the vendor. Maybe it's a BIOS issue.
Tested some more. Found out that the Realtek-supplied r8168-8.046.00 is
buggy (compilation bugged out, see one of my last mails). I just
succeeded in compiling r8168-8.047.00, which ran straight out of the
box. So the NIC is fine and not defect.

I do agree with you: I definitely would prefer an opensource driver but
the r8169 simply didn't work.

In regard of my success with r8168-8.047.00, do you still think it might
be a BIOS-issue?

Regards,
Karsten

^ permalink raw reply

* Re: [PATCH v2 15/27] net: use zeroing allocator rather than allocator followed by memset zero
From: Tariq Toukan @ 2019-06-30 12:19 UTC (permalink / raw)
  To: Fuqian Huang
  Cc: David S. Miller, Derek Chickles, Satanand Burla, Felix Manlunas,
	netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-rdma@vger.kernel.org
In-Reply-To: <20190628024824.15581-1-huangfq.daxian@gmail.com>



On 6/28/2019 5:48 AM, Fuqian Huang wrote:
> Replace allocator followed by memset with 0 with zeroing allocator.
> 
> Signed-off-by: Fuqian Huang <huangfq.daxian@gmail.com>
> ---

..


> --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
> +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
> @@ -1062,7 +1062,7 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn,
>   	struct mlx4_qp_context *context;
>   	int err = 0;
>   
> -	context = kmalloc(sizeof(*context), GFP_KERNEL);
> +	context = kzalloc(sizeof(*context), GFP_KERNEL);
>   	if (!context)
>   		return -ENOMEM;
>   
> @@ -1073,7 +1073,6 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn,
>   	}
>   	qp->event = mlx4_en_sqp_event;
>   
> -	memset(context, 0, sizeof(*context));
>   	mlx4_en_fill_qp_context(priv, ring->actual_size, ring->stride, 0, 0,
>   				qpn, ring->cqn, -1, context);
>   	context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma);
> 


For the mlx4 part:
Reviewed-by: Tariq Toukan <tariqt@mellanox.com>

Tariq

^ permalink raw reply

* Re: [PATCH 87/87] ethernet: mlx4: remove memset after dma_alloc_coherent
From: Tariq Toukan @ 2019-06-30 12:15 UTC (permalink / raw)
  To: Fuqian Huang
  Cc: Tariq Toukan, David S. Miller, netdev@vger.kernel.org,
	linux-rdma@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <20190627174227.4726-1-huangfq.daxian@gmail.com>



On 6/27/2019 8:42 PM, Fuqian Huang wrote:
> In commit af7ddd8a627c
> ("Merge tag 'dma-mapping-4.21' of git://git.infradead.org/users/hch/dma-mapping"),
> dma_alloc_coherent has already zeroed the memory.
> So memset is not needed.
> 
> Signed-off-by: Fuqian Huang <huangfq.daxian@gmail.com>
> ---
>   drivers/net/ethernet/mellanox/mlx4/eq.c | 2 --
>   1 file changed, 2 deletions(-)
> 
> diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c
> index a5be27772b8e..c790a5fcea73 100644
> --- a/drivers/net/ethernet/mellanox/mlx4/eq.c
> +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
> @@ -1013,8 +1013,6 @@ static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
>   
>   		dma_list[i] = t;
>   		eq->page_list[i].map = t;
> -
> -		memset(eq->page_list[i].buf, 0, PAGE_SIZE);
>   	}
>   
>   	eq->eqn = mlx4_bitmap_alloc(&priv->eq_table.bitmap);
> 

Reviewed-by: Tariq Toukan <tariqt@mellanox.com>

Thanks.

^ permalink raw reply

* Re: WARNING in kernfs_create_dir_ns
From: syzbot @ 2019-06-30 10:40 UTC (permalink / raw)
  To: a, b.a.t.m.a.n, davem, gregkh, hongjiefang, linux-kernel,
	linux-mmc, mareklindner, netdev, sw, syzkaller-bugs, tj,
	ulf.hansson
In-Reply-To: <0000000000003ec128058c7624ec@google.com>

syzbot has bisected this bug to:

commit 7f38abf220e2c800a2c451372e9f07ed5fd0ea49
Author: Hongjie Fang <hongjiefang@asrmicro.com>
Date:   Tue Jul 31 02:55:09 2018 +0000

     mmc: core: improve reasonableness of bus width setting for HS400es

bisection log:  https://syzkaller.appspot.com/x/bisect.txt?x=129d6755a00000
start commit:   72825454 Merge branch 'x86-urgent-for-linus' of git://git...
git tree:       upstream
final crash:    https://syzkaller.appspot.com/x/report.txt?x=119d6755a00000
console output: https://syzkaller.appspot.com/x/log.txt?x=169d6755a00000
kernel config:  https://syzkaller.appspot.com/x/.config?x=9a31528e58cc12e2
dashboard link: https://syzkaller.appspot.com/bug?extid=38f5d5cf7ae88c46b11a
syz repro:      https://syzkaller.appspot.com/x/repro.syz?x=12a6c439a00000
C reproducer:   https://syzkaller.appspot.com/x/repro.c?x=1353c323a00000

Reported-by: syzbot+38f5d5cf7ae88c46b11a@syzkaller.appspotmail.com
Fixes: 7f38abf220e2 ("mmc: core: improve reasonableness of bus width  
setting for HS400es")

For information about bisection process see: https://goo.gl/tpsmEJ#bisection

^ permalink raw reply

* Re: r8169 not working on 5.2.0rc6 with GPD MicroPC
From: Heiner Kallweit @ 2019-06-30  9:12 UTC (permalink / raw)
  To: Karsten Wiborg, nic_swsd, romieu; +Cc: netdev
In-Reply-To: <4437a8a6-73f0-26a7-4a61-b215c641ff20@web.de>

On 30.06.2019 02:14, Karsten Wiborg wrote:
> Hi Heiner,
> 
> thanks for the speedy reply.
> 
> On 6/30/19 12:09 AM, Heiner Kallweit wrote:
>> If r8169 (the mainline driver) is running, why do you want to switch
>> to r8168 (the Realtek vendor driver)? The latter is not supported by
>> the kernel community.
> Well I did install r8168 because r8169 is not working.
> Didn't even get to see the MAC of the NIC.
> 
>>> 2: eno1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group
>>> default qlen 1000
>>>     link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
>> Seems like the network isn't started.
> Jepp, that is the output from the r8169.
> 
Indeed the MAC is missing:
[    2.839776] r8169 0000:02:00.0 eth0: RTL8168h/8111h,
00:00:00:00:00:00, XID 541, IRQ 126

This works with RTL8168h in other systems, so I'd say you should
check with the vendor. Maybe it's a BIOS issue.

> Regards,
> Karsten
> 
Heiner

^ permalink raw reply

* Re: [PATCH rdma-next v1 00/12] DEVX asynchronous events
From: Leon Romanovsky @ 2019-06-30  8:53 UTC (permalink / raw)
  To: Saeed Mahameed
  Cc: Jason Gunthorpe, Yishai Hadas, netdev@vger.kernel.org,
	linux-rdma@vger.kernel.org, dledford@redhat.com
In-Reply-To: <a8de53f1acb069057dedc94fb8bd29ea3e658716.camel@mellanox.com>

On Mon, Jun 24, 2019 at 09:57:05PM +0000, Saeed Mahameed wrote:
> On Wed, 2019-06-19 at 07:45 +0300, Leon Romanovsky wrote:
> > On Tue, Jun 18, 2019 at 06:51:45PM +0000, Saeed Mahameed wrote:
> > > On Tue, 2019-06-18 at 20:15 +0300, Leon Romanovsky wrote:
> > > > From: Leon Romanovsky <leonro@mellanox.com>
> > > >
> > > > Changelog:
> > > >  v0 -> v1:
> > >
> > > Normally 1st submission is V1 and 2nd is V2.
> > > so this should have been v1->v2.
> >
> > "Normally" depends on the language you are using. In C, everything
> > starts from 0, including version of patches :).
> >
>
> You are wrong:
> quoting: https://kernelnewbies.org/PatchTipsAndTricks
>
> "For example, if you're sending the second revision of a patch, you
> should use [PATCH v2]."
>
> now don't tell me that second revision is actually 3rd revision or 1st
> is 2nd :)..

:)

If you don't mind, I will stick to common sense (v0, v1, v2 ...)
and official kernel documentation, which mentions existence of v1.

https://elixir.bootlin.com/linux/latest/source/Documentation/process/submitting-patches.rst#L682

>
> > > For mlx5-next patches:
> > >
> > > Acked-by: Saeed Mahameed <saeedm@mellanox.com>
> >
> > Thanks

^ permalink raw reply

* Re: [PATCH net-next v2 1/4] net/sched: Introduce action ct
From: Paul Blakey @ 2019-06-30  8:43 UTC (permalink / raw)
  To: David Miller
  Cc: Jiri Pirko, Roi Dayan, Yossi Kuperman, Oz Shlomo,
	marcelo.leitner@gmail.com, netdev@vger.kernel.org,
	aconole@redhat.com, wangzhike@jd.com, Rony Efraim,
	nst-kernel@redhat.com, john.hurley@netronome.com,
	simon.horman@netronome.com, jpettit@ovn.org
In-Reply-To: <20190627.125339.707372206595841703.davem@davemloft.net>


On 6/27/2019 10:53 PM, David Miller wrote:
> From: Paul Blakey <paulb@mellanox.com>
> Date: Thu, 20 Jun 2019 16:42:18 +0300
>
>> +struct tcf_ct_params {
>   ...
>> +	struct rcu_head rcu;
>> +
>> +};
> Please get ride of that empty line after the 'rcu' member.
>
>> +	switch (skb->protocol) {
>> +	case htons(ETH_P_IP):
>> +		family = NFPROTO_IPV4;
>> +		break;
>> +	case htons(ETH_P_IPV6):
>> +		family = NFPROTO_IPV6;
>> +		break;
>> +	default:
>> +	break;
> Break statement is not indented properly.
>
>> +static __net_init int ct_init_net(struct net *net)
>> +{
>> +	struct tc_ct_action_net *tn = net_generic(net, ct_net_id);
>> +	unsigned int n_bits = FIELD_SIZEOF(struct tcf_ct_params, labels) * 8;
> Reverse christmas tree here please.
Sure thanks.

^ permalink raw reply

* Re: [PATCH net-next v2 0/4] net/sched: Introduce tc connection tracking
From: Paul Blakey @ 2019-06-30  8:43 UTC (permalink / raw)
  To: Cong Wang
  Cc: Jiri Pirko, Roi Dayan, Yossi Kuperman, Oz Shlomo,
	Marcelo Ricardo Leitner, Linux Kernel Network Developers,
	David Miller, Aaron Conole, Zhike Wang, Rony Efraim,
	nst-kernel@redhat.com, John Hurley, Simon Horman, Justin Pettit
In-Reply-To: <CAM_iQpU+EojoF-qOZ3gVB28+Hp-HE=tHTcC7uUh3b3XwMwWJ=w@mail.gmail.com>

On 6/24/2019 8:59 PM, Cong Wang wrote:

> On Thu, Jun 20, 2019 at 6:43 AM Paul Blakey <paulb@mellanox.com> wrote:
>> Hi,
>>
>> This patch series add connection tracking capabilities in tc sw datapath.
>> It does so via a new tc action, called act_ct, and new tc flower classifier matching
>> on conntrack state, mark and label.
> Thanks for more detailed description here.
>
> I still don't see why we have to do this in L2, mind to be more specific?

tc is an complete datapath, and does it's routing/manipulation before 
the kernel stack (here the hooks

are on device ingress qdisc), for example, take this simple namespace setup

#setup 2 reps
sudo ip netns add ns0
sudo ip netns add ns1
sudo ip link add vm type veth peer name vm_rep
sudo ip link add vm2 type veth peer name vm2_rep
sudo ip link set vm netns ns0
sudo ip link set vm2 netns ns1
sudo ip netns exec ns0 ifconfig vm 3.3.3.3/24 up
sudo ip netns exec ns1 ifconfig vm2 3.3.3.4/24 up
sudo ifconfig vm_rep up
sudo ifconfig vm2_rep up
sudo tc qdisc add dev vm_rep ingress
sudo tc qdisc add dev vm2_rep ingress

#outbound
sudo tc filter add dev vm_rep ingress proto ip chain 0 prio 1 flower 
ct_state -trk     action mirred egress redirect dev vm2_rep
sudo tc filter add dev vm_rep ingress proto ip chain 1 prio 1 flower 
ct_state +trk+new action ct commit pipe action mirred egress redirect 
dev vm2_rep
sudo tc filter add dev vm_rep ingress proto ip chain 1 prio 1 flower 
ct_state +trk+est action mirred egress redirect dev vm2_rep

#inbound
sudo tc filter add dev vm2_rep ingress proto ip chain 0 prio 1 flower 
ct_state -trk     action mirred egress redirect dev vm_rep
sudo tc filter add dev vm2_rep ingress proto ip chain 1 prio 1 flower 
ct_state +trk+est action mirred egress redirect dev vm_rep

#handle arps
sudo tc filter add dev vm2_rep ingress proto arp chain 0 prio 2 flower 
action mirred egress redirect dev vm_rep
sudo tc filter add dev vm_rep ingress proto arp chain 0 prio 2 flower 
action mirred egress redirect dev vm2_rep

#run traffic
sudo timeout 20 ip netns exec ns1 iperf -s&
sudo ip netns exec ns0 iperf -c 3.3.3.4 -t 10


The traffic is handled in tc datapath layer and the user here decided 
how to route the packets.

In a real world exmaple,  we are going to use it with SRIOV where the tc 
rules are on representors, and the vms above are

SRIOV vfs attached to VMs. We also don't want to send any packet to 
conntrack just those that we want,

and we might do manipulation on the packet before sending it to 
conntrack such as with tc action pedit , in a router

setup (change macs, ips).

>
> IOW, if you really want to manipulate conntrack info and use it for
> matching, why not do it in netfilter layer as it is where conntrack is?
>
> BTW, if the cls_flower ct_state matching is not in upstream yet, please
> try to push it first, as it is a justification of this patchset.
>
> Thanks.

It's patch 3/4 of this patch set, I can move it to be first


^ permalink raw reply

* Re: [PATCH v3 4/4] kbuild: compile-test kernel headers to ensure they are self-contained
From: Masahiro Yamada @ 2019-06-30  7:57 UTC (permalink / raw)
  To: Sam Ravnborg
  Cc: Linux Kbuild mailing list, Jani Nikula, Tony Luck, John Fastabend,
	Jakub Kicinski, Daniel Borkmann, xdp-newbies, Anton Vorontsov,
	Matthias Brugger, Song Liu, Yonghong Song, Michal Marek,
	Jesper Dangaard Brouer, Martin KaFai Lau,
	moderated list:ARM/Mediatek SoC support, linux-arm-kernel,
	Colin Cross, David S. Miller, Kees Cook, Alexei Starovoitov,
	Networking, Linux Kernel Mailing List, bpf
In-Reply-To: <20190628180057.GA22758@ravnborg.org>

Hi Sam,


On Sat, Jun 29, 2019 at 3:01 AM Sam Ravnborg <sam@ravnborg.org> wrote:
>
> Hi Masahiro.
>
> On Fri, Jun 28, 2019 at 01:39:02AM +0900, Masahiro Yamada wrote:
> > The headers in include/ are globally used in the kernel source tree
> > to provide common APIs. They are included from external modules, too.
> >
> > It will be useful to make as many headers self-contained as possible
> > so that we do not have to rely on a specific include order.
> >
> > There are more than 4000 headers in include/. In my rough analysis,
> > 70% of them are already self-contained. With efforts, most of them
> > can be self-contained.
> >
> > For now, we must exclude more than 1000 headers just because they
> > cannot be compiled as standalone units. I added them to header-test-.
> > The black list was mostly generated by a script, so should be checked
> > later.
> The list is smaller than I had expected.
> And I see why you insisted on avoiding a maze ok Kbuild files.
> It looks good, except there is a few issues..
>
>
> The file kernel/kheaders_data.tar.xz includes all the .s files.
> Something needs to be done to exclude the .s files...

Good catch. I will change scripts/gen_kheaders.sh


> When building a full kernel the build fails like this:
>   LD      vmlinux.o
> aarch64-linux-gnu-ld: cannot find include/lib.a: No such file or directory
> make[1]: *** [/home/sam/kernel/linux-kbuild.git/Makefile:1054: vmlinux] Error 1
> make[1]: Leaving directory '/home/sam/kernel/linux-kbuild.git/.build/arm64-allyesconfig'
> make: *** [Makefile:179: sub-make] Error 2

My bad - I built only include/,
without testing full build.

I will fix.


>
> include/uapi/linux/mman.h fails when building sparc64 allmodconfig.
> There is likely more header files that will fail when we start to
> throw this after diverse randconfigs.
> I have no good idea how to catch this.
> Unless your scripts could automate this across several architectures.

Thanks. I excluded a little more headers.


> I did not continue my testing futher.
>
> > +header-test-                 += uapi/drm/vmwgfx_drm.h
> > +header-test-                 += uapi/linux/a.out.h
> > +header-test-                 += uapi/linux/coda.h
> ...
> > +header-test-                 += uapi/xen/evtchn.h
> > +header-test-                 += uapi/xen/gntdev.h
> > +header-test-                 += uapi/xen/privcmd.h
>
> I though uapi files were covered by another Makefile?
> If they are added because we pull them in using a pattern, maybe they
> should be removed using a specific filer-out?

I have not looked at this closely yet.

usr/include/Makefile tests UAPI headers
crafted by scripts/headers_install.sh

Testing UAPI headers in their raw form
makes sense, I think.



-- 
Best Regards
Masahiro Yamada

^ permalink raw reply

* Re: [PATCH net-next 0/2] net: ipv4: fix circular-list infinite loop
From: Tariq Toukan @ 2019-06-30  7:56 UTC (permalink / raw)
  To: David Miller, fw@strlen.de
  Cc: netdev@vger.kernel.org, Ran Rozenstein, Tariq Toukan
In-Reply-To: <20190627.095458.1221651269287757130.davem@davemloft.net>



On 6/27/2019 7:54 PM, David Miller wrote:
> From: Florian Westphal <fw@strlen.de>
> Date: Thu, 27 Jun 2019 14:03:31 +0200
> 
>> Tariq and Ran reported a regression caused by net-next commit
>> 2638eb8b50cf ("net: ipv4: provide __rcu annotation for ifa_list").
>>
>> This happens when net.ipv4.conf.$dev.promote_secondaries sysctl is
>> enabled -- we can arrange for ifa->next to point at ifa, so next
>> process that tries to walk the list loops forever.
>>
>> Fix this and extend rtnetlink.sh with a small test case for this.
> 
> Series applied, thanks Florian.
> 

Thanks Florian!

Ran, please test and update.

Tariq

^ permalink raw reply

* Re: loss of connectivity after enabling vlan_filtering
From: vtolkm @ 2019-06-30  7:46 UTC (permalink / raw)
  To: netdev; +Cc: Andrew Lunn
In-Reply-To: <1696f8e8-6b83-32c1-9ee0-ca973d7fd70d@gmail.com>


On 30/06/2019 03:13, vtolkm@gmail.com wrote:
> On 30/06/2019 02:37, vtolkm@gmail.com wrote:
>> On 30/06/2019 01:23, vtolkm@gmail.com wrote:
>>> On 30/06/2019 01:11, Andrew Lunn wrote:
>>>> On Sun, Jun 30, 2019 at 01:04:50AM +0200, vtolkm@googlemail.com wrote:
>>>>> On 30/06/2019 00:49, Andrew Lunn wrote:
>>>>>> On Sun, Jun 30, 2019 at 12:01:38AM +0200, vtolkm@googlemail.com wrote:
>>>>>>> * DSA MV88E6060
>>>>>>> * iproute2 v.5.0.0-2.0
>>>>>>> * OpenWRT 19.07 with kernel 4.14.131 armv7l
>>>>>> The mv88e6060 driver is very simple. It has no support for VLANs. It
>>>>>> does not even have support for offloading bridging between ports to
>>>>>> the switch.
>>>>>>
>>>>>> The data sheet for this device is open. So if you want to hack on the
>>>>>> driver, you could do.
>>>>>>
>>>>>> 	Andrew
>>>>> Are you sure? That is a bit confusing after reading
>>>>> https://lore.kernel.org/patchwork/patch/575746/
>>>> Quoting that patch:
>>>>
>>>> 	This commit implements the switchdev operations to add, delete
>>>> 	and dump VLANs for the Marvell 88E6352 and compatible switch
>>>> 	chips.
>>>>
>>>> Vivien added support for the 6352. That uses the mv88e6xxx driver, not
>>>> the mv88e6060. And by compatible switches, he meant those in the 6352
>>>> family, so 6172 6176 6240 6352 and probably the 6171 6175 6350 6351.
>>>>
>>>> 	Andrew
>>> A simple soul might infer that mv88e6xxx includes MV88E6060, at least
>>> that happened to me apparently (being said simpleton).
>>> That may as it be, and pardon my continued ignorance, how is it
>>> explained then that a command as
>>>
>>> # bridge v a dev {bridge} self vid {n} untagged pvid
>>>
>>> reflects in
>>>
>>> # bridge v s
>>> a/o
>>> # bridge mo
>>>
>>> ?
>>>
>>> If the commands are not implemented one would expect them to fail in the
>>> first place or not reflecting a change at all?
>>>
>>>
>> As stated in the initial message - kernel conf
>>
>> CONFIG_NET_DSA_MV88E6060=y
>> CONFIG_NET_DSA_MV88E6XXX=y
>> CONFIG_NET_DSA_MV88E6XXX_GLOBAL2=y
>>
> Just figured that it is a  Marvell 88E6176-TFJ2. Thus that cannot be the
> cause, also considering the that the commands are executing and changes
> being reflected.
>
> However, the loss of access to the node is a mystery.
>
> Apparently the filter is doing its job as in isolating access to the
> bridge if connecting though an enslaved device.
> And yet the bridge is still fully accessible from other devices that or
> not enslaved by that bridge. As if the filter is inverted.
>

The node's kernel log is showing during boot time repeated entries:

mv88e6085 f1072004.mdio-mii:10 lan{n}: configuring for phy/gmii link mode
mv88e6085 f1072004.mdio-mii:10: p3: hw VLAN 1 already used by br-{n}

Could there be a correlation with the described issue?

Is there way to debug the issue otherwise?






^ permalink raw reply

* [PATCH v4 bpf-next 4/4] tools/bpftool: switch map event_pipe to libbpf's perf_buffer
From: Andrii Nakryiko @ 2019-06-30  6:51 UTC (permalink / raw)
  To: andrii.nakryiko, ast, daniel, kernel-team, bpf, netdev,
	jakub.kicinski
  Cc: Andrii Nakryiko
In-Reply-To: <20190630065109.1794420-1-andriin@fb.com>

Switch event_pipe implementation to rely on new libbpf perf buffer API
(it's raw low-level variant).

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
---
 tools/bpf/bpftool/map_perf_ring.c | 201 ++++++++++--------------------
 1 file changed, 64 insertions(+), 137 deletions(-)

diff --git a/tools/bpf/bpftool/map_perf_ring.c b/tools/bpf/bpftool/map_perf_ring.c
index 0507dfaf7a8f..c291de8ef116 100644
--- a/tools/bpf/bpftool/map_perf_ring.c
+++ b/tools/bpf/bpftool/map_perf_ring.c
@@ -28,7 +28,7 @@
 
 #define MMAP_PAGE_CNT	16
 
-static bool stop;
+static volatile bool stop;
 
 struct event_ring_info {
 	int fd;
@@ -44,32 +44,44 @@ struct perf_event_sample {
 	unsigned char data[];
 };
 
+struct perf_event_lost {
+	struct perf_event_header header;
+	__u64 id;
+	__u64 lost;
+};
+
 static void int_exit(int signo)
 {
 	fprintf(stderr, "Stopping...\n");
 	stop = true;
 }
 
+struct event_pipe_ctx {
+	bool all_cpus;
+	int cpu;
+	int idx;
+};
+
 static enum bpf_perf_event_ret
-print_bpf_output(struct perf_event_header *event, void *private_data)
+print_bpf_output(void *private_data, int cpu, struct perf_event_header *event)
 {
-	struct perf_event_sample *e = container_of(event, struct perf_event_sample,
+	struct perf_event_sample *e = container_of(event,
+						   struct perf_event_sample,
 						   header);
-	struct event_ring_info *ring = private_data;
-	struct {
-		struct perf_event_header header;
-		__u64 id;
-		__u64 lost;
-	} *lost = (typeof(lost))event;
+	struct perf_event_lost *lost = container_of(event,
+						    struct perf_event_lost,
+						    header);
+	struct event_pipe_ctx *ctx = private_data;
+	int idx = ctx->all_cpus ? cpu : ctx->idx;
 
 	if (json_output) {
 		jsonw_start_object(json_wtr);
 		jsonw_name(json_wtr, "type");
 		jsonw_uint(json_wtr, e->header.type);
 		jsonw_name(json_wtr, "cpu");
-		jsonw_uint(json_wtr, ring->cpu);
+		jsonw_uint(json_wtr, cpu);
 		jsonw_name(json_wtr, "index");
-		jsonw_uint(json_wtr, ring->key);
+		jsonw_uint(json_wtr, idx);
 		if (e->header.type == PERF_RECORD_SAMPLE) {
 			jsonw_name(json_wtr, "timestamp");
 			jsonw_uint(json_wtr, e->time);
@@ -89,7 +101,7 @@ print_bpf_output(struct perf_event_header *event, void *private_data)
 		if (e->header.type == PERF_RECORD_SAMPLE) {
 			printf("== @%lld.%09lld CPU: %d index: %d =====\n",
 			       e->time / 1000000000ULL, e->time % 1000000000ULL,
-			       ring->cpu, ring->key);
+			       cpu, idx);
 			fprint_hex(stdout, e->data, e->size, " ");
 			printf("\n");
 		} else if (e->header.type == PERF_RECORD_LOST) {
@@ -103,87 +115,25 @@ print_bpf_output(struct perf_event_header *event, void *private_data)
 	return LIBBPF_PERF_EVENT_CONT;
 }
 
-static void
-perf_event_read(struct event_ring_info *ring, void **buf, size_t *buf_len)
-{
-	enum bpf_perf_event_ret ret;
-
-	ret = bpf_perf_event_read_simple(ring->mem,
-					 MMAP_PAGE_CNT * get_page_size(),
-					 get_page_size(), buf, buf_len,
-					 print_bpf_output, ring);
-	if (ret != LIBBPF_PERF_EVENT_CONT) {
-		fprintf(stderr, "perf read loop failed with %d\n", ret);
-		stop = true;
-	}
-}
-
-static int perf_mmap_size(void)
-{
-	return get_page_size() * (MMAP_PAGE_CNT + 1);
-}
-
-static void *perf_event_mmap(int fd)
-{
-	int mmap_size = perf_mmap_size();
-	void *base;
-
-	base = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-	if (base == MAP_FAILED) {
-		p_err("event mmap failed: %s\n", strerror(errno));
-		return NULL;
-	}
-
-	return base;
-}
-
-static void perf_event_unmap(void *mem)
-{
-	if (munmap(mem, perf_mmap_size()))
-		fprintf(stderr, "Can't unmap ring memory!\n");
-}
-
-static int bpf_perf_event_open(int map_fd, int key, int cpu)
+int do_event_pipe(int argc, char **argv)
 {
-	struct perf_event_attr attr = {
+	struct perf_event_attr perf_attr = {
 		.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_TIME,
 		.type = PERF_TYPE_SOFTWARE,
 		.config = PERF_COUNT_SW_BPF_OUTPUT,
+		.sample_period = 1,
+		.wakeup_events = 1,
 	};
-	int pmu_fd;
-
-	pmu_fd = sys_perf_event_open(&attr, -1, cpu, -1, 0);
-	if (pmu_fd < 0) {
-		p_err("failed to open perf event %d for CPU %d", key, cpu);
-		return -1;
-	}
-
-	if (bpf_map_update_elem(map_fd, &key, &pmu_fd, BPF_ANY)) {
-		p_err("failed to update map for event %d for CPU %d", key, cpu);
-		goto err_close;
-	}
-	if (ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) {
-		p_err("failed to enable event %d for CPU %d", key, cpu);
-		goto err_close;
-	}
-
-	return pmu_fd;
-
-err_close:
-	close(pmu_fd);
-	return -1;
-}
-
-int do_event_pipe(int argc, char **argv)
-{
-	int i, nfds, map_fd, index = -1, cpu = -1;
 	struct bpf_map_info map_info = {};
-	struct event_ring_info *rings;
-	size_t tmp_buf_sz = 0;
-	void *tmp_buf = NULL;
-	struct pollfd *pfds;
+	struct perf_buffer_raw_opts opts;
+	struct event_pipe_ctx ctx = {
+		.all_cpus = true,
+		.cpu = -1,
+		.idx = -1,
+	};
+	struct perf_buffer *pb;
 	__u32 map_info_len;
-	bool do_all = true;
+	int err, map_fd;
 
 	map_info_len = sizeof(map_info);
 	map_fd = map_parse_fd_and_info(&argc, &argv, &map_info, &map_info_len);
@@ -205,7 +155,7 @@ int do_event_pipe(int argc, char **argv)
 			char *endptr;
 
 			NEXT_ARG();
-			cpu = strtoul(*argv, &endptr, 0);
+			ctx.cpu = strtoul(*argv, &endptr, 0);
 			if (*endptr) {
 				p_err("can't parse %s as CPU ID", **argv);
 				goto err_close_map;
@@ -216,7 +166,7 @@ int do_event_pipe(int argc, char **argv)
 			char *endptr;
 
 			NEXT_ARG();
-			index = strtoul(*argv, &endptr, 0);
+			ctx.idx = strtoul(*argv, &endptr, 0);
 			if (*endptr) {
 				p_err("can't parse %s as index", **argv);
 				goto err_close_map;
@@ -228,45 +178,32 @@ int do_event_pipe(int argc, char **argv)
 			goto err_close_map;
 		}
 
-		do_all = false;
+		ctx.all_cpus = false;
 	}
 
-	if (!do_all) {
-		if (index == -1 || cpu == -1) {
+	if (!ctx.all_cpus) {
+		if (ctx.idx == -1 || ctx.cpu == -1) {
 			p_err("cpu and index must be specified together");
 			goto err_close_map;
 		}
-
-		nfds = 1;
 	} else {
-		nfds = min(get_possible_cpus(), map_info.max_entries);
-		cpu = 0;
-		index = 0;
+		ctx.cpu = 0;
+		ctx.idx = 0;
 	}
 
-	rings = calloc(nfds, sizeof(rings[0]));
-	if (!rings)
+	opts.attr = &perf_attr;
+	opts.event_cb = print_bpf_output;
+	opts.ctx = &ctx;
+	opts.cpu_cnt = ctx.all_cpus ? 0 : 1;
+	opts.cpus = &ctx.cpu;
+	opts.map_keys = &ctx.idx;
+
+	pb = perf_buffer__new_raw(map_fd, MMAP_PAGE_CNT, &opts);
+	err = libbpf_get_error(pb);
+	if (err) {
+		p_err("failed to create perf buffer: %s (%d)",
+		      strerror(err), err);
 		goto err_close_map;
-
-	pfds = calloc(nfds, sizeof(pfds[0]));
-	if (!pfds)
-		goto err_free_rings;
-
-	for (i = 0; i < nfds; i++) {
-		rings[i].cpu = cpu + i;
-		rings[i].key = index + i;
-
-		rings[i].fd = bpf_perf_event_open(map_fd, rings[i].key,
-						  rings[i].cpu);
-		if (rings[i].fd < 0)
-			goto err_close_fds_prev;
-
-		rings[i].mem = perf_event_mmap(rings[i].fd);
-		if (!rings[i].mem)
-			goto err_close_fds_current;
-
-		pfds[i].fd = rings[i].fd;
-		pfds[i].events = POLLIN;
 	}
 
 	signal(SIGINT, int_exit);
@@ -277,34 +214,24 @@ int do_event_pipe(int argc, char **argv)
 		jsonw_start_array(json_wtr);
 
 	while (!stop) {
-		poll(pfds, nfds, 200);
-		for (i = 0; i < nfds; i++)
-			perf_event_read(&rings[i], &tmp_buf, &tmp_buf_sz);
+		err = perf_buffer__poll(pb, 200);
+		if (err < 0 && err != -EINTR) {
+			p_err("perf buffer polling failed: %s (%d)",
+			      strerror(err), err);
+			goto err_close_pb;
+		}
 	}
-	free(tmp_buf);
 
 	if (json_output)
 		jsonw_end_array(json_wtr);
 
-	for (i = 0; i < nfds; i++) {
-		perf_event_unmap(rings[i].mem);
-		close(rings[i].fd);
-	}
-	free(pfds);
-	free(rings);
+	perf_buffer__free(pb);
 	close(map_fd);
 
 	return 0;
 
-err_close_fds_prev:
-	while (i--) {
-		perf_event_unmap(rings[i].mem);
-err_close_fds_current:
-		close(rings[i].fd);
-	}
-	free(pfds);
-err_free_rings:
-	free(rings);
+err_close_pb:
+	perf_buffer__free(pb);
 err_close_map:
 	close(map_fd);
 	return -1;
-- 
2.17.1


^ permalink raw reply related

* [PATCH v4 bpf-next 1/4] libbpf: add perf buffer API
From: Andrii Nakryiko @ 2019-06-30  6:51 UTC (permalink / raw)
  To: andrii.nakryiko, ast, daniel, kernel-team, bpf, netdev,
	jakub.kicinski
  Cc: Andrii Nakryiko
In-Reply-To: <20190630065109.1794420-1-andriin@fb.com>

BPF_MAP_TYPE_PERF_EVENT_ARRAY map is often used to send data from BPF program
to user space for additional processing. libbpf already has very low-level API
to read single CPU perf buffer, bpf_perf_event_read_simple(), but it's hard to
use and requires a lot of code to set everything up. This patch adds
perf_buffer abstraction on top of it, abstracting setting up and polling
per-CPU logic into simple and convenient API, similar to what BCC provides.

perf_buffer__new() sets up per-CPU ring buffers and updates corresponding BPF
map entries. It accepts two user-provided callbacks: one for handling raw
samples and one for get notifications of lost samples due to buffer overflow.

perf_buffer__new_raw() is similar, but provides more control over how
perf events are set up (by accepting user-provided perf_event_attr), how
they are handled (perf_event_header pointer is passed directly to
user-provided callback), and on which CPUs ring buffers are created
(it's possible to provide a list of CPUs and corresponding map keys to
update). This API allows advanced users fuller control.

perf_buffer__poll() is used to fetch ring buffer data across all CPUs,
utilizing epoll instance.

perf_buffer__free() does corresponding clean up and unsets FDs from BPF map.

All APIs are not thread-safe. User should ensure proper locking/coordination if
used in multi-threaded set up.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
---
 tools/lib/bpf/libbpf.c   | 366 +++++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h   |  49 ++++++
 tools/lib/bpf/libbpf.map |   4 +
 3 files changed, 419 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index f8c7a7ecb35e..e2bf3eedd0ae 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -32,7 +32,9 @@
 #include <linux/limits.h>
 #include <linux/perf_event.h>
 #include <linux/ring_buffer.h>
+#include <sys/epoll.h>
 #include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/vfs.h>
@@ -4348,6 +4350,370 @@ bpf_perf_event_read_simple(void *mmap_mem, size_t mmap_size, size_t page_size,
 	return ret;
 }
 
+struct perf_buffer;
+
+struct perf_buffer_params {
+	struct perf_event_attr *attr;
+	/* if event_cb is specified, it takes precendence */
+	perf_buffer_event_fn event_cb;
+	/* sample_cb and lost_cb are higher-level common-case callbacks */
+	perf_buffer_sample_fn sample_cb;
+	perf_buffer_lost_fn lost_cb;
+	void *ctx;
+	int cpu_cnt;
+	int *cpus;
+	int *map_keys;
+};
+
+struct perf_cpu_buf {
+	struct perf_buffer *pb;
+	void *base; /* mmap()'ed memory */
+	void *buf; /* for reconstructing segmented data */
+	size_t buf_size;
+	int fd;
+	int cpu;
+	int map_key;
+};
+
+struct perf_buffer {
+	perf_buffer_event_fn event_cb;
+	perf_buffer_sample_fn sample_cb;
+	perf_buffer_lost_fn lost_cb;
+	void *ctx; /* passed into callbacks */
+
+	size_t page_size;
+	size_t mmap_size;
+	struct perf_cpu_buf **cpu_bufs;
+	struct epoll_event *events;
+	int cpu_cnt;
+	int epoll_fd; /* perf event FD */
+	int map_fd; /* BPF_MAP_TYPE_PERF_EVENT_ARRAY BPF map FD */
+};
+
+static void perf_buffer__free_cpu_buf(struct perf_buffer *pb,
+				      struct perf_cpu_buf *cpu_buf)
+{
+	if (!cpu_buf)
+		return;
+	if (cpu_buf->base &&
+	    munmap(cpu_buf->base, pb->mmap_size + pb->page_size))
+		pr_warning("failed to munmap cpu_buf #%d\n", cpu_buf->cpu);
+	if (cpu_buf->fd >= 0) {
+		ioctl(cpu_buf->fd, PERF_EVENT_IOC_DISABLE, 0);
+		close(cpu_buf->fd);
+	}
+	free(cpu_buf->buf);
+	free(cpu_buf);
+}
+
+void perf_buffer__free(struct perf_buffer *pb)
+{
+	int i;
+
+	if (!pb)
+		return;
+	if (pb->cpu_bufs) {
+		for (i = 0; i < pb->cpu_cnt && pb->cpu_bufs[i]; i++) {
+			struct perf_cpu_buf *cpu_buf = pb->cpu_bufs[i];
+
+			bpf_map_delete_elem(pb->map_fd, &cpu_buf->map_key);
+			perf_buffer__free_cpu_buf(pb, cpu_buf);
+		}
+		free(pb->cpu_bufs);
+	}
+	if (pb->epoll_fd >= 0)
+		close(pb->epoll_fd);
+	free(pb->events);
+	free(pb);
+}
+
+static struct perf_cpu_buf *
+perf_buffer__open_cpu_buf(struct perf_buffer *pb, struct perf_event_attr *attr,
+			  int cpu, int map_key)
+{
+	struct perf_cpu_buf *cpu_buf;
+	char msg[STRERR_BUFSIZE];
+	int err;
+
+	cpu_buf = calloc(1, sizeof(*cpu_buf));
+	if (!cpu_buf)
+		return ERR_PTR(-ENOMEM);
+
+	cpu_buf->pb = pb;
+	cpu_buf->cpu = cpu;
+	cpu_buf->map_key = map_key;
+
+	cpu_buf->fd = syscall(__NR_perf_event_open, attr, -1 /* pid */, cpu,
+			      -1, PERF_FLAG_FD_CLOEXEC);
+	if (cpu_buf->fd < 0) {
+		err = -errno;
+		pr_warning("failed to open perf buffer event on cpu #%d: %s\n",
+			   cpu, libbpf_strerror_r(err, msg, sizeof(msg)));
+		goto error;
+	}
+
+	cpu_buf->base = mmap(NULL, pb->mmap_size + pb->page_size,
+			     PROT_READ | PROT_WRITE, MAP_SHARED,
+			     cpu_buf->fd, 0);
+	if (cpu_buf->base == MAP_FAILED) {
+		cpu_buf->base = NULL;
+		err = -errno;
+		pr_warning("failed to mmap perf buffer on cpu #%d: %s\n",
+			   cpu, libbpf_strerror_r(err, msg, sizeof(msg)));
+		goto error;
+	}
+
+	if (ioctl(cpu_buf->fd, PERF_EVENT_IOC_ENABLE, 0) < 0) {
+		err = -errno;
+		pr_warning("failed to enable perf buffer event on cpu #%d: %s\n",
+			   cpu, libbpf_strerror_r(err, msg, sizeof(msg)));
+		goto error;
+	}
+
+	return cpu_buf;
+
+error:
+	perf_buffer__free_cpu_buf(pb, cpu_buf);
+	return (struct perf_cpu_buf *)ERR_PTR(err);
+}
+
+static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt,
+					      struct perf_buffer_params *p);
+
+struct perf_buffer *perf_buffer__new(int map_fd, size_t page_cnt,
+				     const struct perf_buffer_opts *opts)
+{
+	struct perf_buffer_params p = {};
+	struct perf_event_attr attr = {
+		.config = PERF_COUNT_SW_BPF_OUTPUT,
+		.type = PERF_TYPE_SOFTWARE,
+		.sample_type = PERF_SAMPLE_RAW,
+		.sample_period = 1,
+		.wakeup_events = 1,
+	};
+
+	p.attr = &attr;
+	p.sample_cb = opts ? opts->sample_cb : NULL;
+	p.lost_cb = opts ? opts->lost_cb : NULL;
+	p.ctx = opts ? opts->ctx : NULL;
+
+	return __perf_buffer__new(map_fd, page_cnt, &p);
+}
+
+struct perf_buffer *
+perf_buffer__new_raw(int map_fd, size_t page_cnt,
+		     const struct perf_buffer_raw_opts *opts)
+{
+	struct perf_buffer_params p = {};
+
+	p.attr = opts->attr;
+	p.event_cb = opts->event_cb;
+	p.ctx = opts->ctx;
+	p.cpu_cnt = opts->cpu_cnt;
+	p.cpus = opts->cpus;
+	p.map_keys = opts->map_keys;
+
+	return __perf_buffer__new(map_fd, page_cnt, &p);
+}
+
+static struct perf_buffer *__perf_buffer__new(int map_fd, size_t page_cnt,
+					      struct perf_buffer_params *p)
+{
+	struct bpf_map_info map = {};
+	char msg[STRERR_BUFSIZE];
+	struct perf_buffer *pb;
+	__u32 map_info_len;
+	int err, i;
+
+	if (page_cnt & (page_cnt - 1)) {
+		pr_warning("page count should be power of two, but is %zu\n",
+			   page_cnt);
+		return ERR_PTR(-EINVAL);
+	}
+
+	map_info_len = sizeof(map);
+	err = bpf_obj_get_info_by_fd(map_fd, &map, &map_info_len);
+	if (err) {
+		err = -errno;
+		pr_warning("failed to get map info for map FD %d: %s\n",
+			   map_fd, libbpf_strerror_r(err, msg, sizeof(msg)));
+		return ERR_PTR(err);
+	}
+
+	if (map.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) {
+		pr_warning("map '%s' should be BPF_MAP_TYPE_PERF_EVENT_ARRAY\n",
+			   map.name);
+		return ERR_PTR(-EINVAL);
+	}
+
+	pb = calloc(1, sizeof(*pb));
+	if (!pb)
+		return ERR_PTR(-ENOMEM);
+
+	pb->event_cb = p->event_cb;
+	pb->sample_cb = p->sample_cb;
+	pb->lost_cb = p->lost_cb;
+	pb->ctx = p->ctx;
+
+	pb->page_size = getpagesize();
+	pb->mmap_size = pb->page_size * page_cnt;
+	pb->map_fd = map_fd;
+
+	pb->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+	if (pb->epoll_fd < 0) {
+		err = -errno;
+		pr_warning("failed to create epoll instance: %s\n",
+			   libbpf_strerror_r(err, msg, sizeof(msg)));
+		goto error;
+	}
+
+	if (p->cpu_cnt > 0) {
+		pb->cpu_cnt = p->cpu_cnt;
+	} else {
+		pb->cpu_cnt = libbpf_num_possible_cpus();
+		if (pb->cpu_cnt < 0) {
+			err = pb->cpu_cnt;
+			goto error;
+		}
+		if (map.max_entries < pb->cpu_cnt)
+			pb->cpu_cnt = map.max_entries;
+	}
+
+	pb->events = calloc(pb->cpu_cnt, sizeof(*pb->events));
+	if (!pb->events) {
+		err = -ENOMEM;
+		pr_warning("failed to allocate events: out of memory\n");
+		goto error;
+	}
+	pb->cpu_bufs = calloc(pb->cpu_cnt, sizeof(*pb->cpu_bufs));
+	if (!pb->cpu_bufs) {
+		err = -ENOMEM;
+		pr_warning("failed to allocate buffers: out of memory\n");
+		goto error;
+	}
+
+	for (i = 0; i < pb->cpu_cnt; i++) {
+		struct perf_cpu_buf *cpu_buf;
+		int cpu, map_key;
+
+		cpu = p->cpu_cnt > 0 ? p->cpus[i] : i;
+		map_key = p->cpu_cnt > 0 ? p->map_keys[i] : i;
+
+		cpu_buf = perf_buffer__open_cpu_buf(pb, p->attr, cpu, map_key);
+		if (IS_ERR(cpu_buf)) {
+			err = PTR_ERR(cpu_buf);
+			goto error;
+		}
+
+		pb->cpu_bufs[i] = cpu_buf;
+
+		err = bpf_map_update_elem(pb->map_fd, &map_key,
+					  &cpu_buf->fd, 0);
+		if (err) {
+			err = -errno;
+			pr_warning("failed to set cpu #%d, key %d -> perf FD %d: %s\n",
+				   cpu, map_key, cpu_buf->fd,
+				   libbpf_strerror_r(err, msg, sizeof(msg)));
+			goto error;
+		}
+
+		pb->events[i].events = EPOLLIN;
+		pb->events[i].data.ptr = cpu_buf;
+		if (epoll_ctl(pb->epoll_fd, EPOLL_CTL_ADD, cpu_buf->fd,
+			      &pb->events[i]) < 0) {
+			err = -errno;
+			pr_warning("failed to epoll_ctl cpu #%d perf FD %d: %s\n",
+				   cpu, cpu_buf->fd,
+				   libbpf_strerror_r(err, msg, sizeof(msg)));
+			goto error;
+		}
+	}
+
+	return pb;
+
+error:
+	if (pb)
+		perf_buffer__free(pb);
+	return ERR_PTR(err);
+}
+
+struct perf_sample_raw {
+	struct perf_event_header header;
+	uint32_t size;
+	char data[0];
+};
+
+struct perf_sample_lost {
+	struct perf_event_header header;
+	uint64_t id;
+	uint64_t lost;
+	uint64_t sample_id;
+};
+
+static enum bpf_perf_event_ret
+perf_buffer__process_record(struct perf_event_header *e, void *ctx)
+{
+	struct perf_cpu_buf *cpu_buf = ctx;
+	struct perf_buffer *pb = cpu_buf->pb;
+	void *data = e;
+
+	/* user wants full control over parsing perf event */
+	if (pb->event_cb)
+		return pb->event_cb(pb->ctx, cpu_buf->cpu, e);
+
+	switch (e->type) {
+	case PERF_RECORD_SAMPLE: {
+		struct perf_sample_raw *s = data;
+
+		if (pb->sample_cb)
+			pb->sample_cb(pb->ctx, cpu_buf->cpu, s->data, s->size);
+		break;
+	}
+	case PERF_RECORD_LOST: {
+		struct perf_sample_lost *s = data;
+
+		if (pb->lost_cb)
+			pb->lost_cb(pb->ctx, cpu_buf->cpu, s->lost);
+		break;
+	}
+	default:
+		pr_warning("unknown perf sample type %d\n", e->type);
+		return LIBBPF_PERF_EVENT_ERROR;
+	}
+	return LIBBPF_PERF_EVENT_CONT;
+}
+
+static int perf_buffer__process_records(struct perf_buffer *pb,
+					struct perf_cpu_buf *cpu_buf)
+{
+	enum bpf_perf_event_ret ret;
+
+	ret = bpf_perf_event_read_simple(cpu_buf->base, pb->mmap_size,
+					 pb->page_size, &cpu_buf->buf,
+					 &cpu_buf->buf_size,
+					 perf_buffer__process_record, cpu_buf);
+	if (ret != LIBBPF_PERF_EVENT_CONT)
+		return ret;
+	return 0;
+}
+
+int perf_buffer__poll(struct perf_buffer *pb, int timeout_ms)
+{
+	int cnt, err;
+
+	cnt = epoll_wait(pb->epoll_fd, pb->events, pb->cpu_cnt, timeout_ms);
+	for (int i = 0; i < cnt; i++) {
+		struct perf_cpu_buf *cpu_buf = pb->events[i].data.ptr;
+
+		err = perf_buffer__process_records(pb, cpu_buf);
+		if (err) {
+			pr_warning("error while processing records: %d\n", err);
+			return err;
+		}
+	}
+	return cnt < 0 ? -errno : cnt;
+}
+
 struct bpf_prog_info_array_desc {
 	int	array_offset;	/* e.g. offset of jited_prog_insns */
 	int	count_offset;	/* e.g. offset of jited_prog_len */
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index f55933784f95..5cbf459ece0b 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -358,6 +358,26 @@ LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type,
 LIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);
 LIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags);
 
+struct perf_buffer;
+
+typedef void (*perf_buffer_sample_fn)(void *ctx, int cpu,
+				      void *data, __u32 size);
+typedef void (*perf_buffer_lost_fn)(void *ctx, int cpu, __u64 cnt);
+
+/* common use perf buffer options */
+struct perf_buffer_opts {
+	/* if specified, sample_cb is called for each sample */
+	perf_buffer_sample_fn sample_cb;
+	/* if specified, lost_cb is called for each batch of lost samples */
+	perf_buffer_lost_fn lost_cb;
+	/* ctx is provided to sample_cb and lost_cb */
+	void *ctx;
+};
+
+LIBBPF_API struct perf_buffer *
+perf_buffer__new(int map_fd, size_t page_cnt,
+		 const struct perf_buffer_opts *opts);
+
 enum bpf_perf_event_ret {
 	LIBBPF_PERF_EVENT_DONE	= 0,
 	LIBBPF_PERF_EVENT_ERROR	= -1,
@@ -365,6 +385,35 @@ enum bpf_perf_event_ret {
 };
 
 struct perf_event_header;
+
+typedef enum bpf_perf_event_ret
+(*perf_buffer_event_fn)(void *ctx, int cpu, struct perf_event_header *event);
+
+/* raw perf buffer options, giving most power and control */
+struct perf_buffer_raw_opts {
+	/* perf event attrs passed directly into perf_event_open() */
+	struct perf_event_attr *attr;
+	/* raw event callback */
+	perf_buffer_event_fn event_cb;
+	/* ctx is provided to event_cb */
+	void *ctx;
+	/* if cpu_cnt == 0, open all on all possible CPUs (up to the number of
+	 * max_entries of given PERF_EVENT_ARRAY map)
+	 */
+	int cpu_cnt;
+	/* if cpu_cnt > 0, cpus is an array of CPUs to open ring buffers on */
+	int *cpus;
+	/* if cpu_cnt > 0, map_keys specify map keys to set per-CPU FDs for */
+	int *map_keys;
+};
+
+LIBBPF_API struct perf_buffer *
+perf_buffer__new_raw(int map_fd, size_t page_cnt,
+		     const struct perf_buffer_raw_opts *opts);
+
+LIBBPF_API void perf_buffer__free(struct perf_buffer *pb);
+LIBBPF_API int perf_buffer__poll(struct perf_buffer *pb, int timeout_ms);
+
 typedef enum bpf_perf_event_ret
 	(*bpf_perf_event_print_t)(struct perf_event_header *hdr,
 				  void *private_data);
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index e6b7d4edbc93..f9d316e873d8 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -179,4 +179,8 @@ LIBBPF_0.0.4 {
 		btf_dump__new;
 		btf__parse_elf;
 		libbpf_num_possible_cpus;
+		perf_buffer__free;
+		perf_buffer__new;
+		perf_buffer__new_raw;
+		perf_buffer__poll;
 } LIBBPF_0.0.3;
-- 
2.17.1


^ permalink raw reply related

* [PATCH v4 bpf-next 3/4] selftests/bpf: test perf buffer API
From: Andrii Nakryiko @ 2019-06-30  6:51 UTC (permalink / raw)
  To: andrii.nakryiko, ast, daniel, kernel-team, bpf, netdev,
	jakub.kicinski
  Cc: Andrii Nakryiko
In-Reply-To: <20190630065109.1794420-1-andriin@fb.com>

Add test verifying perf buffer API functionality.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
---
 .../selftests/bpf/prog_tests/perf_buffer.c    | 94 +++++++++++++++++++
 .../selftests/bpf/progs/test_perf_buffer.c    | 29 ++++++
 2 files changed, 123 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/perf_buffer.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_perf_buffer.c

diff --git a/tools/testing/selftests/bpf/prog_tests/perf_buffer.c b/tools/testing/selftests/bpf/prog_tests/perf_buffer.c
new file mode 100644
index 000000000000..64556ab0d1a9
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/perf_buffer.c
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <pthread.h>
+#include <sched.h>
+#include <sys/socket.h>
+#include <test_progs.h>
+
+static void on_sample(void *ctx, int cpu, void *data, __u32 size)
+{
+	int cpu_data = *(int *)data, duration = 0;
+	cpu_set_t *cpu_seen = ctx;
+
+	if (cpu_data != cpu)
+		CHECK(cpu_data != cpu, "check_cpu_data",
+		      "cpu_data %d != cpu %d\n", cpu_data, cpu);
+
+	CPU_SET(cpu, cpu_seen);
+}
+
+void test_perf_buffer(void)
+{
+	int err, prog_fd, nr_cpus, i, duration = 0;
+	const char *prog_name = "kprobe/sys_nanosleep";
+	const char *file = "./test_perf_buffer.o";
+	struct perf_buffer_opts pb_opts = {};
+	struct bpf_map *perf_buf_map;
+	cpu_set_t cpu_set, cpu_seen;
+	struct bpf_program *prog;
+	struct bpf_object *obj;
+	struct perf_buffer *pb;
+	struct bpf_link *link;
+
+	nr_cpus = libbpf_num_possible_cpus();
+	if (CHECK(nr_cpus < 0, "nr_cpus", "err %d\n", nr_cpus))
+		return;
+
+	/* load program */
+	err = bpf_prog_load(file, BPF_PROG_TYPE_KPROBE, &obj, &prog_fd);
+	if (CHECK(err, "obj_load", "err %d errno %d\n", err, errno))
+		return;
+
+	prog = bpf_object__find_program_by_title(obj, prog_name);
+	if (CHECK(!prog, "find_probe", "prog '%s' not found\n", prog_name))
+		goto out_close;
+
+	/* load map */
+	perf_buf_map = bpf_object__find_map_by_name(obj, "perf_buf_map");
+	if (CHECK(!perf_buf_map, "find_perf_buf_map", "not found\n"))
+		goto out_close;
+
+	/* attach kprobe */
+	link = bpf_program__attach_kprobe(prog, false /* retprobe */,
+					      "sys_nanosleep");
+	if (CHECK(IS_ERR(link), "attach_kprobe", "err %ld\n", PTR_ERR(link)))
+		goto out_close;
+
+	/* set up perf buffer */
+	pb_opts.sample_cb = on_sample;
+	pb_opts.ctx = &cpu_seen;
+	pb = perf_buffer__new(bpf_map__fd(perf_buf_map), 1, &pb_opts);
+	if (CHECK(IS_ERR(pb), "perf_buf__new", "err %ld\n", PTR_ERR(pb)))
+		goto out_detach;
+
+	/* trigger kprobe on every CPU */
+	CPU_ZERO(&cpu_seen);
+	for (i = 0; i < nr_cpus; i++) {
+		CPU_ZERO(&cpu_set);
+		CPU_SET(i, &cpu_set);
+
+		err = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set),
+					     &cpu_set);
+		if (err && CHECK(err, "set_affinity", "cpu #%d, err %d\n",
+				 i, err))
+			goto out_detach;
+
+		usleep(1);
+	}
+
+	/* read perf buffer */
+	err = perf_buffer__poll(pb, 100);
+	if (CHECK(err < 0, "perf_buffer__poll", "err %d\n", err))
+		goto out_free_pb;
+
+	if (CHECK(CPU_COUNT(&cpu_seen) != nr_cpus, "seen_cpu_cnt",
+		  "expect %d, seen %d\n", nr_cpus, CPU_COUNT(&cpu_seen)))
+		goto out_free_pb;
+
+out_free_pb:
+	perf_buffer__free(pb);
+out_detach:
+	bpf_link__destroy(link);
+out_close:
+	bpf_object__close(obj);
+}
diff --git a/tools/testing/selftests/bpf/progs/test_perf_buffer.c b/tools/testing/selftests/bpf/progs/test_perf_buffer.c
new file mode 100644
index 000000000000..8609f0031bc0
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/test_perf_buffer.c
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Facebook
+
+#include <linux/ptrace.h>
+#include <linux/bpf.h>
+#include "bpf_helpers.h"
+
+struct {
+	int type;
+	int key_size;
+	int value_size;
+} perf_buf_map SEC(".maps") = {
+	.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
+	.key_size = sizeof(int),
+	.value_size = sizeof(int),
+};
+
+SEC("kprobe/sys_nanosleep")
+int handle_sys_nanosleep_entry(struct pt_regs *ctx)
+{
+	int cpu = bpf_get_smp_processor_id();
+
+	bpf_perf_event_output(ctx, &perf_buf_map, BPF_F_CURRENT_CPU,
+			      &cpu, sizeof(cpu));
+	return 0;
+}
+
+char _license[] SEC("license") = "GPL";
+__u32 _version SEC("version") = 1;
-- 
2.17.1


^ permalink raw reply related

* [PATCH v4 bpf-next 2/4] libbpf: auto-set PERF_EVENT_ARRAY size to number of CPUs
From: Andrii Nakryiko @ 2019-06-30  6:51 UTC (permalink / raw)
  To: andrii.nakryiko, ast, daniel, kernel-team, bpf, netdev,
	jakub.kicinski
  Cc: Andrii Nakryiko
In-Reply-To: <20190630065109.1794420-1-andriin@fb.com>

For BPF_MAP_TYPE_PERF_EVENT_ARRAY typically correct size is number of
possible CPUs. This is impossible to specify at compilation time. This
change adds automatic setting of PERF_EVENT_ARRAY size to number of
system CPUs, unless non-zero size is specified explicitly. This allows
to adjust size for advanced specific cases, while providing convenient
and logical defaults.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
---
 tools/lib/bpf/libbpf.c | 31 ++++++++++++++++++++++++-------
 1 file changed, 24 insertions(+), 7 deletions(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index e2bf3eedd0ae..a5ae7207d19a 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -2118,6 +2118,7 @@ static int
 bpf_object__create_maps(struct bpf_object *obj)
 {
 	struct bpf_create_map_attr create_attr = {};
+	int nr_cpus = 0;
 	unsigned int i;
 	int err;
 
@@ -2140,7 +2141,22 @@ bpf_object__create_maps(struct bpf_object *obj)
 		create_attr.map_flags = def->map_flags;
 		create_attr.key_size = def->key_size;
 		create_attr.value_size = def->value_size;
-		create_attr.max_entries = def->max_entries;
+		if (def->type == BPF_MAP_TYPE_PERF_EVENT_ARRAY &&
+		    !def->max_entries) {
+			if (!nr_cpus)
+				nr_cpus = libbpf_num_possible_cpus();
+			if (nr_cpus < 0) {
+				pr_warning("failed to determine number of system CPUs: %d\n",
+					   nr_cpus);
+				err = nr_cpus;
+				goto err_out;
+			}
+			pr_debug("map '%s': setting size to %d\n",
+				 map->name, nr_cpus);
+			create_attr.max_entries = nr_cpus;
+		} else {
+			create_attr.max_entries = def->max_entries;
+		}
 		create_attr.btf_fd = 0;
 		create_attr.btf_key_type_id = 0;
 		create_attr.btf_value_type_id = 0;
@@ -2157,9 +2173,10 @@ bpf_object__create_maps(struct bpf_object *obj)
 		*pfd = bpf_create_map_xattr(&create_attr);
 		if (*pfd < 0 && (create_attr.btf_key_type_id ||
 				 create_attr.btf_value_type_id)) {
-			cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));
+			err = -errno;
+			cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg));
 			pr_warning("Error in bpf_create_map_xattr(%s):%s(%d). Retrying without BTF.\n",
-				   map->name, cp, errno);
+				   map->name, cp, err);
 			create_attr.btf_fd = 0;
 			create_attr.btf_key_type_id = 0;
 			create_attr.btf_value_type_id = 0;
@@ -2171,11 +2188,11 @@ bpf_object__create_maps(struct bpf_object *obj)
 		if (*pfd < 0) {
 			size_t j;
 
-			err = *pfd;
+			err = -errno;
 err_out:
-			cp = libbpf_strerror_r(errno, errmsg, sizeof(errmsg));
-			pr_warning("failed to create map (name: '%s'): %s\n",
-				   map->name, cp);
+			cp = libbpf_strerror_r(err, errmsg, sizeof(errmsg));
+			pr_warning("failed to create map (name: '%s'): %s(%d)\n",
+				   map->name, cp, err);
 			for (j = 0; j < i; j++)
 				zclose(obj->maps[j].fd);
 			return err;
-- 
2.17.1


^ permalink raw reply related

* [PATCH v4 bpf-next 0/4] libbpf: add perf buffer abstraction and API
From: Andrii Nakryiko @ 2019-06-30  6:51 UTC (permalink / raw)
  To: andrii.nakryiko, ast, daniel, kernel-team, bpf, netdev,
	jakub.kicinski
  Cc: Andrii Nakryiko

This patchset adds a high-level API for setting up and polling perf buffers
associated with BPF_MAP_TYPE_PERF_EVENT_ARRAY map. Details of APIs are
described in corresponding commit.

Patch #1 adds a set of APIs to set up and work with perf buffer.
Patch #2 enhances libbpf to support auto-setting PERF_EVENT_ARRAY map size.
Patch #3 adds test.
Patch #4 converts bpftool map event_pipe to new API.

v3->v4:
- fixed bpftool event_pipe cmd error handling (Jakub);

v2->v3:
- added perf_buffer__new_raw for more low-level control;
- converted bpftool map event_pipe to new API (Daniel);
- fixed bug with error handling in create_maps (Song);

v1->v2:
- add auto-sizing of PERF_EVENT_ARRAY maps;

Andrii Nakryiko (4):
  libbpf: add perf buffer API
  libbpf: auto-set PERF_EVENT_ARRAY size to number of CPUs
  selftests/bpf: test perf buffer API
  tools/bpftool: switch map event_pipe to libbpf's perf_buffer

 tools/bpf/bpftool/map_perf_ring.c             | 201 +++------
 tools/lib/bpf/libbpf.c                        | 397 +++++++++++++++++-
 tools/lib/bpf/libbpf.h                        |  49 +++
 tools/lib/bpf/libbpf.map                      |   4 +
 .../selftests/bpf/prog_tests/perf_buffer.c    |  94 +++++
 .../selftests/bpf/progs/test_perf_buffer.c    |  29 ++
 6 files changed, 630 insertions(+), 144 deletions(-)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/perf_buffer.c
 create mode 100644 tools/testing/selftests/bpf/progs/test_perf_buffer.c

-- 
2.17.1


^ permalink raw reply

* Re: [PATCH v3 bpf-next 4/4] tools/bpftool: switch map event_pipe to libbpf's perf_buffer
From: Andrii Nakryiko @ 2019-06-30  6:44 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Andrii Nakryiko, Alexei Starovoitov, Daniel Borkmann, bpf,
	Networking, Kernel Team, Song Liu
In-Reply-To: <20190629112453.2c46a114@cakuba.netronome.com>

Re-sending as plain text, first time it somehow turned into HTML... :(


On Sat, Jun 29, 2019 at 11:24 AM Jakub Kicinski
<jakub.kicinski@netronome.com> wrote:
>
> On Fri, 28 Jun 2019 22:53:09 -0700, Andrii Nakryiko wrote:
> >       map_info_len = sizeof(map_info);
> >       map_fd = map_parse_fd_and_info(&argc, &argv, &map_info, &map_info_len);
> > -     if (map_fd < 0)
> > +     if (map_fd < 0) {
> > +             p_err("failed to get map info");
>
> Can't do, map_parse_fd_and_info() prints an error already, we can't
> have multiple errors in JSON.

Oh.. I need to be more careful with printing error in bpftool due to
this JSON business... Thanks!

>
> >               return -1;
> > +     }
> >
> >       if (map_info.type != BPF_MAP_TYPE_PERF_EVENT_ARRAY) {
> >               p_err("map is not a perf event array");
> > @@ -205,7 +157,7 @@ int do_event_pipe(int argc, char **argv)
> >                       char *endptr;
> >
> >                       NEXT_ARG();
> > -                     cpu = strtoul(*argv, &endptr, 0);
> > +                     ctx.cpu = strtoul(*argv, &endptr, 0);
> >                       if (*endptr) {
> >                               p_err("can't parse %s as CPU ID", **argv);
> >                               goto err_close_map;
> > @@ -216,7 +168,7 @@ int do_event_pipe(int argc, char **argv)
> >                       char *endptr;
> >
> >                       NEXT_ARG();
> > -                     index = strtoul(*argv, &endptr, 0);
> > +                     ctx.idx = strtoul(*argv, &endptr, 0);
> >                       if (*endptr) {
> >                               p_err("can't parse %s as index", **argv);
> >                               goto err_close_map;
> > @@ -228,45 +180,32 @@ int do_event_pipe(int argc, char **argv)
> >                       goto err_close_map;
> >               }
> >
> > -             do_all = false;
> > +             ctx.all_cpus = false;
> >       }
> >
> > -     if (!do_all) {
> > -             if (index == -1 || cpu == -1) {
> > +     if (!ctx.all_cpus) {
> > +             if (ctx.idx == -1 || ctx.cpu == -1) {
> >                       p_err("cpu and index must be specified together");
> >                       goto err_close_map;
>
> Now that you look at err looks like we're missing an err = -1 assignment
> here?  but...

No need, see below.

>
> >               }
> > -
> > -             nfds = 1;
> >       } else {
> > -             nfds = min(get_possible_cpus(), map_info.max_entries);
> > -             cpu = 0;
> > -             index = 0;
> > +             ctx.cpu = 0;
> > +             ctx.idx = 0;
> >       }
> >
> > -     rings = calloc(nfds, sizeof(rings[0]));
> > -     if (!rings)
> > +     opts.attr = &perf_attr;
> > +     opts.event_cb = print_bpf_output;
> > +     opts.ctx = &ctx;
> > +     opts.cpu_cnt = ctx.all_cpus ? 0 : 1;
> > +     opts.cpus = &ctx.cpu;
> > +     opts.map_keys = &ctx.idx;
> > +
> > +     pb = perf_buffer__new_raw(map_fd, MMAP_PAGE_CNT, &opts);
> > +     err = libbpf_get_error(pb);
> > +     if (err) {
> > +             p_err("failed to create perf buffer: %s (%d)",
> > +                   strerror(err), err);
> >               goto err_close_map;
> > -
> > -     pfds = calloc(nfds, sizeof(pfds[0]));
> > -     if (!pfds)
> > -             goto err_free_rings;
> > -
> > -     for (i = 0; i < nfds; i++) {
> > -             rings[i].cpu = cpu + i;
> > -             rings[i].key = index + i;
> > -
> > -             rings[i].fd = bpf_perf_event_open(map_fd, rings[i].key,
> > -                                               rings[i].cpu);
> > -             if (rings[i].fd < 0)
> > -                     goto err_close_fds_prev;
> > -
> > -             rings[i].mem = perf_event_mmap(rings[i].fd);
> > -             if (!rings[i].mem)
> > -                     goto err_close_fds_current;
> > -
> > -             pfds[i].fd = rings[i].fd;
> > -             pfds[i].events = POLLIN;
> >       }
> >
> >       signal(SIGINT, int_exit);
> > @@ -277,35 +216,25 @@ int do_event_pipe(int argc, char **argv)
> >               jsonw_start_array(json_wtr);
> >
> >       while (!stop) {
> > -             poll(pfds, nfds, 200);
> > -             for (i = 0; i < nfds; i++)
> > -                     perf_event_read(&rings[i], &tmp_buf, &tmp_buf_sz);
> > +             err = perf_buffer__poll(pb, 200);
> > +             if (err < 0 && err != -EINTR) {
> > +                     p_err("perf buffer polling failed: %s (%d)",
> > +                           strerror(err), err);
> > +                     goto err_close_pb;
> > +             }
> >       }
> > -     free(tmp_buf);
> >
> >       if (json_output)
> >               jsonw_end_array(json_wtr);
> >
> > -     for (i = 0; i < nfds; i++) {
> > -             perf_event_unmap(rings[i].mem);
> > -             close(rings[i].fd);
> > -     }
> > -     free(pfds);
> > -     free(rings);
> > +     perf_buffer__free(pb);
> >       close(map_fd);
> >
> >       return 0;
> >
> > -err_close_fds_prev:
> > -     while (i--) {
> > -             perf_event_unmap(rings[i].mem);
> > -err_close_fds_current:
> > -             close(rings[i].fd);
> > -     }
> > -     free(pfds);
> > -err_free_rings:
> > -     free(rings);
> > +err_close_pb:
> > +     perf_buffer__free(pb);
> >  err_close_map:
> >       close(map_fd);
> > -     return -1;
> > +     return err ? -1 : 0;
>
> ... how can we return 0 on the error path?

Good catch! I initially was going to merge success and error path, but
after seeing how many explicit `err = <something>` I had to do I
abandoned the effort, but forgot to undo this `return -1` change. I'll
return -1 unconditionally.

>
> >  }
>

^ permalink raw reply

* [PATCH net-next v2 16/16] mlxsw: spectrum: PTP: Support ethtool get_ts_info
From: Ido Schimmel @ 2019-06-30  6:05 UTC (permalink / raw)
  To: netdev; +Cc: davem, richardcochran, jiri, petrm, mlxsw, Ido Schimmel
In-Reply-To: <20190630060500.7882-1-idosch@idosch.org>

From: Petr Machata <petrm@mellanox.com>

The get_ts_info callback is used for obtaining information about
timestamping capabilities of a network device. On Spectrum-1, implement
it to advertise the PHC and the capability to do HW timestamping, and
the supported RX and TX filters.

Signed-off-by: Petr Machata <petrm@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../net/ethernet/mellanox/mlxsw/spectrum.c    | 14 +++++++++++
 .../ethernet/mellanox/mlxsw/spectrum_ptp.c    | 18 +++++++++++++++
 .../ethernet/mellanox/mlxsw/spectrum_ptp.h    | 23 +++++++++++++++++++
 3 files changed, 55 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index aeb6462f4d62..755b14b82c8f 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -171,6 +171,8 @@ struct mlxsw_sp_ptp_ops {
 			    struct hwtstamp_config *config);
 	int (*hwtstamp_set)(struct mlxsw_sp_port *mlxsw_sp_port,
 			    struct hwtstamp_config *config);
+	int (*get_ts_info)(struct mlxsw_sp *mlxsw_sp,
+			   struct ethtool_ts_info *info);
 };
 
 static int mlxsw_sp_component_query(struct mlxfw_dev *mlxfw_dev,
@@ -3316,6 +3318,15 @@ static int mlxsw_sp_get_module_eeprom(struct net_device *netdev,
 	return err;
 }
 
+static int
+mlxsw_sp_get_ts_info(struct net_device *netdev, struct ethtool_ts_info *info)
+{
+	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(netdev);
+	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+
+	return mlxsw_sp->ptp_ops->get_ts_info(mlxsw_sp, info);
+}
+
 static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
 	.get_drvinfo		= mlxsw_sp_port_get_drvinfo,
 	.get_link		= ethtool_op_get_link,
@@ -3329,6 +3340,7 @@ static const struct ethtool_ops mlxsw_sp_port_ethtool_ops = {
 	.set_link_ksettings	= mlxsw_sp_port_set_link_ksettings,
 	.get_module_info	= mlxsw_sp_get_module_info,
 	.get_module_eeprom	= mlxsw_sp_get_module_eeprom,
+	.get_ts_info		= mlxsw_sp_get_ts_info,
 };
 
 static int
@@ -4547,6 +4559,7 @@ static const struct mlxsw_sp_ptp_ops mlxsw_sp1_ptp_ops = {
 	.transmitted	= mlxsw_sp1_ptp_transmitted,
 	.hwtstamp_get	= mlxsw_sp1_ptp_hwtstamp_get,
 	.hwtstamp_set	= mlxsw_sp1_ptp_hwtstamp_set,
+	.get_ts_info	= mlxsw_sp1_ptp_get_ts_info,
 };
 
 static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = {
@@ -4558,6 +4571,7 @@ static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = {
 	.transmitted	= mlxsw_sp2_ptp_transmitted,
 	.hwtstamp_get	= mlxsw_sp2_ptp_hwtstamp_get,
 	.hwtstamp_set	= mlxsw_sp2_ptp_hwtstamp_set,
+	.get_ts_info	= mlxsw_sp2_ptp_get_ts_info,
 };
 
 static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
index 950ee489c222..7d42f86237cd 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
@@ -933,3 +933,21 @@ int mlxsw_sp1_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
 
 	return 0;
 }
+
+int mlxsw_sp1_ptp_get_ts_info(struct mlxsw_sp *mlxsw_sp,
+			      struct ethtool_ts_info *info)
+{
+	info->phc_index = ptp_clock_index(mlxsw_sp->clock->ptp);
+
+	info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
+				SOF_TIMESTAMPING_RX_HARDWARE |
+				SOF_TIMESTAMPING_RAW_HARDWARE;
+
+	info->tx_types = BIT(HWTSTAMP_TX_OFF) |
+			 BIT(HWTSTAMP_TX_ON);
+
+	info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) |
+			   BIT(HWTSTAMP_FILTER_ALL);
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h
index 27b4fa8e361d..b23abfc0bd76 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h
@@ -18,6 +18,14 @@ enum {
 	MLXSW_SP_PTP_MESSAGE_TYPE_PDELAY_RESP,
 };
 
+static inline int mlxsw_sp_ptp_get_ts_info_noptp(struct ethtool_ts_info *info)
+{
+	info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
+				SOF_TIMESTAMPING_SOFTWARE;
+	info->phc_index = -1;
+	return 0;
+}
+
 #if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
 
 struct mlxsw_sp_ptp_clock *
@@ -46,6 +54,9 @@ int mlxsw_sp1_ptp_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
 int mlxsw_sp1_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
 			       struct hwtstamp_config *config);
 
+int mlxsw_sp1_ptp_get_ts_info(struct mlxsw_sp *mlxsw_sp,
+			      struct ethtool_ts_info *info);
+
 #else
 
 static inline struct mlxsw_sp_ptp_clock *
@@ -102,6 +113,12 @@ mlxsw_sp1_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
 	return -EOPNOTSUPP;
 }
 
+static inline int mlxsw_sp1_ptp_get_ts_info(struct mlxsw_sp *mlxsw_sp,
+					    struct ethtool_ts_info *info)
+{
+	return mlxsw_sp_ptp_get_ts_info_noptp(info);
+}
+
 #endif
 
 static inline struct mlxsw_sp_ptp_clock *
@@ -150,4 +167,10 @@ mlxsw_sp2_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
 	return -EOPNOTSUPP;
 }
 
+static inline int mlxsw_sp2_ptp_get_ts_info(struct mlxsw_sp *mlxsw_sp,
+					    struct ethtool_ts_info *info)
+{
+	return mlxsw_sp_ptp_get_ts_info_noptp(info);
+}
+
 #endif
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next v2 15/16] mlxsw: spectrum: PTP: Support SIOCGHWTSTAMP, SIOCSHWTSTAMP ioctls
From: Ido Schimmel @ 2019-06-30  6:04 UTC (permalink / raw)
  To: netdev; +Cc: davem, richardcochran, jiri, petrm, mlxsw, Ido Schimmel
In-Reply-To: <20190630060500.7882-1-idosch@idosch.org>

From: Petr Machata <petrm@mellanox.com>

The SIOCSHWTSTAMP ioctl configures HW timestamping on a given port.
Dispatch the ioctls to per-chip handler (which add to ptp_ops). Find
which PTP messages need to be timestamped and configure MTPPPC
accordingly.

The SIOCGHWTSTAMP ioctl is getter for the current configuration.

Signed-off-by: Petr Machata <petrm@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../net/ethernet/mellanox/mlxsw/spectrum.c    |  70 ++++++++++
 .../ethernet/mellanox/mlxsw/spectrum_ptp.c    | 123 ++++++++++++++++++
 .../ethernet/mellanox/mlxsw/spectrum_ptp.h    |  34 +++++
 3 files changed, 227 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index bd405c5018de..aeb6462f4d62 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -166,6 +166,11 @@ struct mlxsw_sp_ptp_ops {
 	 */
 	void (*transmitted)(struct mlxsw_sp *mlxsw_sp, struct sk_buff *skb,
 			    u8 local_port);
+
+	int (*hwtstamp_get)(struct mlxsw_sp_port *mlxsw_sp_port,
+			    struct hwtstamp_config *config);
+	int (*hwtstamp_set)(struct mlxsw_sp_port *mlxsw_sp_port,
+			    struct hwtstamp_config *config);
 };
 
 static int mlxsw_sp_component_query(struct mlxfw_dev *mlxfw_dev,
@@ -1808,6 +1813,65 @@ mlxsw_sp_port_get_devlink_port(struct net_device *dev)
 						mlxsw_sp_port->local_port);
 }
 
+static int mlxsw_sp_port_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
+				      struct ifreq *ifr)
+{
+	struct hwtstamp_config config;
+	int err;
+
+	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+		return -EFAULT;
+
+	err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port,
+							     &config);
+	if (err)
+		return err;
+
+	if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int mlxsw_sp_port_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
+				      struct ifreq *ifr)
+{
+	struct hwtstamp_config config;
+	int err;
+
+	err = mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_get(mlxsw_sp_port,
+							     &config);
+	if (err)
+		return err;
+
+	if (copy_to_user(ifr->ifr_data, &config, sizeof(config)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static inline void mlxsw_sp_port_ptp_clear(struct mlxsw_sp_port *mlxsw_sp_port)
+{
+	struct hwtstamp_config config = {0};
+
+	mlxsw_sp_port->mlxsw_sp->ptp_ops->hwtstamp_set(mlxsw_sp_port, &config);
+}
+
+static int
+mlxsw_sp_port_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
+
+	switch (cmd) {
+	case SIOCSHWTSTAMP:
+		return mlxsw_sp_port_hwtstamp_set(mlxsw_sp_port, ifr);
+	case SIOCGHWTSTAMP:
+		return mlxsw_sp_port_hwtstamp_get(mlxsw_sp_port, ifr);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
 static const struct net_device_ops mlxsw_sp_port_netdev_ops = {
 	.ndo_open		= mlxsw_sp_port_open,
 	.ndo_stop		= mlxsw_sp_port_stop,
@@ -1823,6 +1887,7 @@ static const struct net_device_ops mlxsw_sp_port_netdev_ops = {
 	.ndo_vlan_rx_kill_vid	= mlxsw_sp_port_kill_vid,
 	.ndo_set_features	= mlxsw_sp_set_features,
 	.ndo_get_devlink_port	= mlxsw_sp_port_get_devlink_port,
+	.ndo_do_ioctl		= mlxsw_sp_port_ioctl,
 };
 
 static void mlxsw_sp_port_get_drvinfo(struct net_device *dev,
@@ -3680,6 +3745,7 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
 	struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
 
 	cancel_delayed_work_sync(&mlxsw_sp_port->periodic_hw_stats.update_dw);
+	mlxsw_sp_port_ptp_clear(mlxsw_sp_port);
 	mlxsw_core_port_clear(mlxsw_sp->core, local_port, mlxsw_sp);
 	unregister_netdev(mlxsw_sp_port->dev); /* This calls ndo_stop */
 	mlxsw_sp->ports[local_port] = NULL;
@@ -4479,6 +4545,8 @@ static const struct mlxsw_sp_ptp_ops mlxsw_sp1_ptp_ops = {
 	.fini		= mlxsw_sp1_ptp_fini,
 	.receive	= mlxsw_sp1_ptp_receive,
 	.transmitted	= mlxsw_sp1_ptp_transmitted,
+	.hwtstamp_get	= mlxsw_sp1_ptp_hwtstamp_get,
+	.hwtstamp_set	= mlxsw_sp1_ptp_hwtstamp_set,
 };
 
 static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = {
@@ -4488,6 +4556,8 @@ static const struct mlxsw_sp_ptp_ops mlxsw_sp2_ptp_ops = {
 	.fini		= mlxsw_sp2_ptp_fini,
 	.receive	= mlxsw_sp2_ptp_receive,
 	.transmitted	= mlxsw_sp2_ptp_transmitted,
+	.hwtstamp_get	= mlxsw_sp2_ptp_hwtstamp_get,
+	.hwtstamp_set	= mlxsw_sp2_ptp_hwtstamp_set,
 };
 
 static int mlxsw_sp_netdevice_event(struct notifier_block *unused,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
index b3e4f78d5f07..950ee489c222 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
@@ -10,6 +10,7 @@
 #include <linux/ptp_classify.h>
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
+#include <linux/net_tstamp.h>
 
 #include "spectrum.h"
 #include "spectrum_ptp.h"
@@ -743,6 +744,15 @@ static int mlxsw_sp1_ptp_set_fifo_clr_on_trap(struct mlxsw_sp *mlxsw_sp,
 	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mogcr), mogcr_pl);
 }
 
+static int mlxsw_sp1_ptp_mtpppc_set(struct mlxsw_sp *mlxsw_sp,
+				    u16 ing_types, u16 egr_types)
+{
+	char mtpppc_pl[MLXSW_REG_MTPPPC_LEN];
+
+	mlxsw_reg_mtpppc_pack(mtpppc_pl, ing_types, egr_types);
+	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mtpppc), mtpppc_pl);
+}
+
 struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp)
 {
 	struct mlxsw_sp_ptp_state *ptp_state;
@@ -803,6 +813,7 @@ void mlxsw_sp1_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state)
 	struct mlxsw_sp *mlxsw_sp = ptp_state->mlxsw_sp;
 
 	cancel_delayed_work_sync(&ptp_state->ht_gc_dw);
+	mlxsw_sp1_ptp_mtpppc_set(mlxsw_sp, 0, 0);
 	mlxsw_sp1_ptp_set_fifo_clr_on_trap(mlxsw_sp, false);
 	mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP1, 0);
 	mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP0, 0);
@@ -810,3 +821,115 @@ void mlxsw_sp1_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state)
 				    &mlxsw_sp1_ptp_unmatched_free_fn, NULL);
 	kfree(ptp_state);
 }
+
+int mlxsw_sp1_ptp_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
+			       struct hwtstamp_config *config)
+{
+	*config = mlxsw_sp_port->ptp.hwtstamp_config;
+	return 0;
+}
+
+static int mlxsw_sp_ptp_get_message_types(const struct hwtstamp_config *config,
+					  u16 *p_ing_types, u16 *p_egr_types,
+					  enum hwtstamp_rx_filters *p_rx_filter)
+{
+	enum hwtstamp_rx_filters rx_filter = config->rx_filter;
+	enum hwtstamp_tx_types tx_type = config->tx_type;
+	u16 ing_types = 0x00;
+	u16 egr_types = 0x00;
+
+	switch (tx_type) {
+	case HWTSTAMP_TX_OFF:
+		egr_types = 0x00;
+		break;
+	case HWTSTAMP_TX_ON:
+		egr_types = 0xff;
+		break;
+	case HWTSTAMP_TX_ONESTEP_SYNC:
+		return -ERANGE;
+	}
+
+	switch (rx_filter) {
+	case HWTSTAMP_FILTER_NONE:
+		ing_types = 0x00;
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+	case HWTSTAMP_FILTER_PTP_V2_SYNC:
+		ing_types = 0x01;
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+	case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+		ing_types = 0x02;
+		break;
+	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+	case HWTSTAMP_FILTER_PTP_V2_EVENT:
+		ing_types = 0x0f;
+		break;
+	case HWTSTAMP_FILTER_ALL:
+		ing_types = 0xff;
+		break;
+	case HWTSTAMP_FILTER_SOME:
+	case HWTSTAMP_FILTER_NTP_ALL:
+		return -ERANGE;
+	}
+
+	*p_ing_types = ing_types;
+	*p_egr_types = egr_types;
+	*p_rx_filter = rx_filter;
+	return 0;
+}
+
+static int mlxsw_sp1_ptp_mtpppc_update(struct mlxsw_sp_port *mlxsw_sp_port,
+				       u16 ing_types, u16 egr_types)
+{
+	struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+	struct mlxsw_sp_port *tmp;
+	int i;
+
+	/* MTPPPC configures timestamping globally, not per port. Find the
+	 * configuration that contains all configured timestamping requests.
+	 */
+	for (i = 1; i < mlxsw_core_max_ports(mlxsw_sp->core); i++) {
+		tmp = mlxsw_sp->ports[i];
+		if (tmp && tmp != mlxsw_sp_port) {
+			ing_types |= tmp->ptp.ing_types;
+			egr_types |= tmp->ptp.egr_types;
+		}
+	}
+
+	return mlxsw_sp1_ptp_mtpppc_set(mlxsw_sp_port->mlxsw_sp,
+				       ing_types, egr_types);
+}
+
+int mlxsw_sp1_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
+			       struct hwtstamp_config *config)
+{
+	enum hwtstamp_rx_filters rx_filter;
+	u16 ing_types;
+	u16 egr_types;
+	int err;
+
+	err = mlxsw_sp_ptp_get_message_types(config, &ing_types, &egr_types,
+					     &rx_filter);
+	if (err)
+		return err;
+
+	err = mlxsw_sp1_ptp_mtpppc_update(mlxsw_sp_port, ing_types, egr_types);
+	if (err)
+		return err;
+
+	mlxsw_sp_port->ptp.hwtstamp_config = *config;
+	mlxsw_sp_port->ptp.ing_types = ing_types;
+	mlxsw_sp_port->ptp.egr_types = egr_types;
+
+	/* Notify the ioctl caller what we are actually timestamping. */
+	config->rx_filter = rx_filter;
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h
index 497ff7d90fb9..27b4fa8e361d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h
@@ -40,6 +40,12 @@ void mlxsw_sp1_ptp_got_timestamp(struct mlxsw_sp *mlxsw_sp, bool ingress,
 				 u8 domain_number, u16 sequence_id,
 				 u64 timestamp);
 
+int mlxsw_sp1_ptp_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
+			       struct hwtstamp_config *config);
+
+int mlxsw_sp1_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
+			       struct hwtstamp_config *config);
+
 #else
 
 static inline struct mlxsw_sp_ptp_clock *
@@ -82,6 +88,20 @@ mlxsw_sp1_ptp_got_timestamp(struct mlxsw_sp *mlxsw_sp, bool ingress,
 {
 }
 
+static inline int
+mlxsw_sp1_ptp_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
+			   struct hwtstamp_config *config)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int
+mlxsw_sp1_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
+			   struct hwtstamp_config *config)
+{
+	return -EOPNOTSUPP;
+}
+
 #endif
 
 static inline struct mlxsw_sp_ptp_clock *
@@ -116,4 +136,18 @@ static inline void mlxsw_sp2_ptp_transmitted(struct mlxsw_sp *mlxsw_sp,
 	dev_kfree_skb_any(skb);
 }
 
+static inline int
+mlxsw_sp2_ptp_hwtstamp_get(struct mlxsw_sp_port *mlxsw_sp_port,
+			   struct hwtstamp_config *config)
+{
+	return -EOPNOTSUPP;
+}
+
+static inline int
+mlxsw_sp2_ptp_hwtstamp_set(struct mlxsw_sp_port *mlxsw_sp_port,
+			   struct hwtstamp_config *config)
+{
+	return -EOPNOTSUPP;
+}
+
 #endif
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next v2 14/16] mlxsw: spectrum: PTP: Configure PTP traps and FIFO events
From: Ido Schimmel @ 2019-06-30  6:04 UTC (permalink / raw)
  To: netdev; +Cc: davem, richardcochran, jiri, petrm, mlxsw, Ido Schimmel
In-Reply-To: <20190630060500.7882-1-idosch@idosch.org>

From: Petr Machata <petrm@mellanox.com>

Configure MTPTPT to set which message types should arrive under which
PTP trap, and MOGCR to clear the timestamp queue after its contents are
reported through PTP_ING_FIFO or PTP_EGR_FIFO.

With this configuration, PTP packets start arriving through the PTP
traps. However since timestamping is disabled by default and there is
currently no way to enable it, they will not be timestamped.

Signed-off-by: Petr Machata <petrm@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../ethernet/mellanox/mlxsw/spectrum_ptp.c    | 58 +++++++++++++++++++
 .../ethernet/mellanox/mlxsw/spectrum_ptp.h    |  7 +++
 2 files changed, 65 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
index f0f0c20ecc2e..b3e4f78d5f07 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
@@ -718,9 +718,35 @@ static void mlxsw_sp1_ptp_ht_gc(struct work_struct *work)
 			       MLXSW_SP1_PTP_HT_GC_INTERVAL);
 }
 
+static int mlxsw_sp_ptp_mtptpt_set(struct mlxsw_sp *mlxsw_sp,
+				   enum mlxsw_reg_mtptpt_trap_id trap_id,
+				   u16 message_type)
+{
+	char mtptpt_pl[MLXSW_REG_MTPTPT_LEN];
+
+	mlxsw_reg_mtptptp_pack(mtptpt_pl, trap_id, message_type);
+	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mtptpt), mtptpt_pl);
+}
+
+static int mlxsw_sp1_ptp_set_fifo_clr_on_trap(struct mlxsw_sp *mlxsw_sp,
+					      bool clr)
+{
+	char mogcr_pl[MLXSW_REG_MOGCR_LEN] = {0};
+	int err;
+
+	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(mogcr), mogcr_pl);
+	if (err)
+		return err;
+
+	mlxsw_reg_mogcr_ptp_iftc_set(mogcr_pl, clr);
+	mlxsw_reg_mogcr_ptp_eftc_set(mogcr_pl, clr);
+	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mogcr), mogcr_pl);
+}
+
 struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp)
 {
 	struct mlxsw_sp_ptp_state *ptp_state;
+	u16 message_type;
 	int err;
 
 	ptp_state = kzalloc(sizeof(*ptp_state), GFP_KERNEL);
@@ -735,11 +761,38 @@ struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp)
 	if (err)
 		goto err_hashtable_init;
 
+	/* Delive these message types as PTP0. */
+	message_type = BIT(MLXSW_SP_PTP_MESSAGE_TYPE_SYNC) |
+		       BIT(MLXSW_SP_PTP_MESSAGE_TYPE_DELAY_REQ) |
+		       BIT(MLXSW_SP_PTP_MESSAGE_TYPE_PDELAY_REQ) |
+		       BIT(MLXSW_SP_PTP_MESSAGE_TYPE_PDELAY_RESP);
+	err = mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP0,
+				      message_type);
+	if (err)
+		goto err_mtptpt_set;
+
+	/* Everything else is PTP1. */
+	message_type = ~message_type;
+	err = mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP1,
+				      message_type);
+	if (err)
+		goto err_mtptpt1_set;
+
+	err = mlxsw_sp1_ptp_set_fifo_clr_on_trap(mlxsw_sp, true);
+	if (err)
+		goto err_fifo_clr;
+
 	INIT_DELAYED_WORK(&ptp_state->ht_gc_dw, mlxsw_sp1_ptp_ht_gc);
 	mlxsw_core_schedule_dw(&ptp_state->ht_gc_dw,
 			       MLXSW_SP1_PTP_HT_GC_INTERVAL);
 	return ptp_state;
 
+err_fifo_clr:
+	mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP1, 0);
+err_mtptpt1_set:
+	mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP0, 0);
+err_mtptpt_set:
+	rhashtable_destroy(&ptp_state->unmatched_ht);
 err_hashtable_init:
 	kfree(ptp_state);
 	return ERR_PTR(err);
@@ -747,7 +800,12 @@ struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp)
 
 void mlxsw_sp1_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state)
 {
+	struct mlxsw_sp *mlxsw_sp = ptp_state->mlxsw_sp;
+
 	cancel_delayed_work_sync(&ptp_state->ht_gc_dw);
+	mlxsw_sp1_ptp_set_fifo_clr_on_trap(mlxsw_sp, false);
+	mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP1, 0);
+	mlxsw_sp_ptp_mtptpt_set(mlxsw_sp, MLXSW_REG_MTPTPT_TRAP_ID_PTP0, 0);
 	rhashtable_free_and_destroy(&ptp_state->unmatched_ht,
 				    &mlxsw_sp1_ptp_unmatched_free_fn, NULL);
 	kfree(ptp_state);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h
index 40c9e82e2920..497ff7d90fb9 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.h
@@ -11,6 +11,13 @@ struct mlxsw_sp;
 struct mlxsw_sp_port;
 struct mlxsw_sp_ptp_clock;
 
+enum {
+	MLXSW_SP_PTP_MESSAGE_TYPE_SYNC,
+	MLXSW_SP_PTP_MESSAGE_TYPE_DELAY_REQ,
+	MLXSW_SP_PTP_MESSAGE_TYPE_PDELAY_REQ,
+	MLXSW_SP_PTP_MESSAGE_TYPE_PDELAY_RESP,
+};
+
 #if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
 
 struct mlxsw_sp_ptp_clock *
-- 
2.20.1


^ permalink raw reply related

* [PATCH net-next v2 13/16] mlxsw: spectrum: PTP: Garbage-collect unmatched entries
From: Ido Schimmel @ 2019-06-30  6:04 UTC (permalink / raw)
  To: netdev; +Cc: davem, richardcochran, jiri, petrm, mlxsw, Ido Schimmel
In-Reply-To: <20190630060500.7882-1-idosch@idosch.org>

From: Petr Machata <petrm@mellanox.com>

On Spectrum-1, timestamped PTP packets and the corresponding timestamps
need to be kept in caches until both are available, at which point they are
matched up and packets forwarded as appropriate. However, not all packets
will ever see their timestamp, and not all timestamps will ever see their
packet. It is therefore necessary to dispose of such abandoned entries.

To that end, introduce a garbage collector to collect entries that have
not had their counterpart turn up within about a second. The GC
maintains a monotonously-increasing value of GC cycle. Every entry that
is put to the hash table is annotated with the GC cycle at which it
should be collected. When the GC runs, it walks the hash table, and
collects the objects according to their GC cycle annotation.

Signed-off-by: Petr Machata <petrm@mellanox.com>
Acked-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
---
 .../ethernet/mellanox/mlxsw/spectrum_ptp.c    | 86 +++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
index e87066f65860..f0f0c20ecc2e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c
@@ -19,9 +19,19 @@
 #define MLXSW_SP1_PTP_CLOCK_FREQ_KHZ		156257 /* 6.4nSec */
 #define MLXSW_SP1_PTP_CLOCK_MASK		64
 
+#define MLXSW_SP1_PTP_HT_GC_INTERVAL		500 /* ms */
+
+/* How long, approximately, should the unmatched entries stay in the hash table
+ * before they are collected. Should be evenly divisible by the GC interval.
+ */
+#define MLXSW_SP1_PTP_HT_GC_TIMEOUT		1000 /* ms */
+
 struct mlxsw_sp_ptp_state {
+	struct mlxsw_sp *mlxsw_sp;
 	struct rhashtable unmatched_ht;
 	spinlock_t unmatched_lock; /* protects the HT */
+	struct delayed_work ht_gc_dw;
+	u32 gc_cycle;
 };
 
 struct mlxsw_sp1_ptp_key {
@@ -38,6 +48,7 @@ struct mlxsw_sp1_ptp_unmatched {
 	struct rcu_head rcu;
 	struct sk_buff *skb;
 	u64 timestamp;
+	u32 gc_cycle;
 };
 
 static const struct rhashtable_params mlxsw_sp1_ptp_unmatched_ht_params = {
@@ -353,6 +364,7 @@ mlxsw_sp1_ptp_unmatched_save(struct mlxsw_sp *mlxsw_sp,
 			     struct sk_buff *skb,
 			     u64 timestamp)
 {
+	int cycles = MLXSW_SP1_PTP_HT_GC_TIMEOUT / MLXSW_SP1_PTP_HT_GC_INTERVAL;
 	struct mlxsw_sp_ptp_state *ptp_state = mlxsw_sp->ptp_state;
 	struct mlxsw_sp1_ptp_unmatched *unmatched;
 	struct mlxsw_sp1_ptp_unmatched *conflict;
@@ -364,6 +376,7 @@ mlxsw_sp1_ptp_unmatched_save(struct mlxsw_sp *mlxsw_sp,
 	unmatched->key = key;
 	unmatched->skb = skb;
 	unmatched->timestamp = timestamp;
+	unmatched->gc_cycle = mlxsw_sp->ptp_state->gc_cycle + cycles;
 
 	conflict = rhashtable_lookup_get_insert_fast(&ptp_state->unmatched_ht,
 					    &unmatched->ht_node,
@@ -396,6 +409,8 @@ mlxsw_sp1_ptp_unmatched_remove(struct mlxsw_sp *mlxsw_sp,
  * 1) When a packet is matched with its timestamp.
  * 2) In several situation when it is necessary to immediately pass on
  *    an SKB without a timestamp.
+ * 3) From GC indirectly through mlxsw_sp1_ptp_unmatched_finish().
+ *    This case is similar to 2) above.
  */
 static void mlxsw_sp1_ptp_packet_finish(struct mlxsw_sp *mlxsw_sp,
 					struct sk_buff *skb, u8 local_port,
@@ -637,6 +652,72 @@ void mlxsw_sp1_ptp_transmitted(struct mlxsw_sp *mlxsw_sp,
 	mlxsw_sp1_ptp_got_packet(mlxsw_sp, skb, local_port, false);
 }
 
+static void
+mlxsw_sp1_ptp_ht_gc_collect(struct mlxsw_sp_ptp_state *ptp_state,
+			    struct mlxsw_sp1_ptp_unmatched *unmatched)
+{
+	int err;
+
+	/* If an unmatched entry has an SKB, it has to be handed over to the
+	 * networking stack. This is usually done from a trap handler, which is
+	 * invoked in a softirq context. Here we are going to do it in process
+	 * context. If that were to be interrupted by a softirq, it could cause
+	 * a deadlock when an attempt is made to take an already-taken lock
+	 * somewhere along the sending path. Disable softirqs to prevent this.
+	 */
+	local_bh_disable();
+
+	spin_lock(&ptp_state->unmatched_lock);
+	err = rhashtable_remove_fast(&ptp_state->unmatched_ht,
+				     &unmatched->ht_node,
+				     mlxsw_sp1_ptp_unmatched_ht_params);
+	spin_unlock(&ptp_state->unmatched_lock);
+
+	if (err)
+		/* The packet was matched with timestamp during the walk. */
+		goto out;
+
+	/* mlxsw_sp1_ptp_unmatched_finish() invokes netif_receive_skb(). While
+	 * the comment at that function states that it can only be called in
+	 * soft IRQ context, this pattern of local_bh_disable() +
+	 * netif_receive_skb(), in process context, is seen elsewhere in the
+	 * kernel, notably in pktgen.
+	 */
+	mlxsw_sp1_ptp_unmatched_finish(ptp_state->mlxsw_sp, unmatched);
+
+out:
+	local_bh_enable();
+}
+
+static void mlxsw_sp1_ptp_ht_gc(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct mlxsw_sp1_ptp_unmatched *unmatched;
+	struct mlxsw_sp_ptp_state *ptp_state;
+	struct rhashtable_iter iter;
+	u32 gc_cycle;
+	void *obj;
+
+	ptp_state = container_of(dwork, struct mlxsw_sp_ptp_state, ht_gc_dw);
+	gc_cycle = ptp_state->gc_cycle++;
+
+	rhashtable_walk_enter(&ptp_state->unmatched_ht, &iter);
+	rhashtable_walk_start(&iter);
+	while ((obj = rhashtable_walk_next(&iter))) {
+		if (IS_ERR(obj))
+			continue;
+
+		unmatched = obj;
+		if (unmatched->gc_cycle <= gc_cycle)
+			mlxsw_sp1_ptp_ht_gc_collect(ptp_state, unmatched);
+	}
+	rhashtable_walk_stop(&iter);
+	rhashtable_walk_exit(&iter);
+
+	mlxsw_core_schedule_dw(&ptp_state->ht_gc_dw,
+			       MLXSW_SP1_PTP_HT_GC_INTERVAL);
+}
+
 struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp)
 {
 	struct mlxsw_sp_ptp_state *ptp_state;
@@ -645,6 +726,7 @@ struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp)
 	ptp_state = kzalloc(sizeof(*ptp_state), GFP_KERNEL);
 	if (!ptp_state)
 		return ERR_PTR(-ENOMEM);
+	ptp_state->mlxsw_sp = mlxsw_sp;
 
 	spin_lock_init(&ptp_state->unmatched_lock);
 
@@ -653,6 +735,9 @@ struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp)
 	if (err)
 		goto err_hashtable_init;
 
+	INIT_DELAYED_WORK(&ptp_state->ht_gc_dw, mlxsw_sp1_ptp_ht_gc);
+	mlxsw_core_schedule_dw(&ptp_state->ht_gc_dw,
+			       MLXSW_SP1_PTP_HT_GC_INTERVAL);
 	return ptp_state;
 
 err_hashtable_init:
@@ -662,6 +747,7 @@ struct mlxsw_sp_ptp_state *mlxsw_sp1_ptp_init(struct mlxsw_sp *mlxsw_sp)
 
 void mlxsw_sp1_ptp_fini(struct mlxsw_sp_ptp_state *ptp_state)
 {
+	cancel_delayed_work_sync(&ptp_state->ht_gc_dw);
 	rhashtable_free_and_destroy(&ptp_state->unmatched_ht,
 				    &mlxsw_sp1_ptp_unmatched_free_fn, NULL);
 	kfree(ptp_state);
-- 
2.20.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox