* [PATCH net-next 0/3] tcp: improve setsockopt() TCP_USER_TIMEOUT accuracy
From: Jon Maxwell @ 2018-07-18 0:46 UTC (permalink / raw)
To: davem
Cc: edumazet, eric.dumazet, ncardwell, David.Laight, kuznet, yoshfuji,
netdev, linux-kernel, jmaxwell
Based on:
https://patchwork.kernel.org/patch/10516195/
Every time the TCP retransmission timer fires. It checks to see if
there is a timeout before scheduling the next retransmit timer. The
retransmit interval between each retransmission increases
exponentially. The issue is that in order for the timeout to occur the
retransmit timer needs to fire again. If the user timeout check happens
after the 9th retransmit for example. It needs to wait for the 10th
retransmit timer to fire in order to evaluate whether a timeout has
occurred or not. If the interval is large enough then the timeout will
be inaccurate.
For example with a TCP_USER_TIMEOUT of 10 seconds without patch:
1st retransmit:
22:25:18.973488 IP host1.49310 > host2.search-agent: Flags [.]
Last retransmit:
22:25:26.205499 IP host1.49310 > host2.search-agent: Flags [.]
Timeout:
send: Connection timed out
Sun Jul 1 22:25:34 EDT 2018
We can see that last retransmit took ~7 seconds. Which pushed the total
timeout to ~15 seconds instead of the expected 10 seconds. This gets
more inaccurate the larger the TCP_USER_TIMEOUT value. As the interval
increases.
Add tcp_clamp_rto_to_user_timeout() to determine if the user rto has
expired. Or whether the rto interval needs to be recalculated. Use the
original interval if user rto is not set.
Test results with the patch is the expected 10 second timeout:
1st retransmit:
01:37:59.022555 IP host1.49310 > host2.search-agent: Flags [.]
Last retransmit:
01:38:06.486558 IP host1.49310 > host2.search-agent: Flags [.]
Timeout:
send: Connection timed out
Mon Jul 2 01:38:09 EDT 2018
Jon Maxwell (3):
tcp: convert icsk_user_timeout from jiffies to msecs
tcp: Add tcp_retransmit_time() helper routine
tcp: Add tcp_clamp_rto_to_user_timeout() helper to improve accuracy
net/ipv4/tcp.c | 4 ++--
net/ipv4/tcp_timer.c | 51 ++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 40 insertions(+), 15 deletions(-)
--
2.13.6
^ permalink raw reply
* Re: [PATCH net-next] net/mlx5: fix an unused-function warning
From: Saeed Mahameed @ 2018-07-18 0:42 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Saeed Mahameed, Leon Romanovsky, David S. Miller, Ilya Lesokhin,
Boris Pismenny, Linux Netdev List, RDMA mailing list,
linux-kernel
In-Reply-To: <20180717135009.3584984-1-arnd@arndb.de>
On Tue, Jul 17, 2018 at 6:49 AM, Arnd Bergmann <arnd@arndb.de> wrote:
> These dummy helpers are all intended to be inline functions,
> but one of them by accident came without the 'inline' keyword,
> causing a harmless warning:
>
> In file included from drivers/net/ethernet/mellanox/mlx5/core/main.c:63:
> drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h:79:1: error: 'mlx5_accel_tls_add_flow' defined but not used [-Werror=unused-function]
> mlx5_accel_tls_add_flow(struct mlx5_core_dev *mdev, void *flow,
>
> Fixes: ab412e1dd7db ("net/mlx5: Accel, add TLS rx offload routines")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Acked-by: Saeed Mahameed <saeedm@mellanox.com>
Dave, you can take this one to net-next.
Thanks!
> ---
> drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h b/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h
> index 2228c1083528..def4093ebfae 100644
> --- a/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h
> +++ b/drivers/net/ethernet/mellanox/mlx5/core/accel/tls.h
> @@ -75,7 +75,7 @@ void mlx5_accel_tls_cleanup(struct mlx5_core_dev *mdev);
>
> #else
>
> -static int
> +static inline int
> mlx5_accel_tls_add_flow(struct mlx5_core_dev *mdev, void *flow,
> struct tls_crypto_info *crypto_info,
> u32 start_offload_tcp_sn, u32 *p_swid,
> --
> 2.9.0
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 0/3] tcp: improve setsockopt() TCP_USER_TIMEOUT accuracy
From: Jon Maxwell @ 2018-07-18 0:32 UTC (permalink / raw)
To: davem
Cc: edumazet, eric.dumazet, ncardwell, David.Laight, kuznet, yoshfuji,
netdev, linux-kernel, jmaxwell
Based on:
https://patchwork.kernel.org/patch/10516195/
Every time the TCP retransmission timer fires. It checks to see if
there is a timeout before scheduling the next retransmit timer. The
retransmit interval between each retransmission increases
exponentially. The issue is that in order for the timeout to occur the
retransmit timer needs to fire again. If the user timeout check happens
after the 9th retransmit for example. It needs to wait for the 10th
retransmit timer to fire in order to evaluate whether a timeout has
occurred or not. If the interval is large enough then the timeout will
be inaccurate.
For example with a TCP_USER_TIMEOUT of 10 seconds without patch:
1st retransmit:
22:25:18.973488 IP host1.49310 > host2.search-agent: Flags [.]
Last retransmit:
22:25:26.205499 IP host1.49310 > host2.search-agent: Flags [.]
Timeout:
send: Connection timed out
Sun Jul 1 22:25:34 EDT 2018
We can see that last retransmit took ~7 seconds. Which pushed the total
timeout to ~15 seconds instead of the expected 10 seconds. This gets
more inaccurate the larger the TCP_USER_TIMEOUT value. As the interval
increases.
Add tcp_clamp_rto_to_user_timeout() to determine if the user rto has
expired. Or whether the rto interval needs to be recalculated. Use the
original interval if user rto is not set.
Test results with the patch is the expected 10 second timeout:
1st retransmit:
01:37:59.022555 IP host1.49310 > host2.search-agent: Flags [.]
Last retransmit:
01:38:06.486558 IP host1.49310 > host2.search-agent: Flags [.]
Timeout:
send: Connection timed out
Mon Jul 2 01:38:09 EDT 2018
Jon Maxwell (3):
tcp: convert icsk_user_timeout from jiffies to msecs
tcp: Add tcp_retransmit_time() helper routine
tcp: Add tcp_clamp_rto_to_user_timeout() helper to improve accuracy
net/ipv4/tcp.c | 4 ++--
net/ipv4/tcp_timer.c | 51 ++++++++++++++++++++++++++++++++++++++-------------
2 files changed, 40 insertions(+), 15 deletions(-)
--
2.13.6
^ permalink raw reply
* Re: [PATCH 0/6] lib/crc32: treewide: Use existing define with polynomial
From: Eric Biggers @ 2018-07-18 0:12 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Prashant Sreedharan, Pantelis Antoniou, devel, Herbert Xu,
Jose Abreu, Tom Lendacky, Alexandre Torgue, Siva Reddy Kallam,
Michael Chan, Thomas Gleixner, linux-arm-kernel,
Florian Schilhabel, Fugang Duan, Greg Kroah-Hartman, linux-kernel,
linux-crypto, Maxime Coquelin, netdev, Vitaly Bordug,
linuxppc-dev, David S. Miller, Larry Finger
In-Reply-To: <20180717160541.3843-1-krzk@kernel.org>
Hi Krzysztof,
On Tue, Jul 17, 2018 at 06:05:35PM +0200, Krzysztof Kozlowski wrote:
> Hi,
>
> Kernel defines same polynomial for CRC-32 in few places.
> This is unnecessary duplication of the same value. Also this might
> be error-prone for future code - every driver will define the
> polynomial again.
>
> This is an attempt to unify definition of polynomial. Few obvious
> hard-coded locations are fixed with define.
>
> All series depend on each 1/6 and 2/6.
>
> This could be merged in two different merge windows (1st lib/crc and then
> the rest) or taken through one tree.
>
> It would be nice to get some testing. Only generic lib/crc, bunzip, xz_crc32
> and Freescale's Ethernet driver were tested on HW. Rest got just different
> builds.
>
> Best regards,
> Krzysztof
>
> Krzysztof Kozlowski (6):
> lib/crc: Move polynomial definition to separate header
> lib/crc: Use consistent naming for CRC-32 polynomials
> crypto: stm32_crc32 - Use existing define with polynomial
> net: ethernet: Use existing define with polynomial
> staging: rtl: Use existing define with polynomial
> lib: Use existing define with polynomial
>
> drivers/crypto/stm32/stm32_crc32.c | 11 ++++-------
> drivers/net/ethernet/amd/xgbe/xgbe-dev.c | 4 ++--
> drivers/net/ethernet/apple/bmac.c | 8 ++------
> drivers/net/ethernet/broadcom/tg3.c | 3 ++-
> drivers/net/ethernet/freescale/fec_main.c | 4 ++--
> drivers/net/ethernet/freescale/fs_enet/fec.h | 3 ---
> drivers/net/ethernet/freescale/fs_enet/mac-fec.c | 3 ++-
> drivers/net/ethernet/micrel/ks8851_mll.c | 3 ++-
> drivers/net/ethernet/synopsys/dwc-xlgmac-hw.c | 4 ++--
> drivers/staging/rtl8712/rtl871x_security.c | 5 ++---
> drivers/staging/rtl8723bs/core/rtw_security.c | 5 ++---
> include/linux/crc32poly.h | 20 ++++++++++++++++++++
> lib/crc32.c | 11 ++++++-----
> lib/crc32defs.h | 14 --------------
> lib/decompress_bunzip2.c | 3 ++-
> lib/gen_crc32table.c | 5 +++--
> lib/xz/xz_crc32.c | 3 ++-
> 17 files changed, 55 insertions(+), 54 deletions(-)
> create mode 100644 include/linux/crc32poly.h
>
Did you check whether any of these users can be converted to use the CRC
implementations in lib/, so they wouldn't need the polynomial definition
themselves?
- Eric
^ permalink raw reply
* [PATCH iproute2 4/5] bpf: implement bpf to bpf calls support
From: Daniel Borkmann @ 2018-07-17 23:31 UTC (permalink / raw)
To: dsahern; +Cc: jakub.kicinski, alexei.starovoitov, netdev, Daniel Borkmann
In-Reply-To: <20180717233122.29390-1-daniel@iogearbox.net>
Implement missing bpf to bpf calls support. The loader will
recognize .text section and handle relocation entries that
are emitted by LLVM.
First step is processing of map related relocation entries
for .text section, and in a second step loader will copy .text
section into program section and adjust call instruction
offset accordingly.
Example with test_xdp_noinline.o from kernel selftests:
1) Every function as __attribute__ ((always_inline)), rest
left unchanged:
# ip -force link set dev lo xdp obj test_xdp_noinline.o sec xdp-test
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 xdpgeneric/id:233 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
[...]
# bpftool prog dump xlated id 233
[...]
1669: (2d) if r3 > r2 goto pc+4
1670: (79) r2 = *(u64 *)(r10 -136)
1671: (61) r2 = *(u32 *)(r2 +0)
1672: (63) *(u32 *)(r1 +0) = r2
1673: (b7) r0 = 1
1674: (95) exit <-- 1674 insns total
2) Every function as __attribute__ ((noinline)), rest
left unchanged:
# ip -force link set dev lo xdp obj test_xdp_noinline.o sec xdp-test
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 xdpgeneric/id:236 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
[...]
# bpftool prog dump xlated id 236
[...]
1000: (bf) r1 = r6
1001: (b7) r2 = 24
1002: (85) call pc+3 <-- pc-relative call insns
1003: (1f) r7 -= r0
1004: (bf) r0 = r7
1005: (95) exit
1006: (bf) r0 = r1
1007: (bf) r1 = r2
1008: (67) r1 <<= 32
1009: (77) r1 >>= 32
1010: (bf) r3 = r0
1011: (6f) r3 <<= r1
1012: (87) r2 = -r2
1013: (57) r2 &= 31
1014: (67) r0 <<= 32
1015: (77) r0 >>= 32
1016: (7f) r0 >>= r2
1017: (4f) r0 |= r3
1018: (95) exit <-- 1018 insns total
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
lib/bpf.c | 233 ++++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 157 insertions(+), 76 deletions(-)
diff --git a/lib/bpf.c b/lib/bpf.c
index 135f496..cea1273 100644
--- a/lib/bpf.c
+++ b/lib/bpf.c
@@ -1104,7 +1104,8 @@ int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns,
#ifdef HAVE_ELF
struct bpf_elf_prog {
enum bpf_prog_type type;
- const struct bpf_insn *insns;
+ struct bpf_insn *insns;
+ unsigned int insns_num;
size_t size;
const char *license;
};
@@ -1130,11 +1131,13 @@ struct bpf_elf_ctx {
int map_fds[ELF_MAX_MAPS];
struct bpf_elf_map maps[ELF_MAX_MAPS];
struct bpf_map_ext maps_ext[ELF_MAX_MAPS];
+ struct bpf_elf_prog prog_text;
int sym_num;
int map_num;
int map_len;
bool *sec_done;
int sec_maps;
+ int sec_text;
char license[ELF_MAX_LICENSE_LEN];
enum bpf_prog_type type;
__u32 ifindex;
@@ -1899,12 +1902,25 @@ static int bpf_fetch_strtab(struct bpf_elf_ctx *ctx, int section,
return 0;
}
+static int bpf_fetch_text(struct bpf_elf_ctx *ctx, int section,
+ struct bpf_elf_sec_data *data)
+{
+ ctx->sec_text = section;
+ ctx->sec_done[section] = true;
+ return 0;
+}
+
static bool bpf_has_map_data(const struct bpf_elf_ctx *ctx)
{
return ctx->sym_tab && ctx->str_tab && ctx->sec_maps;
}
-static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx)
+static bool bpf_has_call_data(const struct bpf_elf_ctx *ctx)
+{
+ return ctx->sec_text;
+}
+
+static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx, bool check_text_sec)
{
struct bpf_elf_sec_data data;
int i, ret = -1;
@@ -1920,6 +1936,11 @@ static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx)
else if (data.sec_hdr.sh_type == SHT_PROGBITS &&
!strcmp(data.sec_name, ELF_SECTION_LICENSE))
ret = bpf_fetch_license(ctx, i, &data);
+ else if (data.sec_hdr.sh_type == SHT_PROGBITS &&
+ (data.sec_hdr.sh_flags & SHF_EXECINSTR) &&
+ !strcmp(data.sec_name, ".text") &&
+ check_text_sec)
+ ret = bpf_fetch_text(ctx, i, &data);
else if (data.sec_hdr.sh_type == SHT_SYMTAB &&
!strcmp(data.sec_name, ".symtab"))
ret = bpf_fetch_symtab(ctx, i, &data);
@@ -1964,17 +1985,18 @@ static int bpf_fetch_prog(struct bpf_elf_ctx *ctx, const char *section,
ret = bpf_fill_section_data(ctx, i, &data);
if (ret < 0 ||
!(data.sec_hdr.sh_type == SHT_PROGBITS &&
- data.sec_hdr.sh_flags & SHF_EXECINSTR &&
+ (data.sec_hdr.sh_flags & SHF_EXECINSTR) &&
!strcmp(data.sec_name, section)))
continue;
*sseen = true;
memset(&prog, 0, sizeof(prog));
- prog.type = ctx->type;
- prog.insns = data.sec_data->d_buf;
- prog.size = data.sec_data->d_size;
- prog.license = ctx->license;
+ prog.type = ctx->type;
+ prog.license = ctx->license;
+ prog.size = data.sec_data->d_size;
+ prog.insns_num = prog.size / sizeof(struct bpf_insn);
+ prog.insns = data.sec_data->d_buf;
fd = bpf_prog_attach(section, &prog, ctx);
if (fd < 0)
@@ -1987,84 +2009,120 @@ static int bpf_fetch_prog(struct bpf_elf_ctx *ctx, const char *section,
return fd;
}
-struct bpf_tail_call_props {
- unsigned int total;
- unsigned int jited;
+struct bpf_relo_props {
+ struct bpf_tail_call {
+ unsigned int total;
+ unsigned int jited;
+ } tc;
+ int main_num;
};
+static int bpf_apply_relo_map(struct bpf_elf_ctx *ctx, struct bpf_elf_prog *prog,
+ GElf_Rel *relo, GElf_Sym *sym,
+ struct bpf_relo_props *props)
+{
+ unsigned int insn_off = relo->r_offset / sizeof(struct bpf_insn);
+ unsigned int map_idx = sym->st_value / ctx->map_len;
+
+ if (insn_off >= prog->insns_num)
+ return -EINVAL;
+ if (prog->insns[insn_off].code != (BPF_LD | BPF_IMM | BPF_DW)) {
+ fprintf(stderr, "ELF contains relo data for non ld64 instruction at offset %u! Compiler bug?!\n",
+ insn_off);
+ return -EINVAL;
+ }
+
+ if (map_idx >= ARRAY_SIZE(ctx->map_fds))
+ return -EINVAL;
+ if (!ctx->map_fds[map_idx])
+ return -EINVAL;
+ if (ctx->maps[map_idx].type == BPF_MAP_TYPE_PROG_ARRAY) {
+ props->tc.total++;
+ if (ctx->maps_ext[map_idx].owner.jited ||
+ (ctx->maps_ext[map_idx].owner.type == 0 &&
+ ctx->cfg.jit_enabled))
+ props->tc.jited++;
+ }
+
+ prog->insns[insn_off].src_reg = BPF_PSEUDO_MAP_FD;
+ prog->insns[insn_off].imm = ctx->map_fds[map_idx];
+ return 0;
+}
+
+static int bpf_apply_relo_call(struct bpf_elf_ctx *ctx, struct bpf_elf_prog *prog,
+ GElf_Rel *relo, GElf_Sym *sym,
+ struct bpf_relo_props *props)
+{
+ unsigned int insn_off = relo->r_offset / sizeof(struct bpf_insn);
+ struct bpf_elf_prog *prog_text = &ctx->prog_text;
+
+ if (insn_off >= prog->insns_num)
+ return -EINVAL;
+ if (prog->insns[insn_off].code != (BPF_JMP | BPF_CALL) &&
+ prog->insns[insn_off].src_reg != BPF_PSEUDO_CALL) {
+ fprintf(stderr, "ELF contains relo data for non call instruction at offset %u! Compiler bug?!\n",
+ insn_off);
+ return -EINVAL;
+ }
+
+ if (!props->main_num) {
+ struct bpf_insn *insns = realloc(prog->insns,
+ prog->size + prog_text->size);
+ if (!insns)
+ return -ENOMEM;
+
+ memcpy(insns + prog->insns_num, prog_text->insns,
+ prog_text->size);
+ props->main_num = prog->insns_num;
+ prog->insns = insns;
+ prog->insns_num += prog_text->insns_num;
+ prog->size += prog_text->size;
+ }
+
+ prog->insns[insn_off].imm += props->main_num - insn_off;
+ return 0;
+}
+
static int bpf_apply_relo_data(struct bpf_elf_ctx *ctx,
struct bpf_elf_sec_data *data_relo,
- struct bpf_elf_sec_data *data_insn,
- struct bpf_tail_call_props *props)
+ struct bpf_elf_prog *prog,
+ struct bpf_relo_props *props)
{
- Elf_Data *idata = data_insn->sec_data;
GElf_Shdr *rhdr = &data_relo->sec_hdr;
int relo_ent, relo_num = rhdr->sh_size / rhdr->sh_entsize;
- struct bpf_insn *insns = idata->d_buf;
- unsigned int num_insns = idata->d_size / sizeof(*insns);
for (relo_ent = 0; relo_ent < relo_num; relo_ent++) {
- unsigned int ioff, rmap;
GElf_Rel relo;
GElf_Sym sym;
+ int ret = -EIO;
if (gelf_getrel(data_relo->sec_data, relo_ent, &relo) != &relo)
return -EIO;
-
- ioff = relo.r_offset / sizeof(struct bpf_insn);
- if (ioff >= num_insns ||
- insns[ioff].code != (BPF_LD | BPF_IMM | BPF_DW)) {
- fprintf(stderr, "ELF contains relo data for non ld64 instruction at offset %u! Compiler bug?!\n",
- ioff);
- fprintf(stderr, " - Current section: %s\n", data_relo->sec_name);
- if (ioff < num_insns &&
- insns[ioff].code == (BPF_JMP | BPF_CALL))
- fprintf(stderr, " - Try to annotate functions with always_inline attribute!\n");
- return -EINVAL;
- }
-
if (gelf_getsym(ctx->sym_tab, GELF_R_SYM(relo.r_info), &sym) != &sym)
return -EIO;
- if (sym.st_shndx != ctx->sec_maps) {
- fprintf(stderr, "ELF contains non-map related relo data in entry %u pointing to section %u! Compiler bug?!\n",
- relo_ent, sym.st_shndx);
- return -EIO;
- }
- rmap = sym.st_value / ctx->map_len;
- if (rmap >= ARRAY_SIZE(ctx->map_fds))
- return -EINVAL;
- if (!ctx->map_fds[rmap])
- return -EINVAL;
- if (ctx->maps[rmap].type == BPF_MAP_TYPE_PROG_ARRAY) {
- props->total++;
- if (ctx->maps_ext[rmap].owner.jited ||
- (ctx->maps_ext[rmap].owner.type == 0 &&
- ctx->cfg.jit_enabled))
- props->jited++;
- }
-
- if (ctx->verbose)
- fprintf(stderr, "Map \'%s\' (%d) injected into prog section \'%s\' at offset %u!\n",
- bpf_str_tab_name(ctx, &sym), ctx->map_fds[rmap],
- data_insn->sec_name, ioff);
-
- insns[ioff].src_reg = BPF_PSEUDO_MAP_FD;
- insns[ioff].imm = ctx->map_fds[rmap];
+ if (sym.st_shndx == ctx->sec_maps)
+ ret = bpf_apply_relo_map(ctx, prog, &relo, &sym, props);
+ else if (sym.st_shndx == ctx->sec_text)
+ ret = bpf_apply_relo_call(ctx, prog, &relo, &sym, props);
+ else
+ fprintf(stderr, "ELF contains non-{map,call} related relo data in entry %u pointing to section %u! Compiler bug?!\n",
+ relo_ent, sym.st_shndx);
+ if (ret < 0)
+ return ret;
}
return 0;
}
static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section,
- bool *lderr, bool *sseen)
+ bool *lderr, bool *sseen, struct bpf_elf_prog *prog)
{
struct bpf_elf_sec_data data_relo, data_insn;
- struct bpf_elf_prog prog;
int ret, idx, i, fd = -1;
for (i = 1; i < ctx->elf_hdr.e_shnum; i++) {
- struct bpf_tail_call_props props = {};
+ struct bpf_relo_props props = {};
ret = bpf_fill_section_data(ctx, i, &data_relo);
if (ret < 0 || data_relo.sec_hdr.sh_type != SHT_REL)
@@ -2075,40 +2133,54 @@ static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section,
ret = bpf_fill_section_data(ctx, idx, &data_insn);
if (ret < 0 ||
!(data_insn.sec_hdr.sh_type == SHT_PROGBITS &&
- data_insn.sec_hdr.sh_flags & SHF_EXECINSTR &&
+ (data_insn.sec_hdr.sh_flags & SHF_EXECINSTR) &&
!strcmp(data_insn.sec_name, section)))
continue;
+ if (sseen)
+ *sseen = true;
+
+ memset(prog, 0, sizeof(*prog));
+ prog->type = ctx->type;
+ prog->license = ctx->license;
+ prog->size = data_insn.sec_data->d_size;
+ prog->insns_num = prog->size / sizeof(struct bpf_insn);
+ prog->insns = malloc(prog->size);
+ if (!prog->insns) {
+ *lderr = true;
+ return -ENOMEM;
+ }
- *sseen = true;
+ memcpy(prog->insns, data_insn.sec_data->d_buf, prog->size);
- ret = bpf_apply_relo_data(ctx, &data_relo, &data_insn, &props);
+ ret = bpf_apply_relo_data(ctx, &data_relo, prog, &props);
if (ret < 0) {
*lderr = true;
+ if (ctx->sec_text != idx)
+ free(prog->insns);
return ret;
}
+ if (ctx->sec_text == idx) {
+ fd = 0;
+ goto out;
+ }
- memset(&prog, 0, sizeof(prog));
- prog.type = ctx->type;
- prog.insns = data_insn.sec_data->d_buf;
- prog.size = data_insn.sec_data->d_size;
- prog.license = ctx->license;
-
- fd = bpf_prog_attach(section, &prog, ctx);
+ fd = bpf_prog_attach(section, prog, ctx);
+ free(prog->insns);
if (fd < 0) {
*lderr = true;
- if (props.total) {
+ if (props.tc.total) {
if (ctx->cfg.jit_enabled &&
- props.total != props.jited)
+ props.tc.total != props.tc.jited)
fprintf(stderr, "JIT enabled, but only %u/%u tail call maps in the program have JITed owner!\n",
- props.jited, props.total);
+ props.tc.jited, props.tc.total);
if (!ctx->cfg.jit_enabled &&
- props.jited)
+ props.tc.jited)
fprintf(stderr, "JIT disabled, but %u/%u tail call maps in the program have JITed owner!\n",
- props.jited, props.total);
+ props.tc.jited, props.tc.total);
}
return fd;
}
-
+out:
ctx->sec_done[i] = true;
ctx->sec_done[idx] = true;
break;
@@ -2120,10 +2192,18 @@ static int bpf_fetch_prog_relo(struct bpf_elf_ctx *ctx, const char *section,
static int bpf_fetch_prog_sec(struct bpf_elf_ctx *ctx, const char *section)
{
bool lderr = false, sseen = false;
+ struct bpf_elf_prog prog;
int ret = -1;
- if (bpf_has_map_data(ctx))
- ret = bpf_fetch_prog_relo(ctx, section, &lderr, &sseen);
+ if (bpf_has_call_data(ctx)) {
+ ret = bpf_fetch_prog_relo(ctx, ".text", &lderr, NULL,
+ &ctx->prog_text);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (bpf_has_map_data(ctx) || bpf_has_call_data(ctx))
+ ret = bpf_fetch_prog_relo(ctx, section, &lderr, &sseen, &prog);
if (ret < 0 && !lderr)
ret = bpf_fetch_prog(ctx, section, &sseen);
if (ret < 0 && !sseen)
@@ -2520,6 +2600,7 @@ static void bpf_elf_ctx_destroy(struct bpf_elf_ctx *ctx, bool failure)
bpf_hash_destroy(ctx);
+ free(ctx->prog_text.insns);
free(ctx->sec_done);
free(ctx->log);
@@ -2541,7 +2622,7 @@ static int bpf_obj_open(const char *pathname, enum bpf_prog_type type,
return ret;
}
- ret = bpf_fetch_ancillary(ctx);
+ ret = bpf_fetch_ancillary(ctx, strcmp(section, ".text"));
if (ret < 0) {
fprintf(stderr, "Error fetching ELF ancillary data!\n");
goto out;
--
2.9.5
^ permalink raw reply related
* [PATCH iproute2 1/5] bpf: import btf uapi kernel header
From: Daniel Borkmann @ 2018-07-17 23:31 UTC (permalink / raw)
To: dsahern; +Cc: jakub.kicinski, alexei.starovoitov, netdev, Daniel Borkmann
In-Reply-To: <20180717233122.29390-1-daniel@iogearbox.net>
Needed later on for BTF loader.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
include/uapi/linux/btf.h | 113 +++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 113 insertions(+)
create mode 100644 include/uapi/linux/btf.h
diff --git a/include/uapi/linux/btf.h b/include/uapi/linux/btf.h
new file mode 100644
index 0000000..0b5ddbe
--- /dev/null
+++ b/include/uapi/linux/btf.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* Copyright (c) 2018 Facebook */
+#ifndef _UAPI__LINUX_BTF_H__
+#define _UAPI__LINUX_BTF_H__
+
+#include <linux/types.h>
+
+#define BTF_MAGIC 0xeB9F
+#define BTF_VERSION 1
+
+struct btf_header {
+ __u16 magic;
+ __u8 version;
+ __u8 flags;
+ __u32 hdr_len;
+
+ /* All offsets are in bytes relative to the end of this header */
+ __u32 type_off; /* offset of type section */
+ __u32 type_len; /* length of type section */
+ __u32 str_off; /* offset of string section */
+ __u32 str_len; /* length of string section */
+};
+
+/* Max # of type identifier */
+#define BTF_MAX_TYPE 0x0000ffff
+/* Max offset into the string section */
+#define BTF_MAX_NAME_OFFSET 0x0000ffff
+/* Max # of struct/union/enum members or func args */
+#define BTF_MAX_VLEN 0xffff
+
+struct btf_type {
+ __u32 name_off;
+ /* "info" bits arrangement
+ * bits 0-15: vlen (e.g. # of struct's members)
+ * bits 16-23: unused
+ * bits 24-27: kind (e.g. int, ptr, array...etc)
+ * bits 28-31: unused
+ */
+ __u32 info;
+ /* "size" is used by INT, ENUM, STRUCT and UNION.
+ * "size" tells the size of the type it is describing.
+ *
+ * "type" is used by PTR, TYPEDEF, VOLATILE, CONST and RESTRICT.
+ * "type" is a type_id referring to another type.
+ */
+ union {
+ __u32 size;
+ __u32 type;
+ };
+};
+
+#define BTF_INFO_KIND(info) (((info) >> 24) & 0x0f)
+#define BTF_INFO_VLEN(info) ((info) & 0xffff)
+
+#define BTF_KIND_UNKN 0 /* Unknown */
+#define BTF_KIND_INT 1 /* Integer */
+#define BTF_KIND_PTR 2 /* Pointer */
+#define BTF_KIND_ARRAY 3 /* Array */
+#define BTF_KIND_STRUCT 4 /* Struct */
+#define BTF_KIND_UNION 5 /* Union */
+#define BTF_KIND_ENUM 6 /* Enumeration */
+#define BTF_KIND_FWD 7 /* Forward */
+#define BTF_KIND_TYPEDEF 8 /* Typedef */
+#define BTF_KIND_VOLATILE 9 /* Volatile */
+#define BTF_KIND_CONST 10 /* Const */
+#define BTF_KIND_RESTRICT 11 /* Restrict */
+#define BTF_KIND_MAX 11
+#define NR_BTF_KINDS 12
+
+/* For some specific BTF_KIND, "struct btf_type" is immediately
+ * followed by extra data.
+ */
+
+/* BTF_KIND_INT is followed by a u32 and the following
+ * is the 32 bits arrangement:
+ */
+#define BTF_INT_ENCODING(VAL) (((VAL) & 0x0f000000) >> 24)
+#define BTF_INT_OFFSET(VAL) (((VAL & 0x00ff0000)) >> 16)
+#define BTF_INT_BITS(VAL) ((VAL) & 0x0000ffff)
+
+/* Attributes stored in the BTF_INT_ENCODING */
+#define BTF_INT_SIGNED (1 << 0)
+#define BTF_INT_CHAR (1 << 1)
+#define BTF_INT_BOOL (1 << 2)
+
+/* BTF_KIND_ENUM is followed by multiple "struct btf_enum".
+ * The exact number of btf_enum is stored in the vlen (of the
+ * info in "struct btf_type").
+ */
+struct btf_enum {
+ __u32 name_off;
+ __s32 val;
+};
+
+/* BTF_KIND_ARRAY is followed by one "struct btf_array" */
+struct btf_array {
+ __u32 type;
+ __u32 index_type;
+ __u32 nelems;
+};
+
+/* BTF_KIND_STRUCT and BTF_KIND_UNION are followed
+ * by multiple "struct btf_member". The exact number
+ * of btf_member is stored in the vlen (of the info in
+ * "struct btf_type").
+ */
+struct btf_member {
+ __u32 name_off;
+ __u32 type;
+ __u32 offset; /* offset in bits */
+};
+
+#endif /* _UAPI__LINUX_BTF_H__ */
--
2.9.5
^ permalink raw reply related
* [PATCH iproute2 5/5] bpf: implement btf handling and map annotation
From: Daniel Borkmann @ 2018-07-17 23:31 UTC (permalink / raw)
To: dsahern; +Cc: jakub.kicinski, alexei.starovoitov, netdev, Daniel Borkmann
In-Reply-To: <20180717233122.29390-1-daniel@iogearbox.net>
Implement loading of .BTF section from object file and build up
internal table for retrieving key/value id related to maps in
the BPF program. Latter is done by setting up struct btf_type
table.
One of the issues is that there's a disconnect between the data
types used in the map and struct bpf_elf_map, meaning the underlying
types are unknown from the map description. One way to overcome
this is to add a annotation such that the loader will recognize
the relation to both. BPF_ANNOTATE_KV_PAIR(map_foo, struct key,
struct val); has been added to the API that programs can use.
The loader will then pick the corresponding key/value type ids and
attach it to the maps for creation. This can later on be dumped via
bpftool for introspection.
Example with test_xdp_noinline.o from kernel selftests:
[...]
struct ctl_value {
union {
__u64 value;
__u32 ifindex;
__u8 mac[6];
};
};
struct bpf_map_def __attribute__ ((section("maps"), used)) ctl_array = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(struct ctl_value),
.max_entries = 16,
.map_flags = 0,
};
BPF_ANNOTATE_KV_PAIR(ctl_array, __u32, struct ctl_value);
[...]
Above could also further be wrapped in a macro. Compiling through LLVM and
converting to BTF:
# llc --version
LLVM (http://llvm.org/):
LLVM version 7.0.0svn
Optimized build.
Default target: x86_64-unknown-linux-gnu
Host CPU: skylake
Registered Targets:
bpf - BPF (host endian)
bpfeb - BPF (big endian)
bpfel - BPF (little endian)
[...]
# clang [...] -O2 -target bpf -g -emit-llvm -c test_xdp_noinline.c -o - |
llc -march=bpf -mcpu=probe -mattr=dwarfris -filetype=obj -o test_xdp_noinline.o
# pahole -J test_xdp_noinline.o
Checking pahole dump of BPF object file:
# file test_xdp_noinline.o
test_xdp_noinline.o: ELF 64-bit LSB relocatable, *unknown arch 0xf7* version 1 (SYSV), with debug_info, not stripped
# pahole test_xdp_noinline.o
[...]
struct ctl_value {
union {
__u64 value; /* 0 8 */
__u32 ifindex; /* 0 4 */
__u8 mac[0]; /* 0 0 */
}; /* 0 8 */
/* size: 8, cachelines: 1, members: 1 */
/* last cacheline: 8 bytes */
};
Now loading into kernel and dumping the map via bpftool:
# ip -force link set dev lo xdp obj test_xdp_noinline.o sec xdp-test
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 xdpgeneric/id:227 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
[...]
# bpftool prog show id 227
227: xdp tag a85e060c275c5616 gpl
loaded_at 2018-07-17T14:41:29+0000 uid 0
xlated 8152B not jited memlock 12288B map_ids 381,385,386,382,384,383
# bpftool map dump id 386
[{
"key": 0,
"value": {
"": {
"value": 0,
"ifindex": 0,
"mac": []
}
}
},{
"key": 1,
"value": {
"": {
"value": 0,
"ifindex": 0,
"mac": []
}
}
},{
[...]
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
include/bpf_elf.h | 9 ++
include/bpf_util.h | 1 +
lib/bpf.c | 332 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 338 insertions(+), 4 deletions(-)
diff --git a/include/bpf_elf.h b/include/bpf_elf.h
index a8e360f..84e8ae0 100644
--- a/include/bpf_elf.h
+++ b/include/bpf_elf.h
@@ -41,4 +41,13 @@ struct bpf_elf_map {
__u32 inner_idx;
};
+#define BPF_ANNOTATE_KV_PAIR(name, type_key, type_val) \
+ struct ____btf_map_##name { \
+ type_key key; \
+ type_val value; \
+ }; \
+ struct ____btf_map_##name \
+ __attribute__ ((section(".maps." #name), used)) \
+ ____btf_map_##name = { }
+
#endif /* __BPF_ELF__ */
diff --git a/include/bpf_util.h b/include/bpf_util.h
index 219beb4..63837a0 100644
--- a/include/bpf_util.h
+++ b/include/bpf_util.h
@@ -14,6 +14,7 @@
#define __BPF_UTIL__
#include <linux/bpf.h>
+#include <linux/btf.h>
#include <linux/filter.h>
#include <linux/magic.h>
#include <linux/elf-em.h>
diff --git a/lib/bpf.c b/lib/bpf.c
index cea1273..794ad19 100644
--- a/lib/bpf.c
+++ b/lib/bpf.c
@@ -388,6 +388,8 @@ struct bpf_prog_data {
struct bpf_map_ext {
struct bpf_prog_data owner;
+ unsigned int btf_id_key;
+ unsigned int btf_id_val;
};
static int bpf_derive_elf_map_from_fdinfo(int fd, struct bpf_elf_map *map,
@@ -1120,24 +1122,36 @@ struct bpf_config {
unsigned int jit_enabled;
};
+struct bpf_btf {
+ const struct btf_header *hdr;
+ const void *raw;
+ const char *strings;
+ const struct btf_type **types;
+ int types_num;
+};
+
struct bpf_elf_ctx {
struct bpf_config cfg;
Elf *elf_fd;
GElf_Ehdr elf_hdr;
Elf_Data *sym_tab;
Elf_Data *str_tab;
+ Elf_Data *btf_data;
char obj_uid[64];
int obj_fd;
+ int btf_fd;
int map_fds[ELF_MAX_MAPS];
struct bpf_elf_map maps[ELF_MAX_MAPS];
struct bpf_map_ext maps_ext[ELF_MAX_MAPS];
struct bpf_elf_prog prog_text;
+ struct bpf_btf btf;
int sym_num;
int map_num;
int map_len;
bool *sec_done;
int sec_maps;
int sec_text;
+ int sec_btf;
char license[ELF_MAX_LICENSE_LEN];
enum bpf_prog_type type;
__u32 ifindex;
@@ -1162,6 +1176,11 @@ struct bpf_map_data {
struct bpf_elf_map *ent;
};
+static bool bpf_log_has_data(struct bpf_elf_ctx *ctx)
+{
+ return ctx->log && ctx->log[0];
+}
+
static __check_format_string(2, 3) void
bpf_dump_error(struct bpf_elf_ctx *ctx, const char *format, ...)
{
@@ -1171,7 +1190,7 @@ bpf_dump_error(struct bpf_elf_ctx *ctx, const char *format, ...)
vfprintf(stderr, format, vl);
va_end(vl);
- if (ctx->log && ctx->log[0]) {
+ if (bpf_log_has_data(ctx)) {
if (ctx->verbose) {
fprintf(stderr, "%s\n", ctx->log);
} else {
@@ -1218,7 +1237,9 @@ static int bpf_log_realloc(struct bpf_elf_ctx *ctx)
static int bpf_map_create(enum bpf_map_type type, uint32_t size_key,
uint32_t size_value, uint32_t max_elem,
- uint32_t flags, int inner_fd, uint32_t ifindex)
+ uint32_t flags, int inner_fd, int btf_fd,
+ uint32_t ifindex, uint32_t btf_id_key,
+ uint32_t btf_id_val)
{
union bpf_attr attr = {};
@@ -1229,10 +1250,30 @@ static int bpf_map_create(enum bpf_map_type type, uint32_t size_key,
attr.map_flags = flags;
attr.inner_map_fd = inner_fd;
attr.map_ifindex = ifindex;
+ attr.btf_fd = btf_fd;
+ attr.btf_key_type_id = btf_id_key;
+ attr.btf_value_type_id = btf_id_val;
return bpf(BPF_MAP_CREATE, &attr, sizeof(attr));
}
+static int bpf_btf_load(void *btf, size_t size_btf,
+ char *log, size_t size_log)
+{
+ union bpf_attr attr = {};
+
+ attr.btf = bpf_ptr_to_u64(btf);
+ attr.btf_size = size_btf;
+
+ if (size_log > 0) {
+ attr.btf_log_buf = bpf_ptr_to_u64(log);
+ attr.btf_log_size = size_log;
+ attr.btf_log_level = 1;
+ }
+
+ return bpf(BPF_BTF_LOAD, &attr, sizeof(attr));
+}
+
static int bpf_obj_pin(int fd, const char *pathname)
{
union bpf_attr attr = {};
@@ -1608,7 +1649,8 @@ static int bpf_map_attach(const char *name, struct bpf_elf_ctx *ctx,
ifindex = bpf_map_offload_neutral(map->type) ? 0 : ctx->ifindex;
errno = 0;
fd = bpf_map_create(map->type, map->size_key, map->size_value,
- map->max_elem, map->flags, map_inner_fd, ifindex);
+ map->max_elem, map->flags, map_inner_fd, ctx->btf_fd,
+ ifindex, ext->btf_id_key, ext->btf_id_val);
if (fd < 0 || ctx->verbose) {
bpf_map_report(fd, name, map, ctx, map_inner_fd);
@@ -1633,8 +1675,80 @@ static const char *bpf_str_tab_name(const struct bpf_elf_ctx *ctx,
return ctx->str_tab->d_buf + sym->st_name;
}
+static int bpf_btf_find(struct bpf_elf_ctx *ctx, const char *name)
+{
+ const struct btf_type *type;
+ const char *res;
+ int id;
+
+ for (id = 1; id < ctx->btf.types_num; id++) {
+ type = ctx->btf.types[id];
+ if (type->name_off >= ctx->btf.hdr->str_len)
+ continue;
+ res = &ctx->btf.strings[type->name_off];
+ if (!strcmp(res, name))
+ return id;
+ }
+
+ return -ENOENT;
+}
+
+static int bpf_btf_find_kv(struct bpf_elf_ctx *ctx, const struct bpf_elf_map *map,
+ const char *name, uint32_t *id_key, uint32_t *id_val)
+{
+ const struct btf_member *key, *val;
+ const struct btf_type *type;
+ char btf_name[512];
+ const char *res;
+ int id;
+
+ snprintf(btf_name, sizeof(btf_name), "____btf_map_%s", name);
+ id = bpf_btf_find(ctx, btf_name);
+ if (id < 0)
+ return id;
+
+ type = ctx->btf.types[id];
+ if (BTF_INFO_KIND(type->info) != BTF_KIND_STRUCT)
+ return -EINVAL;
+ if (BTF_INFO_VLEN(type->info) != 2)
+ return -EINVAL;
+
+ key = ((void *) type) + sizeof(*type);
+ val = key + 1;
+ if (!key->type || key->type >= ctx->btf.types_num ||
+ !val->type || val->type >= ctx->btf.types_num)
+ return -EINVAL;
+
+ if (key->name_off >= ctx->btf.hdr->str_len ||
+ val->name_off >= ctx->btf.hdr->str_len)
+ return -EINVAL;
+
+ res = &ctx->btf.strings[key->name_off];
+ if (strcmp(res, "key"))
+ return -EINVAL;
+
+ res = &ctx->btf.strings[val->name_off];
+ if (strcmp(res, "value"))
+ return -EINVAL;
+
+ *id_key = key->type;
+ *id_val = val->type;
+ return 0;
+}
+
+static void bpf_btf_annotate(struct bpf_elf_ctx *ctx, int which, const char *name)
+{
+ uint32_t id_key = 0, id_val = 0;
+
+ if (!bpf_btf_find_kv(ctx, &ctx->maps[which], name, &id_key, &id_val)) {
+ ctx->maps_ext[which].btf_id_key = id_key;
+ ctx->maps_ext[which].btf_id_val = id_val;
+ }
+}
+
static const char *bpf_map_fetch_name(struct bpf_elf_ctx *ctx, int which)
{
+ const char *name;
GElf_Sym sym;
int i;
@@ -1648,7 +1762,9 @@ static const char *bpf_map_fetch_name(struct bpf_elf_ctx *ctx, int which)
sym.st_value / ctx->map_len != which)
continue;
- return bpf_str_tab_name(ctx, &sym);
+ name = bpf_str_tab_name(ctx, &sym);
+ bpf_btf_annotate(ctx, which, name);
+ return name;
}
return NULL;
@@ -1910,11 +2026,210 @@ static int bpf_fetch_text(struct bpf_elf_ctx *ctx, int section,
return 0;
}
+static void bpf_btf_report(int fd, struct bpf_elf_ctx *ctx)
+{
+ fprintf(stderr, "\nBTF debug data section \'.BTF\' %s%s (%d)!\n",
+ fd < 0 ? "rejected: " : "loaded",
+ fd < 0 ? strerror(errno) : "",
+ fd < 0 ? errno : fd);
+
+ fprintf(stderr, " - Length: %zu\n", ctx->btf_data->d_size);
+
+ bpf_dump_error(ctx, "Verifier analysis:\n\n");
+}
+
+static int bpf_btf_attach(struct bpf_elf_ctx *ctx)
+{
+ int tries = 0, fd;
+retry:
+ errno = 0;
+ fd = bpf_btf_load(ctx->btf_data->d_buf, ctx->btf_data->d_size,
+ ctx->log, ctx->log_size);
+ if (fd < 0 || ctx->verbose) {
+ if (fd < 0 && (errno == ENOSPC || !ctx->log_size)) {
+ if (tries++ < 10 && !bpf_log_realloc(ctx))
+ goto retry;
+
+ fprintf(stderr, "Log buffer too small to dump verifier log %zu bytes (%d tries)!\n",
+ ctx->log_size, tries);
+ return fd;
+ }
+
+ if (bpf_log_has_data(ctx))
+ bpf_btf_report(fd, ctx);
+ }
+
+ return fd;
+}
+
+static int bpf_fetch_btf_begin(struct bpf_elf_ctx *ctx, int section,
+ struct bpf_elf_sec_data *data)
+{
+ ctx->btf_data = data->sec_data;
+ ctx->sec_btf = section;
+ ctx->sec_done[section] = true;
+ return 0;
+}
+
+static int bpf_btf_check_header(struct bpf_elf_ctx *ctx)
+{
+ const struct btf_header *hdr = ctx->btf_data->d_buf;
+ const char *str_start, *str_end;
+ unsigned int data_len;
+
+ if (hdr->magic != BTF_MAGIC) {
+ fprintf(stderr, "Object has wrong BTF magic: %x, expected: %x!\n",
+ hdr->magic, BTF_MAGIC);
+ return -EINVAL;
+ }
+
+ if (hdr->version != BTF_VERSION) {
+ fprintf(stderr, "Object has wrong BTF version: %u, expected: %u!\n",
+ hdr->version, BTF_VERSION);
+ return -EINVAL;
+ }
+
+ if (hdr->flags) {
+ fprintf(stderr, "Object has unsupported BTF flags %x!\n",
+ hdr->flags);
+ return -EINVAL;
+ }
+
+ data_len = ctx->btf_data->d_size - sizeof(*hdr);
+ if (data_len < hdr->type_off ||
+ data_len < hdr->str_off ||
+ data_len < hdr->type_len + hdr->str_len ||
+ hdr->type_off >= hdr->str_off ||
+ hdr->type_off + hdr->type_len != hdr->str_off ||
+ hdr->str_off + hdr->str_len != data_len ||
+ (hdr->type_off & (sizeof(uint32_t) - 1))) {
+ fprintf(stderr, "Object has malformed BTF data!\n");
+ return -EINVAL;
+ }
+
+ ctx->btf.hdr = hdr;
+ ctx->btf.raw = hdr + 1;
+
+ str_start = ctx->btf.raw + hdr->str_off;
+ str_end = str_start + hdr->str_len;
+ if (!hdr->str_len ||
+ hdr->str_len - 1 > BTF_MAX_NAME_OFFSET ||
+ str_start[0] || str_end[-1]) {
+ fprintf(stderr, "Object has malformed BTF string data!\n");
+ return -EINVAL;
+ }
+
+ ctx->btf.strings = str_start;
+ return 0;
+}
+
+static int bpf_btf_register_type(struct bpf_elf_ctx *ctx,
+ const struct btf_type *type)
+{
+ int cur = ctx->btf.types_num, num = cur + 1;
+ const struct btf_type **types;
+
+ types = realloc(ctx->btf.types, num * sizeof(type));
+ if (!types) {
+ free(ctx->btf.types);
+ ctx->btf.types = NULL;
+ ctx->btf.types_num = 0;
+ return -ENOMEM;
+ }
+
+ ctx->btf.types = types;
+ ctx->btf.types[cur] = type;
+ ctx->btf.types_num = num;
+ return 0;
+}
+
+static struct btf_type btf_type_void;
+
+static int bpf_btf_prep_type_data(struct bpf_elf_ctx *ctx)
+{
+ const void *type_cur = ctx->btf.raw + ctx->btf.hdr->type_off;
+ const void *type_end = ctx->btf.raw + ctx->btf.hdr->str_off;
+ const struct btf_type *type;
+ uint16_t var_len;
+ int ret, kind;
+
+ ret = bpf_btf_register_type(ctx, &btf_type_void);
+ if (ret < 0)
+ return ret;
+
+ while (type_cur < type_end) {
+ type = type_cur;
+ type_cur += sizeof(*type);
+
+ var_len = BTF_INFO_VLEN(type->info);
+ kind = BTF_INFO_KIND(type->info);
+
+ switch (kind) {
+ case BTF_KIND_INT:
+ type_cur += sizeof(int);
+ break;
+ case BTF_KIND_ARRAY:
+ type_cur += sizeof(struct btf_array);
+ break;
+ case BTF_KIND_STRUCT:
+ case BTF_KIND_UNION:
+ type_cur += var_len * sizeof(struct btf_member);
+ break;
+ case BTF_KIND_ENUM:
+ type_cur += var_len * sizeof(struct btf_enum);
+ break;
+ case BTF_KIND_TYPEDEF:
+ case BTF_KIND_PTR:
+ case BTF_KIND_FWD:
+ case BTF_KIND_VOLATILE:
+ case BTF_KIND_CONST:
+ case BTF_KIND_RESTRICT:
+ break;
+ default:
+ fprintf(stderr, "Object has unknown BTF type: %u!\n", kind);
+ return -EINVAL;
+ }
+
+ ret = bpf_btf_register_type(ctx, type);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int bpf_btf_prep_data(struct bpf_elf_ctx *ctx)
+{
+ int ret = bpf_btf_check_header(ctx);
+
+ if (!ret)
+ return bpf_btf_prep_type_data(ctx);
+ return ret;
+}
+
+static void bpf_fetch_btf_end(struct bpf_elf_ctx *ctx)
+{
+ int fd = bpf_btf_attach(ctx);
+
+ if (fd < 0)
+ return;
+ ctx->btf_fd = fd;
+ if (bpf_btf_prep_data(ctx) < 0) {
+ close(ctx->btf_fd);
+ ctx->btf_fd = 0;
+ }
+}
+
static bool bpf_has_map_data(const struct bpf_elf_ctx *ctx)
{
return ctx->sym_tab && ctx->str_tab && ctx->sec_maps;
}
+static bool bpf_has_btf_data(const struct bpf_elf_ctx *ctx)
+{
+ return ctx->sec_btf;
+}
+
static bool bpf_has_call_data(const struct bpf_elf_ctx *ctx)
{
return ctx->sec_text;
@@ -1947,6 +2262,9 @@ static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx, bool check_text_sec)
else if (data.sec_hdr.sh_type == SHT_STRTAB &&
!strcmp(data.sec_name, ".strtab"))
ret = bpf_fetch_strtab(ctx, i, &data);
+ else if (data.sec_hdr.sh_type == SHT_PROGBITS &&
+ !strcmp(data.sec_name, ".BTF"))
+ ret = bpf_fetch_btf_begin(ctx, i, &data);
if (ret < 0) {
fprintf(stderr, "Error parsing section %d! Perhaps check with readelf -a?\n",
i);
@@ -1954,6 +2272,8 @@ static int bpf_fetch_ancillary(struct bpf_elf_ctx *ctx, bool check_text_sec)
}
}
+ if (bpf_has_btf_data(ctx))
+ bpf_fetch_btf_end(ctx);
if (bpf_has_map_data(ctx)) {
ret = bpf_fetch_maps_end(ctx);
if (ret < 0) {
@@ -2591,6 +2911,10 @@ static void bpf_maps_teardown(struct bpf_elf_ctx *ctx)
if (ctx->map_fds[i])
close(ctx->map_fds[i]);
}
+
+ if (ctx->btf_fd)
+ close(ctx->btf_fd);
+ free(ctx->btf.types);
}
static void bpf_elf_ctx_destroy(struct bpf_elf_ctx *ctx, bool failure)
--
2.9.5
^ permalink raw reply related
* [PATCH iproute2 3/5] bpf: remove strict dependency on af_alg
From: Daniel Borkmann @ 2018-07-17 23:31 UTC (permalink / raw)
To: dsahern; +Cc: jakub.kicinski, alexei.starovoitov, netdev, Daniel Borkmann
In-Reply-To: <20180717233122.29390-1-daniel@iogearbox.net>
Do not bail out when AF_ALG is not supported by the kernel and
only do so when a map is requested in object ns where we're
calculating the hash. Otherwise, the loader can operate just
fine, therefore lets not fail early when it's not needed.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
lib/bpf.c | 74 ++++++++++++++++++++++++---------------------------------------
1 file changed, 28 insertions(+), 46 deletions(-)
diff --git a/lib/bpf.c b/lib/bpf.c
index 42093db..135f496 100644
--- a/lib/bpf.c
+++ b/lib/bpf.c
@@ -1125,6 +1125,7 @@ struct bpf_elf_ctx {
GElf_Ehdr elf_hdr;
Elf_Data *sym_tab;
Elf_Data *str_tab;
+ char obj_uid[64];
int obj_fd;
int map_fds[ELF_MAX_MAPS];
struct bpf_elf_map maps[ELF_MAX_MAPS];
@@ -1138,6 +1139,7 @@ struct bpf_elf_ctx {
enum bpf_prog_type type;
__u32 ifindex;
bool verbose;
+ bool noafalg;
struct bpf_elf_st stat;
struct bpf_hash_entry *ht[256];
char *log;
@@ -1253,22 +1255,15 @@ static int bpf_obj_hash(const char *object, uint8_t *out, size_t len)
return -EINVAL;
cfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
- if (cfd < 0) {
- fprintf(stderr, "Cannot get AF_ALG socket: %s\n",
- strerror(errno));
+ if (cfd < 0)
return cfd;
- }
ret = bind(cfd, (struct sockaddr *)&alg, sizeof(alg));
- if (ret < 0) {
- fprintf(stderr, "Error binding socket: %s\n", strerror(errno));
+ if (ret < 0)
goto out_cfd;
- }
ofd = accept(cfd, NULL, 0);
if (ofd < 0) {
- fprintf(stderr, "Error accepting socket: %s\n",
- strerror(errno));
ret = ofd;
goto out_cfd;
}
@@ -1313,29 +1308,7 @@ out_cfd:
return ret;
}
-static const char *bpf_get_obj_uid(const char *pathname)
-{
- static bool bpf_uid_cached;
- static char bpf_uid[64];
- uint8_t tmp[20];
- int ret;
-
- if (bpf_uid_cached)
- goto done;
-
- ret = bpf_obj_hash(pathname, tmp, sizeof(tmp));
- if (ret) {
- fprintf(stderr, "Object hashing failed!\n");
- return NULL;
- }
-
- hexstring_n2a(tmp, sizeof(tmp), bpf_uid, sizeof(bpf_uid));
- bpf_uid_cached = true;
-done:
- return bpf_uid;
-}
-
-static int bpf_init_env(const char *pathname)
+static void bpf_init_env(void)
{
struct rlimit limit = {
.rlim_cur = RLIM_INFINITY,
@@ -1345,15 +1318,8 @@ static int bpf_init_env(const char *pathname)
/* Don't bother in case we fail! */
setrlimit(RLIMIT_MEMLOCK, &limit);
- if (!bpf_get_work_dir(BPF_PROG_TYPE_UNSPEC)) {
+ if (!bpf_get_work_dir(BPF_PROG_TYPE_UNSPEC))
fprintf(stderr, "Continuing without mounted eBPF fs. Too old kernel?\n");
- return 0;
- }
-
- if (!bpf_get_obj_uid(pathname))
- return -1;
-
- return 0;
}
static const char *bpf_custom_pinning(const struct bpf_elf_ctx *ctx,
@@ -1389,7 +1355,7 @@ static void bpf_make_pathname(char *pathname, size_t len, const char *name,
case PIN_OBJECT_NS:
snprintf(pathname, len, "%s/%s/%s",
bpf_get_work_dir(ctx->type),
- bpf_get_obj_uid(NULL), name);
+ ctx->obj_uid, name);
break;
case PIN_GLOBAL_NS:
snprintf(pathname, len, "%s/%s/%s",
@@ -1422,7 +1388,7 @@ static int bpf_make_obj_path(const struct bpf_elf_ctx *ctx)
int ret;
snprintf(tmp, sizeof(tmp), "%s/%s", bpf_get_work_dir(ctx->type),
- bpf_get_obj_uid(NULL));
+ ctx->obj_uid);
ret = mkdir(tmp, S_IRWXU);
if (ret && errno != EEXIST) {
@@ -1691,6 +1657,12 @@ static int bpf_maps_attach_all(struct bpf_elf_ctx *ctx)
const char *map_name;
for (i = 0; i < ctx->map_num; i++) {
+ if (ctx->maps[i].pinning == PIN_OBJECT_NS &&
+ ctx->noafalg) {
+ fprintf(stderr, "Missing kernel AF_ALG support for PIN_OBJECT_NS!\n");
+ return -ENOTSUP;
+ }
+
map_name = bpf_map_fetch_name(ctx, i);
if (!map_name)
return -EIO;
@@ -2446,14 +2418,24 @@ static int bpf_elf_ctx_init(struct bpf_elf_ctx *ctx, const char *pathname,
enum bpf_prog_type type, __u32 ifindex,
bool verbose)
{
- int ret = -EINVAL;
+ uint8_t tmp[20];
+ int ret;
- if (elf_version(EV_CURRENT) == EV_NONE ||
- bpf_init_env(pathname))
- return ret;
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ return -EINVAL;
+
+ bpf_init_env();
memset(ctx, 0, sizeof(*ctx));
bpf_get_cfg(ctx);
+
+ ret = bpf_obj_hash(pathname, tmp, sizeof(tmp));
+ if (ret)
+ ctx->noafalg = true;
+ else
+ hexstring_n2a(tmp, sizeof(tmp), ctx->obj_uid,
+ sizeof(ctx->obj_uid));
+
ctx->verbose = verbose;
ctx->type = type;
ctx->ifindex = ifindex;
--
2.9.5
^ permalink raw reply related
* [PATCH iproute2 2/5] bpf: move bpf_elf_map fixup notification under verbose
From: Daniel Borkmann @ 2018-07-17 23:31 UTC (permalink / raw)
To: dsahern; +Cc: jakub.kicinski, alexei.starovoitov, netdev, Daniel Borkmann
In-Reply-To: <20180717233122.29390-1-daniel@iogearbox.net>
No need to spam the user with this if it can be fixed gracefully
anyway. Therefore, move it under verbose option.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
lib/bpf.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/bpf.c b/lib/bpf.c
index 4e26c0d..42093db 100644
--- a/lib/bpf.c
+++ b/lib/bpf.c
@@ -1893,9 +1893,9 @@ static int bpf_fetch_maps_end(struct bpf_elf_ctx *ctx)
}
memcpy(ctx->maps, fixup, sizeof(fixup));
-
- printf("Note: %zu bytes struct bpf_elf_map fixup performed due to size mismatch!\n",
- sizeof(struct bpf_elf_map) - ctx->map_len);
+ if (ctx->verbose)
+ printf("%zu bytes struct bpf_elf_map fixup performed due to size mismatch!\n",
+ sizeof(struct bpf_elf_map) - ctx->map_len);
return 0;
}
--
2.9.5
^ permalink raw reply related
* [PATCH iproute2 0/5] Various BPF improvements
From: Daniel Borkmann @ 2018-07-17 23:31 UTC (permalink / raw)
To: dsahern; +Cc: jakub.kicinski, alexei.starovoitov, netdev, Daniel Borkmann
Main part of this set is to: i) avoid strict af_alg kernel dependency,
ii) add loader support for bpf to bpf calls and iii) add btf loader
support with an option to annotate maps. For details please see the
individual patches. Thanks!
Daniel Borkmann (5):
bpf: import btf uapi kernel header
bpf: move bpf_elf_map fixup notification under verbose
bpf: remove strict dependency on af_alg
bpf: implement bpf to bpf calls support
bpf: implement btf handling and map annotation
include/bpf_elf.h | 9 +
include/bpf_util.h | 1 +
include/uapi/linux/btf.h | 113 +++++++++
lib/bpf.c | 645 +++++++++++++++++++++++++++++++++++++----------
4 files changed, 639 insertions(+), 129 deletions(-)
create mode 100644 include/uapi/linux/btf.h
--
2.9.5
^ permalink raw reply
* Re: [PATCH v2 bpf 3/5] bpf: bpf_prog_array_free() should take a generic non-rcu pointer
From: Roman Gushchin @ 2018-07-17 22:55 UTC (permalink / raw)
To: Daniel Borkmann; +Cc: netdev, linux-kernel, kernel-team, Alexei Starovoitov
In-Reply-To: <1a40b0a8-7440-f2d2-d743-64901b5d1bfe@iogearbox.net>
On Wed, Jul 18, 2018 at 12:38:50AM +0200, Daniel Borkmann wrote:
> On 07/17/2018 12:57 AM, Roman Gushchin wrote:
> > On Tue, Jul 17, 2018 at 12:30:18AM +0200, Daniel Borkmann wrote:
> >> On 07/13/2018 09:41 PM, Roman Gushchin wrote:
> >>> bpf_prog_array_free() should take a generic non-rcu pointer
> >>> as an argument, as freeing the objects assumes that we're
> >>> holding an exclusive rights on it.
> >>>
> >>> rcu_access_pointer() can be used to convert a __rcu pointer to
> >>> a generic pointer before passing it to bpf_prog_array_free(),
> >>> if necessary.
> >>>
> >>> This patch eliminates the following sparse warning:
> >>> kernel/bpf/core.c:1556:9: warning: incorrect type in argument 1 (different address spaces)
> >>> kernel/bpf/core.c:1556:9: expected struct callback_head *head
> >>> kernel/bpf/core.c:1556:9: got struct callback_head [noderef] <asn:4>*<noident>
> >>>
> >>> Fixes: 324bda9e6c5a ("bpf: multi program support for cgroup+bpf")
> >>> Signed-off-by: Roman Gushchin <guro@fb.com>
> >>> Cc: Alexei Starovoitov <ast@kernel.org>
> >>> Cc: Daniel Borkmann <daniel@iogearbox.net>
> >>> ---
> >>> drivers/media/rc/bpf-lirc.c | 6 +++---
> >>> include/linux/bpf.h | 2 +-
> >>> kernel/bpf/cgroup.c | 11 ++++++-----
> >>> kernel/bpf/core.c | 5 ++---
> >>> kernel/trace/bpf_trace.c | 8 ++++----
> >>> 5 files changed, 16 insertions(+), 16 deletions(-)
> >>>
> >>> diff --git a/drivers/media/rc/bpf-lirc.c b/drivers/media/rc/bpf-lirc.c
> >>> index fcfab6635f9c..509b262aa0dc 100644
> >>> --- a/drivers/media/rc/bpf-lirc.c
> >>> +++ b/drivers/media/rc/bpf-lirc.c
> >>> @@ -135,7 +135,7 @@ static int lirc_bpf_attach(struct rc_dev *rcdev, struct bpf_prog *prog)
> >>> goto unlock;
> >>>
> >>> rcu_assign_pointer(raw->progs, new_array);
> >>> - bpf_prog_array_free(old_array);
> >>> + bpf_prog_array_free(rcu_access_pointer(old_array));
> >>
> >> Taking this one as an example, why can't we already do the rcu_dereference() on the
> >> 'old_array = raw->progs' where we fetch the old_array initially? Then we also wouldn't
> >> need the rcu_access_pointer() on bpf_prog_array_free() and yet another rcu_dereference()
> >> inside the bpf_prog_array_copy() from your later patch?
> >
> > We can, but then we have to change bpf_prog_array_copy() args annotation,
> > and also all places, where it's called.
> > IMO, basically all local variables and function args marked as __rcu
> > should be not marked as RCU, but fixing them all is beyond this patchset.
>
> Right, agree, the __rcu markings seem somewhat arbitrary. :-( I think we need to
> investigate this a bit deeper and do a proper audit on the whole bpf prog array's
> RCU handling (probably won't get to it in next two weeks but put onto backlog just
> in case it's still unresolved till then). That said, given this has been there for
> quite a while and it's rc5 now, I think we could start out on bpf-next with the
> obvious candidates which should be okay even if it ends up bigger.
Totally agree.
> First two from this series we could already take in if you prefer.
That would be nice!
Maybe it will be enough to land the cgroup local storage patchset,
what is my primary goal now. After that I'll try to look at __rcu
annotations too.
Thanks!
^ permalink raw reply
* Re: dvb usb issues since kernel 4.9
From: Mauro Carvalho Chehab @ 2018-07-17 22:21 UTC (permalink / raw)
To: Linus Torvalds
Cc: hannah, Jonathan Corbet, David Miller, Eric Dumazet,
Greg Kroah-Hartman, Josef Griebichler, Hannes Frederic Sowa,
Jesper Dangaard Brouer, Linux Kernel Mailing List,
Linux Media Mailing List, USB list, Mauro Carvalho Chehab,
Ingo Molnar, Network Development, Paolo Abeni, Peter Zijlstra,
Rik van Riel, Alan Stern, dma
In-Reply-To: <CA+55aFwb5hPtPFbB02SSn+wTkqTDSgHGFkiw7LB57mj42VzyZQ@mail.gmail.com>
Hi Linus,
Em Tue, 17 Jul 2018 10:09:28 -0700
Linus Torvalds <torvalds@linux-foundation.org> escreveu:
> On Tue, Jul 17, 2018 at 4:58 AM Hanna Hawa <hannah@marvell.com> wrote:
> >
> > After some debug/bisect/diff, found that patch "softirq: Let ksoftirqd
> > do its job" is problematic patch.
>
> Ok, this thread died down without any resolution.
>
> >- Using v4.14.0 (including softirq patch) and the additional fix
> > proposed by Linus - no timeout issue.
>
> Are you talking about the patch that made HI_SOFTIRQ and
> TASKLET_SOFTIRQ special, and had this:
>
> #define SOFTIRQ_NOW_MASK ((1 << HI_SOFTIRQ) | (1 << TASKLET_SOFTIRQ))
>
> in it?
>
> I think I'll just commit the damn thing. It's hacky, but it's simple,
> and it never got applied because we had smarter suggestions. But the
> smarter suggestions never ended up being applied either, so..
Yeah, IMHO the best would be to apply your patch[1], c/c stable up to
4.9. Nothing prevents applying a better/smarter solution once we
have it. From my side, I can keep testing whatever smart suggestions
people propose. Yet, better to have one fix on our hand than two
fixes flying around.
[1] e. g.
https://git.linuxtv.org/mchehab/experimental.git/commit/?h=v4.15%2bmedia%2bdwc2&id=ccf833fd4a5b99c3d3cf2c09c065670f74a230a7
Regards,
Mauro
^ permalink raw reply
* Re: [PATCH next] bonding: pass link-local packets to bonding master also.
From: Michal Soltys @ 2018-07-17 22:17 UTC (permalink / raw)
To: Mahesh Bandewar (महेश बंडेवार),
Jay Vosburgh
Cc: Mahesh Bandewar, Andy Gospodarek, Veaceslav Falico, David Miller,
Netdev, Stephen Hemminger
In-Reply-To: <1e7bc087-06e7-e3e1-aae2-2169a0170189@ziu.info>
On 2018-07-17 11:32, Michal Soltys wrote:
> On 07/17/2018 01:53 AM, Mahesh Bandewar (महेश बंडेवार) wrote:
>> On Mon, Jul 16, 2018 at 2:24 PM, Jay Vosburgh
>> <jay.vosburgh@canonical.com> wrote:
>>> Mahesh Bandewar <mahesh@bandewar.net> wrote:
>>>
>>>> From: Mahesh Bandewar <maheshb@google.com>
>>>>
>>>> Commit b89f04c61efe ("bonding: deliver link-local packets with
>>>> skb->dev set to link that packets arrived on") changed the behavior
>>>> of how link-local-multicast packets are processed. The change in
>>>> the behavior broke some legacy use cases where these packets are
>>>> expected to arrive on bonding master device also.
>>>>
>>>> This patch passes the packet to the stack with the link it arrived
>>>> on as well as passes to the bonding-master device to preserve the
>>>> legacy use case.
>>>
>>> Michal, can you test this? I'm travelling this week and won't
>>> be able to run the patch.
>
>
> Yes, will test today and report.
>
The patch looks to be working fine - tested both passive bridge
(stp_state == 0) and with in-kernel implementation active (stp_state ==
1). No loops, no issues so far.
^ permalink raw reply
* Re: [PATCH v2 bpf 3/5] bpf: bpf_prog_array_free() should take a generic non-rcu pointer
From: Daniel Borkmann @ 2018-07-17 22:38 UTC (permalink / raw)
To: Roman Gushchin; +Cc: netdev, linux-kernel, kernel-team, Alexei Starovoitov
In-Reply-To: <20180716225715.GB3898@castle.DHCP.thefacebook.com>
On 07/17/2018 12:57 AM, Roman Gushchin wrote:
> On Tue, Jul 17, 2018 at 12:30:18AM +0200, Daniel Borkmann wrote:
>> On 07/13/2018 09:41 PM, Roman Gushchin wrote:
>>> bpf_prog_array_free() should take a generic non-rcu pointer
>>> as an argument, as freeing the objects assumes that we're
>>> holding an exclusive rights on it.
>>>
>>> rcu_access_pointer() can be used to convert a __rcu pointer to
>>> a generic pointer before passing it to bpf_prog_array_free(),
>>> if necessary.
>>>
>>> This patch eliminates the following sparse warning:
>>> kernel/bpf/core.c:1556:9: warning: incorrect type in argument 1 (different address spaces)
>>> kernel/bpf/core.c:1556:9: expected struct callback_head *head
>>> kernel/bpf/core.c:1556:9: got struct callback_head [noderef] <asn:4>*<noident>
>>>
>>> Fixes: 324bda9e6c5a ("bpf: multi program support for cgroup+bpf")
>>> Signed-off-by: Roman Gushchin <guro@fb.com>
>>> Cc: Alexei Starovoitov <ast@kernel.org>
>>> Cc: Daniel Borkmann <daniel@iogearbox.net>
>>> ---
>>> drivers/media/rc/bpf-lirc.c | 6 +++---
>>> include/linux/bpf.h | 2 +-
>>> kernel/bpf/cgroup.c | 11 ++++++-----
>>> kernel/bpf/core.c | 5 ++---
>>> kernel/trace/bpf_trace.c | 8 ++++----
>>> 5 files changed, 16 insertions(+), 16 deletions(-)
>>>
>>> diff --git a/drivers/media/rc/bpf-lirc.c b/drivers/media/rc/bpf-lirc.c
>>> index fcfab6635f9c..509b262aa0dc 100644
>>> --- a/drivers/media/rc/bpf-lirc.c
>>> +++ b/drivers/media/rc/bpf-lirc.c
>>> @@ -135,7 +135,7 @@ static int lirc_bpf_attach(struct rc_dev *rcdev, struct bpf_prog *prog)
>>> goto unlock;
>>>
>>> rcu_assign_pointer(raw->progs, new_array);
>>> - bpf_prog_array_free(old_array);
>>> + bpf_prog_array_free(rcu_access_pointer(old_array));
>>
>> Taking this one as an example, why can't we already do the rcu_dereference() on the
>> 'old_array = raw->progs' where we fetch the old_array initially? Then we also wouldn't
>> need the rcu_access_pointer() on bpf_prog_array_free() and yet another rcu_dereference()
>> inside the bpf_prog_array_copy() from your later patch?
>
> We can, but then we have to change bpf_prog_array_copy() args annotation,
> and also all places, where it's called.
> IMO, basically all local variables and function args marked as __rcu
> should be not marked as RCU, but fixing them all is beyond this patchset.
Right, agree, the __rcu markings seem somewhat arbitrary. :-( I think we need to
investigate this a bit deeper and do a proper audit on the whole bpf prog array's
RCU handling (probably won't get to it in next two weeks but put onto backlog just
in case it's still unresolved till then). That said, given this has been there for
quite a while and it's rc5 now, I think we could start out on bpf-next with the
obvious candidates which should be okay even if it ends up bigger. First two from
this series we could already take in if you prefer.
Thanks,
Daniel
^ permalink raw reply
* Re: [PATCH] lib/rhashtable: consider param->min_size when setting initial table size
From: Davidlohr Bueso @ 2018-07-17 22:30 UTC (permalink / raw)
To: Herbert Xu; +Cc: akpm, tgraf, linux-kernel, Davidlohr Bueso, netdev
In-Reply-To: <20180716000046.yscgnpr256qhm2qg@gondor.apana.org.au>
On Mon, 16 Jul 2018, Herbert Xu wrote:
>On Fri, Jul 13, 2018 at 11:25:16PM -0700, Davidlohr Bueso wrote:
>> rhashtable_init() currently does not take into account the user-passed
>> min_size parameter unless param->nelem_hint is set as well. As such,
>> the default size (number of buckets) will always be HASH_DEFAULT_SIZE
>> even if the smallest allowed size is larger than that. Remediate this
>> by unconditionally calling into rounded_hashtable_size() and handling
>> things accordingly.
>>
>> Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
>
>Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
>
>Normally these patches go through netdev so could you please resend
>it with my ack to netdev@vger.kernel.org?
So I've done the resend, but at least would think that routing the
patch through Andrew would work best as he picked up the rhashtable
changes regarding ipc and this touches the same call.
Thanks,
Davidlohr
^ permalink raw reply
* [PATCH net-next 2/8] net: dsa: mv88e6xxx: Add MV88E6165 AVB register access
From: Andrew Lunn @ 2018-07-17 21:48 UTC (permalink / raw)
To: David Miller; +Cc: richardcochran, Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1531864140-31233-1-git-send-email-andrew@lunn.ch>
The MV88E6165 PTP registers are all in AVB bank F, unlike newer
generations which spread them over AVB bank E and F. Implement AVB ops
for the MV88E6165 which hides this difference.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 2 ++
drivers/net/dsa/mv88e6xxx/global2.h | 3 +++
drivers/net/dsa/mv88e6xxx/global2_avb.c | 25 +++++++++++++++++++++++++
3 files changed, 30 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 94939a24dd62..09b627cc1ca3 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2810,6 +2810,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.reset = mv88e6352_g1_reset,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+ .avb_ops = &mv88e6165_avb_ops,
};
static const struct mv88e6xxx_ops mv88e6165_ops = {
@@ -2838,6 +2839,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
.reset = mv88e6352_g1_reset,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+ .avb_ops = &mv88e6165_avb_ops,
};
static const struct mv88e6xxx_ops mv88e6171_ops = {
diff --git a/drivers/net/dsa/mv88e6xxx/global2.h b/drivers/net/dsa/mv88e6xxx/global2.h
index 37e8ce2c72a0..194660d8c783 100644
--- a/drivers/net/dsa/mv88e6xxx/global2.h
+++ b/drivers/net/dsa/mv88e6xxx/global2.h
@@ -160,6 +160,7 @@
#define MV88E6390_G2_AVB_CMD_OP_WRITE 0x6000
#define MV88E6352_G2_AVB_CMD_PORT_MASK 0x0f00
#define MV88E6352_G2_AVB_CMD_PORT_TAIGLOBAL 0xe
+#define MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL 0xf
#define MV88E6352_G2_AVB_CMD_PORT_PTPGLOBAL 0xf
#define MV88E6390_G2_AVB_CMD_PORT_MASK 0x1f00
#define MV88E6390_G2_AVB_CMD_PORT_TAIGLOBAL 0x1e
@@ -335,6 +336,7 @@ int mv88e6xxx_g2_device_mapping_write(struct mv88e6xxx_chip *chip, int target,
extern const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops;
extern const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops;
+extern const struct mv88e6xxx_avb_ops mv88e6165_avb_ops;
extern const struct mv88e6xxx_avb_ops mv88e6352_avb_ops;
extern const struct mv88e6xxx_avb_ops mv88e6390_avb_ops;
@@ -484,6 +486,7 @@ static inline int mv88e6xxx_g2_pot_clear(struct mv88e6xxx_chip *chip)
static const struct mv88e6xxx_irq_ops mv88e6097_watchdog_ops = {};
static const struct mv88e6xxx_irq_ops mv88e6390_watchdog_ops = {};
+static const struct mv88e6xxx_avb_ops mv88e6165_avb_ops = {};
static const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {};
static const struct mv88e6xxx_avb_ops mv88e6390_avb_ops = {};
diff --git a/drivers/net/dsa/mv88e6xxx/global2_avb.c b/drivers/net/dsa/mv88e6xxx/global2_avb.c
index 2e398ccb88ca..672b503a67e1 100644
--- a/drivers/net/dsa/mv88e6xxx/global2_avb.c
+++ b/drivers/net/dsa/mv88e6xxx/global2_avb.c
@@ -130,6 +130,31 @@ const struct mv88e6xxx_avb_ops mv88e6352_avb_ops = {
.tai_write = mv88e6352_g2_avb_tai_write,
};
+static int mv88e6165_g2_avb_tai_read(struct mv88e6xxx_chip *chip, int addr,
+ u16 *data, int len)
+{
+ return mv88e6352_g2_avb_port_ptp_read(chip,
+ MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL,
+ addr, data, len);
+}
+
+static int mv88e6165_g2_avb_tai_write(struct mv88e6xxx_chip *chip, int addr,
+ u16 data)
+{
+ return mv88e6352_g2_avb_port_ptp_write(chip,
+ MV88E6165_G2_AVB_CMD_PORT_PTPGLOBAL,
+ addr, data);
+}
+
+const struct mv88e6xxx_avb_ops mv88e6165_avb_ops = {
+ .port_ptp_read = mv88e6352_g2_avb_port_ptp_read,
+ .port_ptp_write = mv88e6352_g2_avb_port_ptp_write,
+ .ptp_read = mv88e6352_g2_avb_ptp_read,
+ .ptp_write = mv88e6352_g2_avb_ptp_write,
+ .tai_read = mv88e6165_g2_avb_tai_read,
+ .tai_write = mv88e6165_g2_avb_tai_write,
+};
+
static int mv88e6390_g2_avb_port_ptp_read(struct mv88e6xxx_chip *chip,
int port, int addr, u16 *data,
int len)
--
2.18.0
^ permalink raw reply related
* [PATCH net-next 4/8] net: dsa: mv88e6xxx: Abstract HW timestamp setup
From: Andrew Lunn @ 2018-07-17 21:48 UTC (permalink / raw)
To: David Miller; +Cc: richardcochran, Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1531864140-31233-1-git-send-email-andrew@lunn.ch>
The 6165 family does not have per port PTP control registers. Also, it
places the timestamp data in different registers. Abstract the current
implementation of 6352 compatible PTP devices so that 6165 can be
added.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.h | 5 +++
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 51 ++++++++++++++++------------
drivers/net/dsa/mv88e6xxx/hwtstamp.h | 2 ++
drivers/net/dsa/mv88e6xxx/ptp.c | 6 ++++
4 files changed, 42 insertions(+), 22 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index e12a489c22d4..2cc4deb110d6 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -497,7 +497,12 @@ struct mv88e6xxx_ptp_ops {
int (*ptp_verify)(struct ptp_clock_info *ptp, unsigned int pin,
enum ptp_pin_function func, unsigned int chan);
void (*event_work)(struct work_struct *ugly);
+ int (*port_enable)(struct mv88e6xxx_chip *chip, int port);
+ int (*port_disable)(struct mv88e6xxx_chip *chip, int port);
int n_ext_ts;
+ int arr0_sts_reg;
+ int arr1_sts_reg;
+ int dep_sts_reg;
};
#define STATS_TYPE_PORT BIT(0)
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index a036c490b7ce..1378c9d102a1 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -92,10 +92,9 @@ int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
struct hwtstamp_config *config)
{
+ const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
bool tstamp_enable = false;
- u16 port_config0;
- int err;
/* Prevent the TX/RX paths from trying to interact with the
* timestamp hardware while we reconfigure it.
@@ -141,24 +140,16 @@ static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
return -ERANGE;
}
+ mutex_lock(&chip->reg_lock);
if (tstamp_enable) {
- /* Disable transportSpecific value matching, so that packets
- * with either 1588 (0) and 802.1AS (1) will be timestamped.
- */
- port_config0 = MV88E6XXX_PORT_PTP_CFG0_DISABLE_TSPEC_MATCH;
+ if (ptp_ops->port_enable)
+ ptp_ops->port_enable(chip, port);
} else {
- /* Disable PTP. This disables both RX and TX timestamping. */
- port_config0 = MV88E6XXX_PORT_PTP_CFG0_DISABLE_PTP;
+ if (ptp_ops->port_disable)
+ ptp_ops->port_disable(chip, port);
}
-
- mutex_lock(&chip->reg_lock);
- err = mv88e6xxx_port_ptp_write(chip, port, MV88E6XXX_PORT_PTP_CFG0,
- port_config0);
mutex_unlock(&chip->reg_lock);
- if (err < 0)
- return err;
-
/* Once hardware has been configured, enable timestamp checks
* in the RX/TX paths.
*/
@@ -338,17 +329,18 @@ static void mv88e6xxx_get_rxts(struct mv88e6xxx_chip *chip,
static void mv88e6xxx_rxtstamp_work(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_port_hwtstamp *ps)
{
+ const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
struct sk_buff *skb;
skb = skb_dequeue(&ps->rx_queue);
if (skb)
- mv88e6xxx_get_rxts(chip, ps, skb, MV88E6XXX_PORT_PTP_ARR0_STS,
+ mv88e6xxx_get_rxts(chip, ps, skb, ptp_ops->arr0_sts_reg,
&ps->rx_queue);
skb = skb_dequeue(&ps->rx_queue2);
if (skb)
- mv88e6xxx_get_rxts(chip, ps, skb, MV88E6XXX_PORT_PTP_ARR1_STS,
+ mv88e6xxx_get_rxts(chip, ps, skb, ptp_ops->arr1_sts_reg,
&ps->rx_queue2);
}
@@ -389,6 +381,7 @@ bool mv88e6xxx_port_rxtstamp(struct dsa_switch *ds, int port,
static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_port_hwtstamp *ps)
{
+ const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
struct skb_shared_hwtstamps shhwtstamps;
u16 departure_block[4], status;
struct sk_buff *tmp_skb;
@@ -401,7 +394,7 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
mutex_lock(&chip->reg_lock);
err = mv88e6xxx_port_ptp_read(chip, ps->port_id,
- MV88E6XXX_PORT_PTP_DEP_STS,
+ ptp_ops->dep_sts_reg,
departure_block,
ARRAY_SIZE(departure_block));
mutex_unlock(&chip->reg_lock);
@@ -425,8 +418,7 @@ static int mv88e6xxx_txtstamp_work(struct mv88e6xxx_chip *chip,
/* We have the timestamp; go ahead and clear valid now */
mutex_lock(&chip->reg_lock);
- mv88e6xxx_port_ptp_write(chip, ps->port_id,
- MV88E6XXX_PORT_PTP_DEP_STS, 0);
+ mv88e6xxx_port_ptp_write(chip, ps->port_id, ptp_ops->dep_sts_reg, 0);
mutex_unlock(&chip->reg_lock);
status = departure_block[0] & MV88E6XXX_PTP_TS_STATUS_MASK;
@@ -522,8 +514,21 @@ bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
return true;
}
+int mv88e6352_hwtstamp_port_disable(struct mv88e6xxx_chip *chip, int port)
+{
+ return mv88e6xxx_port_ptp_write(chip, port, MV88E6XXX_PORT_PTP_CFG0,
+ MV88E6XXX_PORT_PTP_CFG0_DISABLE_PTP);
+}
+
+int mv88e6352_hwtstamp_port_enable(struct mv88e6xxx_chip *chip, int port)
+{
+ return mv88e6xxx_port_ptp_write(chip, port, MV88E6XXX_PORT_PTP_CFG0,
+ MV88E6XXX_PORT_PTP_CFG0_DISABLE_TSPEC_MATCH);
+}
+
static int mv88e6xxx_hwtstamp_port_setup(struct mv88e6xxx_chip *chip, int port)
{
+ const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
struct mv88e6xxx_port_hwtstamp *ps = &chip->port_hwtstamp[port];
ps->port_id = port;
@@ -531,8 +536,10 @@ static int mv88e6xxx_hwtstamp_port_setup(struct mv88e6xxx_chip *chip, int port)
skb_queue_head_init(&ps->rx_queue);
skb_queue_head_init(&ps->rx_queue2);
- return mv88e6xxx_port_ptp_write(chip, port, MV88E6XXX_PORT_PTP_CFG0,
- MV88E6XXX_PORT_PTP_CFG0_DISABLE_PTP);
+ if (ptp_ops->port_disable)
+ return ptp_ops->port_disable(chip, port);
+
+ return 0;
}
int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.h b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
index bc71c9212a08..3e601051f7c0 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.h
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
@@ -123,6 +123,8 @@ int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip);
void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip);
+int mv88e6352_hwtstamp_port_enable(struct mv88e6xxx_chip *chip, int port);
+int mv88e6352_hwtstamp_port_disable(struct mv88e6xxx_chip *chip, int port);
#else /* !CONFIG_NET_DSA_MV88E6XXX_PTP */
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index 6d1304a27906..9dbe2ec7b60a 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -16,6 +16,7 @@
#include "chip.h"
#include "global2.h"
+#include "hwtstamp.h"
#include "ptp.h"
/* Raw timestamps are in units of 8-ns clock periods. */
@@ -318,7 +319,12 @@ const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {
.ptp_enable = mv88e6352_ptp_enable,
.ptp_verify = mv88e6352_ptp_verify,
.event_work = mv88e6352_tai_event_work,
+ .port_enable = mv88e6352_hwtstamp_port_enable,
+ .port_disable = mv88e6352_hwtstamp_port_disable,
.n_ext_ts = 1,
+ .arr0_sts_reg = MV88E6XXX_PORT_PTP_ARR0_STS,
+ .arr1_sts_reg = MV88E6XXX_PORT_PTP_ARR1_STS,
+ .dep_sts_reg = MV88E6XXX_PORT_PTP_DEP_STS,
};
const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = {
--
2.18.0
^ permalink raw reply related
* [PATCH net-next 3/8] net: dsa: mv88e6xxx: Add mv88e6165 PTP support
From: Andrew Lunn @ 2018-07-17 21:48 UTC (permalink / raw)
To: David Miller; +Cc: richardcochran, Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1531864140-31233-1-git-send-email-andrew@lunn.ch>
The mv88e6165 family has its global clock in the PTP global
registers. It does not support any form of PTP events. Add a function
to read the clock, fill in an ops structure, and register it with the
two members of the family.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 4 ++++
drivers/net/dsa/mv88e6xxx/ptp.c | 18 ++++++++++++++++++
drivers/net/dsa/mv88e6xxx/ptp.h | 29 +++++++++++++++++++++++++++++
3 files changed, 51 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 09b627cc1ca3..9dd270978064 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2811,6 +2811,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = {
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.avb_ops = &mv88e6165_avb_ops,
+ .ptp_ops = &mv88e6165_ptp_ops,
};
static const struct mv88e6xxx_ops mv88e6165_ops = {
@@ -2840,6 +2841,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = {
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.avb_ops = &mv88e6165_avb_ops,
+ .ptp_ops = &mv88e6165_ptp_ops,
};
static const struct mv88e6xxx_ops mv88e6171_ops = {
@@ -3693,6 +3695,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.pvt = true,
.multi_chip = true,
.tag_protocol = DSA_TAG_PROTO_EDSA,
+ .ptp_support = true,
.ops = &mv88e6161_ops,
},
@@ -3715,6 +3718,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.pvt = true,
.multi_chip = true,
.tag_protocol = DSA_TAG_PROTO_DSA,
+ .ptp_support = true,
.ops = &mv88e6165_ops,
},
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index 175a5ef8ec8d..6d1304a27906 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -79,6 +79,20 @@ static u64 mv88e6352_ptp_clock_read(const struct cyclecounter *cc)
return ((u32)phc_time[1] << 16) | phc_time[0];
}
+static u64 mv88e6165_ptp_clock_read(const struct cyclecounter *cc)
+{
+ struct mv88e6xxx_chip *chip = cc_to_chip(cc);
+ u16 phc_time[2];
+ int err;
+
+ err = mv88e6xxx_tai_read(chip, MV88E6XXX_PTP_GC_TIME_LO, phc_time,
+ ARRAY_SIZE(phc_time));
+ if (err)
+ return 0;
+ else
+ return ((u32)phc_time[1] << 16) | phc_time[0];
+}
+
/* mv88e6352_config_eventcap - configure TAI event capture
* @event: PTP_CLOCK_PPS (internal) or PTP_CLOCK_EXTTS (external)
* @rising: zero for falling-edge trigger, else rising-edge trigger
@@ -307,6 +321,10 @@ const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {
.n_ext_ts = 1,
};
+const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = {
+ .clock_read = mv88e6165_ptp_clock_read,
+};
+
static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc)
{
struct mv88e6xxx_chip *chip = cc_to_chip(cc);
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.h b/drivers/net/dsa/mv88e6xxx/ptp.h
index 16a310679f12..979eecc8ae01 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.h
+++ b/drivers/net/dsa/mv88e6xxx/ptp.h
@@ -78,6 +78,33 @@
/* Offset 0x12: Lock Status */
#define MV88E6XXX_TAI_LOCK_STATUS 0x12
+/* Offset 0x00: Ether Type */
+#define MV88E6XXX_PTP_GC_ETYPE 0x00
+
+/* Offset 0x01: Message ID */
+#define MV88E6XXX_PTP_GC_MESSAGE_ID 0x01
+
+/* Offset 0x02: Time Stamp Arrive Time */
+#define MV88E6XXX_PTP_GC_TS_ARR_PTR 0x02
+
+/* Offset 0x03: Port Arrival Interrupt Enable */
+#define MV88E6XXX_PTP_GC_PORT_ARR_INT_EN 0x03
+
+/* Offset 0x04: Port Departure Interrupt Enable */
+#define MV88E6XXX_PTP_GC_PORT_DEP_INT_EN 0x04
+
+/* Offset 0x05: Configuration */
+#define MV88E6XXX_PTP_GC_CONFIG 0x05
+#define MV88E6XXX_PTP_GC_CONFIG_DIS_OVERWRITE BIT(1)
+#define MV88E6XXX_PTP_GC_CONFIG_DIS_TS BIT(0)
+
+/* Offset 0x8: Interrupt Status */
+#define MV88E6XXX_PTP_GC_INT_STATUS 0x08
+
+/* Offset 0x9/0xa: Global Time */
+#define MV88E6XXX_PTP_GC_TIME_LO 0x09
+#define MV88E6XXX_PTP_GC_TIME_HI 0x0A
+
#ifdef CONFIG_NET_DSA_MV88E6XXX_PTP
long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp);
@@ -88,6 +115,7 @@ void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip);
ptp_clock_info)
extern const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops;
+extern const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops;
#else /* !CONFIG_NET_DSA_MV88E6XXX_PTP */
@@ -106,6 +134,7 @@ static inline void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
}
static const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {};
+static const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = {};
#endif /* CONFIG_NET_DSA_MV88E6XXX_PTP */
--
2.18.0
^ permalink raw reply related
* [PATCH net-next 0/8] PTP support for mv88e6165 family
From: Andrew Lunn @ 2018-07-17 21:48 UTC (permalink / raw)
To: David Miller; +Cc: richardcochran, Vivien Didelot, netdev, Andrew Lunn
The mv88e6165 family of switches supports PTP. It is however not fully
compatible with the current PTP support in the mv88e6xxx driver. This
patchset adds a level of abstraction to the PTP code, and then adds
the code needed to support the mv88e6165 family.
Andrew Lunn (8):
net: dsa: mv88e6xxx: Abstract PTP operations
net: dsa: mv88e6xxx: Add MV88E6165 AVB register access
net: dsa: mv88e6xxx: Add mv88e6165 PTP support
net: dsa: mv88e6xxx: Abstract HW timestamp setup
net: dsa: mv88e6xxx: Abstract supported PTP filters
net: dsa: mv88e6xxx: Add hwtimestamp support for the 6165
net: dsa: mv88e6xxx: Set PTP Ethertype
net: dsa: mv88e6xxx: Longer timeout for PTP TX timestamp
drivers/net/dsa/mv88e6xxx/chip.c | 17 +++
drivers/net/dsa/mv88e6xxx/chip.h | 23 ++++
drivers/net/dsa/mv88e6xxx/global2.h | 3 +
drivers/net/dsa/mv88e6xxx/global2_avb.c | 25 +++++
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 134 +++++++++++++++++-------
drivers/net/dsa/mv88e6xxx/hwtstamp.h | 14 ++-
drivers/net/dsa/mv88e6xxx/ptp.c | 102 +++++++++++++++---
drivers/net/dsa/mv88e6xxx/ptp.h | 71 +++++++++++++
8 files changed, 335 insertions(+), 54 deletions(-)
--
2.18.0
^ permalink raw reply
* [PATCH net-next 7/8] net: dsa: mv88e6xxx: Set PTP Ethertype
From: Andrew Lunn @ 2018-07-17 21:48 UTC (permalink / raw)
To: David Miller; +Cc: richardcochran, Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1531864140-31233-1-git-send-email-andrew@lunn.ch>
For the 6352 and newer switches, the PTP Ethertype defaults to
ETH_P_1588. Hence it was not explicitly set. The 6165 however defaults
to 0. So explicitly set the EtherType.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 5 +++++
drivers/net/dsa/mv88e6xxx/ptp.h | 3 +++
2 files changed, 8 insertions(+)
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index 01e60a8c97fb..ac71910c63c0 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -606,6 +606,11 @@ int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
return err;
}
+ /* Set the ethertype of L2 PTP messages */
+ err = mv88e6xxx_ptp_write(chip, MV88E6XXX_PTP_GC_ETYPE, ETH_P_1588);
+ if (err)
+ return err;
+
/* MV88E6XXX_PTP_MSG_TYPE is a mask of PTP message types to
* timestamp. This affects all ports that have timestamping enabled,
* but the timestamp config is per-port; thus we configure all events
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.h b/drivers/net/dsa/mv88e6xxx/ptp.h
index 747f90bb9393..28a030840517 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.h
+++ b/drivers/net/dsa/mv88e6xxx/ptp.h
@@ -82,6 +82,9 @@
#define MV88E6XXX_PTP_GC_ETYPE 0x00
/* 6165 Global Control Registers */
+/* Offset 0x00: Ether Type */
+#define MV88E6XXX_PTP_GC_ETYPE 0x00
+
/* Offset 0x01: Message ID */
#define MV88E6XXX_PTP_GC_MESSAGE_ID 0x01
--
2.18.0
^ permalink raw reply related
* [PATCH net-next 1/8] net: dsa: mv88e6xxx: Abstract PTP operations
From: Andrew Lunn @ 2018-07-17 21:48 UTC (permalink / raw)
To: David Miller; +Cc: richardcochran, Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1531864140-31233-1-git-send-email-andrew@lunn.ch>
The mv88e6165 family supports PTP, but its registers use a different
layout to the currently supported devices. Abstract accessing the PTP
registers into a set of ops, so making space for a second
implementation.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.c | 11 +++++++
drivers/net/dsa/mv88e6xxx/chip.h | 14 ++++++++
drivers/net/dsa/mv88e6xxx/ptp.c | 56 ++++++++++++++++++++++----------
drivers/net/dsa/mv88e6xxx/ptp.h | 4 +++
4 files changed, 68 insertions(+), 17 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 437cd6eb4faa..94939a24dd62 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3134,6 +3134,8 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
.vtu_getnext = mv88e6390_g1_vtu_getnext,
.vtu_loadpurge = mv88e6390_g1_vtu_loadpurge,
.serdes_power = mv88e6390_serdes_power,
+ .avb_ops = &mv88e6390_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
};
static const struct mv88e6xxx_ops mv88e6240_ops = {
@@ -3176,6 +3178,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.serdes_power = mv88e6352_serdes_power,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6352_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
};
static const struct mv88e6xxx_ops mv88e6290_ops = {
@@ -3215,6 +3218,7 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
.serdes_power = mv88e6390_serdes_power,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
};
static const struct mv88e6xxx_ops mv88e6320_ops = {
@@ -3253,6 +3257,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = {
.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6352_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
};
static const struct mv88e6xxx_ops mv88e6321_ops = {
@@ -3289,6 +3294,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = {
.vtu_loadpurge = mv88e6185_g1_vtu_loadpurge,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6352_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
};
static const struct mv88e6xxx_ops mv88e6341_ops = {
@@ -3329,6 +3335,7 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
};
static const struct mv88e6xxx_ops mv88e6350_ops = {
@@ -3402,6 +3409,7 @@ static const struct mv88e6xxx_ops mv88e6351_ops = {
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
.avb_ops = &mv88e6352_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
};
static const struct mv88e6xxx_ops mv88e6352_ops = {
@@ -3444,6 +3452,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.serdes_power = mv88e6352_serdes_power,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6352_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
.serdes_get_sset_count = mv88e6352_serdes_get_sset_count,
.serdes_get_strings = mv88e6352_serdes_get_strings,
.serdes_get_stats = mv88e6352_serdes_get_stats,
@@ -3488,6 +3497,7 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
.serdes_power = mv88e6390_serdes_power,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
};
static const struct mv88e6xxx_ops mv88e6390x_ops = {
@@ -3529,6 +3539,7 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
.serdes_power = mv88e6390_serdes_power,
.gpio_ops = &mv88e6352_gpio_ops,
.avb_ops = &mv88e6390_avb_ops,
+ .ptp_ops = &mv88e6352_ptp_ops,
};
static const struct mv88e6xxx_info mv88e6xxx_table[] = {
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 8ac3fbb15352..e12a489c22d4 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -155,6 +155,7 @@ struct mv88e6xxx_bus_ops;
struct mv88e6xxx_irq_ops;
struct mv88e6xxx_gpio_ops;
struct mv88e6xxx_avb_ops;
+struct mv88e6xxx_ptp_ops;
struct mv88e6xxx_irq {
u16 masked;
@@ -439,6 +440,9 @@ struct mv88e6xxx_ops {
/* Remote Management Unit operations */
int (*rmu_disable)(struct mv88e6xxx_chip *chip);
+
+ /* Precision Time Protocol operations */
+ const struct mv88e6xxx_ptp_ops *ptp_ops;
};
struct mv88e6xxx_irq_ops {
@@ -486,6 +490,16 @@ struct mv88e6xxx_avb_ops {
int (*tai_write)(struct mv88e6xxx_chip *chip, int addr, u16 data);
};
+struct mv88e6xxx_ptp_ops {
+ u64 (*clock_read)(const struct cyclecounter *cc);
+ int (*ptp_enable)(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on);
+ int (*ptp_verify)(struct ptp_clock_info *ptp, unsigned int pin,
+ enum ptp_pin_function func, unsigned int chan);
+ void (*event_work)(struct work_struct *ugly);
+ int n_ext_ts;
+};
+
#define STATS_TYPE_PORT BIT(0)
#define STATS_TYPE_BANK0 BIT(1)
#define STATS_TYPE_BANK1 BIT(2)
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index bd85e2c390e1..175a5ef8ec8d 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -50,7 +50,7 @@ static int mv88e6xxx_tai_write(struct mv88e6xxx_chip *chip, int addr, u16 data)
}
/* TODO: places where this are called should be using pinctrl */
-static int mv88e6xxx_set_gpio_func(struct mv88e6xxx_chip *chip, int pin,
+static int mv88e6352_set_gpio_func(struct mv88e6xxx_chip *chip, int pin,
int func, int input)
{
int err;
@@ -65,7 +65,7 @@ static int mv88e6xxx_set_gpio_func(struct mv88e6xxx_chip *chip, int pin,
return chip->info->ops->gpio_ops->set_pctl(chip, pin, func);
}
-static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc)
+static u64 mv88e6352_ptp_clock_read(const struct cyclecounter *cc)
{
struct mv88e6xxx_chip *chip = cc_to_chip(cc);
u16 phc_time[2];
@@ -79,13 +79,13 @@ static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc)
return ((u32)phc_time[1] << 16) | phc_time[0];
}
-/* mv88e6xxx_config_eventcap - configure TAI event capture
+/* mv88e6352_config_eventcap - configure TAI event capture
* @event: PTP_CLOCK_PPS (internal) or PTP_CLOCK_EXTTS (external)
* @rising: zero for falling-edge trigger, else rising-edge trigger
*
* This will also reset the capture sequence counter.
*/
-static int mv88e6xxx_config_eventcap(struct mv88e6xxx_chip *chip, int event,
+static int mv88e6352_config_eventcap(struct mv88e6xxx_chip *chip, int event,
int rising)
{
u16 global_config;
@@ -118,7 +118,7 @@ static int mv88e6xxx_config_eventcap(struct mv88e6xxx_chip *chip, int event,
return err;
}
-static void mv88e6xxx_tai_event_work(struct work_struct *ugly)
+static void mv88e6352_tai_event_work(struct work_struct *ugly)
{
struct delayed_work *dw = to_delayed_work(ugly);
struct mv88e6xxx_chip *chip = dw_tai_event_to_chip(dw);
@@ -232,7 +232,7 @@ static int mv88e6xxx_ptp_settime(struct ptp_clock_info *ptp,
return 0;
}
-static int mv88e6xxx_ptp_enable_extts(struct mv88e6xxx_chip *chip,
+static int mv88e6352_ptp_enable_extts(struct mv88e6xxx_chip *chip,
struct ptp_clock_request *rq, int on)
{
int rising = (rq->extts.flags & PTP_RISING_EDGE);
@@ -250,18 +250,18 @@ static int mv88e6xxx_ptp_enable_extts(struct mv88e6xxx_chip *chip,
if (on) {
func = MV88E6352_G2_SCRATCH_GPIO_PCTL_EVREQ;
- err = mv88e6xxx_set_gpio_func(chip, pin, func, true);
+ err = mv88e6352_set_gpio_func(chip, pin, func, true);
if (err)
goto out;
schedule_delayed_work(&chip->tai_event_work,
TAI_EVENT_WORK_INTERVAL);
- err = mv88e6xxx_config_eventcap(chip, PTP_CLOCK_EXTTS, rising);
+ err = mv88e6352_config_eventcap(chip, PTP_CLOCK_EXTTS, rising);
} else {
func = MV88E6352_G2_SCRATCH_GPIO_PCTL_GPIO;
- err = mv88e6xxx_set_gpio_func(chip, pin, func, true);
+ err = mv88e6352_set_gpio_func(chip, pin, func, true);
cancel_delayed_work_sync(&chip->tai_event_work);
}
@@ -272,20 +272,20 @@ static int mv88e6xxx_ptp_enable_extts(struct mv88e6xxx_chip *chip,
return err;
}
-static int mv88e6xxx_ptp_enable(struct ptp_clock_info *ptp,
+static int mv88e6352_ptp_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on)
{
struct mv88e6xxx_chip *chip = ptp_to_chip(ptp);
switch (rq->type) {
case PTP_CLK_REQ_EXTTS:
- return mv88e6xxx_ptp_enable_extts(chip, rq, on);
+ return mv88e6352_ptp_enable_extts(chip, rq, on);
default:
return -EOPNOTSUPP;
}
}
-static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
+static int mv88e6352_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
enum ptp_pin_function func, unsigned int chan)
{
switch (func) {
@@ -299,6 +299,24 @@ static int mv88e6xxx_ptp_verify(struct ptp_clock_info *ptp, unsigned int pin,
return 0;
}
+const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {
+ .clock_read = mv88e6352_ptp_clock_read,
+ .ptp_enable = mv88e6352_ptp_enable,
+ .ptp_verify = mv88e6352_ptp_verify,
+ .event_work = mv88e6352_tai_event_work,
+ .n_ext_ts = 1,
+};
+
+static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc)
+{
+ struct mv88e6xxx_chip *chip = cc_to_chip(cc);
+
+ if (chip->info->ops->ptp_ops->clock_read)
+ return chip->info->ops->ptp_ops->clock_read(cc);
+
+ return 0;
+}
+
/* With a 125MHz input clock, the 32-bit timestamp counter overflows in ~34.3
* seconds; this task forces periodic reads so that we don't miss any.
*/
@@ -319,6 +337,8 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
{
int i;
+ const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
+
/* Set up the cycle counter */
memset(&chip->tstamp_cc, 0, sizeof(chip->tstamp_cc));
chip->tstamp_cc.read = mv88e6xxx_ptp_clock_read;
@@ -330,14 +350,15 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
ktime_to_ns(ktime_get_real()));
INIT_DELAYED_WORK(&chip->overflow_work, mv88e6xxx_ptp_overflow_check);
- INIT_DELAYED_WORK(&chip->tai_event_work, mv88e6xxx_tai_event_work);
+ if (ptp_ops->event_work)
+ INIT_DELAYED_WORK(&chip->tai_event_work, ptp_ops->event_work);
chip->ptp_clock_info.owner = THIS_MODULE;
snprintf(chip->ptp_clock_info.name, sizeof(chip->ptp_clock_info.name),
dev_name(chip->dev));
chip->ptp_clock_info.max_adj = 1000000;
- chip->ptp_clock_info.n_ext_ts = 1;
+ chip->ptp_clock_info.n_ext_ts = ptp_ops->n_ext_ts;
chip->ptp_clock_info.n_per_out = 0;
chip->ptp_clock_info.n_pins = mv88e6xxx_num_gpio(chip);
chip->ptp_clock_info.pps = 0;
@@ -355,8 +376,8 @@ int mv88e6xxx_ptp_setup(struct mv88e6xxx_chip *chip)
chip->ptp_clock_info.adjtime = mv88e6xxx_ptp_adjtime;
chip->ptp_clock_info.gettime64 = mv88e6xxx_ptp_gettime;
chip->ptp_clock_info.settime64 = mv88e6xxx_ptp_settime;
- chip->ptp_clock_info.enable = mv88e6xxx_ptp_enable;
- chip->ptp_clock_info.verify = mv88e6xxx_ptp_verify;
+ chip->ptp_clock_info.enable = ptp_ops->ptp_enable;
+ chip->ptp_clock_info.verify = ptp_ops->ptp_verify;
chip->ptp_clock_info.do_aux_work = mv88e6xxx_hwtstamp_work;
chip->ptp_clock = ptp_clock_register(&chip->ptp_clock_info, chip->dev);
@@ -373,7 +394,8 @@ void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
{
if (chip->ptp_clock) {
cancel_delayed_work_sync(&chip->overflow_work);
- cancel_delayed_work_sync(&chip->tai_event_work);
+ if (chip->info->ops->ptp_ops->event_work)
+ cancel_delayed_work_sync(&chip->tai_event_work);
ptp_clock_unregister(chip->ptp_clock);
chip->ptp_clock = NULL;
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.h b/drivers/net/dsa/mv88e6xxx/ptp.h
index 10f271ab650d..16a310679f12 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.h
+++ b/drivers/net/dsa/mv88e6xxx/ptp.h
@@ -87,6 +87,8 @@ void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip);
#define ptp_to_chip(ptp) container_of(ptp, struct mv88e6xxx_chip, \
ptp_clock_info)
+extern const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops;
+
#else /* !CONFIG_NET_DSA_MV88E6XXX_PTP */
static inline long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp)
@@ -103,6 +105,8 @@ static inline void mv88e6xxx_ptp_free(struct mv88e6xxx_chip *chip)
{
}
+static const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {};
+
#endif /* CONFIG_NET_DSA_MV88E6XXX_PTP */
#endif /* _MV88E6XXX_PTP_H */
--
2.18.0
^ permalink raw reply related
* [PATCH net-next 5/8] net: dsa: mv88e6xxx: Abstract supported PTP filters
From: Andrew Lunn @ 2018-07-17 21:48 UTC (permalink / raw)
To: David Miller; +Cc: richardcochran, Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1531864140-31233-1-git-send-email-andrew@lunn.ch>
The 6165 only supports layer L2 PTP, where as the more modern devices
also support UDP and UDPv6, i.e. L4. Abstract the supported receive
filters.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.h | 1 +
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 26 ++++++++++++++------------
drivers/net/dsa/mv88e6xxx/ptp.c | 10 ++++++++++
3 files changed, 25 insertions(+), 12 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 2cc4deb110d6..432e7e8e6e3d 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -503,6 +503,7 @@ struct mv88e6xxx_ptp_ops {
int arr0_sts_reg;
int arr1_sts_reg;
int dep_sts_reg;
+ u32 rx_filters;
};
#define STATS_TYPE_PORT BIT(0)
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index 1378c9d102a1..0307704e0063 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -61,7 +61,11 @@ static int mv88e6xxx_ptp_write(struct mv88e6xxx_chip *chip, int addr,
int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
struct ethtool_ts_info *info)
{
- struct mv88e6xxx_chip *chip = ds->priv;
+ const struct mv88e6xxx_ptp_ops *ptp_ops;
+ struct mv88e6xxx_chip *chip;
+
+ chip = ds->priv;
+ ptp_ops = chip->info->ops->ptp_ops;
if (!chip->info->ptp_support)
return -EOPNOTSUPP;
@@ -74,17 +78,7 @@ int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
info->tx_types =
(1 << HWTSTAMP_TX_OFF) |
(1 << HWTSTAMP_TX_ON);
- info->rx_filters =
- (1 << HWTSTAMP_FILTER_NONE) |
- (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
- (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
- (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
- (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
- (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
- (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
- (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
- (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
- (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ);
+ info->rx_filters = ptp_ops->rx_filters;
return 0;
}
@@ -119,6 +113,14 @@ static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
/* The switch supports timestamping both L2 and L4; one cannot be
* disabled independently of the other.
*/
+
+ if (!(BIT(config->rx_filter) & ptp_ops->rx_filters)) {
+ config->rx_filter = HWTSTAMP_FILTER_NONE;
+ dev_dbg(chip->dev, "Unsupported rx_filter %d\n",
+ config->rx_filter);
+ return -ERANGE;
+ }
+
switch (config->rx_filter) {
case HWTSTAMP_FILTER_NONE:
tstamp_enable = false;
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index 9dbe2ec7b60a..d1ea2fafe4e5 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -325,6 +325,16 @@ const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {
.arr0_sts_reg = MV88E6XXX_PORT_PTP_ARR0_STS,
.arr1_sts_reg = MV88E6XXX_PORT_PTP_ARR1_STS,
.dep_sts_reg = MV88E6XXX_PORT_PTP_DEP_STS,
+ .rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ),
};
const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = {
--
2.18.0
^ permalink raw reply related
* [PATCH net-next 8/8] net: dsa: mv88e6xxx: Longer timeout for PTP TX timestamp
From: Andrew Lunn @ 2018-07-17 21:49 UTC (permalink / raw)
To: David Miller; +Cc: richardcochran, Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1531864140-31233-1-git-send-email-andrew@lunn.ch>
For slow processors using bit-banging MDIO, 20ms can be too short a
timeout when waiting for the transmit timestamp to become
available. Double it to 40ms.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index ac71910c63c0..a17c16a2ab78 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -65,7 +65,7 @@ static int mv88e6xxx_ptp_read(struct mv88e6xxx_chip *chip, int addr,
* within 1ms. Software may enounter delays due to MDIO contention, so
* the timeout is set accordingly.
*/
-#define TX_TSTAMP_TIMEOUT msecs_to_jiffies(20)
+#define TX_TSTAMP_TIMEOUT msecs_to_jiffies(40)
int mv88e6xxx_get_ts_info(struct dsa_switch *ds, int port,
struct ethtool_ts_info *info)
--
2.18.0
^ permalink raw reply related
* [PATCH net-next 6/8] net: dsa: mv88e6xxx: Add hwtimestamp support for the 6165
From: Andrew Lunn @ 2018-07-17 21:48 UTC (permalink / raw)
To: David Miller; +Cc: richardcochran, Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1531864140-31233-1-git-send-email-andrew@lunn.ch>
The 6165 family supports a more restricted version of hardware time
stamps. Only L2 PTP is supported. All ports have to use the same
EtherType, and transport spec configuration. PTP can only be
enabled/disabled globally, not per port.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/chip.h | 3 ++
drivers/net/dsa/mv88e6xxx/hwtstamp.c | 50 ++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/hwtstamp.h | 12 +++++--
drivers/net/dsa/mv88e6xxx/ptp.c | 12 +++++++
drivers/net/dsa/mv88e6xxx/ptp.h | 35 +++++++++++++++++++
5 files changed, 110 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index 432e7e8e6e3d..6aa6197ddc10 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -274,6 +274,7 @@ struct mv88e6xxx_chip {
struct ptp_pin_desc pin_config[MV88E6XXX_MAX_GPIO];
u16 trig_config;
u16 evcap_config;
+ u16 enable_count;
/* Per-port timestamping resources. */
struct mv88e6xxx_port_hwtstamp port_hwtstamp[DSA_MAX_PORTS];
@@ -499,6 +500,8 @@ struct mv88e6xxx_ptp_ops {
void (*event_work)(struct work_struct *ugly);
int (*port_enable)(struct mv88e6xxx_chip *chip, int port);
int (*port_disable)(struct mv88e6xxx_chip *chip, int port);
+ int (*global_enable)(struct mv88e6xxx_chip *chip);
+ int (*global_disable)(struct mv88e6xxx_chip *chip);
int n_ext_ts;
int arr0_sts_reg;
int arr1_sts_reg;
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.c b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
index 0307704e0063..01e60a8c97fb 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.c
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.c
@@ -51,6 +51,15 @@ static int mv88e6xxx_ptp_write(struct mv88e6xxx_chip *chip, int addr,
return chip->info->ops->avb_ops->ptp_write(chip, addr, data);
}
+static int mv88e6xxx_ptp_read(struct mv88e6xxx_chip *chip, int addr,
+ u16 *data)
+{
+ if (!chip->info->ops->avb_ops->ptp_read)
+ return -EOPNOTSUPP;
+
+ return chip->info->ops->avb_ops->ptp_read(chip, addr, data, 1);
+}
+
/* TX_TSTAMP_TIMEOUT: This limits the time spent polling for a TX
* timestamp. When working properly, hardware will produce a timestamp
* within 1ms. Software may enounter delays due to MDIO contention, so
@@ -144,11 +153,17 @@ static int mv88e6xxx_set_hwtstamp_config(struct mv88e6xxx_chip *chip, int port,
mutex_lock(&chip->reg_lock);
if (tstamp_enable) {
+ chip->enable_count += 1;
+ if (chip->enable_count == 1 && ptp_ops->global_enable)
+ ptp_ops->global_enable(chip);
if (ptp_ops->port_enable)
ptp_ops->port_enable(chip, port);
} else {
if (ptp_ops->port_disable)
ptp_ops->port_disable(chip, port);
+ chip->enable_count -= 1;
+ if (chip->enable_count == 0 && ptp_ops->global_disable)
+ ptp_ops->global_disable(chip);
}
mutex_unlock(&chip->reg_lock);
@@ -516,6 +531,33 @@ bool mv88e6xxx_port_txtstamp(struct dsa_switch *ds, int port,
return true;
}
+int mv88e6165_global_disable(struct mv88e6xxx_chip *chip)
+{
+ u16 val;
+ int err;
+
+ err = mv88e6xxx_ptp_read(chip, MV88E6165_PTP_CFG, &val);
+ if (err)
+ return err;
+ val |= MV88E6165_PTP_CFG_DISABLE_PTP;
+
+ return mv88e6xxx_ptp_write(chip, MV88E6165_PTP_CFG, val);
+}
+
+int mv88e6165_global_enable(struct mv88e6xxx_chip *chip)
+{
+ u16 val;
+ int err;
+
+ err = mv88e6xxx_ptp_read(chip, MV88E6165_PTP_CFG, &val);
+ if (err)
+ return err;
+
+ val &= ~(MV88E6165_PTP_CFG_DISABLE_PTP | MV88E6165_PTP_CFG_TSPEC_MASK);
+
+ return mv88e6xxx_ptp_write(chip, MV88E6165_PTP_CFG, val);
+}
+
int mv88e6352_hwtstamp_port_disable(struct mv88e6xxx_chip *chip, int port)
{
return mv88e6xxx_port_ptp_write(chip, port, MV88E6XXX_PORT_PTP_CFG0,
@@ -546,6 +588,7 @@ static int mv88e6xxx_hwtstamp_port_setup(struct mv88e6xxx_chip *chip, int port)
int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
{
+ const struct mv88e6xxx_ptp_ops *ptp_ops = chip->info->ops->ptp_ops;
int err;
int i;
@@ -556,6 +599,13 @@ int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip)
return err;
}
+ /* Disable PTP globally */
+ if (ptp_ops->global_disable) {
+ err = ptp_ops->global_disable(chip);
+ if (err)
+ return err;
+ }
+
/* MV88E6XXX_PTP_MSG_TYPE is a mask of PTP message types to
* timestamp. This affects all ports that have timestamping enabled,
* but the timestamp config is per-port; thus we configure all events
diff --git a/drivers/net/dsa/mv88e6xxx/hwtstamp.h b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
index 3e601051f7c0..b9a72661bcc4 100644
--- a/drivers/net/dsa/mv88e6xxx/hwtstamp.h
+++ b/drivers/net/dsa/mv88e6xxx/hwtstamp.h
@@ -19,7 +19,7 @@
#include "chip.h"
-/* Global PTP registers */
+/* Global 6352 PTP registers */
/* Offset 0x00: PTP EtherType */
#define MV88E6XXX_PTP_ETHERTYPE 0x00
@@ -34,6 +34,12 @@
/* Offset 0x02: Timestamp Arrival Capture Pointers */
#define MV88E6XXX_PTP_TS_ARRIVAL_PTR 0x02
+/* Offset 0x05: PTP Global Configuration */
+#define MV88E6165_PTP_CFG 0x05
+#define MV88E6165_PTP_CFG_TSPEC_MASK 0xf000
+#define MV88E6165_PTP_CFG_DISABLE_TS_OVERWRITE BIT(1)
+#define MV88E6165_PTP_CFG_DISABLE_PTP BIT(0)
+
/* Offset 0x07: PTP Global Configuration */
#define MV88E6341_PTP_CFG 0x07
#define MV88E6341_PTP_CFG_UPDATE 0x8000
@@ -46,7 +52,7 @@
/* Offset 0x08: PTP Interrupt Status */
#define MV88E6XXX_PTP_IRQ_STATUS 0x08
-/* Per-Port PTP Registers */
+/* Per-Port 6352 PTP Registers */
/* Offset 0x00: PTP Configuration 0 */
#define MV88E6XXX_PORT_PTP_CFG0 0x00
#define MV88E6XXX_PORT_PTP_CFG0_TSPEC_SHIFT 12
@@ -125,6 +131,8 @@ int mv88e6xxx_hwtstamp_setup(struct mv88e6xxx_chip *chip);
void mv88e6xxx_hwtstamp_free(struct mv88e6xxx_chip *chip);
int mv88e6352_hwtstamp_port_enable(struct mv88e6xxx_chip *chip, int port);
int mv88e6352_hwtstamp_port_disable(struct mv88e6xxx_chip *chip, int port);
+int mv88e6165_global_enable(struct mv88e6xxx_chip *chip);
+int mv88e6165_global_disable(struct mv88e6xxx_chip *chip);
#else /* !CONFIG_NET_DSA_MV88E6XXX_PTP */
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.c b/drivers/net/dsa/mv88e6xxx/ptp.c
index d1ea2fafe4e5..3aa8cd20c237 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.c
+++ b/drivers/net/dsa/mv88e6xxx/ptp.c
@@ -339,6 +339,18 @@ const struct mv88e6xxx_ptp_ops mv88e6352_ptp_ops = {
const struct mv88e6xxx_ptp_ops mv88e6165_ptp_ops = {
.clock_read = mv88e6165_ptp_clock_read,
+ .global_enable = mv88e6165_global_enable,
+ .global_disable = mv88e6165_global_disable,
+ .arr0_sts_reg = MV88E6165_PORT_PTP_ARR0_STS,
+ .arr1_sts_reg = MV88E6165_PORT_PTP_ARR1_STS,
+ .dep_sts_reg = MV88E6165_PORT_PTP_DEP_STS,
+ .rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) |
+ (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ),
};
static u64 mv88e6xxx_ptp_clock_read(const struct cyclecounter *cc)
diff --git a/drivers/net/dsa/mv88e6xxx/ptp.h b/drivers/net/dsa/mv88e6xxx/ptp.h
index 979eecc8ae01..747f90bb9393 100644
--- a/drivers/net/dsa/mv88e6xxx/ptp.h
+++ b/drivers/net/dsa/mv88e6xxx/ptp.h
@@ -81,6 +81,7 @@
/* Offset 0x00: Ether Type */
#define MV88E6XXX_PTP_GC_ETYPE 0x00
+/* 6165 Global Control Registers */
/* Offset 0x01: Message ID */
#define MV88E6XXX_PTP_GC_MESSAGE_ID 0x01
@@ -105,6 +106,40 @@
#define MV88E6XXX_PTP_GC_TIME_LO 0x09
#define MV88E6XXX_PTP_GC_TIME_HI 0x0A
+/* 6165 Per Port Registers */
+/* Offset 0: Arrival Time 0 Status */
+#define MV88E6165_PORT_PTP_ARR0_STS 0x00
+
+/* Offset 0x01/0x02: PTP Arrival 0 Time */
+#define MV88E6165_PORT_PTP_ARR0_TIME_LO 0x01
+#define MV88E6165_PORT_PTP_ARR0_TIME_HI 0x02
+
+/* Offset 0x03: PTP Arrival 0 Sequence ID */
+#define MV88E6165_PORT_PTP_ARR0_SEQID 0x03
+
+/* Offset 0x04: PTP Arrival 1 Status */
+#define MV88E6165_PORT_PTP_ARR1_STS 0x04
+
+/* Offset 0x05/0x6E: PTP Arrival 1 Time */
+#define MV88E6165_PORT_PTP_ARR1_TIME_LO 0x05
+#define MV88E6165_PORT_PTP_ARR1_TIME_HI 0x06
+
+/* Offset 0x07: PTP Arrival 1 Sequence ID */
+#define MV88E6165_PORT_PTP_ARR1_SEQID 0x07
+
+/* Offset 0x08: PTP Departure Status */
+#define MV88E6165_PORT_PTP_DEP_STS 0x08
+
+/* Offset 0x09/0x0a: PTP Deperture Time */
+#define MV88E6165_PORT_PTP_DEP_TIME_LO 0x09
+#define MV88E6165_PORT_PTP_DEP_TIME_HI 0x0a
+
+/* Offset 0x0b: PTP Departure Sequence ID */
+#define MV88E6165_PORT_PTP_DEP_SEQID 0x0b
+
+/* Offset 0x0d: Port Status */
+#define MV88E6164_PORT_STATUS 0x0d
+
#ifdef CONFIG_NET_DSA_MV88E6XXX_PTP
long mv88e6xxx_hwtstamp_work(struct ptp_clock_info *ptp);
--
2.18.0
^ permalink raw reply related
* [RFC ipsec-next] xfrm: Remove xfrmi interface ID from flowi
From: Benedict Wong @ 2018-07-17 21:40 UTC (permalink / raw)
To: netdev; +Cc: nharold, lorenzo, Benedict Wong
In order to remove performance impact of having the extra u32 in every
single flowi, this change removes the flowi_xfrm struct, prefering to
take the if_id as a method parameter where needed.
In the inbound direction, if_id is only needed during the
__xfrm_check_policy() function, and the if_id can be determined at that
point based on the skb. As such, xfrmi_decode_session() is only called
with the skb in __xfrm_check_policy().
In the outbound direction, the only place where if_id is needed is the
xfrm_lookup() call in xfrmi_xmit2(). With this change, the if_id is
directly passed into the xfrm_lookup_with_ifid() call. All existing
callers can still call xfrm_lookup(), which uses a default if_id of 0.
This change does not change any behavior of XFRMIs except for improving
overall system performance via flowi size reduction.
This change has been tested against the Android Kernel Networking Tests:
https://android.googlesource.com/kernel/tests/+/master/net/test
Signed-off-by: Benedict Wong <benedictwong@google.com>
---
include/net/dst.h | 14 ++++++
include/net/flow.h | 7 ---
include/net/xfrm.h | 2 +-
net/xfrm/xfrm_interface.c | 4 +-
net/xfrm/xfrm_policy.c | 98 ++++++++++++++++++++++++++-------------
net/xfrm/xfrm_state.c | 3 +-
6 files changed, 83 insertions(+), 45 deletions(-)
diff --git a/include/net/dst.h b/include/net/dst.h
index b3219cd8a5a1..7f735e76ca73 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -475,6 +475,14 @@ static inline struct dst_entry *xfrm_lookup(struct net *net,
return dst_orig;
}
+static inline struct dst_entry *
+xfrm_lookup_with_ifid(struct net *net, struct dst_entry *dst_orig,
+ const struct flowi *fl, const struct sock *sk,
+ int flags, u32 if_id)
+{
+ return dst_orig;
+}
+
static inline struct dst_entry *xfrm_lookup_route(struct net *net,
struct dst_entry *dst_orig,
const struct flowi *fl,
@@ -494,6 +502,12 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
const struct flowi *fl, const struct sock *sk,
int flags);
+struct dst_entry *xfrm_lookup_with_ifid(struct net *net,
+ struct dst_entry *dst_orig,
+ const struct flowi *fl,
+ const struct sock *sk, int flags,
+ u32 if_id);
+
struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig,
const struct flowi *fl, const struct sock *sk,
int flags);
diff --git a/include/net/flow.h b/include/net/flow.h
index 187c9bef672f..cb1205c526ef 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -26,10 +26,6 @@ struct flowi_tunnel {
__be64 tun_id;
};
-struct flowi_xfrm {
- __u32 if_id;
-};
-
struct flowi_common {
int flowic_oif;
int flowic_iif;
@@ -43,7 +39,6 @@ struct flowi_common {
#define FLOWI_FLAG_SKIP_NH_OIF 0x04
__u32 flowic_secid;
struct flowi_tunnel flowic_tun_key;
- struct flowi_xfrm xfrm;
kuid_t flowic_uid;
};
@@ -115,7 +110,6 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
fl4->flowi4_flags = flags;
fl4->flowi4_secid = 0;
fl4->flowi4_tun_key.tun_id = 0;
- fl4->flowi4_xfrm.if_id = 0;
fl4->flowi4_uid = uid;
fl4->daddr = daddr;
fl4->saddr = saddr;
@@ -193,7 +187,6 @@ struct flowi {
#define flowi_secid u.__fl_common.flowic_secid
#define flowi_tun_key u.__fl_common.flowic_tun_key
#define flowi_uid u.__fl_common.flowic_uid
-#define flowi_xfrm u.__fl_common.xfrm
} __attribute__((__aligned__(BITS_PER_LONG/8)));
static inline struct flowi *flowi4_to_flowi(struct flowi4 *fl4)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index a5378613a49c..0721d899ce00 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1557,7 +1557,7 @@ struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr,
const struct flowi *fl,
struct xfrm_tmpl *tmpl,
struct xfrm_policy *pol, int *err,
- unsigned short family);
+ unsigned short family, u32 if_id);
struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark, u32 if_id,
xfrm_address_t *daddr,
xfrm_address_t *saddr,
diff --git a/net/xfrm/xfrm_interface.c b/net/xfrm/xfrm_interface.c
index 31cb1c7e3881..ccfe18d67e98 100644
--- a/net/xfrm/xfrm_interface.c
+++ b/net/xfrm/xfrm_interface.c
@@ -307,10 +307,8 @@ xfrmi_xmit2(struct sk_buff *skb, struct net_device *dev, struct flowi *fl)
if (!dst)
goto tx_err_link_failure;
- fl->flowi_xfrm.if_id = xi->p.if_id;
-
dst_hold(dst);
- dst = xfrm_lookup(xi->net, dst, fl, NULL, 0);
+ dst = xfrm_lookup_with_ifid(xi->net, dst, fl, NULL, 0, xi->p.if_id);
if (IS_ERR(dst)) {
err = PTR_ERR(dst);
dst = NULL;
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index ef75891450e7..33eef87914f1 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -1068,14 +1068,14 @@ EXPORT_SYMBOL(xfrm_policy_walk_done);
*/
static int xfrm_policy_match(const struct xfrm_policy *pol,
const struct flowi *fl,
- u8 type, u16 family, int dir)
+ u8 type, u16 family, int dir, u32 if_id)
{
const struct xfrm_selector *sel = &pol->selector;
int ret = -ESRCH;
bool match;
if (pol->family != family ||
- pol->if_id != fl->flowi_xfrm.if_id ||
+ pol->if_id != if_id ||
(fl->flowi_mark & pol->mark.m) != pol->mark.v ||
pol->type != type)
return ret;
@@ -1090,7 +1090,8 @@ static int xfrm_policy_match(const struct xfrm_policy *pol,
static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
const struct flowi *fl,
- u16 family, u8 dir)
+ u16 family, u8 dir,
+ u32 if_id)
{
int err;
struct xfrm_policy *pol, *ret;
@@ -1114,7 +1115,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
priority = ~0U;
ret = NULL;
hlist_for_each_entry_rcu(pol, chain, bydst) {
- err = xfrm_policy_match(pol, fl, type, family, dir);
+ err = xfrm_policy_match(pol, fl, type, family, dir, if_id);
if (err) {
if (err == -ESRCH)
continue;
@@ -1133,7 +1134,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
if ((pol->priority >= priority) && ret)
break;
- err = xfrm_policy_match(pol, fl, type, family, dir);
+ err = xfrm_policy_match(pol, fl, type, family, dir, if_id);
if (err) {
if (err == -ESRCH)
continue;
@@ -1158,21 +1159,25 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type,
return ret;
}
-static struct xfrm_policy *
-xfrm_policy_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir)
+static struct xfrm_policy *xfrm_policy_lookup(struct net *net,
+ const struct flowi *fl,
+ u16 family, u8 dir, u32 if_id)
{
#ifdef CONFIG_XFRM_SUB_POLICY
struct xfrm_policy *pol;
- pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir);
+ pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family,
+ dir, if_id);
if (pol != NULL)
return pol;
#endif
- return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir);
+ return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family,
+ dir, if_id);
}
static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
- const struct flowi *fl, u16 family)
+ const struct flowi *fl,
+ u16 family, u32 if_id)
{
struct xfrm_policy *pol;
@@ -1191,7 +1196,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
match = xfrm_selector_match(&pol->selector, fl, family);
if (match) {
if ((sk->sk_mark & pol->mark.m) != pol->mark.v ||
- pol->if_id != fl->flowi_xfrm.if_id) {
+ pol->if_id != if_id) {
pol = NULL;
goto out;
}
@@ -1405,7 +1410,8 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl,
}
}
- x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family);
+ x = xfrm_state_find(remote, local, fl, tmpl, policy, &error,
+ family, policy->if_id);
if (x && x->km.state == XFRM_STATE_VALID) {
xfrm[nx++] = x;
@@ -1708,7 +1714,8 @@ static int xfrm_expand_policies(const struct flowi *fl, u16 family,
pols[1] = xfrm_policy_lookup_bytype(xp_net(pols[0]),
XFRM_POLICY_TYPE_MAIN,
fl, family,
- XFRM_POLICY_OUT);
+ XFRM_POLICY_OUT,
+ pols[0]->if_id);
if (pols[1]) {
if (IS_ERR(pols[1])) {
xfrm_pols_put(pols, *num_pols);
@@ -1942,8 +1949,10 @@ static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net,
goto out;
}
-static struct xfrm_dst *
-xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, struct xfrm_flo *xflo)
+static struct xfrm_dst *xfrm_bundle_lookup(struct net *net,
+ const struct flowi *fl,
+ u16 family, u8 dir,
+ struct xfrm_flo *xflo, u32 if_id)
{
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
int num_pols = 0, num_xfrms = 0, err;
@@ -1952,7 +1961,7 @@ xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir,
/* Resolve policies to use if we couldn't get them from
* previous cache entry */
num_pols = 1;
- pols[0] = xfrm_policy_lookup(net, fl, family, dir);
+ pols[0] = xfrm_policy_lookup(net, fl, family, dir, if_id);
err = xfrm_expand_policies(fl, family, pols,
&num_pols, &num_xfrms);
if (err < 0)
@@ -2020,14 +2029,19 @@ static struct dst_entry *make_blackhole(struct net *net, u16 family,
return ret;
}
-/* Main function: finds/creates a bundle for given flow.
+/* Finds/creates a bundle for given flow and if_id
*
* At the moment we eat a raw IP route. Mostly to speed up lookups
* on interfaces with disabled IPsec.
+ *
+ * xfrm_lookup uses an if_id of 0 by default, and is provided for
+ * compatibility
*/
-struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
- const struct flowi *fl,
- const struct sock *sk, int flags)
+struct dst_entry *xfrm_lookup_with_ifid(struct net *net,
+ struct dst_entry *dst_orig,
+ const struct flowi *fl,
+ const struct sock *sk,
+ int flags, u32 if_id)
{
struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX];
struct xfrm_dst *xdst;
@@ -2043,7 +2057,8 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
sk = sk_const_to_full_sk(sk);
if (sk && sk->sk_policy[XFRM_POLICY_OUT]) {
num_pols = 1;
- pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, family);
+ pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl, family,
+ if_id);
err = xfrm_expand_policies(fl, family, pols,
&num_pols, &num_xfrms);
if (err < 0)
@@ -2087,7 +2102,7 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
!net->xfrm.policy_count[XFRM_POLICY_OUT])
goto nopol;
- xdst = xfrm_bundle_lookup(net, fl, family, dir, &xflo);
+ xdst = xfrm_bundle_lookup(net, fl, family, dir, &xflo, if_id);
if (xdst == NULL)
goto nopol;
if (IS_ERR(xdst)) {
@@ -2168,6 +2183,19 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
xfrm_pols_put(pols, drop_pols);
return ERR_PTR(err);
}
+EXPORT_SYMBOL(xfrm_lookup_with_ifid);
+
+/* Main function: finds/creates a bundle for given flow.
+ *
+ * At the moment we eat a raw IP route. Mostly to speed up lookups
+ * on interfaces with disabled IPsec.
+ */
+struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
+ const struct flowi *fl, const struct sock *sk,
+ int flags)
+{
+ return xfrm_lookup_with_ifid(net, dst_orig, fl, sk, flags, 0);
+}
EXPORT_SYMBOL(xfrm_lookup);
/* Callers of xfrm_lookup_route() must ensure a call to dst_output().
@@ -2257,19 +2285,12 @@ int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl,
unsigned int family, int reverse)
{
const struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
- const struct xfrm_if_cb *ifcb = xfrm_if_get_cb();
- struct xfrm_if *xi;
int err;
if (unlikely(afinfo == NULL))
return -EAFNOSUPPORT;
afinfo->decode_session(skb, fl, reverse);
- if (ifcb) {
- xi = ifcb->decode_session(skb);
- if (xi)
- fl->flowi_xfrm.if_id = xi->p.if_id;
- }
err = security_xfrm_decode_session(skb, &fl->flowi_secid);
rcu_read_unlock();
@@ -2301,6 +2322,13 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
int reverse;
struct flowi fl;
int xerr_idx = -1;
+ const struct xfrm_if_cb *ifcb;
+ struct xfrm_if *xi;
+ u32 if_id = 0;
+
+ rcu_read_lock();
+ ifcb = xfrm_if_get_cb();
+ rcu_read_unlock();
reverse = dir & ~XFRM_POLICY_MASK;
dir &= XFRM_POLICY_MASK;
@@ -2325,10 +2353,16 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
}
}
+ if (ifcb) {
+ xi = ifcb->decode_session(skb);
+ if (xi)
+ if_id = xi->p.if_id;
+ }
+
pol = NULL;
sk = sk_to_full_sk(sk);
if (sk && sk->sk_policy[dir]) {
- pol = xfrm_sk_policy_lookup(sk, dir, &fl, family);
+ pol = xfrm_sk_policy_lookup(sk, dir, &fl, family, if_id);
if (IS_ERR(pol)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
return 0;
@@ -2336,7 +2370,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
}
if (!pol)
- pol = xfrm_policy_lookup(net, &fl, family, dir);
+ pol = xfrm_policy_lookup(net, &fl, family, dir, if_id);
if (IS_ERR(pol)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
@@ -2360,7 +2394,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) {
pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN,
&fl, family,
- XFRM_POLICY_IN);
+ XFRM_POLICY_IN, if_id);
if (pols[1]) {
if (IS_ERR(pols[1])) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index e04a510ec992..045c5d525df1 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -930,7 +930,7 @@ struct xfrm_state *
xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
const struct flowi *fl, struct xfrm_tmpl *tmpl,
struct xfrm_policy *pol, int *err,
- unsigned short family)
+ unsigned short family, u32 if_id)
{
static xfrm_address_t saddr_wildcard = { };
struct net *net = xp_net(pol);
@@ -940,7 +940,6 @@ xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr,
int error = 0;
struct xfrm_state *best = NULL;
u32 mark = pol->mark.v & pol->mark.m;
- u32 if_id = fl->flowi_xfrm.if_id;
unsigned short encap_family = tmpl->encap_family;
unsigned int sequence;
struct km_event c;
--
2.18.0.233.g985f88cf7e-goog
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox