* NEIGH: BUG, double timer add, state is 8
From: Marek Majkowski @ 2019-07-04 21:59 UTC (permalink / raw)
To: David Miller, dsahern; +Cc: netdev, kernel-team
Morning,
I found a way to hit an obscure BUG in the
net/core/neighbour.c:neigh_add_timer(), by piping two carefully
crafted messages into AF_NETLINK socket.
https://github.com/torvalds/linux/blob/v5.2-rc7/net/core/neighbour.c#L259
if (unlikely(mod_timer(&n->timer, when))) {
printk("NEIGH: BUG, double timer add, state is %x\n", n->nud_state);
dump_stack();
}
The repro is here:
https://gist.github.com/majek/d70297b9d72bc2e2b82145e122722a0c
wget https://gist.githubusercontent.com/majek/d70297b9d72bc2e2b82145e122722a0c/raw/9e140bcedecc28d722022f1da142a379a9b7a7b0/double_timer_add_bug.c
You need root for AF_NETLINK socket. I would lie if I said I
understand what these netlink messages actually do.
Tested under virtme, with 5.2-rc7 kernel.
Full stack trace:
4,147643,57161310899,-;NEIGH: BUG, double timer add, state is 8
4,147644,57161311114,-;CPU: 0 PID: 266 Comm: xxx Not tainted 5.2.0-rc7kvm+ #6
4,147645,57161311260,-;Hardware name: QEMU Standard PC (i440FX + PIIX,
1996), BIOS 1.10.2-1ubuntu1 04/01/2014
4,147646,57161311401,-;Call Trace:
4,147647,57161311616,-; dump_stack (linux/lib/dump_stack.c:115)
4,147648,57161311771,-; neigh_add_timer
(linux/net/core/neighbour.c:265 linux/net/core/neighbour.c:259)
4,147649,57161311878,-; __neigh_event_send (linux/net/core/neighbour.c:1143)
4,147650,57161312043,-; ? lockdep_hardirqs_on
(linux/kernel/locking/lockdep.c:3218
linux/kernel/locking/lockdep.c:3263)
4,147651,57161312205,-; ? __local_bh_enable_ip
(linux/arch/x86/include/asm/paravirt.h:777 linux/kernel/softirq.c:194)
4,147652,57161312311,-; ? neigh_lookup
(linux/include/linux/rcupdate.h:213 linux/include/linux/rcupdate.h:680
linux/net/core/neighbour.c:539)
4,147653,57161312454,-; ? trace_hardirqs_on
(linux/kernel/trace/trace_preemptirq.c:32)
4,147654,57161312579,-; ? neigh_lookup (linux/net/core/neighbour.c:1106)
4,147655,57161312700,-; ? __local_bh_enable_ip
(linux/arch/x86/include/asm/paravirt.h:777 linux/kernel/softirq.c:194)
4,147656,57161312804,-; ? neigh_lookup (linux/net/core/neighbour.c:541)
4,147657,57161312949,-; ? udp_gro_receive.cold.8 (linux/net/ipv4/arp.c:216)
4,147658,57161313087,-; neigh_add (linux/include/net/neighbour.h:445
linux/net/core/neighbour.c:1963)
4,147659,57161313216,-; ? neigh_xmit (linux/net/core/neighbour.c:1850)
4,147660,57161313346,-; ? __sanitizer_cov_trace_const_cmp8
(linux/kernel/kcov.c:198)
4,147661,57161313522,-; ? neigh_xmit (linux/net/core/neighbour.c:1850)
4,147662,57161313644,-; rtnetlink_rcv_msg (linux/net/core/rtnetlink.c:5214)
4,147663,57161313751,-; ? rtnetlink_put_metrics
(linux/net/core/rtnetlink.c:5117)
4,147664,57161313875,-; ? find_held_lock (linux/kernel/locking/lockdep.c:3898)
4,147665,57161314023,-; netlink_rcv_skb (linux/net/netlink/af_netlink.c:2483)
4,147666,57161314152,-; ? rtnetlink_put_metrics
(linux/net/core/rtnetlink.c:5117)
4,147667,57161314311,-; ? netlink_ack (linux/net/netlink/af_netlink.c:2459)
4,147668,57161314416,-; ? netlink_deliver_tap
(linux/net/netlink/af_netlink.c:333)
4,147669,57161314538,-; rtnetlink_rcv (linux/net/core/rtnetlink.c:5233)
4,147670,57161314701,-; netlink_unicast
(linux/net/netlink/af_netlink.c:1308
linux/net/netlink/af_netlink.c:1333)
4,147671,57161314811,-; ? netlink_attachskb
(linux/net/netlink/af_netlink.c:1318)
4,147672,57161315093,-; ? _copy_from_iter_full (linux/lib/iov_iter.c:780)
4,147673,57161315239,-; netlink_sendmsg (linux/net/netlink/af_netlink.c:1922)
4,147674,57161315349,-; ? netlink_unicast (linux/net/netlink/af_netlink.c:1848)
4,147675,57161315543,-; ? apparmor_socket_sendmsg
(linux/security/apparmor/lsm.c:937)
4,147676,57161315690,-; ? netlink_unicast (linux/net/netlink/af_netlink.c:1848)
4,147677,57161315838,-; sock_sendmsg (linux/net/socket.c:646
linux/net/socket.c:665)
4,147678,57161315983,-; ___sys_sendmsg (linux/net/socket.c:2286)
4,147679,57161316105,-; ? trace_hardirqs_on
(linux/kernel/trace/trace_preemptirq.c:32)
4,147680,57161316247,-; ? copy_msghdr_from_user (linux/net/socket.c:2214)
4,147681,57161316361,-; ? __wake_up_common_lock (linux/kernel/sched/wait.c:125)
4,147682,57161316470,-; ? __wake_up_common (linux/kernel/sched/wait.c:112)
4,147683,57161316584,-; ? _raw_write_unlock_irq
(linux/arch/x86/include/asm/paravirt.h:777
linux/include/linux/rwlock_api_smp.h:267
linux/kernel/locking/spinlock.c:343)
4,147684,57161316757,-; ? trace_hardirqs_on
(linux/kernel/trace/trace_preemptirq.c:32)
4,147685,57161316867,-; ? __wake_up (linux/kernel/sched/wait.c:147)
4,147686,57161316985,-; ? netlink_bind (linux/net/netlink/af_netlink.c:981)
4,147687,57161317096,-; ? netlink_setsockopt
(linux/net/netlink/af_netlink.c:981)
4,147688,57161317223,-; ? kasan_check_read (linux/mm/kasan/common.c:95)
4,147689,57161317346,-; ? __fget_light
(linux/include/linux/compiler.h:194
linux/arch/x86/include/asm/atomic.h:31
linux/include/asm-generic/atomic-instrumented.h:27
linux/fs/file.c:770)
4,147690,57161317454,-; ? __sanitizer_cov_trace_const_cmp8
(linux/kernel/kcov.c:198)
4,147691,57161317561,-; ? sockfd_lookup_light (linux/net/socket.c:505)
4,147692,57161317685,-; __sys_sendmsg (linux/net/socket.c:2326)
4,147693,57161317821,-; ? __ia32_sys_shutdown (linux/net/socket.c:2312)
4,147694,57161317927,-; ? __fd_install
(linux/arch/x86/include/asm/preempt.h:84
linux/include/linux/rcupdate.h:724 linux/fs/file.c:608)
4,147695,57161318050,-; ? fd_install (linux/fs/file.c:614)
4,147696,57161318162,-; ? entry_SYSCALL_64_after_hwframe
(linux/arch/x86/entry/entry_64.S:177)
4,147697,57161318270,-; ? lockdep_hardirqs_on
(linux/kernel/locking/lockdep.c:3218
linux/kernel/locking/lockdep.c:3263)
4,147698,57161318413,-; __x64_sys_sendmsg (linux/net/socket.c:2331)
4,147699,57161318532,-; do_syscall_64 (linux/arch/x86/entry/common.c:301)
4,147700,57161318640,-; entry_SYSCALL_64_after_hwframe
(linux/arch/x86/entry/entry_64.S:177)
4,147701,57161318768,-;RIP: 0033:0x7f7c28863d04
4,147702,57161318901,-;Code: 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb
b5 0f 1f 80 00 00 00 00 48 8d 05 01 dc 2c 00 8b 00 85 c0 75 13 b8 2e
00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 54 f3 c3 66 90 41 54 55 41 89 d4
53 48 89 f5
All code
========
0: 00 f7 add %dh,%bh
2: d8 64 89 02 fsubs 0x2(%rcx,%rcx,4)
6: 48 c7 c0 ff ff ff ff mov $0xffffffffffffffff,%rax
d: eb b5 jmp 0xffffffffffffffc4
f: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
16: 48 8d 05 01 dc 2c 00 lea 0x2cdc01(%rip),%rax # 0x2cdc1e
1d: 8b 00 mov (%rax),%eax
1f: 85 c0 test %eax,%eax
21: 75 13 jne 0x36
23: b8 2e 00 00 00 mov $0x2e,%eax
28: 0f 05 syscall
2a:* 48 3d 00 f0 ff ff cmp $0xfffffffffffff000,%rax <-- trapping instruction
30: 77 54 ja 0x86
32: f3 c3 repz retq
34: 66 90 xchg %ax,%ax
36: 41 54 push %r12
38: 55 push %rbp
39: 41 89 d4 mov %edx,%r12d
3c: 53 push %rbx
3d: 48 89 f5 mov %rsi,%rbp
Code starting with the faulting instruction
===========================================
0: 48 3d 00 f0 ff ff cmp $0xfffffffffffff000,%rax
6: 77 54 ja 0x5c
8: f3 c3 repz retq
a: 66 90 xchg %ax,%ax
c: 41 54 push %r12
e: 55 push %rbp
f: 41 89 d4 mov %edx,%r12d
12: 53 push %rbx
13: 48 89 f5 mov %rsi,%rbp
4,147703,57161319051,-;RSP: 002b:00007ffd5901b648 EFLAGS: 00000246
ORIG_RAX: 000000000000002e
4,147704,57161319210,-;RAX: ffffffffffffffda RBX: 000000000000003b
RCX: 00007f7c28863d04
4,147705,57161319369,-;RDX: 0000000000000000 RSI: 00007ffd5901b710
RDI: 0000000000000006
4,147706,57161319495,-;RBP: 0000000000000006 R08: 0000000000000010
R09: 0000000000000000
4,147707,57161319664,-;R10: 00007ffd5901b758 R11: 0000000000000246
R12: 00007f7c28cc3f70
4,147708,57161319771,-;R13: 00007ffd5901d790 R14: 0000000000000000
R15: 00007ffd5901b750
Cheers,
Marek
^ permalink raw reply
* Re: [PATCH v2 4/4] net: dsa: vsc73xx: Assert reset if iCPU is enabled
From: Paweł Dembicki @ 2019-07-04 21:57 UTC (permalink / raw)
To: Linus Walleij
Cc: Andrew Lunn, Vivien Didelot, Florian Fainelli, David S. Miller,
Rob Herring, Mark Rutland, netdev,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
linux-kernel@vger.kernel.org
In-Reply-To: <CACRpkdYsA5437Sb8J539AJ=cYtnO2MiD7w7V_Emrmk8dNKbaEQ@mail.gmail.com>
On 4/7/19 09:22 Linus Walleij <linus.walleij@linaro.org> wrote:
>
> My devices do not have direct access to the reset line so I
> can't assert reset no matter how I try, if it works for you, the
> code is certainly better like this.
>
In P2020RDB, VSC7385 reset is connected to GPIO. U-boot put binary
file to iCPU and make VSC7385 unmanaged.
However reset flush internal memory and iCPU stop.
In this case bootlog looks like that:
[ 2.989047] vsc73xx-platform ffb00000.switch: VSC7385 (rev: 2) switch found
[ 2.996192] vsc73xx-platform ffb00000.switch: iCPU enabled boots
from PI/SI, no external memory
[ 3.005057] vsc73xx-platform ffb00000.switch: Chip seems to be out
of control. Assert reset and try again.
[ 3.045034] vsc73xx-platform ffb00000.switch: VSC7385 (rev: 2) switch found
[ 3.052171] vsc73xx-platform ffb00000.switch: iCPU disabled, no
external memory
Best Regards,
Pawel Dembicki
^ permalink raw reply
* Re: [PATCH net-next v3 1/4] net/sched: Introduce action ct
From: Jakub Kicinski @ 2019-07-04 21:55 UTC (permalink / raw)
To: Paul Blakey
Cc: Jiri Pirko, Roi Dayan, Yossi Kuperman, Oz Shlomo,
Marcelo Ricardo Leitner, netdev, David Miller, Aaron Conole,
Zhike Wang, Rony Efraim, nst-kernel, John Hurley, Simon Horman,
Justin Pettit
In-Reply-To: <1562241233-5176-2-git-send-email-paulb@mellanox.com>
On Thu, 4 Jul 2019 14:53:50 +0300, Paul Blakey wrote:
> +static const struct nla_policy ct_policy[TCA_CT_MAX + 1] = {
> + [TCA_CT_ACTION] = { .type = NLA_U16 },
Please use strict checking in all new policies.
attr 0 must have .strict_start_type set.
^ permalink raw reply
* [PATCH net 2/2] selftests/tls: add test for poll() with data in TLS ULP
From: Jakub Kicinski @ 2019-07-04 21:50 UTC (permalink / raw)
To: davem
Cc: netdev, oss-drivers, alexei.starovoitov, Jakub Kicinski,
Dirk van der Merwe
In-Reply-To: <20190704215037.6008-1-jakub.kicinski@netronome.com>
Add a test which checks if leftover record data in TLS
layer correctly wakes up poll().
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com>
---
tools/testing/selftests/net/tls.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c
index 278c86134556..090fff9dbc48 100644
--- a/tools/testing/selftests/net/tls.c
+++ b/tools/testing/selftests/net/tls.c
@@ -644,6 +644,32 @@ TEST_F(tls, poll_wait)
EXPECT_EQ(recv(self->cfd, recv_mem, send_len, MSG_WAITALL), send_len);
}
+TEST_F(tls, poll_wait_split)
+{
+ struct pollfd fd = { 0, 0, 0 };
+ char send_mem[20] = {};
+ char recv_mem[15];
+
+ fd.fd = self->cfd;
+ fd.events = POLLIN;
+ /* Send 20 bytes */
+ EXPECT_EQ(send(self->fd, send_mem, sizeof(send_mem), 0),
+ sizeof(send_mem));
+ /* Poll with inf. timeout */
+ EXPECT_EQ(poll(&fd, 1, -1), 1);
+ EXPECT_EQ(fd.revents & POLLIN, 1);
+ EXPECT_EQ(recv(self->cfd, recv_mem, sizeof(recv_mem), MSG_WAITALL),
+ sizeof(recv_mem));
+
+ /* Now the remaining 5 bytes of record data are in TLS ULP */
+ fd.fd = self->cfd;
+ fd.events = POLLIN;
+ EXPECT_EQ(poll(&fd, 1, -1), 1);
+ EXPECT_EQ(fd.revents & POLLIN, 1);
+ EXPECT_EQ(recv(self->cfd, recv_mem, sizeof(recv_mem), 0),
+ sizeof(send_mem) - sizeof(recv_mem));
+}
+
TEST_F(tls, blocking)
{
size_t data = 100000;
--
2.21.0
^ permalink raw reply related
* [PATCH net 1/2] net/tls: fix poll ignoring partially copied records
From: Jakub Kicinski @ 2019-07-04 21:50 UTC (permalink / raw)
To: davem
Cc: netdev, oss-drivers, alexei.starovoitov, Jakub Kicinski,
David Beckett, Dirk van der Merwe
In-Reply-To: <20190704215037.6008-1-jakub.kicinski@netronome.com>
David reports that RPC applications which use epoll() occasionally
get stuck, and that TLS ULP causes the kernel to not wake applications,
even though read() will return data.
This is indeed true. The ctx->rx_list which holds partially copied
records is not consulted when deciding whether socket is readable.
Note that SO_RCVLOWAT with epoll() is and has always been broken for
kernel TLS. We'd need to parse all records from the TCP layer, instead
of just the first one.
Fixes: 692d7b5d1f91 ("tls: Fix recvmsg() to be able to peek across multiple records")
Reported-by: David Beckett <david.beckett@netronome.com>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com>
---
net/tls/tls_sw.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
index 455a782c7658..e2385183526e 100644
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -1958,7 +1958,8 @@ bool tls_sw_stream_read(const struct sock *sk)
ingress_empty = list_empty(&psock->ingress_msg);
rcu_read_unlock();
- return !ingress_empty || ctx->recv_pkt;
+ return !ingress_empty || ctx->recv_pkt ||
+ !skb_queue_empty(&ctx->rx_list);
}
static int tls_read_size(struct strparser *strp, struct sk_buff *skb)
--
2.21.0
^ permalink raw reply related
* [PATCH net 0/2] net/tls: fix poll() wake up
From: Jakub Kicinski @ 2019-07-04 21:50 UTC (permalink / raw)
To: davem; +Cc: netdev, oss-drivers, alexei.starovoitov, Jakub Kicinski
Hi!
This small fix + selftest series is very similar to the previous
commit 04b25a5411f9 ("net/tls: fix no wakeup on partial reads").
This time instead of recvmsg we're fixing poll wake up.
Jakub Kicinski (2):
net/tls: fix poll ignoring partially copied records
selftests/tls: add test for poll() with data in TLS ULP
net/tls/tls_sw.c | 3 ++-
tools/testing/selftests/net/tls.c | 26 ++++++++++++++++++++++++++
2 files changed, 28 insertions(+), 1 deletion(-)
--
2.21.0
^ permalink raw reply
* Re: [net-next 14/14] net/mlx5e: Add kTLS TX HW offload support
From: Jakub Kicinski @ 2019-07-04 21:35 UTC (permalink / raw)
To: Saeed Mahameed
Cc: David S. Miller, netdev@vger.kernel.org, Tariq Toukan,
Eran Ben Elisha, Boris Pismenny
In-Reply-To: <20190704181235.8966-15-saeedm@mellanox.com>
On Thu, 4 Jul 2019 18:16:15 +0000, Saeed Mahameed wrote:
> +struct sk_buff *mlx5e_ktls_handle_tx_skb(struct net_device *netdev,
> + struct mlx5e_txqsq *sq,
> + struct sk_buff *skb,
> + struct mlx5e_tx_wqe **wqe, u16 *pi)
> +{
> + struct mlx5e_ktls_offload_context_tx *priv_tx;
> + struct mlx5e_sq_stats *stats = sq->stats;
> + struct mlx5_wqe_ctrl_seg *cseg;
> + struct tls_context *tls_ctx;
> + int datalen;
> + u32 seq;
> +
> + if (!skb->sk || !tls_is_sk_tx_device_offloaded(skb->sk))
> + goto out;
> +
> + datalen = skb->len - (skb_transport_offset(skb) + tcp_hdrlen(skb));
> + if (!datalen)
> + goto out;
> +
> + tls_ctx = tls_get_ctx(skb->sk);
> + if (unlikely(tls_ctx->netdev != netdev))
> + goto out;
If a frame for a different device leaked through the stack, we need to
fix the stack. Also you should drop the frame in this case, the device
will no encrypt it.
> + priv_tx = mlx5e_get_ktls_tx_priv_ctx(tls_ctx);
> +
> + if (unlikely(mlx5e_ktls_tx_offload_test_and_clear_pending(priv_tx))) {
> + mlx5e_ktls_tx_post_param_wqes(sq, priv_tx, false, false);
> + *wqe = mlx5e_sq_fetch_wqe(sq, sizeof(**wqe), pi);
> + stats->ktls_ctx++;
> + }
> +
> + seq = ntohl(tcp_hdr(skb)->seq);
> + if (unlikely(priv_tx->expected_seq != seq)) {
> + skb = mlx5e_ktls_tx_handle_ooo(priv_tx, sq, skb, seq);
> + if (unlikely(!skb))
> + goto out;
> + *wqe = mlx5e_sq_fetch_wqe(sq, sizeof(**wqe), pi);
> + }
> +
> + priv_tx->expected_seq = seq + datalen;
> +
> + cseg = &(*wqe)->ctrl;
> + cseg->imm = cpu_to_be32(priv_tx->tisn);
> +
> + stats->ktls_enc_packets += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1;
> + stats->ktls_enc_bytes += datalen;
> +
> +out:
> + return skb;
> +}
> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
> index 483d321d2151..6854f132d505 100644
> --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
> +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.c
> @@ -50,6 +50,15 @@ static const struct counter_desc sw_stats_desc[] = {
> #ifdef CONFIG_MLX5_EN_TLS
> { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_ooo) },
> { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_tls_resync_bytes) },
> +
> + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_ooo) },
> + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_ooo_drop_no_sync_data) },
> + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_ooo_drop_bypass_req) },
> + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_ooo_dump_bytes) },
> + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_ooo_dump_packets) },
> + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_enc_packets) },
> + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_enc_bytes) },
> + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_ctx) },
> #endif
>
> { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_packets) },
> @@ -218,6 +227,16 @@ static void mlx5e_grp_sw_update_stats(struct mlx5e_priv *priv)
> #ifdef CONFIG_MLX5_EN_TLS
> s->tx_tls_ooo += sq_stats->tls_ooo;
> s->tx_tls_resync_bytes += sq_stats->tls_resync_bytes;
> +
> + s->tx_ktls_enc_packets += sq_stats->ktls_enc_packets;
> + s->tx_ktls_enc_bytes += sq_stats->ktls_enc_bytes;
> + s->tx_ktls_ooo += sq_stats->ktls_ooo;
> + s->tx_ktls_ooo_drop_no_sync_data +=
> + sq_stats->ktls_ooo_drop_no_sync_data;
> + s->tx_ktls_ooo_drop_bypass_req += sq_stats->ktls_ooo_drop_bypass_req;
> + s->tx_ktls_ooo_dump_bytes += sq_stats->ktls_ooo_dump_bytes;
> + s->tx_ktls_ooo_dump_packets += sq_stats->ktls_ooo_dump_packets;
> + s->tx_ktls_ctx += sq_stats->ktls_ctx;
> #endif
> s->tx_cqes += sq_stats->cqes;
> }
> @@ -1238,6 +1257,16 @@ static const struct counter_desc sq_stats_desc[] = {
> { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, csum_partial_inner) },
> { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, added_vlan_packets) },
> { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, nop) },
> +#ifdef CONFIG_MLX5_EN_TLS
> + { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, ktls_ooo) },
> + { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, ktls_ooo_drop_no_sync_data) },
> + { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, ktls_ooo_drop_bypass_req) },
> + { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, ktls_ooo_dump_bytes) },
> + { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, ktls_ooo_dump_packets) },
> + { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, ktls_enc_packets) },
> + { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, ktls_enc_bytes) },
> + { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, ktls_ctx) },
> +#endif
> { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, csum_none) },
> { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, stopped) },
> { MLX5E_DECLARE_TX_STAT(struct mlx5e_sq_stats, dropped) },
For the stats as discussed please use common names, and preferably
add yours to the doc too, so we have them documented. Unless the
stat seems very specific to your implementation, perhaps.
^ permalink raw reply
* [RFC bpf-next 5/8] bpf: migrate fixup_bpf_calls to list patching infra
From: Jiong Wang @ 2019-07-04 21:26 UTC (permalink / raw)
To: alexei.starovoitov, daniel
Cc: ecree, naveen.n.rao, andriin, jakub.kicinski, bpf, netdev,
oss-drivers, Jiong Wang
In-Reply-To: <1562275611-31790-1-git-send-email-jiong.wang@netronome.com>
This patch migrate fixup_bpf_calls to new list patching
infrastructure.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
---
kernel/bpf/verifier.c | 94 +++++++++++++++++++++++++++------------------------
1 file changed, 49 insertions(+), 45 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2d16e85..30ed28e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -9033,16 +9033,19 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
{
struct bpf_prog *prog = env->prog;
struct bpf_insn *insn = prog->insnsi;
+ struct bpf_list_insn *list, *elem;
const struct bpf_func_proto *fn;
- const int insn_cnt = prog->len;
const struct bpf_map_ops *ops;
struct bpf_insn_aux_data *aux;
struct bpf_insn insn_buf[16];
- struct bpf_prog *new_prog;
struct bpf_map *map_ptr;
- int i, cnt, delta = 0;
+ int cnt, ret = 0;
- for (i = 0; i < insn_cnt; i++, insn++) {
+ list = bpf_create_list_insn(env->prog);
+ if (IS_ERR(list))
+ return PTR_ERR(list);
+ for (elem = list; elem; elem = elem->next) {
+ insn = &elem->insn;
if (insn->code == (BPF_ALU64 | BPF_MOD | BPF_X) ||
insn->code == (BPF_ALU64 | BPF_DIV | BPF_X) ||
insn->code == (BPF_ALU | BPF_MOD | BPF_X) ||
@@ -9073,13 +9076,11 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
cnt = ARRAY_SIZE(mask_and_mod) - (is64 ? 1 : 0);
}
- new_prog = bpf_patch_insn_data(env, i + delta, patchlet, cnt);
- if (!new_prog)
- return -ENOMEM;
-
- delta += cnt - 1;
- env->prog = prog = new_prog;
- insn = new_prog->insnsi + i + delta;
+ elem = bpf_patch_list_insn(elem, patchlet, cnt);
+ if (IS_ERR(elem)) {
+ ret = PTR_ERR(elem);
+ goto free_list_ret;
+ }
continue;
}
@@ -9089,16 +9090,15 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
cnt = env->ops->gen_ld_abs(insn, insn_buf);
if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf)) {
verbose(env, "bpf verifier is misconfigured\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_list_ret;
}
- new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
- if (!new_prog)
- return -ENOMEM;
-
- delta += cnt - 1;
- env->prog = prog = new_prog;
- insn = new_prog->insnsi + i + delta;
+ elem = bpf_patch_list_insn(elem, insn_buf, cnt);
+ if (IS_ERR(elem)) {
+ ret = PTR_ERR(elem);
+ goto free_list_ret;
+ }
continue;
}
@@ -9111,7 +9111,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
bool issrc, isneg;
u32 off_reg;
- aux = &env->insn_aux_data[i + delta];
+ aux = &env->insn_aux_data[elem->orig_idx - 1];
if (!aux->alu_state ||
aux->alu_state == BPF_ALU_NON_POINTER)
continue;
@@ -9144,13 +9144,12 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
*patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1);
cnt = patch - insn_buf;
- new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
- if (!new_prog)
- return -ENOMEM;
+ elem = bpf_patch_list_insn(elem, insn_buf, cnt);
+ if (IS_ERR(elem)) {
+ ret = PTR_ERR(elem);
+ goto free_list_ret;
+ }
- delta += cnt - 1;
- env->prog = prog = new_prog;
- insn = new_prog->insnsi + i + delta;
continue;
}
@@ -9183,7 +9182,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
insn->imm = 0;
insn->code = BPF_JMP | BPF_TAIL_CALL;
- aux = &env->insn_aux_data[i + delta];
+ aux = &env->insn_aux_data[elem->orig_idx - 1];
if (!bpf_map_ptr_unpriv(aux))
continue;
@@ -9195,7 +9194,8 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
*/
if (bpf_map_ptr_poisoned(aux)) {
verbose(env, "tail_call abusing map_ptr\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_list_ret;
}
map_ptr = BPF_MAP_PTR(aux->map_state);
@@ -9207,13 +9207,12 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
map)->index_mask);
insn_buf[2] = *insn;
cnt = 3;
- new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
- if (!new_prog)
- return -ENOMEM;
+ elem = bpf_patch_list_insn(elem, insn_buf, cnt);
+ if (IS_ERR(elem)) {
+ ret = PTR_ERR(elem);
+ goto free_list_ret;
+ }
- delta += cnt - 1;
- env->prog = prog = new_prog;
- insn = new_prog->insnsi + i + delta;
continue;
}
@@ -9228,7 +9227,7 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
insn->imm == BPF_FUNC_map_push_elem ||
insn->imm == BPF_FUNC_map_pop_elem ||
insn->imm == BPF_FUNC_map_peek_elem)) {
- aux = &env->insn_aux_data[i + delta];
+ aux = &env->insn_aux_data[elem->orig_idx - 1];
if (bpf_map_ptr_poisoned(aux))
goto patch_call_imm;
@@ -9239,17 +9238,16 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
cnt = ops->map_gen_lookup(map_ptr, insn_buf);
if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf)) {
verbose(env, "bpf verifier is misconfigured\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_list_ret;
}
- new_prog = bpf_patch_insn_data(env, i + delta,
- insn_buf, cnt);
- if (!new_prog)
- return -ENOMEM;
+ elem = bpf_patch_list_insn(elem, insn_buf, cnt);
+ if (IS_ERR(elem)) {
+ ret = PTR_ERR(elem);
+ goto free_list_ret;
+ }
- delta += cnt - 1;
- env->prog = prog = new_prog;
- insn = new_prog->insnsi + i + delta;
continue;
}
@@ -9307,12 +9305,18 @@ static int fixup_bpf_calls(struct bpf_verifier_env *env)
verbose(env,
"kernel subsystem misconfigured func %s#%d\n",
func_id_name(insn->imm), insn->imm);
- return -EFAULT;
+ ret = -EFAULT;
+ goto free_list_ret;
}
insn->imm = fn->func - __bpf_call_base;
}
- return 0;
+ env = verifier_linearize_list_insn(env, list);
+ if (IS_ERR(env))
+ ret = PTR_ERR(env);
+free_list_ret:
+ bpf_destroy_list_insn(list);
+ return ret;
}
static void free_states(struct bpf_verifier_env *env)
--
2.7.4
^ permalink raw reply related
* [RFC bpf-next 8/8] bpf: delete all those code around old insn patching infrastructure
From: Jiong Wang @ 2019-07-04 21:26 UTC (permalink / raw)
To: alexei.starovoitov, daniel
Cc: ecree, naveen.n.rao, andriin, jakub.kicinski, bpf, netdev,
oss-drivers, Jiong Wang
In-Reply-To: <1562275611-31790-1-git-send-email-jiong.wang@netronome.com>
This patch delete all code around old insn patching infrastructure.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
---
include/linux/bpf_verifier.h | 1 -
include/linux/filter.h | 4 -
kernel/bpf/core.c | 169 ---------------------------------
kernel/bpf/verifier.c | 221 +------------------------------------------
4 files changed, 1 insertion(+), 394 deletions(-)
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 5fe99f3..79c1733 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -305,7 +305,6 @@ struct bpf_insn_aux_data {
bool zext_dst; /* this insn zero extends dst reg */
u8 alu_state; /* used in combination with alu_limit */
bool prune_point;
- unsigned int orig_idx; /* original instruction index */
};
#define MAX_USED_MAPS 64 /* max number of maps accessed by one eBPF program */
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 1fea68c..fcfe0b0 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -838,10 +838,6 @@ static inline bool bpf_dump_raw_ok(void)
return kallsyms_show_value() == 1;
}
-struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
- const struct bpf_insn *patch, u32 len);
-int bpf_remove_insns(struct bpf_prog *prog, u32 off, u32 cnt);
-
int bpf_jit_adj_imm_off(struct bpf_insn *insn, int old_idx, int new_idx,
int idx_map[]);
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index c3a5f84..716220b 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -333,175 +333,6 @@ int bpf_prog_calc_tag(struct bpf_prog *fp)
return 0;
}
-static int bpf_adj_delta_to_imm(struct bpf_insn *insn, u32 pos, s32 end_old,
- s32 end_new, s32 curr, const bool probe_pass)
-{
- const s64 imm_min = S32_MIN, imm_max = S32_MAX;
- s32 delta = end_new - end_old;
- s64 imm = insn->imm;
-
- if (curr < pos && curr + imm + 1 >= end_old)
- imm += delta;
- else if (curr >= end_new && curr + imm + 1 < end_new)
- imm -= delta;
- if (imm < imm_min || imm > imm_max)
- return -ERANGE;
- if (!probe_pass)
- insn->imm = imm;
- return 0;
-}
-
-static int bpf_adj_delta_to_off(struct bpf_insn *insn, u32 pos, s32 end_old,
- s32 end_new, s32 curr, const bool probe_pass)
-{
- const s32 off_min = S16_MIN, off_max = S16_MAX;
- s32 delta = end_new - end_old;
- s32 off = insn->off;
-
- if (curr < pos && curr + off + 1 >= end_old)
- off += delta;
- else if (curr >= end_new && curr + off + 1 < end_new)
- off -= delta;
- if (off < off_min || off > off_max)
- return -ERANGE;
- if (!probe_pass)
- insn->off = off;
- return 0;
-}
-
-static int bpf_adj_branches(struct bpf_prog *prog, u32 pos, s32 end_old,
- s32 end_new, const bool probe_pass)
-{
- u32 i, insn_cnt = prog->len + (probe_pass ? end_new - end_old : 0);
- struct bpf_insn *insn = prog->insnsi;
- int ret = 0;
-
- for (i = 0; i < insn_cnt; i++, insn++) {
- u8 code;
-
- /* In the probing pass we still operate on the original,
- * unpatched image in order to check overflows before we
- * do any other adjustments. Therefore skip the patchlet.
- */
- if (probe_pass && i == pos) {
- i = end_new;
- insn = prog->insnsi + end_old;
- }
- code = insn->code;
- if ((BPF_CLASS(code) != BPF_JMP &&
- BPF_CLASS(code) != BPF_JMP32) ||
- BPF_OP(code) == BPF_EXIT)
- continue;
- /* Adjust offset of jmps if we cross patch boundaries. */
- if (BPF_OP(code) == BPF_CALL) {
- if (insn->src_reg != BPF_PSEUDO_CALL)
- continue;
- ret = bpf_adj_delta_to_imm(insn, pos, end_old,
- end_new, i, probe_pass);
- } else {
- ret = bpf_adj_delta_to_off(insn, pos, end_old,
- end_new, i, probe_pass);
- }
- if (ret)
- break;
- }
-
- return ret;
-}
-
-static void bpf_adj_linfo(struct bpf_prog *prog, u32 off, u32 delta)
-{
- struct bpf_line_info *linfo;
- u32 i, nr_linfo;
-
- nr_linfo = prog->aux->nr_linfo;
- if (!nr_linfo || !delta)
- return;
-
- linfo = prog->aux->linfo;
-
- for (i = 0; i < nr_linfo; i++)
- if (off < linfo[i].insn_off)
- break;
-
- /* Push all off < linfo[i].insn_off by delta */
- for (; i < nr_linfo; i++)
- linfo[i].insn_off += delta;
-}
-
-struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
- const struct bpf_insn *patch, u32 len)
-{
- u32 insn_adj_cnt, insn_rest, insn_delta = len - 1;
- const u32 cnt_max = S16_MAX;
- struct bpf_prog *prog_adj;
- int err;
-
- /* Since our patchlet doesn't expand the image, we're done. */
- if (insn_delta == 0) {
- memcpy(prog->insnsi + off, patch, sizeof(*patch));
- return prog;
- }
-
- insn_adj_cnt = prog->len + insn_delta;
-
- /* Reject anything that would potentially let the insn->off
- * target overflow when we have excessive program expansions.
- * We need to probe here before we do any reallocation where
- * we afterwards may not fail anymore.
- */
- if (insn_adj_cnt > cnt_max &&
- (err = bpf_adj_branches(prog, off, off + 1, off + len, true)))
- return ERR_PTR(err);
-
- /* Several new instructions need to be inserted. Make room
- * for them. Likely, there's no need for a new allocation as
- * last page could have large enough tailroom.
- */
- prog_adj = bpf_prog_realloc(prog, bpf_prog_size(insn_adj_cnt),
- GFP_USER);
- if (!prog_adj)
- return ERR_PTR(-ENOMEM);
-
- prog_adj->len = insn_adj_cnt;
-
- /* Patching happens in 3 steps:
- *
- * 1) Move over tail of insnsi from next instruction onwards,
- * so we can patch the single target insn with one or more
- * new ones (patching is always from 1 to n insns, n > 0).
- * 2) Inject new instructions at the target location.
- * 3) Adjust branch offsets if necessary.
- */
- insn_rest = insn_adj_cnt - off - len;
-
- memmove(prog_adj->insnsi + off + len, prog_adj->insnsi + off + 1,
- sizeof(*patch) * insn_rest);
- memcpy(prog_adj->insnsi + off, patch, sizeof(*patch) * len);
-
- /* We are guaranteed to not fail at this point, otherwise
- * the ship has sailed to reverse to the original state. An
- * overflow cannot happen at this point.
- */
- BUG_ON(bpf_adj_branches(prog_adj, off, off + 1, off + len, false));
-
- bpf_adj_linfo(prog_adj, off, insn_delta);
-
- return prog_adj;
-}
-
-int bpf_remove_insns(struct bpf_prog *prog, u32 off, u32 cnt)
-{
- /* Branch offsets can't overflow when program is shrinking, no need
- * to call bpf_adj_branches(..., true) here
- */
- memmove(prog->insnsi + off, prog->insnsi + off + cnt,
- sizeof(struct bpf_insn) * (prog->len - off - cnt));
- prog->len -= cnt;
-
- return WARN_ON_ONCE(bpf_adj_branches(prog, off, off + cnt, off, false));
-}
-
int bpf_jit_adj_imm_off(struct bpf_insn *insn, int old_idx, int new_idx,
s32 idx_map[])
{
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index abe11fd..9e5618f 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -8067,223 +8067,6 @@ static void convert_pseudo_ld_imm64(struct bpf_verifier_env *env)
insn->src_reg = 0;
}
-/* single env->prog->insni[off] instruction was replaced with the range
- * insni[off, off + cnt). Adjust corresponding insn_aux_data by copying
- * [0, off) and [off, end) to new locations, so the patched range stays zero
- */
-static int adjust_insn_aux_data(struct bpf_verifier_env *env,
- struct bpf_prog *new_prog, u32 off, u32 cnt)
-{
- struct bpf_insn_aux_data *new_data, *old_data = env->insn_aux_data;
- struct bpf_insn *insn = new_prog->insnsi;
- u32 prog_len;
- int i;
-
- /* aux info at OFF always needs adjustment, no matter fast path
- * (cnt == 1) is taken or not. There is no guarantee INSN at OFF is the
- * original insn at old prog.
- */
- old_data[off].zext_dst = insn_has_def32(env, insn + off + cnt - 1);
-
- if (cnt == 1)
- return 0;
- prog_len = new_prog->len;
- new_data = vzalloc(array_size(prog_len,
- sizeof(struct bpf_insn_aux_data)));
- if (!new_data)
- return -ENOMEM;
- memcpy(new_data, old_data, sizeof(struct bpf_insn_aux_data) * off);
- memcpy(new_data + off + cnt - 1, old_data + off,
- sizeof(struct bpf_insn_aux_data) * (prog_len - off - cnt + 1));
- for (i = off; i < off + cnt - 1; i++) {
- new_data[i].seen = true;
- new_data[i].zext_dst = insn_has_def32(env, insn + i);
- }
- env->insn_aux_data = new_data;
- vfree(old_data);
- return 0;
-}
-
-static void adjust_subprog_starts(struct bpf_verifier_env *env, u32 off, u32 len)
-{
- int i;
-
- if (len == 1)
- return;
- /* NOTE: fake 'exit' subprog should be updated as well. */
- for (i = 0; i <= env->subprog_cnt; i++) {
- if (env->subprog_info[i].start <= off)
- continue;
- env->subprog_info[i].start += len - 1;
- }
-}
-
-static struct bpf_prog *bpf_patch_insn_data(struct bpf_verifier_env *env, u32 off,
- const struct bpf_insn *patch, u32 len)
-{
- struct bpf_prog *new_prog;
-
- new_prog = bpf_patch_insn_single(env->prog, off, patch, len);
- if (IS_ERR(new_prog)) {
- if (PTR_ERR(new_prog) == -ERANGE)
- verbose(env,
- "insn %d cannot be patched due to 16-bit range\n",
- env->insn_aux_data[off].orig_idx);
- return NULL;
- }
- if (adjust_insn_aux_data(env, new_prog, off, len))
- return NULL;
- adjust_subprog_starts(env, off, len);
- return new_prog;
-}
-
-static int adjust_subprog_starts_after_remove(struct bpf_verifier_env *env,
- u32 off, u32 cnt)
-{
- int i, j;
-
- /* find first prog starting at or after off (first to remove) */
- for (i = 0; i < env->subprog_cnt; i++)
- if (env->subprog_info[i].start >= off)
- break;
- /* find first prog starting at or after off + cnt (first to stay) */
- for (j = i; j < env->subprog_cnt; j++)
- if (env->subprog_info[j].start >= off + cnt)
- break;
- /* if j doesn't start exactly at off + cnt, we are just removing
- * the front of previous prog
- */
- if (env->subprog_info[j].start != off + cnt)
- j--;
-
- if (j > i) {
- struct bpf_prog_aux *aux = env->prog->aux;
- int move;
-
- /* move fake 'exit' subprog as well */
- move = env->subprog_cnt + 1 - j;
-
- memmove(env->subprog_info + i,
- env->subprog_info + j,
- sizeof(*env->subprog_info) * move);
- env->subprog_cnt -= j - i;
-
- /* remove func_info */
- if (aux->func_info) {
- move = aux->func_info_cnt - j;
-
- memmove(aux->func_info + i,
- aux->func_info + j,
- sizeof(*aux->func_info) * move);
- aux->func_info_cnt -= j - i;
- /* func_info->insn_off is set after all code rewrites,
- * in adjust_btf_func() - no need to adjust
- */
- }
- } else {
- /* convert i from "first prog to remove" to "first to adjust" */
- if (env->subprog_info[i].start == off)
- i++;
- }
-
- /* update fake 'exit' subprog as well */
- for (; i <= env->subprog_cnt; i++)
- env->subprog_info[i].start -= cnt;
-
- return 0;
-}
-
-static int bpf_adj_linfo_after_remove(struct bpf_verifier_env *env, u32 off,
- u32 cnt)
-{
- struct bpf_prog *prog = env->prog;
- u32 i, l_off, l_cnt, nr_linfo;
- struct bpf_line_info *linfo;
-
- nr_linfo = prog->aux->nr_linfo;
- if (!nr_linfo)
- return 0;
-
- linfo = prog->aux->linfo;
-
- /* find first line info to remove, count lines to be removed */
- for (i = 0; i < nr_linfo; i++)
- if (linfo[i].insn_off >= off)
- break;
-
- l_off = i;
- l_cnt = 0;
- for (; i < nr_linfo; i++)
- if (linfo[i].insn_off < off + cnt)
- l_cnt++;
- else
- break;
-
- /* First live insn doesn't match first live linfo, it needs to "inherit"
- * last removed linfo. prog is already modified, so prog->len == off
- * means no live instructions after (tail of the program was removed).
- */
- if (prog->len != off && l_cnt &&
- (i == nr_linfo || linfo[i].insn_off != off + cnt)) {
- l_cnt--;
- linfo[--i].insn_off = off + cnt;
- }
-
- /* remove the line info which refer to the removed instructions */
- if (l_cnt) {
- memmove(linfo + l_off, linfo + i,
- sizeof(*linfo) * (nr_linfo - i));
-
- prog->aux->nr_linfo -= l_cnt;
- nr_linfo = prog->aux->nr_linfo;
- }
-
- /* pull all linfo[i].insn_off >= off + cnt in by cnt */
- for (i = l_off; i < nr_linfo; i++)
- linfo[i].insn_off -= cnt;
-
- /* fix up all subprogs (incl. 'exit') which start >= off */
- for (i = 0; i <= env->subprog_cnt; i++)
- if (env->subprog_info[i].linfo_idx > l_off) {
- /* program may have started in the removed region but
- * may not be fully removed
- */
- if (env->subprog_info[i].linfo_idx >= l_off + l_cnt)
- env->subprog_info[i].linfo_idx -= l_cnt;
- else
- env->subprog_info[i].linfo_idx = l_off;
- }
-
- return 0;
-}
-
-static int verifier_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt)
-{
- struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
- unsigned int orig_prog_len = env->prog->len;
- int err;
-
- if (bpf_prog_is_dev_bound(env->prog->aux))
- bpf_prog_offload_remove_insns(env, off, cnt);
-
- err = bpf_remove_insns(env->prog, off, cnt);
- if (err)
- return err;
-
- err = adjust_subprog_starts_after_remove(env, off, cnt);
- if (err)
- return err;
-
- err = bpf_adj_linfo_after_remove(env, off, cnt);
- if (err)
- return err;
-
- memmove(aux_data + off, aux_data + off + cnt,
- sizeof(*aux_data) * (orig_prog_len - off - cnt));
-
- return 0;
-}
-
/* The verifier does more data flow analysis than llvm and will not
* explore branches that are dead at run time. Malicious programs can
* have dead code too. Therefore replace all dead at-run-time code
@@ -9365,7 +9148,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
u64 start_time = ktime_get_ns();
struct bpf_verifier_env *env;
struct bpf_verifier_log *log;
- int i, len, ret = -EINVAL;
+ int len, ret = -EINVAL;
bool is_priv;
/* no program is valid */
@@ -9386,8 +9169,6 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
ret = -ENOMEM;
if (!env->insn_aux_data)
goto err_free_env;
- for (i = 0; i < len; i++)
- env->insn_aux_data[i].orig_idx = i;
env->prog = *prog;
env->ops = bpf_verifier_ops[env->prog->type];
is_priv = capable(CAP_SYS_ADMIN);
--
2.7.4
^ permalink raw reply related
* [RFC bpf-next 6/8] bpf: migrate zero extension opt to list patching infra
From: Jiong Wang @ 2019-07-04 21:26 UTC (permalink / raw)
To: alexei.starovoitov, daniel
Cc: ecree, naveen.n.rao, andriin, jakub.kicinski, bpf, netdev,
oss-drivers, Jiong Wang
In-Reply-To: <1562275611-31790-1-git-send-email-jiong.wang@netronome.com>
This patch migrate 32-bit zero extension insertion to new list patching
infrastructure.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
---
kernel/bpf/verifier.c | 45 +++++++++++++++++++++++++--------------------
1 file changed, 25 insertions(+), 20 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 30ed28e..58d6bbe 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -8549,10 +8549,9 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
const union bpf_attr *attr)
{
struct bpf_insn *patch, zext_patch[2], rnd_hi32_patch[4];
- struct bpf_insn_aux_data *aux = env->insn_aux_data;
- int i, patch_len, delta = 0, len = env->prog->len;
- struct bpf_insn *insns = env->prog->insnsi;
- struct bpf_prog *new_prog;
+ struct bpf_list_insn *list, *elem;
+ struct bpf_insn_aux_data *aux;
+ int patch_len, ret = 0;
bool rnd_hi32;
rnd_hi32 = attr->prog_flags & BPF_F_TEST_RND_HI32;
@@ -8560,12 +8559,16 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
rnd_hi32_patch[1] = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, 0);
rnd_hi32_patch[2] = BPF_ALU64_IMM(BPF_LSH, BPF_REG_AX, 32);
rnd_hi32_patch[3] = BPF_ALU64_REG(BPF_OR, 0, BPF_REG_AX);
- for (i = 0; i < len; i++) {
- int adj_idx = i + delta;
- struct bpf_insn insn;
- insn = insns[adj_idx];
- if (!aux[adj_idx].zext_dst) {
+ list = bpf_create_list_insn(env->prog);
+ if (IS_ERR(list))
+ return PTR_ERR(list);
+
+ for (elem = list; elem; elem = elem->next) {
+ struct bpf_insn insn = elem->insn;
+
+ aux = &env->insn_aux_data[elem->orig_idx - 1];
+ if (!aux->zext_dst) {
u8 code, class;
u32 imm_rnd;
@@ -8584,13 +8587,13 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
if (is_reg64(env, &insn, insn.dst_reg, NULL, DST_OP)) {
if (class == BPF_LD &&
BPF_MODE(code) == BPF_IMM)
- i++;
+ elem = elem->next;
continue;
}
/* ctx load could be transformed into wider load. */
if (class == BPF_LDX &&
- aux[adj_idx].ptr_type == PTR_TO_CTX)
+ aux->ptr_type == PTR_TO_CTX)
continue;
imm_rnd = get_random_int();
@@ -8611,16 +8614,18 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
patch = zext_patch;
patch_len = 2;
apply_patch_buffer:
- new_prog = bpf_patch_insn_data(env, adj_idx, patch, patch_len);
- if (!new_prog)
- return -ENOMEM;
- env->prog = new_prog;
- insns = new_prog->insnsi;
- aux = env->insn_aux_data;
- delta += patch_len - 1;
+ elem = bpf_patch_list_insn(elem, patch, patch_len);
+ if (IS_ERR(elem)) {
+ ret = PTR_ERR(elem);
+ goto free_list_ret;
+ }
}
-
- return 0;
+ env = verifier_linearize_list_insn(env, list);
+ if (IS_ERR(env))
+ ret = PTR_ERR(env);
+free_list_ret:
+ bpf_destroy_list_insn(list);
+ return ret;
}
/* convert load instructions that access fields of a context type into a
--
2.7.4
^ permalink raw reply related
* [RFC bpf-next 4/8] bpf: migrate convert_ctx_accesses to list patching infra
From: Jiong Wang @ 2019-07-04 21:26 UTC (permalink / raw)
To: alexei.starovoitov, daniel
Cc: ecree, naveen.n.rao, andriin, jakub.kicinski, bpf, netdev,
oss-drivers, Jiong Wang
In-Reply-To: <1562275611-31790-1-git-send-email-jiong.wang@netronome.com>
This patch migrate convert_ctx_accesses to new list patching
infrastructure. pre-patch is used for generating prologue, because what we
really want to do is insert the prog before prog start without touching
the first insn.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
---
kernel/bpf/verifier.c | 98 ++++++++++++++++++++++++++++++---------------------
1 file changed, 58 insertions(+), 40 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 2026d64..2d16e85 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -8631,41 +8631,59 @@ static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
static int convert_ctx_accesses(struct bpf_verifier_env *env)
{
const struct bpf_verifier_ops *ops = env->ops;
- int i, cnt, size, ctx_field_size, delta = 0;
- const int insn_cnt = env->prog->len;
struct bpf_insn insn_buf[16], *insn;
u32 target_size, size_default, off;
- struct bpf_prog *new_prog;
+ struct bpf_list_insn *list, *elem;
+ int cnt, size, ctx_field_size;
enum bpf_access_type type;
bool is_narrower_load;
+ int ret = 0;
+
+ list = bpf_create_list_insn(env->prog);
+ if (IS_ERR(list))
+ return PTR_ERR(list);
+ elem = list;
if (ops->gen_prologue || env->seen_direct_write) {
if (!ops->gen_prologue) {
verbose(env, "bpf verifier is misconfigured\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_list_ret;
}
cnt = ops->gen_prologue(insn_buf, env->seen_direct_write,
env->prog);
if (cnt >= ARRAY_SIZE(insn_buf)) {
verbose(env, "bpf verifier is misconfigured\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_list_ret;
} else if (cnt) {
- new_prog = bpf_patch_insn_data(env, 0, insn_buf, cnt);
- if (!new_prog)
- return -ENOMEM;
+ struct bpf_list_insn *new_hdr;
- env->prog = new_prog;
- delta += cnt - 1;
+ /* "gen_prologue" generates patch buffer, we want to use
+ * pre-patch buffer because we don't want to touch the
+ * insn/aux at start offset.
+ */
+ new_hdr = bpf_prepatch_list_insn(list, insn_buf,
+ cnt - 1);
+ if (IS_ERR(new_hdr)) {
+ ret = -ENOMEM;
+ goto free_list_ret;
+ }
+ /* Update list head, so new pre-patched nodes could be
+ * freed by destroyer.
+ */
+ list = new_hdr;
}
}
if (bpf_prog_is_dev_bound(env->prog->aux))
- return 0;
+ goto linearize_list_ret;
- insn = env->prog->insnsi + delta;
-
- for (i = 0; i < insn_cnt; i++, insn++) {
+ for (; elem; elem = elem->next) {
bpf_convert_ctx_access_t convert_ctx_access;
+ struct bpf_insn_aux_data *aux;
+
+ insn = &elem->insn;
if (insn->code == (BPF_LDX | BPF_MEM | BPF_B) ||
insn->code == (BPF_LDX | BPF_MEM | BPF_H) ||
@@ -8680,8 +8698,8 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
else
continue;
- if (type == BPF_WRITE &&
- env->insn_aux_data[i + delta].sanitize_stack_off) {
+ aux = &env->insn_aux_data[elem->orig_idx - 1];
+ if (type == BPF_WRITE && aux->sanitize_stack_off) {
struct bpf_insn patch[] = {
/* Sanitize suspicious stack slot with zero.
* There are no memory dependencies for this store,
@@ -8689,8 +8707,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
* constant of zero
*/
BPF_ST_MEM(BPF_DW, BPF_REG_FP,
- env->insn_aux_data[i + delta].sanitize_stack_off,
- 0),
+ aux->sanitize_stack_off, 0),
/* the original STX instruction will immediately
* overwrite the same stack slot with appropriate value
*/
@@ -8698,17 +8715,15 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
};
cnt = ARRAY_SIZE(patch);
- new_prog = bpf_patch_insn_data(env, i + delta, patch, cnt);
- if (!new_prog)
- return -ENOMEM;
-
- delta += cnt - 1;
- env->prog = new_prog;
- insn = new_prog->insnsi + i + delta;
+ elem = bpf_patch_list_insn(elem, patch, cnt);
+ if (IS_ERR(elem)) {
+ ret = PTR_ERR(elem);
+ goto free_list_ret;
+ }
continue;
}
- switch (env->insn_aux_data[i + delta].ptr_type) {
+ switch (aux->ptr_type) {
case PTR_TO_CTX:
if (!ops->convert_ctx_access)
continue;
@@ -8728,7 +8743,7 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
continue;
}
- ctx_field_size = env->insn_aux_data[i + delta].ctx_field_size;
+ ctx_field_size = aux->ctx_field_size;
size = BPF_LDST_BYTES(insn);
/* If the read access is a narrower load of the field,
@@ -8744,7 +8759,8 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
if (type == BPF_WRITE) {
verbose(env, "bpf verifier narrow ctx access misconfigured\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_list_ret;
}
size_code = BPF_H;
@@ -8763,7 +8779,8 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
if (cnt == 0 || cnt >= ARRAY_SIZE(insn_buf) ||
(ctx_field_size && !target_size)) {
verbose(env, "bpf verifier is misconfigured\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto free_list_ret;
}
if (is_narrower_load && size < target_size) {
@@ -8786,18 +8803,19 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
}
}
- new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
- if (!new_prog)
- return -ENOMEM;
-
- delta += cnt - 1;
-
- /* keep walking new program and skip insns we just inserted */
- env->prog = new_prog;
- insn = new_prog->insnsi + i + delta;
+ elem = bpf_patch_list_insn(elem, insn_buf, cnt);
+ if (IS_ERR(elem)) {
+ ret = PTR_ERR(elem);
+ goto free_list_ret;
+ }
}
-
- return 0;
+linearize_list_ret:
+ env = verifier_linearize_list_insn(env, list);
+ if (IS_ERR(env))
+ ret = PTR_ERR(env);
+free_list_ret:
+ bpf_destroy_list_insn(list);
+ return ret;
}
static int jit_subprogs(struct bpf_verifier_env *env)
--
2.7.4
^ permalink raw reply related
* [RFC bpf-next 7/8] bpf: migrate insn remove to list patching infra
From: Jiong Wang @ 2019-07-04 21:26 UTC (permalink / raw)
To: alexei.starovoitov, daniel
Cc: ecree, naveen.n.rao, andriin, jakub.kicinski, bpf, netdev,
oss-drivers, Jiong Wang
In-Reply-To: <1562275611-31790-1-git-send-email-jiong.wang@netronome.com>
This patch migrate dead code remove pass to new list patching
infrastructure.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
---
kernel/bpf/verifier.c | 59 +++++++++++++++++----------------------------------
1 file changed, 19 insertions(+), 40 deletions(-)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 58d6bbe..abe11fd 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -8500,49 +8500,30 @@ verifier_linearize_list_insn(struct bpf_verifier_env *env,
return ret_env;
}
-static int opt_remove_dead_code(struct bpf_verifier_env *env)
+static int opt_remove_useless_code(struct bpf_verifier_env *env)
{
- struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
- int insn_cnt = env->prog->len;
- int i, err;
-
- for (i = 0; i < insn_cnt; i++) {
- int j;
-
- j = 0;
- while (i + j < insn_cnt && !aux_data[i + j].seen)
- j++;
- if (!j)
- continue;
-
- err = verifier_remove_insns(env, i, j);
- if (err)
- return err;
- insn_cnt = env->prog->len;
- }
-
- return 0;
-}
-
-static int opt_remove_nops(struct bpf_verifier_env *env)
-{
- const struct bpf_insn ja = BPF_JMP_IMM(BPF_JA, 0, 0, 0);
- struct bpf_insn *insn = env->prog->insnsi;
- int insn_cnt = env->prog->len;
- int i, err;
+ struct bpf_insn_aux_data *auxs = env->insn_aux_data;
+ const struct bpf_insn nop =
+ BPF_JMP_IMM(BPF_JA, 0, 0, 0);
+ struct bpf_list_insn *list, *elem;
+ int ret = 0;
- for (i = 0; i < insn_cnt; i++) {
- if (memcmp(&insn[i], &ja, sizeof(ja)))
+ list = bpf_create_list_insn(env->prog);
+ if (IS_ERR(list))
+ return PTR_ERR(list);
+ for (elem = list; elem; elem = elem->next) {
+ if (auxs[elem->orig_idx - 1].seen &&
+ memcmp(&elem->insn, &nop, sizeof(nop)))
continue;
- err = verifier_remove_insns(env, i, 1);
- if (err)
- return err;
- insn_cnt--;
- i--;
+ elem->flag |= LIST_INSN_FLAG_REMOVED;
}
- return 0;
+ env = verifier_linearize_list_insn(env, list);
+ if (IS_ERR(env))
+ ret = PTR_ERR(env);
+ bpf_destroy_list_insn(list);
+ return ret;
}
static int opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env,
@@ -9488,9 +9469,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
if (ret == 0)
opt_hard_wire_dead_code_branches(env);
if (ret == 0)
- ret = opt_remove_dead_code(env);
- if (ret == 0)
- ret = opt_remove_nops(env);
+ ret = opt_remove_useless_code(env);
} else {
if (ret == 0)
sanitize_dead_code(env);
--
2.7.4
^ permalink raw reply related
* [RFC bpf-next 3/8] bpf: migrate jit blinding to list patching infra
From: Jiong Wang @ 2019-07-04 21:26 UTC (permalink / raw)
To: alexei.starovoitov, daniel
Cc: ecree, naveen.n.rao, andriin, jakub.kicinski, bpf, netdev,
oss-drivers, Jiong Wang
In-Reply-To: <1562275611-31790-1-git-send-email-jiong.wang@netronome.com>
List linerization function will figure out the new jump destination of
patched/blinded jumps. No need of destination adjustment inside
bpf_jit_blind_insn any more.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
---
kernel/bpf/core.c | 76 ++++++++++++++++++++++++++-----------------------------
1 file changed, 36 insertions(+), 40 deletions(-)
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index e60703e..c3a5f84 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -1162,7 +1162,6 @@ static int bpf_jit_blind_insn(const struct bpf_insn *from,
{
struct bpf_insn *to = to_buff;
u32 imm_rnd = get_random_int();
- s16 off;
BUILD_BUG_ON(BPF_REG_AX + 1 != MAX_BPF_JIT_REG);
BUILD_BUG_ON(MAX_BPF_REG + 1 != MAX_BPF_JIT_REG);
@@ -1234,13 +1233,10 @@ static int bpf_jit_blind_insn(const struct bpf_insn *from,
case BPF_JMP | BPF_JSGE | BPF_K:
case BPF_JMP | BPF_JSLE | BPF_K:
case BPF_JMP | BPF_JSET | BPF_K:
- /* Accommodate for extra offset in case of a backjump. */
- off = from->off;
- if (off < 0)
- off -= 2;
*to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
*to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
- *to++ = BPF_JMP_REG(from->code, from->dst_reg, BPF_REG_AX, off);
+ *to++ = BPF_JMP_REG(from->code, from->dst_reg, BPF_REG_AX,
+ from->off);
break;
case BPF_JMP32 | BPF_JEQ | BPF_K:
@@ -1254,14 +1250,10 @@ static int bpf_jit_blind_insn(const struct bpf_insn *from,
case BPF_JMP32 | BPF_JSGE | BPF_K:
case BPF_JMP32 | BPF_JSLE | BPF_K:
case BPF_JMP32 | BPF_JSET | BPF_K:
- /* Accommodate for extra offset in case of a backjump. */
- off = from->off;
- if (off < 0)
- off -= 2;
*to++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm);
*to++ = BPF_ALU32_IMM(BPF_XOR, BPF_REG_AX, imm_rnd);
*to++ = BPF_JMP32_REG(from->code, from->dst_reg, BPF_REG_AX,
- off);
+ from->off);
break;
case BPF_LD | BPF_IMM | BPF_DW:
@@ -1332,10 +1324,9 @@ void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other)
struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
{
struct bpf_insn insn_buff[16], aux[2];
- struct bpf_prog *clone, *tmp;
- int insn_delta, insn_cnt;
- struct bpf_insn *insn;
- int i, rewritten;
+ struct bpf_list_insn *list, *elem;
+ struct bpf_prog *clone, *ret_prog;
+ int rewritten;
if (!bpf_jit_blinding_enabled(prog) || prog->blinded)
return prog;
@@ -1344,43 +1335,48 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog)
if (!clone)
return ERR_PTR(-ENOMEM);
- insn_cnt = clone->len;
- insn = clone->insnsi;
+ list = bpf_create_list_insn(clone);
+ if (IS_ERR(list))
+ return (struct bpf_prog *)list;
+
+ /* kill uninitialized warning on some gcc versions. */
+ memset(&aux, 0, sizeof(aux));
+
+ for (elem = list; elem; elem = elem->next) {
+ struct bpf_list_insn *next = elem->next;
+ struct bpf_insn insn = elem->insn;
- for (i = 0; i < insn_cnt; i++, insn++) {
/* We temporarily need to hold the original ld64 insn
* so that we can still access the first part in the
* second blinding run.
*/
- if (insn[0].code == (BPF_LD | BPF_IMM | BPF_DW) &&
- insn[1].code == 0)
- memcpy(aux, insn, sizeof(aux));
+ if (insn.code == (BPF_LD | BPF_IMM | BPF_DW)) {
+ struct bpf_insn next_insn = next->insn;
- rewritten = bpf_jit_blind_insn(insn, aux, insn_buff);
+ if (next_insn.code == 0) {
+ aux[0] = insn;
+ aux[1] = next_insn;
+ }
+ }
+
+ rewritten = bpf_jit_blind_insn(&insn, aux, insn_buff);
if (!rewritten)
continue;
- tmp = bpf_patch_insn_single(clone, i, insn_buff, rewritten);
- if (IS_ERR(tmp)) {
- /* Patching may have repointed aux->prog during
- * realloc from the original one, so we need to
- * fix it up here on error.
- */
- bpf_jit_prog_release_other(prog, clone);
- return tmp;
+ elem = bpf_patch_list_insn(elem, insn_buff, rewritten);
+ if (IS_ERR(elem)) {
+ ret_prog = (struct bpf_prog *)elem;
+ goto free_list_ret;
}
-
- clone = tmp;
- insn_delta = rewritten - 1;
-
- /* Walk new program and skip insns we just inserted. */
- insn = clone->insnsi + i + insn_delta;
- insn_cnt += insn_delta;
- i += insn_delta;
}
- clone->blinded = 1;
- return clone;
+ clone = bpf_linearize_list_insn(clone, list);
+ if (!IS_ERR(clone))
+ clone->blinded = 1;
+ ret_prog = clone;
+free_list_ret:
+ bpf_destroy_list_insn(list);
+ return ret_prog;
}
#endif /* CONFIG_BPF_JIT */
--
2.7.4
^ permalink raw reply related
* [RFC bpf-next 2/8] bpf: extend list based insn patching infra to verification layer
From: Jiong Wang @ 2019-07-04 21:26 UTC (permalink / raw)
To: alexei.starovoitov, daniel
Cc: ecree, naveen.n.rao, andriin, jakub.kicinski, bpf, netdev,
oss-drivers, Jiong Wang
In-Reply-To: <1562275611-31790-1-git-send-email-jiong.wang@netronome.com>
Verification layer also needs to handle auxiliar info as well as adjusting
subprog start.
At this layer, insns inside patch buffer could be jump, but they should
have been resolved, meaning they shouldn't jump to insn outside of the
patch buffer. Lineration function for this layer won't touch insns inside
patch buffer.
Adjusting subprog is finished along with adjusting jump target when the
input will cover bpf to bpf call insn, re-register subprog start is cheap.
But adjustment when there is insn deleteion is not considered yet.
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
---
kernel/bpf/verifier.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 150 insertions(+)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index a2e7637..2026d64 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -8350,6 +8350,156 @@ static void opt_hard_wire_dead_code_branches(struct bpf_verifier_env *env)
}
}
+/* Linearize bpf list insn to array (verifier layer). */
+static struct bpf_verifier_env *
+verifier_linearize_list_insn(struct bpf_verifier_env *env,
+ struct bpf_list_insn *list)
+{
+ u32 *idx_map, idx, orig_cnt, fini_cnt = 0;
+ struct bpf_subprog_info *new_subinfo;
+ struct bpf_insn_aux_data *new_data;
+ struct bpf_prog *prog = env->prog;
+ struct bpf_verifier_env *ret_env;
+ struct bpf_insn *insns, *insn;
+ struct bpf_list_insn *elem;
+ int ret;
+
+ /* Calculate final size. */
+ for (elem = list; elem; elem = elem->next)
+ if (!(elem->flag & LIST_INSN_FLAG_REMOVED))
+ fini_cnt++;
+
+ orig_cnt = prog->len;
+ insns = prog->insnsi;
+ /* If prog length remains same, nothing else to do. */
+ if (fini_cnt == orig_cnt) {
+ for (insn = insns, elem = list; elem; elem = elem->next, insn++)
+ *insn = elem->insn;
+ return env;
+ }
+ /* Realloc insn buffer when necessary. */
+ if (fini_cnt > orig_cnt)
+ prog = bpf_prog_realloc(prog, bpf_prog_size(fini_cnt),
+ GFP_USER);
+ if (!prog)
+ return ERR_PTR(-ENOMEM);
+ insns = prog->insnsi;
+ prog->len = fini_cnt;
+ ret_env = env;
+
+ /* idx_map[OLD_IDX] = NEW_IDX */
+ idx_map = kvmalloc(orig_cnt * sizeof(u32), GFP_KERNEL);
+ if (!idx_map)
+ return ERR_PTR(-ENOMEM);
+ memset(idx_map, 0xff, orig_cnt * sizeof(u32));
+
+ /* Use the same alloc method used when allocating env->insn_aux_data. */
+ new_data = vzalloc(array_size(sizeof(*new_data), fini_cnt));
+ if (!new_data) {
+ kvfree(idx_map);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ /* Copy over insn + calculate idx_map. */
+ for (idx = 0, elem = list; elem; elem = elem->next) {
+ int orig_idx = elem->orig_idx - 1;
+
+ if (orig_idx >= 0) {
+ idx_map[orig_idx] = idx;
+
+ if (elem->flag & LIST_INSN_FLAG_REMOVED)
+ continue;
+
+ new_data[idx] = env->insn_aux_data[orig_idx];
+
+ if (elem->flag & LIST_INSN_FLAG_PATCHED)
+ new_data[idx].zext_dst =
+ insn_has_def32(env, &elem->insn);
+ } else {
+ new_data[idx].seen = true;
+ new_data[idx].zext_dst = insn_has_def32(env,
+ &elem->insn);
+ }
+ insns[idx++] = elem->insn;
+ }
+
+ new_subinfo = kvzalloc(sizeof(env->subprog_info), GFP_KERNEL);
+ if (!new_subinfo) {
+ kvfree(idx_map);
+ vfree(new_data);
+ return ERR_PTR(-ENOMEM);
+ }
+ memcpy(new_subinfo, env->subprog_info, sizeof(env->subprog_info));
+ memset(env->subprog_info, 0, sizeof(env->subprog_info));
+ env->subprog_cnt = 0;
+ env->prog = prog;
+ ret = add_subprog(env, 0);
+ if (ret < 0) {
+ ret_env = ERR_PTR(ret);
+ goto free_all_ret;
+ }
+ /* Relocate jumps using idx_map.
+ * old_dst = jmp_insn.old_target + old_pc + 1;
+ * new_dst = idx_map[old_dst] = jmp_insn.new_target + new_pc + 1;
+ * jmp_insn.new_target = new_dst - new_pc - 1;
+ */
+ for (idx = 0, elem = list; elem; elem = elem->next) {
+ int orig_idx = elem->orig_idx;
+
+ if (elem->flag & LIST_INSN_FLAG_REMOVED)
+ continue;
+ if ((elem->flag & LIST_INSN_FLAG_PATCHED) || !orig_idx) {
+ idx++;
+ continue;
+ }
+
+ ret = bpf_jit_adj_imm_off(&insns[idx], orig_idx - 1, idx,
+ idx_map);
+ if (ret < 0) {
+ ret_env = ERR_PTR(ret);
+ goto free_all_ret;
+ }
+ /* Recalculate subprog start as we are at bpf2bpf call insn. */
+ if (ret > 0) {
+ ret = add_subprog(env, idx + insns[idx].imm + 1);
+ if (ret < 0) {
+ ret_env = ERR_PTR(ret);
+ goto free_all_ret;
+ }
+ }
+ idx++;
+ }
+ if (ret < 0) {
+ ret_env = ERR_PTR(ret);
+ goto free_all_ret;
+ }
+
+ env->subprog_info[env->subprog_cnt].start = fini_cnt;
+ for (idx = 0; idx <= env->subprog_cnt; idx++)
+ new_subinfo[idx].start = env->subprog_info[idx].start;
+ memcpy(env->subprog_info, new_subinfo, sizeof(env->subprog_info));
+
+ /* Adjust linfo.
+ * FIXME: no support for insn removal at the moment.
+ */
+ if (prog->aux->nr_linfo) {
+ struct bpf_line_info *linfo = prog->aux->linfo;
+ u32 nr_linfo = prog->aux->nr_linfo;
+
+ for (idx = 0; idx < nr_linfo; idx++)
+ linfo[idx].insn_off = idx_map[linfo[idx].insn_off];
+ }
+ vfree(env->insn_aux_data);
+ env->insn_aux_data = new_data;
+ goto free_mem_list_ret;
+free_all_ret:
+ vfree(new_data);
+free_mem_list_ret:
+ kvfree(new_subinfo);
+ kvfree(idx_map);
+ return ret_env;
+}
+
static int opt_remove_dead_code(struct bpf_verifier_env *env)
{
struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
--
2.7.4
^ permalink raw reply related
* [RFC bpf-next 1/8] bpf: introducing list based insn patching infra to core layer
From: Jiong Wang @ 2019-07-04 21:26 UTC (permalink / raw)
To: alexei.starovoitov, daniel
Cc: ecree, naveen.n.rao, andriin, jakub.kicinski, bpf, netdev,
oss-drivers, Jiong Wang
In-Reply-To: <1562275611-31790-1-git-send-email-jiong.wang@netronome.com>
This patch introduces list based bpf insn patching infra to bpf core layer
which is lower than verification layer.
This layer has bpf insn sequence as the solo input, therefore the tasks
to be finished during list linerization is:
- copy insn
- relocate jumps
- relocation line info.
Suggested-by: Alexei Starovoitov <ast@kernel.org>
Suggested-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
---
include/linux/filter.h | 25 +++++
kernel/bpf/core.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 293 insertions(+)
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 1fe53e7..1fea68c 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -842,6 +842,31 @@ struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off,
const struct bpf_insn *patch, u32 len);
int bpf_remove_insns(struct bpf_prog *prog, u32 off, u32 cnt);
+int bpf_jit_adj_imm_off(struct bpf_insn *insn, int old_idx, int new_idx,
+ int idx_map[]);
+
+#define LIST_INSN_FLAG_PATCHED 0x1
+#define LIST_INSN_FLAG_REMOVED 0x2
+struct bpf_list_insn {
+ struct bpf_insn insn;
+ struct bpf_list_insn *next;
+ s32 orig_idx;
+ u32 flag;
+};
+
+struct bpf_list_insn *bpf_create_list_insn(struct bpf_prog *prog);
+void bpf_destroy_list_insn(struct bpf_list_insn *list);
+/* Replace LIST_INSN with new list insns generated from PATCH. */
+struct bpf_list_insn *bpf_patch_list_insn(struct bpf_list_insn *list_insn,
+ const struct bpf_insn *patch,
+ u32 len);
+/* Pre-patch list_insn with insns inside PATCH, meaning LIST_INSN is not
+ * touched. New list insns are inserted before it.
+ */
+struct bpf_list_insn *bpf_prepatch_list_insn(struct bpf_list_insn *list_insn,
+ const struct bpf_insn *patch,
+ u32 len);
+
void bpf_clear_redirect_map(struct bpf_map *map);
static inline bool xdp_return_frame_no_direct(void)
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index e2c1b43..e60703e 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -502,6 +502,274 @@ int bpf_remove_insns(struct bpf_prog *prog, u32 off, u32 cnt)
return WARN_ON_ONCE(bpf_adj_branches(prog, off, off + cnt, off, false));
}
+int bpf_jit_adj_imm_off(struct bpf_insn *insn, int old_idx, int new_idx,
+ s32 idx_map[])
+{
+ u8 code = insn->code;
+ s64 imm;
+ s32 off;
+
+ if (BPF_CLASS(code) != BPF_JMP && BPF_CLASS(code) != BPF_JMP32)
+ return 0;
+
+ if (BPF_CLASS(code) == BPF_JMP &&
+ (BPF_OP(code) == BPF_EXIT ||
+ (BPF_OP(code) == BPF_CALL && insn->src_reg != BPF_PSEUDO_CALL)))
+ return 0;
+
+ /* BPF to BPF call. */
+ if (BPF_OP(code) == BPF_CALL) {
+ imm = idx_map[old_idx + insn->imm + 1] - new_idx - 1;
+ if (imm < S32_MIN || imm > S32_MAX)
+ return -ERANGE;
+ insn->imm = imm;
+ return 1;
+ }
+
+ /* Jump. */
+ off = idx_map[old_idx + insn->off + 1] - new_idx - 1;
+ if (off < S16_MIN || off > S16_MAX)
+ return -ERANGE;
+ insn->off = off;
+ return 0;
+}
+
+void bpf_destroy_list_insn(struct bpf_list_insn *list)
+{
+ struct bpf_list_insn *elem, *next;
+
+ for (elem = list; elem; elem = next) {
+ next = elem->next;
+ kvfree(elem);
+ }
+}
+
+struct bpf_list_insn *bpf_create_list_insn(struct bpf_prog *prog)
+{
+ unsigned int idx, len = prog->len;
+ struct bpf_list_insn *hdr, *prev;
+ struct bpf_insn *insns;
+
+ hdr = kvzalloc(sizeof(*hdr), GFP_KERNEL);
+ if (!hdr)
+ return ERR_PTR(-ENOMEM);
+
+ insns = prog->insnsi;
+ hdr->insn = insns[0];
+ hdr->orig_idx = 1;
+ prev = hdr;
+
+ for (idx = 1; idx < len; idx++) {
+ struct bpf_list_insn *node = kvzalloc(sizeof(*node),
+ GFP_KERNEL);
+
+ if (!node) {
+ /* Destroy what has been allocated. */
+ bpf_destroy_list_insn(hdr);
+ return ERR_PTR(-ENOMEM);
+ }
+ node->insn = insns[idx];
+ node->orig_idx = idx + 1;
+ prev->next = node;
+ prev = node;
+ }
+
+ return hdr;
+}
+
+/* Linearize bpf list insn to array. */
+static struct bpf_prog *bpf_linearize_list_insn(struct bpf_prog *prog,
+ struct bpf_list_insn *list)
+{
+ u32 *idx_map, idx, prev_idx, fini_cnt = 0, orig_cnt = prog->len;
+ struct bpf_insn *insns, *insn;
+ struct bpf_list_insn *elem;
+
+ /* Calculate final size. */
+ for (elem = list; elem; elem = elem->next)
+ if (!(elem->flag & LIST_INSN_FLAG_REMOVED))
+ fini_cnt++;
+
+ insns = prog->insnsi;
+ /* If prog length remains same, nothing else to do. */
+ if (fini_cnt == orig_cnt) {
+ for (insn = insns, elem = list; elem; elem = elem->next, insn++)
+ *insn = elem->insn;
+ return prog;
+ }
+ /* Realloc insn buffer when necessary. */
+ if (fini_cnt > orig_cnt)
+ prog = bpf_prog_realloc(prog, bpf_prog_size(fini_cnt),
+ GFP_USER);
+ if (!prog)
+ return ERR_PTR(-ENOMEM);
+ insns = prog->insnsi;
+ prog->len = fini_cnt;
+
+ /* idx_map[OLD_IDX] = NEW_IDX */
+ idx_map = kvmalloc(orig_cnt * sizeof(u32), GFP_KERNEL);
+ if (!idx_map)
+ return ERR_PTR(-ENOMEM);
+ memset(idx_map, 0xff, orig_cnt * sizeof(u32));
+
+ /* Copy over insn + calculate idx_map. */
+ for (idx = 0, elem = list; elem; elem = elem->next) {
+ int orig_idx = elem->orig_idx - 1;
+
+ if (orig_idx >= 0) {
+ idx_map[orig_idx] = idx;
+
+ if (elem->flag & LIST_INSN_FLAG_REMOVED)
+ continue;
+ }
+ insns[idx++] = elem->insn;
+ }
+
+ /* Relocate jumps using idx_map.
+ * old_dst = jmp_insn.old_target + old_pc + 1;
+ * new_dst = idx_map[old_dst] = jmp_insn.new_target + new_pc + 1;
+ * jmp_insn.new_target = new_dst - new_pc - 1;
+ */
+ for (idx = 0, prev_idx = 0, elem = list; elem; elem = elem->next) {
+ int ret, orig_idx;
+
+ /* A removed insn doesn't increase new_pc */
+ if (elem->flag & LIST_INSN_FLAG_REMOVED)
+ continue;
+
+ orig_idx = elem->orig_idx - 1;
+ ret = bpf_jit_adj_imm_off(&insns[idx],
+ orig_idx >= 0 ? orig_idx : prev_idx,
+ idx, idx_map);
+ idx++;
+ if (ret < 0) {
+ kvfree(idx_map);
+ return ERR_PTR(ret);
+ }
+ if (orig_idx >= 0)
+ /* Record prev_idx. it is used for relocating jump insn
+ * inside patch buffer. For example, when doing jit
+ * blinding, a jump could be moved to some other
+ * positions inside the patch buffer, and its old_dst
+ * could be calculated using prev_idx.
+ */
+ prev_idx = orig_idx;
+ }
+
+ /* Adjust linfo.
+ *
+ * NOTE: the prog reached core layer has been adjusted to contain insns
+ * for single function, however linfo contains information for
+ * whole program, so we need to make sure linfo beyond current
+ * function is handled properly.
+ */
+ if (prog->aux->nr_linfo) {
+ u32 linfo_idx, insn_start, insn_end, nr_linfo, idx, delta;
+ struct bpf_line_info *linfo;
+
+ linfo_idx = prog->aux->linfo_idx;
+ linfo = &prog->aux->linfo[linfo_idx];
+ insn_start = linfo[0].insn_off;
+ insn_end = insn_start + orig_cnt;
+ nr_linfo = prog->aux->nr_linfo - linfo_idx;
+ delta = fini_cnt - orig_cnt;
+ for (idx = 0; idx < nr_linfo; idx++) {
+ int adj_off;
+
+ if (linfo[idx].insn_off >= insn_end) {
+ linfo[idx].insn_off += delta;
+ continue;
+ }
+
+ adj_off = linfo[idx].insn_off - insn_start;
+ linfo[idx].insn_off = idx_map[adj_off] + insn_start;
+ }
+ }
+ kvfree(idx_map);
+
+ return prog;
+}
+
+struct bpf_list_insn *bpf_patch_list_insn(struct bpf_list_insn *list_insn,
+ const struct bpf_insn *patch,
+ u32 len)
+{
+ struct bpf_list_insn *prev, *next;
+ u32 insn_delta = len - 1;
+ u32 idx;
+
+ list_insn->insn = *patch;
+ list_insn->flag |= LIST_INSN_FLAG_PATCHED;
+
+ /* Since our patchlet doesn't expand the image, we're done. */
+ if (insn_delta == 0)
+ return list_insn;
+
+ len--;
+ patch++;
+
+ prev = list_insn;
+ next = list_insn->next;
+ for (idx = 0; idx < len; idx++) {
+ struct bpf_list_insn *node = kvzalloc(sizeof(*node),
+ GFP_KERNEL);
+
+ if (!node) {
+ /* Link what's allocated, so list destroyer could
+ * free them.
+ */
+ prev->next = next;
+ return ERR_PTR(-ENOMEM);
+ }
+
+ node->insn = patch[idx];
+ prev->next = node;
+ prev = node;
+ }
+
+ prev->next = next;
+ return prev;
+}
+
+struct bpf_list_insn *bpf_prepatch_list_insn(struct bpf_list_insn *list_insn,
+ const struct bpf_insn *patch,
+ u32 len)
+{
+ struct bpf_list_insn *prev, *node, *begin_node;
+ u32 idx;
+
+ if (!len)
+ return list_insn;
+
+ node = kvzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return ERR_PTR(-ENOMEM);
+ node->insn = patch[0];
+ begin_node = node;
+ prev = node;
+
+ for (idx = 1; idx < len; idx++) {
+ node = kvzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node) {
+ node = begin_node;
+ /* Release what's has been allocated. */
+ while (node) {
+ struct bpf_list_insn *next = node->next;
+
+ kvfree(node);
+ node = next;
+ }
+ return ERR_PTR(-ENOMEM);
+ }
+ node->insn = patch[idx];
+ prev->next = node;
+ prev = node;
+ }
+
+ prev->next = list_insn;
+ return begin_node;
+}
+
void bpf_prog_kallsyms_del_subprogs(struct bpf_prog *fp)
{
int i;
--
2.7.4
^ permalink raw reply related
* [RFC bpf-next 0/8] bpf: accelerate insn patching speed
From: Jiong Wang @ 2019-07-04 21:26 UTC (permalink / raw)
To: alexei.starovoitov, daniel
Cc: ecree, naveen.n.rao, andriin, jakub.kicinski, bpf, netdev,
oss-drivers, Jiong Wang
This is an RFC based on latest bpf-next about acclerating insn patching
speed, it is now near the shape of final PATCH set, and we could see the
changes migrating to list patching would brings, so send out for
comments. Most of the info are in cover letter. I splitted the code in a
way to show API migration more easily.
Test Results
===
- Full pass on test_verifier/test_prog/test_prog_32 under all three
modes (interpreter, JIT, JIT with blinding).
- Benchmarking shows 10 ~ 15x faster on medium sized prog, and reduce
patching time from 5100s (nearly one and a half hour) to less than
0.5s for 1M insn patching.
Known Issues
===
- The following warning is triggered when running scale test which
contains 1M insns and patching:
warning of mm/page_alloc.c:4639 __alloc_pages_nodemask+0x29e/0x330
This is caused by existing code, it can be reproduced on bpf-next
master with jit blinding enabled, then run scale unit test, it will
shown up after half an hour. After this set, patching is very fast, so
it shows up quickly.
- No line info adjustment support when doing insn delete, subprog adj
is with bug when doing insn delete as well. Generally, removal of insns
could possibly cause remove of entire line or subprog, therefore
entries of prog->aux->linfo or env->subprog needs to be deleted. I
don't have good idea and clean code for integrating this into the
linearization code at the moment, will do more experimenting,
appreciate ideas and suggestions on this.
Insn delete doesn't happen on normal programs, for example Cilium
benchmarks, and happens rarely on test_progs, so the test coverage is
not good. That's also why this RFC have a full pass on selftest with
this known issue.
- Could further use mem pool to accelerate the speed, changes are trivial
on top of this RFC, and could be 2x extra faster. Not included in this
RFC as reducing the algo complexity from quadratic to linear of insn
number is the first step.
Background
===
This RFC aims to accelerate BPF insn patching speed, patching means expand
one bpf insn at any offset inside bpf prog into a set of new insns, or
remove insns.
At the moment, insn patching is quadratic of insn number, this is due to
branch targets of jump insns needs to be adjusted, and the algo used is:
for insn inside prog
patch insn + regeneate bpf prog
for insn inside new prog
adjust jump target
This is causing significant time spending when a bpf prog requires large
amount of patching on different insns. Benchmarking shows it could take
more than half minutes to finish patching when patching number is more
than 50K, and the time spent could be more than one hour when patching
number is around 1M.
15000 : 3s
45000 : 29s
95000 : 125s
195000 : 712s
1000000 : 5100s
This RFC introduces new patching infrastructure. Before doing insn
patching, insns in bpf prog are turned into a singly linked list, insert
new insns just insert new list node, delete insns just set delete flag.
And finally, the list is linearized back into array, and branch target
adjustment is done for all jump insns during linearization. This algo
brings the time complexity from quadratic to linear of insn number.
Benchmarking shows the new patching infrastructure could be 10 ~ 15x faster
on medium sized prog, and for a 1M patching it reduce the time from 5100s
to less than 0.5s.
Patching API
===
Insn patching could happen on two layers inside BPF. One is "core layer"
where only BPF insns are patched. The other is "verification layer" where
insns have corresponding aux info as well high level subprog info, so
insn patching means aux info needs to be patched as well, and subprog info
needs to be adjusted. BPF prog also has debug info associated, so line info
should always be updated after insn patching.
So, list creation, destroy, insert, delete is the same for both layer,
but lineration is different. "verification layer" patching require extra
work. Therefore the patch APIs are:
list creation: bpf_create_list_insn
list patch: bpf_patch_list_insn
list pre-patch: bpf_prepatch_list_insn
list lineration (core layer): prog = bpf_linearize_list_insn(prog, list)
list lineration (veri layer): env = verifier_linearize_list_insn(env, list)
list destroy: bpf_destroy_list_insn
list patch could change the insn at patch point, it will invalid the aux
info at patching point. list pre-patch insert new insns before patch point
where the insn and associated aux info are not touched, it is used for
example in convert_ctx_access when generating prologue.
Typical API sequence for one patching pass:
struct bpf_list_insn list = bpf_create_list_insn(struct bpf_prog);
for (elem = list; elem; elem = elem->next)
patch_buf = gen_patch_buf_logic;
elem = bpf_patch_list_insn(elem, patch_buf, cnt);
bpf_prog = bpf_linearize_list_insn(list)
bpf_destroy_list_insn(list)
Several patching passes could also share the same list:
struct bpf_list_insn list = bpf_create_list_insn(struct bpf_prog);
for (elem = list; elem; elem = elem->next)
patch_buf = gen_patch_buf_logic1;
elem = bpf_patch_list_insn(elem, patch_buf, cnt);
for (elem = list; elem; elem = elem->next)
patch_buf = gen_patch_buf_logic2;
elem = bpf_patch_list_insn(elem, patch_buf, cnt);
bpf_prog = bpf_linearize_list_insn(list)
bpf_destroy_list_insn(list)
but note new inserted insns int early passes won't have aux info except
zext info. So, if one patch pass requires all aux info updated and
recalculated for all insns including those pathced, it should first
linearize the old list, then re-create the list. The RFC always create and
linearize the list for each migrated patching pass separately.
Compared with old patching code, this new infrastructure has much less core
code, even though the final code has a couple of extra lines but that is
mostly due to for list based infrastructure, we need to do more error
checks, so the list and associated aux data structure could be freed when
errors happens.
Patching Restrictions
===
- For core layer, the linearization assume no new jumps inside patch buf.
Currently, the only user of this layer is jit blinding.
- For verifier layer, there could be new jumps inside patch buf, but
they should have branch target resolved themselves, meaning new jumps
doesn't jump to insns out of the patch buf. This is the case for all
existing verifier layer users.
- bpf_insn_aux_data for all patched insns including the one at patch
point are invalidated, only 32-bit zext info will be recalcuated.
If the aux data of insn at patch point needs to be retained, it is
purely insn insertion, so need to use the pre-patch API.
I plan to send out a PATCH set once I finished insn deletion line info adj
support, please have a looks at this RFC, and appreciate feedbacks.
Jiong Wang (8):
bpf: introducing list based insn patching infra to core layer
bpf: extend list based insn patching infra to verification layer
bpf: migrate jit blinding to list patching infra
bpf: migrate convert_ctx_accesses to list patching infra
bpf: migrate fixup_bpf_calls to list patching infra
bpf: migrate zero extension opt to list patching infra
bpf: migrate insn remove to list patching infra
bpf: delete all those code around old insn patching infrastructure
include/linux/bpf_verifier.h | 1 -
include/linux/filter.h | 27 +-
kernel/bpf/core.c | 431 +++++++++++++++++-----------
kernel/bpf/verifier.c | 649 +++++++++++++++++++------------------------
4 files changed, 580 insertions(+), 528 deletions(-)
--
2.7.4
^ permalink raw reply
* Re: [PATCH net-next 0/2] Mellanox, mlx5 devlink versions query
From: Saeed Mahameed @ 2019-07-04 20:54 UTC (permalink / raw)
To: David Miller; +Cc: Saeed Mahameed, Linux Netdev List
In-Reply-To: <20190704.135005.2091981554195496315.davem@davemloft.net>
On Thu, Jul 4, 2019 at 4:50 PM David Miller <davem@davemloft.net> wrote:
>
> From: Saeed Mahameed <saeedm@dev.mellanox.co.il>
> Date: Wed, 3 Jul 2019 16:07:11 -0700
>
> > Or just wait for my next pull request.
>
> Please resubmit this series once I pull your pull request in.
>
Done just submitted:
"[pull request][net-next V2 0/2] Mellanox, mlx5 updates 2019-07-04"
it includes both of the dependencies and the 2 mlx5 devlink fw version patches.
> Thanks.
^ permalink raw reply
* [net-next V2 2/2] net/mlx5: Added devlink info callback
From: Saeed Mahameed @ 2019-07-04 20:51 UTC (permalink / raw)
To: David S. Miller
Cc: netdev@vger.kernel.org, Tariq Toukan, Shay Agroskin,
Jakub Kicinski, Saeed Mahameed
In-Reply-To: <20190704205050.3354-1-saeedm@mellanox.com>
From: Shay Agroskin <shayag@mellanox.com>
The callback is invoked using 'devlink dev info <pci>' command and returns
the running and pending firmware version of the HCA and the name of the
kernel driver.
If there is a pending firmware version (a new version is burned but the
HCA still runs with the previous) it is returned as the stored
firmware version. Otherwise, the running version is returned for this
field.
Output example:
$ devlink dev info pci/0000:00:06.0
pci/0000:00:06.0:
driver mlx5_core
versions:
fixed:
fw.psid MT_0000000009
running:
fw.version 16.26.0100
stored:
fw.version 16.26.0100
Signed-off-by: Shay Agroskin <shayag@mellanox.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
.../device_drivers/mellanox/mlx5.rst | 19 ++++++
.../net/ethernet/mellanox/mlx5/core/devlink.c | 60 +++++++++++++++++++
2 files changed, 79 insertions(+)
diff --git a/Documentation/networking/device_drivers/mellanox/mlx5.rst b/Documentation/networking/device_drivers/mellanox/mlx5.rst
index 4eeef2df912f..214325897732 100644
--- a/Documentation/networking/device_drivers/mellanox/mlx5.rst
+++ b/Documentation/networking/device_drivers/mellanox/mlx5.rst
@@ -10,6 +10,7 @@ Contents
========
- `Enabling the driver and kconfig options`_
+- `Devlink info`_
- `Devlink health reporters`_
Enabling the driver and kconfig options
@@ -101,6 +102,24 @@ Enabling the driver and kconfig options
- CONFIG_VXLAN: When chosen, mlx5 vxaln support will be enabled.
- CONFIG_MLXFW: When chosen, mlx5 firmware flashing support will be enabled (via devlink and ethtool).
+Devlink info
+============
+
+The devlink info reports the running and stored firmware versions on device.
+It also prints the device PSID which represents the HCA board type ID.
+
+User command example::
+
+ $ devlink dev info pci/0000:00:06.0
+ pci/0000:00:06.0:
+ driver mlx5_core
+ versions:
+ fixed:
+ fw.psid MT_0000000009
+ running:
+ fw.version 16.26.0100
+ stored:
+ fw.version 16.26.0100
Devlink health reporters
========================
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
index 1533c657220b..a400f4430c28 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c
@@ -25,6 +25,65 @@ static int mlx5_devlink_flash_update(struct devlink *devlink,
return mlx5_firmware_flash(dev, fw, extack);
}
+static u8 mlx5_fw_ver_major(u32 version)
+{
+ return (version >> 24) & 0xff;
+}
+
+static u8 mlx5_fw_ver_minor(u32 version)
+{
+ return (version >> 16) & 0xff;
+}
+
+static u16 mlx5_fw_ver_subminor(u32 version)
+{
+ return version & 0xffff;
+}
+
+#define DEVLINK_FW_STRING_LEN 32
+
+static int
+mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
+ struct netlink_ext_ack *extack)
+{
+ struct mlx5_core_dev *dev = devlink_priv(devlink);
+ char version_str[DEVLINK_FW_STRING_LEN];
+ u32 running_fw, stored_fw;
+ int err;
+
+ err = devlink_info_driver_name_put(req, DRIVER_NAME);
+ if (err)
+ return err;
+
+ err = devlink_info_version_fixed_put(req, "fw.psid", dev->board_id);
+ if (err)
+ return err;
+
+ err = mlx5_fw_version_query(dev, &running_fw, &stored_fw);
+ if (err)
+ return err;
+
+ snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
+ mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw),
+ mlx5_fw_ver_subminor(running_fw));
+ err = devlink_info_version_running_put(req, "fw.version", version_str);
+ if (err)
+ return err;
+
+ /* no pending version, return running (stored) version */
+ if (stored_fw == 0)
+ stored_fw = running_fw;
+
+ snprintf(version_str, sizeof(version_str), "%d.%d.%04d",
+ mlx5_fw_ver_major(stored_fw), mlx5_fw_ver_minor(stored_fw),
+ mlx5_fw_ver_subminor(stored_fw));
+ err = devlink_info_version_stored_put(req, "fw.version", version_str);
+ if (err)
+ return err;
+
+ return 0;
+}
+
static const struct devlink_ops mlx5_devlink_ops = {
#ifdef CONFIG_MLX5_ESWITCH
.eswitch_mode_set = mlx5_devlink_eswitch_mode_set,
@@ -35,6 +94,7 @@ static const struct devlink_ops mlx5_devlink_ops = {
.eswitch_encap_mode_get = mlx5_devlink_eswitch_encap_mode_get,
#endif
.flash_update = mlx5_devlink_flash_update,
+ .info_get = mlx5_devlink_info_get,
};
struct devlink *mlx5_devlink_alloc(void)
--
2.21.0
^ permalink raw reply related
* [net-next V2 1/2] net/mlx5: Added fw version query command
From: Saeed Mahameed @ 2019-07-04 20:51 UTC (permalink / raw)
To: David S. Miller
Cc: netdev@vger.kernel.org, Tariq Toukan, Shay Agroskin,
Jakub Kicinski, Saeed Mahameed
In-Reply-To: <20190704205050.3354-1-saeedm@mellanox.com>
From: Shay Agroskin <shayag@mellanox.com>
Using the MCQI and MCQS registers, we query the running and pending
fw version of the HCA.
The MCQS is queried with sequentially increasing component index, until
a component of type BOOT_IMG is found. Querying this component's version
using the MCQI register yields the running and pending fw version of the
HCA.
Querying MCQI for the pending fw version should be done only after
validating that such fw version exists. This is done my checking
'component update state' field in MCQS output.
Signed-off-by: Shay Agroskin <shayag@mellanox.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
---
drivers/net/ethernet/mellanox/mlx5/core/fw.c | 219 ++++++++++++++++--
.../ethernet/mellanox/mlx5/core/mlx5_core.h | 2 +
2 files changed, 201 insertions(+), 20 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
index 6452b62eff15..eb9680293b06 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c
@@ -37,6 +37,37 @@
#include "mlx5_core.h"
#include "../../mlxfw/mlxfw.h"
+enum {
+ MCQS_IDENTIFIER_BOOT_IMG = 0x1,
+ MCQS_IDENTIFIER_OEM_NVCONFIG = 0x4,
+ MCQS_IDENTIFIER_MLNX_NVCONFIG = 0x5,
+ MCQS_IDENTIFIER_CS_TOKEN = 0x6,
+ MCQS_IDENTIFIER_DBG_TOKEN = 0x7,
+ MCQS_IDENTIFIER_GEARBOX = 0xA,
+};
+
+enum {
+ MCQS_UPDATE_STATE_IDLE,
+ MCQS_UPDATE_STATE_IN_PROGRESS,
+ MCQS_UPDATE_STATE_APPLIED,
+ MCQS_UPDATE_STATE_ACTIVE,
+ MCQS_UPDATE_STATE_ACTIVE_PENDING_RESET,
+ MCQS_UPDATE_STATE_FAILED,
+ MCQS_UPDATE_STATE_CANCELED,
+ MCQS_UPDATE_STATE_BUSY,
+};
+
+enum {
+ MCQI_INFO_TYPE_CAPABILITIES = 0x0,
+ MCQI_INFO_TYPE_VERSION = 0x1,
+ MCQI_INFO_TYPE_ACTIVATION_METHOD = 0x5,
+};
+
+enum {
+ MCQI_FW_RUNNING_VERSION = 0,
+ MCQI_FW_STORED_VERSION = 1,
+};
+
static int mlx5_cmd_query_adapter(struct mlx5_core_dev *dev, u32 *out,
int outlen)
{
@@ -398,33 +429,49 @@ static int mlx5_reg_mcda_set(struct mlx5_core_dev *dev,
}
static int mlx5_reg_mcqi_query(struct mlx5_core_dev *dev,
- u16 component_index,
- u32 *max_component_size,
- u8 *log_mcda_word_size,
- u16 *mcda_max_write_size)
+ u16 component_index, bool read_pending,
+ u8 info_type, u16 data_size, void *mcqi_data)
{
- u32 out[MLX5_ST_SZ_DW(mcqi_reg) + MLX5_ST_SZ_DW(mcqi_cap)];
- int offset = MLX5_ST_SZ_DW(mcqi_reg);
- u32 in[MLX5_ST_SZ_DW(mcqi_reg)];
+ u32 out[MLX5_ST_SZ_DW(mcqi_reg) + MLX5_UN_SZ_DW(mcqi_reg_data)] = {};
+ u32 in[MLX5_ST_SZ_DW(mcqi_reg)] = {};
+ void *data;
int err;
- memset(in, 0, sizeof(in));
- memset(out, 0, sizeof(out));
-
MLX5_SET(mcqi_reg, in, component_index, component_index);
- MLX5_SET(mcqi_reg, in, data_size, MLX5_ST_SZ_BYTES(mcqi_cap));
+ MLX5_SET(mcqi_reg, in, read_pending_component, read_pending);
+ MLX5_SET(mcqi_reg, in, info_type, info_type);
+ MLX5_SET(mcqi_reg, in, data_size, data_size);
err = mlx5_core_access_reg(dev, in, sizeof(in), out,
- sizeof(out), MLX5_REG_MCQI, 0, 0);
+ MLX5_ST_SZ_BYTES(mcqi_reg) + data_size,
+ MLX5_REG_MCQI, 0, 0);
if (err)
- goto out;
+ return err;
- *max_component_size = MLX5_GET(mcqi_cap, out + offset, max_component_size);
- *log_mcda_word_size = MLX5_GET(mcqi_cap, out + offset, log_mcda_word_size);
- *mcda_max_write_size = MLX5_GET(mcqi_cap, out + offset, mcda_max_write_size);
+ data = MLX5_ADDR_OF(mcqi_reg, out, data);
+ memcpy(mcqi_data, data, data_size);
-out:
- return err;
+ return 0;
+}
+
+static int mlx5_reg_mcqi_caps_query(struct mlx5_core_dev *dev, u16 component_index,
+ u32 *max_component_size, u8 *log_mcda_word_size,
+ u16 *mcda_max_write_size)
+{
+ u32 mcqi_reg[MLX5_ST_SZ_DW(mcqi_cap)] = {};
+ int err;
+
+ err = mlx5_reg_mcqi_query(dev, component_index, 0,
+ MCQI_INFO_TYPE_CAPABILITIES,
+ MLX5_ST_SZ_BYTES(mcqi_cap), mcqi_reg);
+ if (err)
+ return err;
+
+ *max_component_size = MLX5_GET(mcqi_cap, mcqi_reg, max_component_size);
+ *log_mcda_word_size = MLX5_GET(mcqi_cap, mcqi_reg, log_mcda_word_size);
+ *mcda_max_write_size = MLX5_GET(mcqi_cap, mcqi_reg, mcda_max_write_size);
+
+ return 0;
}
struct mlx5_mlxfw_dev {
@@ -440,8 +487,13 @@ static int mlx5_component_query(struct mlxfw_dev *mlxfw_dev,
container_of(mlxfw_dev, struct mlx5_mlxfw_dev, mlxfw_dev);
struct mlx5_core_dev *dev = mlx5_mlxfw_dev->mlx5_core_dev;
- return mlx5_reg_mcqi_query(dev, component_index, p_max_size,
- p_align_bits, p_max_write_size);
+ if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi)) {
+ mlx5_core_warn(dev, "caps query isn't supported by running FW\n");
+ return -EOPNOTSUPP;
+ }
+
+ return mlx5_reg_mcqi_caps_query(dev, component_index, p_max_size,
+ p_align_bits, p_max_write_size);
}
static int mlx5_fsm_lock(struct mlxfw_dev *mlxfw_dev, u32 *fwhandle)
@@ -581,3 +633,130 @@ int mlx5_firmware_flash(struct mlx5_core_dev *dev,
return mlxfw_firmware_flash(&mlx5_mlxfw_dev.mlxfw_dev,
firmware, extack);
}
+
+static int mlx5_reg_mcqi_version_query(struct mlx5_core_dev *dev,
+ u16 component_index, bool read_pending,
+ u32 *mcqi_version_out)
+{
+ return mlx5_reg_mcqi_query(dev, component_index, read_pending,
+ MCQI_INFO_TYPE_VERSION,
+ MLX5_ST_SZ_BYTES(mcqi_version),
+ mcqi_version_out);
+}
+
+static int mlx5_reg_mcqs_query(struct mlx5_core_dev *dev, u32 *out,
+ u16 component_index)
+{
+ u8 out_sz = MLX5_ST_SZ_BYTES(mcqs_reg);
+ u32 in[MLX5_ST_SZ_DW(mcqs_reg)] = {};
+ int err;
+
+ memset(out, 0, out_sz);
+
+ MLX5_SET(mcqs_reg, in, component_index, component_index);
+
+ err = mlx5_core_access_reg(dev, in, sizeof(in), out,
+ out_sz, MLX5_REG_MCQS, 0, 0);
+ return err;
+}
+
+/* scans component index sequentially, to find the boot img index */
+static int mlx5_get_boot_img_component_index(struct mlx5_core_dev *dev)
+{
+ u32 out[MLX5_ST_SZ_DW(mcqs_reg)] = {};
+ u16 identifier, component_idx = 0;
+ bool quit;
+ int err;
+
+ do {
+ err = mlx5_reg_mcqs_query(dev, out, component_idx);
+ if (err)
+ return err;
+
+ identifier = MLX5_GET(mcqs_reg, out, identifier);
+ quit = !!MLX5_GET(mcqs_reg, out, last_index_flag);
+ quit |= identifier == MCQS_IDENTIFIER_BOOT_IMG;
+ } while (!quit && ++component_idx);
+
+ if (identifier != MCQS_IDENTIFIER_BOOT_IMG) {
+ mlx5_core_warn(dev, "mcqs: can't find boot_img component ix, last scanned idx %d\n",
+ component_idx);
+ return -EOPNOTSUPP;
+ }
+
+ return component_idx;
+}
+
+static int
+mlx5_fw_image_pending(struct mlx5_core_dev *dev,
+ int component_index,
+ bool *pending_version_exists)
+{
+ u32 out[MLX5_ST_SZ_DW(mcqs_reg)];
+ u8 component_update_state;
+ int err;
+
+ err = mlx5_reg_mcqs_query(dev, out, component_index);
+ if (err)
+ return err;
+
+ component_update_state = MLX5_GET(mcqs_reg, out, component_update_state);
+
+ if (component_update_state == MCQS_UPDATE_STATE_IDLE) {
+ *pending_version_exists = false;
+ } else if (component_update_state == MCQS_UPDATE_STATE_ACTIVE_PENDING_RESET) {
+ *pending_version_exists = true;
+ } else {
+ mlx5_core_warn(dev,
+ "mcqs: can't read pending fw version while fw state is %d\n",
+ component_update_state);
+ return -ENODATA;
+ }
+ return 0;
+}
+
+int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+ u32 *running_ver, u32 *pending_ver)
+{
+ u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {};
+ bool pending_version_exists;
+ int component_index;
+ int err;
+
+ if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) ||
+ !MLX5_CAP_MCAM_REG(dev, mcqs)) {
+ mlx5_core_warn(dev, "fw query isn't supported by the FW\n");
+ return -EOPNOTSUPP;
+ }
+
+ component_index = mlx5_get_boot_img_component_index(dev);
+ if (component_index < 0)
+ return component_index;
+
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_RUNNING_VERSION,
+ reg_mcqi_version);
+ if (err)
+ return err;
+
+ *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+
+ err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists);
+ if (err)
+ return err;
+
+ if (!pending_version_exists) {
+ *pending_ver = 0;
+ return 0;
+ }
+
+ err = mlx5_reg_mcqi_version_query(dev, component_index,
+ MCQI_FW_STORED_VERSION,
+ reg_mcqi_version);
+ if (err)
+ return err;
+
+ *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
index 958769702823..471bbc48bc1f 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h
@@ -205,6 +205,8 @@ int mlx5_set_mtppse(struct mlx5_core_dev *mdev, u8 pin, u8 arm, u8 mode);
int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw,
struct netlink_ext_ack *extack);
+int mlx5_fw_version_query(struct mlx5_core_dev *dev,
+ u32 *running_ver, u32 *stored_ver);
void mlx5e_init(void);
void mlx5e_cleanup(void);
--
2.21.0
^ permalink raw reply related
* [pull request][net-next V2 0/2] Mellanox, mlx5 updates 2019-07-04
From: Saeed Mahameed @ 2019-07-04 20:51 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev@vger.kernel.org, Tariq Toukan, Saeed Mahameed
Hi Dave,
This series adds the support for devlink fw query in mlx5
Please pull and let me know if there is any problem.
Please note that the series starts with a merge of mlx5-next branch,
to resolve and avoid dependency with rdma tree.
This what was actually missing from my previous submission of the 2
devlink patches.
v1->v2:
- Removed the TLS patches from the pull request and will post them as a
standalone series for Jakub to review.
Thanks,
Saeed.
---
The following changes since commit e08a976a16cafc20931db1d17aed9183202bfa8d:
Merge branch 'mlx5-next' of git://git.kernel.org/pub/scm/linux/kernel/git/mellanox/linux (2019-07-04 16:42:59 -0400)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux.git tags/mlx5-updates-2019-07-04-v2
for you to fetch changes up to 8338d93788950e63d12bd1d5eb09e239550e80e9:
net/mlx5: Added devlink info callback (2019-07-04 16:43:16 -0400)
----------------------------------------------------------------
mlx5-update-2019-07-04
This series adds mlx5 support for devlink fw versions query.
1) Implement the required low level firmware commands
2) Implement the devlink knobs and callbacks for fw versions query.
----------------------------------------------------------------
Shay Agroskin (2):
net/mlx5: Added fw version query command
net/mlx5: Added devlink info callback
.../networking/device_drivers/mellanox/mlx5.rst | 19 ++
drivers/net/ethernet/mellanox/mlx5/core/devlink.c | 60 ++++++
drivers/net/ethernet/mellanox/mlx5/core/fw.c | 219 +++++++++++++++++++--
.../net/ethernet/mellanox/mlx5/core/mlx5_core.h | 2 +
4 files changed, 280 insertions(+), 20 deletions(-)
^ permalink raw reply
* Re: [net-next 05/14] net/mlx5: Add crypto library to support create/destroy encryption key
From: Jakub Kicinski @ 2019-07-04 20:50 UTC (permalink / raw)
To: Saeed Mahameed
Cc: David S. Miller, netdev@vger.kernel.org, Tariq Toukan,
Eran Ben Elisha
In-Reply-To: <20190704181235.8966-6-saeedm@mellanox.com>
On Thu, 4 Jul 2019 18:15:55 +0000, Saeed Mahameed wrote:
> + /* avoid leaking key on the stack */
> + memset(in, 0, sizeof(in));
memzero_explicit() ?
^ permalink raw reply
* Re: [PATCH net-next 0/2] Mellanox, mlx5 devlink versions query
From: David Miller @ 2019-07-04 20:50 UTC (permalink / raw)
To: saeedm; +Cc: saeedm, netdev
In-Reply-To: <CALzJLG97wQ8EE+XwuCO-wuS0YcYQmSfzu12TFJupp3AAg76U=w@mail.gmail.com>
From: Saeed Mahameed <saeedm@dev.mellanox.co.il>
Date: Wed, 3 Jul 2019 16:07:11 -0700
> Or just wait for my next pull request.
Please resubmit this series once I pull your pull request in.
Thanks.
^ permalink raw reply
* Re: pull-request: bpf-next 2019-07-03
From: David Miller @ 2019-07-04 20:49 UTC (permalink / raw)
To: daniel; +Cc: ast, saeedm, netdev, bpf
In-Reply-To: <20190703224740.15354-1-daniel@iogearbox.net>
From: Daniel Borkmann <daniel@iogearbox.net>
Date: Thu, 4 Jul 2019 00:47:40 +0200
> The following pull-request contains BPF updates for your *net-next* tree.
>
> There is a minor merge conflict in mlx5 due to 8960b38932be ("linux/dim:
> Rename externally used net_dim members") which has been pulled into your
> tree in the meantime, but resolution seems not that bad ... getting current
> bpf-next out now before there's coming more on mlx5. ;) I'm Cc'ing Saeed
> just so he's aware of the resolution below:
...
Thanks for the detailed merge resolution guidance, it helps a lot.
> Let me know if you run into any issues. Anyway, the main changes are:
...
> Please consider pulling these changes from:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git
Pulled.
^ permalink raw reply
* Re: [net-next 14/14] net/mlx5e: Add kTLS TX HW offload support
From: Jakub Kicinski @ 2019-07-04 20:45 UTC (permalink / raw)
To: Saeed Mahameed
Cc: Saeed Mahameed, David S. Miller, netdev@vger.kernel.org,
Tariq Toukan, Eran Ben Elisha, Boris Pismenny
In-Reply-To: <CALzJLG_qF=Yv58_EpV0bRm8_=Kn2AtsOywDDMjhwxSUOW44EAQ@mail.gmail.com>
On Thu, 4 Jul 2019 16:30:21 -0400, Saeed Mahameed wrote:
> > > + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_ooo_drop_no_sync_data) },
> > > + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_ooo_drop_bypass_req) },
> > > + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_ooo_dump_bytes) },
> > > + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_ooo_dump_packets) },
> > > + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_enc_packets) },
> > > + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_enc_bytes) },
> > > + { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, tx_ktls_ctx) },
> > > #endif
> > >
> > > { MLX5E_DECLARE_STAT(struct mlx5e_sw_stats, rx_lro_packets) },
> >
> > Dave, please don't apply this, I will review in depth once I get
> > through the earlier 200 emails ;)
>
> Jakub can you please expedite ?
Sure thing! Looking now..
> Dave if it is ok with you i will re-spin and push a new pull request
> with mlx5-next dependencies + 2 Devlink fw version patches,
> and independently, i will post the TLS series for Jakub to review ?
^ permalink raw reply
* Re: [PATCH 6/7] nfp: Use spinlock_t instead of struct spinlock
From: Jakub Kicinski @ 2019-07-04 20:42 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: LKML, tglx, Peter Zijlstra, David S. Miller, OSS Drivers,
Linux Netdev List
In-Reply-To: <20190704153803.12739-7-bigeasy@linutronix.de>
On Thu, 4 Jul 2019 17:38:02 +0200, Sebastian Andrzej Siewior wrote:
> For spinlocks the type spinlock_t should be used instead of "struct
> spinlock".
>
> Use spinlock_t for spinlock's definition.
>
> Cc: Jakub Kicinski <jakub.kicinski@netronome.com>
Acked-by: Jakub Kicinski <jakub.kicinski@netronome.com>
> Cc: "David S. Miller" <davem@davemloft.net>
> Cc: oss-drivers@netronome.com
> Cc: netdev@vger.kernel.org
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> ---
> drivers/net/ethernet/netronome/nfp/nfp_net.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h
> index df9aff2684ed0..4690363fc5421 100644
> --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h
> +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h
> @@ -392,7 +392,7 @@ struct nfp_net_r_vector {
> struct {
> struct tasklet_struct tasklet;
> struct sk_buff_head queue;
> - struct spinlock lock;
> + spinlock_t lock;
> };
> };
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox