* Re: [PATCH net-next] tcp: expose both send and receive intervals for rate sample
From: Neal Cardwell @ 2018-07-09 18:09 UTC (permalink / raw)
To: deeptir; +Cc: David Miller, Netdev
In-Reply-To: <1531158819-7901-1-git-send-email-deeptir@mit.edu>
On Mon, Jul 9, 2018 at 1:58 PM Deepti Raghavan <deeptir@mit.edu> wrote:
>
> Congestion control algorithms, which access the rate sample
> through the tcp_cong_control function, only have access to the maximum
> of the send and receive interval, for cases where the acknowledgment
> rate may be inaccurate due to ACK compression or decimation. Algorithms
> may want to use send rates and receive rates as separate signals.
>
> Signed-off-by: Deepti Raghavan <deeptir@mit.edu>
> ---
> include/net/tcp.h | 2 ++
> net/ipv4/tcp_rate.c | 4 ++++
> 2 files changed, 6 insertions(+)
Thanks for re-sending. It does seem to be showing up in patchwork now:
https://patchwork.ozlabs.org/patch/941532/
And I can confirm I'm able to apply it to net-next.
Acked-by: Neal Cardwell <ncardwell@google.com>
thanks,
neal
^ permalink raw reply
* [PATCH bpf-next v2 12/12] tools: bpftool: allow reuse of maps with bpftool prog load
From: Jakub Kicinski @ 2018-07-09 17:59 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20180709175944.32265-1-jakub.kicinski@netronome.com>
Add map parameter to prog load which will allow reuse of existing
maps instead of creating new ones.
We need feature detection and compat code for reallocarray, since
it's not available in many libc versions.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
.../bpftool/Documentation/bpftool-prog.rst | 20 ++-
tools/bpf/bpftool/bash-completion/bpftool | 67 +++++++-
tools/bpf/bpftool/main.h | 3 +
tools/bpf/bpftool/map.c | 4 +-
tools/bpf/bpftool/prog.c | 148 ++++++++++++++++--
5 files changed, 219 insertions(+), 23 deletions(-)
diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
index e53e1ad2caf0..64156a16d530 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
@@ -24,9 +24,10 @@ MAP COMMANDS
| **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}]
| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}]
| **bpftool** **prog pin** *PROG* *FILE*
-| **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**dev** *NAME*]
+| **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
| **bpftool** **prog help**
|
+| *MAP* := { **id** *MAP_ID* | **pinned** *FILE* }
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
| *TYPE* := {
| **socket** | **kprobe** | **kretprobe** | **classifier** | **action** |
@@ -73,10 +74,17 @@ DESCRIPTION
Note: *FILE* must be located in *bpffs* mount.
- **bpftool prog load** *OBJ* *FILE* [**type** *TYPE*] [**dev** *NAME*]
+ **bpftool prog load** *OBJ* *FILE* [**type** *TYPE*] [**map** {**idx** *IDX* | **name** *NAME*} *MAP*] [**dev** *NAME*]
Load bpf program from binary *OBJ* and pin as *FILE*.
**type** is optional, if not specified program type will be
inferred from section names.
+ By default bpftool will create new maps as declared in the ELF
+ object being loaded. **map** parameter allows for the reuse
+ of existing maps. It can be specified multiple times, each
+ time for a different map. *IDX* refers to index of the map
+ to be replaced in the ELF file counting from 0, while *NAME*
+ allows to replace a map by name. *MAP* specifies the map to
+ use, referring to it by **id** or through a **pinned** file.
If **dev** *NAME* is specified program will be loaded onto
given networking device (offload).
@@ -172,6 +180,14 @@ EXAMPLES
mov %rbx,0x0(%rbp)
48 89 5d 00
+|
+| **# bpftool prog load xdp1_kern.o /sys/fs/bpf/xdp1 type xdp map name rxcnt id 7**
+| **# bpftool prog show pinned /sys/fs/bpf/xdp1**
+| 9: xdp name xdp_prog1 tag 539ec6ce11b52f98 gpl
+| loaded_at 2018-06-25T16:17:31-0700 uid 0
+| xlated 488B jited 336B memlock 4096B map_ids 7
+| **# rm /sys/fs/bpf/xdp1**
+|
SEE ALSO
========
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index caf8711993be..598066c40191 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -99,6 +99,29 @@ _bpftool_get_prog_tags()
command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) )
}
+_bpftool_get_obj_map_names()
+{
+ local obj
+
+ obj=$1
+
+ maps=$(objdump -j maps -t $obj 2>/dev/null | \
+ command awk '/g . maps/ {print $NF}')
+
+ COMPREPLY+=( $( compgen -W "$maps" -- "$cur" ) )
+}
+
+_bpftool_get_obj_map_idxs()
+{
+ local obj
+
+ obj=$1
+
+ nmaps=$(objdump -j maps -t $obj 2>/dev/null | grep -c 'g . maps')
+
+ COMPREPLY+=( $( compgen -W "$(seq 0 $((nmaps - 1)))" -- "$cur" ) )
+}
+
_sysfs_get_netdevs()
{
COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \
@@ -220,12 +243,14 @@ _bpftool()
# Completion depends on object and command in use
case $object in
prog)
- case $prev in
- id)
- _bpftool_get_prog_ids
- return 0
- ;;
- esac
+ if [[ $command != "load" ]]; then
+ case $prev in
+ id)
+ _bpftool_get_prog_ids
+ return 0
+ ;;
+ esac
+ fi
local PROG_TYPE='id pinned tag'
case $command in
@@ -268,22 +293,52 @@ _bpftool()
return 0
;;
load)
+ local obj
+
if [[ ${#words[@]} -lt 6 ]]; then
_filedir
return 0
fi
+ obj=${words[3]}
+
+ if [[ ${words[-4]} == "map" ]]; then
+ COMPREPLY=( $( compgen -W "id pinned" -- "$cur" ) )
+ return 0
+ fi
+ if [[ ${words[-3]} == "map" ]]; then
+ if [[ ${words[-2]} == "idx" ]]; then
+ _bpftool_get_obj_map_idxs $obj
+ elif [[ ${words[-2]} == "name" ]]; then
+ _bpftool_get_obj_map_names $obj
+ fi
+ return 0
+ fi
+ if [[ ${words[-2]} == "map" ]]; then
+ COMPREPLY=( $( compgen -W "idx name" -- "$cur" ) )
+ return 0
+ fi
+
case $prev in
type)
COMPREPLY=( $( compgen -W "socket kprobe kretprobe classifier action tracepoint raw_tracepoint xdp perf_event cgroup/skb cgroup/sock cgroup/dev lwt_in lwt_out lwt_xmit lwt_seg6local sockops sk_skb sk_msg lirc_mode2 cgroup/bind4 cgroup/bind6 cgroup/connect4 cgroup/connect6 cgroup/sendmsg4 cgroup/sendmsg6 cgroup/post_bind4 cgroup/post_bind6" -- \
"$cur" ) )
return 0
;;
+ id)
+ _bpftool_get_map_ids
+ return 0
+ ;;
+ pinned)
+ _filedir
+ return 0
+ ;;
dev)
_sysfs_get_netdevs
return 0
;;
*)
+ COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
_bpftool_once_attr 'type'
_bpftool_once_attr 'dev'
return 0
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 1e02e4031693..41004bb2644a 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -75,6 +75,8 @@
"PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }"
#define HELP_SPEC_OPTIONS \
"OPTIONS := { {-j|--json} [{-p|--pretty}] | {-f|--bpffs} }"
+#define HELP_SPEC_MAP \
+ "MAP := { id MAP_ID | pinned FILE }"
enum bpf_obj_type {
BPF_OBJ_UNKNOWN,
@@ -136,6 +138,7 @@ int do_cgroup(int argc, char **arg);
int do_perf(int argc, char **arg);
int prog_parse_fd(int *argc, char ***argv);
+int map_parse_fd(int *argc, char ***argv);
int map_parse_fd_and_info(int *argc, char ***argv, void *info, __u32 *info_len);
void disasm_print_insn(unsigned char *image, ssize_t len, int opcodes,
diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index 5989e1575ae4..e2baec1122fb 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -93,7 +93,7 @@ static void *alloc_value(struct bpf_map_info *info)
return malloc(info->value_size);
}
-static int map_parse_fd(int *argc, char ***argv)
+int map_parse_fd(int *argc, char ***argv)
{
int fd;
@@ -824,7 +824,7 @@ static int do_help(int argc, char **argv)
" %s %s event_pipe MAP [cpu N index M]\n"
" %s %s help\n"
"\n"
- " MAP := { id MAP_ID | pinned FILE }\n"
+ " " HELP_SPEC_MAP "\n"
" DATA := { [hex] BYTES }\n"
" " HELP_SPEC_PROGRAM "\n"
" VALUE := { DATA | MAP | PROG }\n"
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index 267d653c93f5..0f8bdab62864 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -31,6 +31,7 @@
* SOFTWARE.
*/
+#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
@@ -682,18 +683,34 @@ static int do_pin(int argc, char **argv)
return err;
}
+struct map_replace {
+ int idx;
+ int fd;
+ char *name;
+};
+
+int map_replace_compar(const void *p1, const void *p2)
+{
+ const struct map_replace *a = p1, *b = p2;
+
+ return a->idx - b->idx;
+}
+
static int do_load(int argc, char **argv)
{
enum bpf_attach_type expected_attach_type;
struct bpf_object_open_attr attr = {
.prog_type = BPF_PROG_TYPE_UNSPEC,
};
+ struct map_replace *map_replace = NULL;
const char *objfile, *pinfile;
+ unsigned int old_map_fds = 0;
struct bpf_program *prog;
struct bpf_object *obj;
struct bpf_map *map;
+ unsigned int i, j;
__u32 ifindex = 0;
- int err;
+ int idx, err;
if (!REQ_ARGS(2))
return -1;
@@ -708,16 +725,16 @@ static int do_load(int argc, char **argv)
if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) {
p_err("program type already specified");
- return -1;
+ goto err_free_reuse_maps;
}
if (!REQ_ARGS(1))
- return -1;
+ goto err_free_reuse_maps;
/* Put a '/' at the end of type to appease libbpf */
type = malloc(strlen(*argv) + 2);
if (!type) {
p_err("mem alloc failed");
- return -1;
+ goto err_free_reuse_maps;
}
*type = 0;
strcat(type, *argv);
@@ -728,37 +745,81 @@ static int do_load(int argc, char **argv)
free(type);
if (err < 0) {
p_err("unknown program type '%s'", *argv);
- return err;
+ goto err_free_reuse_maps;
}
NEXT_ARG();
+ } else if (is_prefix(*argv, "map")) {
+ char *endptr, *name;
+ int fd;
+
+ NEXT_ARG();
+
+ if (!REQ_ARGS(4))
+ goto err_free_reuse_maps;
+
+ if (is_prefix(*argv, "idx")) {
+ NEXT_ARG();
+
+ idx = strtoul(*argv, &endptr, 0);
+ if (*endptr) {
+ p_err("can't parse %s as IDX", *argv);
+ goto err_free_reuse_maps;
+ }
+ name = NULL;
+ } else if (is_prefix(*argv, "name")) {
+ NEXT_ARG();
+
+ name = *argv;
+ idx = -1;
+ } else {
+ p_err("expected 'idx' or 'name', got: '%s'?",
+ *argv);
+ goto err_free_reuse_maps;
+ }
+ NEXT_ARG();
+
+ fd = map_parse_fd(&argc, &argv);
+ if (fd < 0)
+ goto err_free_reuse_maps;
+
+ map_replace = reallocarray(map_replace, old_map_fds + 1,
+ sizeof(*map_replace));
+ if (!map_replace) {
+ p_err("mem alloc failed");
+ goto err_free_reuse_maps;
+ }
+ map_replace[old_map_fds].idx = idx;
+ map_replace[old_map_fds].name = name;
+ map_replace[old_map_fds].fd = fd;
+ old_map_fds++;
} else if (is_prefix(*argv, "dev")) {
NEXT_ARG();
if (ifindex) {
p_err("offload device already specified");
- return -1;
+ goto err_free_reuse_maps;
}
if (!REQ_ARGS(1))
- return -1;
+ goto err_free_reuse_maps;
ifindex = if_nametoindex(*argv);
if (!ifindex) {
p_err("unrecognized netdevice '%s': %s",
*argv, strerror(errno));
- return -1;
+ goto err_free_reuse_maps;
}
NEXT_ARG();
} else {
- p_err("expected no more arguments, 'type' or 'dev', got: '%s'?",
+ p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?",
*argv);
- return -1;
+ goto err_free_reuse_maps;
}
}
obj = bpf_object__open_xattr(objfile, &attr);
if (IS_ERR_OR_NULL(obj)) {
p_err("failed to open object file");
- return -1;
+ goto err_free_reuse_maps;
}
prog = bpf_program__next(NULL, obj);
@@ -782,10 +843,62 @@ static int do_load(int argc, char **argv)
bpf_program__set_type(prog, attr.prog_type);
bpf_program__set_expected_attach_type(prog, expected_attach_type);
- bpf_map__for_each(map, obj)
+ qsort(map_replace, old_map_fds, sizeof(*map_replace),
+ map_replace_compar);
+
+ /* After the sort maps by name will be first on the list, because they
+ * have idx == -1. Resolve them.
+ */
+ j = 0;
+ while (j < old_map_fds && map_replace[j].name) {
+ i = 0;
+ bpf_map__for_each(map, obj) {
+ if (!strcmp(bpf_map__name(map), map_replace[j].name)) {
+ map_replace[j].idx = i;
+ break;
+ }
+ i++;
+ }
+ if (map_replace[j].idx == -1) {
+ p_err("unable to find map '%s'", map_replace[j].name);
+ goto err_close_obj;
+ }
+ j++;
+ }
+ /* Resort if any names were resolved */
+ if (j)
+ qsort(map_replace, old_map_fds, sizeof(*map_replace),
+ map_replace_compar);
+
+ /* Set ifindex and name reuse */
+ j = 0;
+ idx = 0;
+ bpf_map__for_each(map, obj) {
if (!bpf_map__is_offload_neutral(map))
bpf_map__set_ifindex(map, ifindex);
+ if (j < old_map_fds && idx == map_replace[j].idx) {
+ err = bpf_map__reuse_fd(map, map_replace[j++].fd);
+ if (err) {
+ p_err("unable to set up map reuse: %d", err);
+ goto err_close_obj;
+ }
+
+ /* Next reuse wants to apply to the same map */
+ if (j < old_map_fds && map_replace[j].idx == idx) {
+ p_err("replacement for map idx %d specified more than once",
+ idx);
+ goto err_close_obj;
+ }
+ }
+
+ idx++;
+ }
+ if (j < old_map_fds) {
+ p_err("map idx '%d' not used", map_replace[j].idx);
+ goto err_close_obj;
+ }
+
err = bpf_object__load(obj);
if (err) {
p_err("failed to load object file");
@@ -799,11 +912,18 @@ static int do_load(int argc, char **argv)
jsonw_null(json_wtr);
bpf_object__close(obj);
+ for (i = 0; i < old_map_fds; i++)
+ close(map_replace[i].fd);
+ free(map_replace);
return 0;
err_close_obj:
bpf_object__close(obj);
+err_free_reuse_maps:
+ for (i = 0; i < old_map_fds; i++)
+ close(map_replace[i].fd);
+ free(map_replace);
return -1;
}
@@ -819,9 +939,11 @@ static int do_help(int argc, char **argv)
" %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n"
" %s %s dump jited PROG [{ file FILE | opcodes }]\n"
" %s %s pin PROG FILE\n"
- " %s %s load OBJ FILE [type TYPE] [dev NAME]\n"
+ " %s %s load OBJ FILE [type TYPE] [dev NAME] \\\n"
+ " [map { idx IDX | name NAME } MAP]\n"
" %s %s help\n"
"\n"
+ " " HELP_SPEC_MAP "\n"
" " HELP_SPEC_PROGRAM "\n"
" TYPE := { socket | kprobe | kretprobe | classifier | action |\n"
" tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n"
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next v2 11/12] tools: libbpf: allow map reuse
From: Jakub Kicinski @ 2018-07-09 17:59 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20180709175944.32265-1-jakub.kicinski@netronome.com>
More advanced applications may want to only replace programs without
destroying associated maps. Allow libbpf users to achieve that.
Instead of always creating all of the maps at load time, expose to
users an API to reconstruct the map object from already existing
map.
The map parameters are read from the kernel and replace the parameters
of the ELF map. libbpf does not restrict the map replacement, i.e.
the reused map does not have to be compatible with the ELF map
definition. We relay on the verifier for checking the compatibility
between maps and programs. The ELF map definition is completely
overwritten by the information read from the kernel, to make sure
libbpf's view of map object corresponds to the actual map.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tools/lib/bpf/libbpf.c | 35 +++++++++++++++++++++++++++++++++++
tools/lib/bpf/libbpf.h | 1 +
2 files changed, 36 insertions(+)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index b653dbb266c7..c80033fe66c3 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -215,6 +215,7 @@ struct bpf_map {
int fd;
char *name;
size_t offset;
+ bool fd_preset;
int map_ifindex;
struct bpf_map_def def;
uint32_t btf_key_type_id;
@@ -1082,6 +1083,34 @@ static int bpf_map_find_btf_info(struct bpf_map *map, const struct btf *btf)
return 0;
}
+int bpf_map__reuse_fd(struct bpf_map *map, int fd)
+{
+ struct bpf_map_info info = {};
+ __u32 len = sizeof(info);
+ int err;
+
+ err = bpf_obj_get_info_by_fd(fd, &info, &len);
+ if (err)
+ return err;
+
+ map->fd = dup(fd);
+ if (map->fd < 0)
+ return map->fd;
+ map->fd_preset = true;
+
+ free(map->name);
+ map->name = strdup(info.name);
+ map->def.type = info.type;
+ map->def.key_size = info.key_size;
+ map->def.value_size = info.value_size;
+ map->def.max_entries = info.max_entries;
+ map->def.map_flags = info.map_flags;
+ map->btf_key_type_id = info.btf_key_type_id;
+ map->btf_value_type_id = info.btf_value_type_id;
+
+ return 0;
+}
+
static int
bpf_object__create_maps(struct bpf_object *obj)
{
@@ -1094,6 +1123,12 @@ bpf_object__create_maps(struct bpf_object *obj)
struct bpf_map_def *def = &map->def;
int *pfd = &map->fd;
+ if (map->fd_preset) {
+ pr_debug("skip map create (preset) %s: fd=%d\n",
+ map->name, map->fd);
+ continue;
+ }
+
create_attr.name = map->name;
create_attr.map_ifindex = map->map_ifindex;
create_attr.map_type = def->type;
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 60593ac44700..8e709a74f47c 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -261,6 +261,7 @@ typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
int bpf_map__set_priv(struct bpf_map *map, void *priv,
bpf_map_clear_priv_t clear_priv);
void *bpf_map__priv(struct bpf_map *map);
+int bpf_map__reuse_fd(struct bpf_map *map, int fd);
bool bpf_map__is_offload_neutral(struct bpf_map *map);
void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
int bpf_map__pin(struct bpf_map *map, const char *path);
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next v2 10/12] tools: bpf: make use of reallocarray
From: Jakub Kicinski @ 2018-07-09 17:59 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20180709175944.32265-1-jakub.kicinski@netronome.com>
reallocarray() is a safer variant of realloc which checks for
multiplication overflow in case of array allocation. Since it's
not available in Glibc < 2.26 import kernel's overflow.h and
add a static inline implementation when needed. Use feature
detection to probe for existence of reallocarray.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
Reviewed-by: Jiong Wang <jiong.wang@netronome.com>
---
tools/bpf/bpftool/Makefile | 6 +-
tools/bpf/bpftool/main.h | 1 +
tools/bpf/bpftool/xlated_dumper.c | 6 +-
tools/build/feature/Makefile | 4 +
tools/build/feature/test-reallocarray.c | 8 +
tools/include/linux/compiler-gcc.h | 4 +
tools/include/linux/overflow.h | 278 ++++++++++++++++++++++++
tools/include/tools/libc_compat.h | 23 ++
tools/lib/bpf/Makefile | 6 +-
tools/lib/bpf/libbpf.c | 9 +-
10 files changed, 336 insertions(+), 9 deletions(-)
create mode 100644 tools/build/feature/test-reallocarray.c
create mode 100644 tools/include/linux/overflow.h
create mode 100644 tools/include/tools/libc_compat.h
diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile
index 0911b00b25cc..6c4830e18879 100644
--- a/tools/bpf/bpftool/Makefile
+++ b/tools/bpf/bpftool/Makefile
@@ -52,7 +52,7 @@ INSTALL ?= install
RM ?= rm -f
FEATURE_USER = .bpftool
-FEATURE_TESTS = libbfd disassembler-four-args
+FEATURE_TESTS = libbfd disassembler-four-args reallocarray
FEATURE_DISPLAY = libbfd disassembler-four-args
check_feat := 1
@@ -75,6 +75,10 @@ ifeq ($(feature-disassembler-four-args), 1)
CFLAGS += -DDISASM_FOUR_ARGS_SIGNATURE
endif
+ifeq ($(feature-reallocarray), 0)
+CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
+endif
+
include $(wildcard $(OUTPUT)*.d)
all: $(OUTPUT)bpftool
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 15b6c49ae533..1e02e4031693 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -42,6 +42,7 @@
#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/hashtable.h>
+#include <tools/libc_compat.h>
#include "json_writer.h"
diff --git a/tools/bpf/bpftool/xlated_dumper.c b/tools/bpf/bpftool/xlated_dumper.c
index b97f1da60dd1..3284759df98a 100644
--- a/tools/bpf/bpftool/xlated_dumper.c
+++ b/tools/bpf/bpftool/xlated_dumper.c
@@ -35,6 +35,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#define _GNU_SOURCE
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -66,9 +67,8 @@ void kernel_syms_load(struct dump_data *dd)
while (!feof(fp)) {
if (!fgets(buff, sizeof(buff), fp))
break;
- tmp = realloc(dd->sym_mapping,
- (dd->sym_count + 1) *
- sizeof(*dd->sym_mapping));
+ tmp = reallocarray(dd->sym_mapping, dd->sym_count + 1,
+ sizeof(*dd->sym_mapping));
if (!tmp) {
out:
free(dd->sym_mapping);
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index dac9563b5470..0516259be70f 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -14,6 +14,7 @@ FILES= \
test-libaudit.bin \
test-libbfd.bin \
test-disassembler-four-args.bin \
+ test-reallocarray.bin \
test-liberty.bin \
test-liberty-z.bin \
test-cplus-demangle.bin \
@@ -204,6 +205,9 @@ FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
$(OUTPUT)test-disassembler-four-args.bin:
$(BUILD) -DPACKAGE='"perf"' -lbfd -lopcodes
+$(OUTPUT)test-reallocarray.bin:
+ $(BUILD)
+
$(OUTPUT)test-liberty.bin:
$(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
diff --git a/tools/build/feature/test-reallocarray.c b/tools/build/feature/test-reallocarray.c
new file mode 100644
index 000000000000..8170de35150d
--- /dev/null
+++ b/tools/build/feature/test-reallocarray.c
@@ -0,0 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <stdlib.h>
+
+int main(void)
+{
+ return !!reallocarray(NULL, 1, 1);
+}
diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compiler-gcc.h
index 70fe61295733..0d35f18006a1 100644
--- a/tools/include/linux/compiler-gcc.h
+++ b/tools/include/linux/compiler-gcc.h
@@ -36,3 +36,7 @@
#endif
#define __printf(a, b) __attribute__((format(printf, a, b)))
#define __scanf(a, b) __attribute__((format(scanf, a, b)))
+
+#if GCC_VERSION >= 50100
+#define COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW 1
+#endif
diff --git a/tools/include/linux/overflow.h b/tools/include/linux/overflow.h
new file mode 100644
index 000000000000..8712ff70995f
--- /dev/null
+++ b/tools/include/linux/overflow.h
@@ -0,0 +1,278 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+#ifndef __LINUX_OVERFLOW_H
+#define __LINUX_OVERFLOW_H
+
+#include <linux/compiler.h>
+
+/*
+ * In the fallback code below, we need to compute the minimum and
+ * maximum values representable in a given type. These macros may also
+ * be useful elsewhere, so we provide them outside the
+ * COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW block.
+ *
+ * It would seem more obvious to do something like
+ *
+ * #define type_min(T) (T)(is_signed_type(T) ? (T)1 << (8*sizeof(T)-1) : 0)
+ * #define type_max(T) (T)(is_signed_type(T) ? ((T)1 << (8*sizeof(T)-1)) - 1 : ~(T)0)
+ *
+ * Unfortunately, the middle expressions, strictly speaking, have
+ * undefined behaviour, and at least some versions of gcc warn about
+ * the type_max expression (but not if -fsanitize=undefined is in
+ * effect; in that case, the warning is deferred to runtime...).
+ *
+ * The slightly excessive casting in type_min is to make sure the
+ * macros also produce sensible values for the exotic type _Bool. [The
+ * overflow checkers only almost work for _Bool, but that's
+ * a-feature-not-a-bug, since people shouldn't be doing arithmetic on
+ * _Bools. Besides, the gcc builtins don't allow _Bool* as third
+ * argument.]
+ *
+ * Idea stolen from
+ * https://mail-index.netbsd.org/tech-misc/2007/02/05/0000.html -
+ * credit to Christian Biere.
+ */
+#define is_signed_type(type) (((type)(-1)) < (type)1)
+#define __type_half_max(type) ((type)1 << (8*sizeof(type) - 1 - is_signed_type(type)))
+#define type_max(T) ((T)((__type_half_max(T) - 1) + __type_half_max(T)))
+#define type_min(T) ((T)((T)-type_max(T)-(T)1))
+
+
+#ifdef COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW
+/*
+ * For simplicity and code hygiene, the fallback code below insists on
+ * a, b and *d having the same type (similar to the min() and max()
+ * macros), whereas gcc's type-generic overflow checkers accept
+ * different types. Hence we don't just make check_add_overflow an
+ * alias for __builtin_add_overflow, but add type checks similar to
+ * below.
+ */
+#define check_add_overflow(a, b, d) ({ \
+ typeof(a) __a = (a); \
+ typeof(b) __b = (b); \
+ typeof(d) __d = (d); \
+ (void) (&__a == &__b); \
+ (void) (&__a == __d); \
+ __builtin_add_overflow(__a, __b, __d); \
+})
+
+#define check_sub_overflow(a, b, d) ({ \
+ typeof(a) __a = (a); \
+ typeof(b) __b = (b); \
+ typeof(d) __d = (d); \
+ (void) (&__a == &__b); \
+ (void) (&__a == __d); \
+ __builtin_sub_overflow(__a, __b, __d); \
+})
+
+#define check_mul_overflow(a, b, d) ({ \
+ typeof(a) __a = (a); \
+ typeof(b) __b = (b); \
+ typeof(d) __d = (d); \
+ (void) (&__a == &__b); \
+ (void) (&__a == __d); \
+ __builtin_mul_overflow(__a, __b, __d); \
+})
+
+#else
+
+
+/* Checking for unsigned overflow is relatively easy without causing UB. */
+#define __unsigned_add_overflow(a, b, d) ({ \
+ typeof(a) __a = (a); \
+ typeof(b) __b = (b); \
+ typeof(d) __d = (d); \
+ (void) (&__a == &__b); \
+ (void) (&__a == __d); \
+ *__d = __a + __b; \
+ *__d < __a; \
+})
+#define __unsigned_sub_overflow(a, b, d) ({ \
+ typeof(a) __a = (a); \
+ typeof(b) __b = (b); \
+ typeof(d) __d = (d); \
+ (void) (&__a == &__b); \
+ (void) (&__a == __d); \
+ *__d = __a - __b; \
+ __a < __b; \
+})
+/*
+ * If one of a or b is a compile-time constant, this avoids a division.
+ */
+#define __unsigned_mul_overflow(a, b, d) ({ \
+ typeof(a) __a = (a); \
+ typeof(b) __b = (b); \
+ typeof(d) __d = (d); \
+ (void) (&__a == &__b); \
+ (void) (&__a == __d); \
+ *__d = __a * __b; \
+ __builtin_constant_p(__b) ? \
+ __b > 0 && __a > type_max(typeof(__a)) / __b : \
+ __a > 0 && __b > type_max(typeof(__b)) / __a; \
+})
+
+/*
+ * For signed types, detecting overflow is much harder, especially if
+ * we want to avoid UB. But the interface of these macros is such that
+ * we must provide a result in *d, and in fact we must produce the
+ * result promised by gcc's builtins, which is simply the possibly
+ * wrapped-around value. Fortunately, we can just formally do the
+ * operations in the widest relevant unsigned type (u64) and then
+ * truncate the result - gcc is smart enough to generate the same code
+ * with and without the (u64) casts.
+ */
+
+/*
+ * Adding two signed integers can overflow only if they have the same
+ * sign, and overflow has happened iff the result has the opposite
+ * sign.
+ */
+#define __signed_add_overflow(a, b, d) ({ \
+ typeof(a) __a = (a); \
+ typeof(b) __b = (b); \
+ typeof(d) __d = (d); \
+ (void) (&__a == &__b); \
+ (void) (&__a == __d); \
+ *__d = (u64)__a + (u64)__b; \
+ (((~(__a ^ __b)) & (*__d ^ __a)) \
+ & type_min(typeof(__a))) != 0; \
+})
+
+/*
+ * Subtraction is similar, except that overflow can now happen only
+ * when the signs are opposite. In this case, overflow has happened if
+ * the result has the opposite sign of a.
+ */
+#define __signed_sub_overflow(a, b, d) ({ \
+ typeof(a) __a = (a); \
+ typeof(b) __b = (b); \
+ typeof(d) __d = (d); \
+ (void) (&__a == &__b); \
+ (void) (&__a == __d); \
+ *__d = (u64)__a - (u64)__b; \
+ ((((__a ^ __b)) & (*__d ^ __a)) \
+ & type_min(typeof(__a))) != 0; \
+})
+
+/*
+ * Signed multiplication is rather hard. gcc always follows C99, so
+ * division is truncated towards 0. This means that we can write the
+ * overflow check like this:
+ *
+ * (a > 0 && (b > MAX/a || b < MIN/a)) ||
+ * (a < -1 && (b > MIN/a || b < MAX/a) ||
+ * (a == -1 && b == MIN)
+ *
+ * The redundant casts of -1 are to silence an annoying -Wtype-limits
+ * (included in -Wextra) warning: When the type is u8 or u16, the
+ * __b_c_e in check_mul_overflow obviously selects
+ * __unsigned_mul_overflow, but unfortunately gcc still parses this
+ * code and warns about the limited range of __b.
+ */
+
+#define __signed_mul_overflow(a, b, d) ({ \
+ typeof(a) __a = (a); \
+ typeof(b) __b = (b); \
+ typeof(d) __d = (d); \
+ typeof(a) __tmax = type_max(typeof(a)); \
+ typeof(a) __tmin = type_min(typeof(a)); \
+ (void) (&__a == &__b); \
+ (void) (&__a == __d); \
+ *__d = (u64)__a * (u64)__b; \
+ (__b > 0 && (__a > __tmax/__b || __a < __tmin/__b)) || \
+ (__b < (typeof(__b))-1 && (__a > __tmin/__b || __a < __tmax/__b)) || \
+ (__b == (typeof(__b))-1 && __a == __tmin); \
+})
+
+
+#define check_add_overflow(a, b, d) \
+ __builtin_choose_expr(is_signed_type(typeof(a)), \
+ __signed_add_overflow(a, b, d), \
+ __unsigned_add_overflow(a, b, d))
+
+#define check_sub_overflow(a, b, d) \
+ __builtin_choose_expr(is_signed_type(typeof(a)), \
+ __signed_sub_overflow(a, b, d), \
+ __unsigned_sub_overflow(a, b, d))
+
+#define check_mul_overflow(a, b, d) \
+ __builtin_choose_expr(is_signed_type(typeof(a)), \
+ __signed_mul_overflow(a, b, d), \
+ __unsigned_mul_overflow(a, b, d))
+
+
+#endif /* COMPILER_HAS_GENERIC_BUILTIN_OVERFLOW */
+
+/**
+ * array_size() - Calculate size of 2-dimensional array.
+ *
+ * @a: dimension one
+ * @b: dimension two
+ *
+ * Calculates size of 2-dimensional array: @a * @b.
+ *
+ * Returns: number of bytes needed to represent the array or SIZE_MAX on
+ * overflow.
+ */
+static inline __must_check size_t array_size(size_t a, size_t b)
+{
+ size_t bytes;
+
+ if (check_mul_overflow(a, b, &bytes))
+ return SIZE_MAX;
+
+ return bytes;
+}
+
+/**
+ * array3_size() - Calculate size of 3-dimensional array.
+ *
+ * @a: dimension one
+ * @b: dimension two
+ * @c: dimension three
+ *
+ * Calculates size of 3-dimensional array: @a * @b * @c.
+ *
+ * Returns: number of bytes needed to represent the array or SIZE_MAX on
+ * overflow.
+ */
+static inline __must_check size_t array3_size(size_t a, size_t b, size_t c)
+{
+ size_t bytes;
+
+ if (check_mul_overflow(a, b, &bytes))
+ return SIZE_MAX;
+ if (check_mul_overflow(bytes, c, &bytes))
+ return SIZE_MAX;
+
+ return bytes;
+}
+
+static inline __must_check size_t __ab_c_size(size_t n, size_t size, size_t c)
+{
+ size_t bytes;
+
+ if (check_mul_overflow(n, size, &bytes))
+ return SIZE_MAX;
+ if (check_add_overflow(bytes, c, &bytes))
+ return SIZE_MAX;
+
+ return bytes;
+}
+
+/**
+ * struct_size() - Calculate size of structure with trailing array.
+ * @p: Pointer to the structure.
+ * @member: Name of the array member.
+ * @n: Number of elements in the array.
+ *
+ * Calculates size of memory needed for structure @p followed by an
+ * array of @n @member elements.
+ *
+ * Return: number of bytes needed or SIZE_MAX on overflow.
+ */
+#define struct_size(p, member, n) \
+ __ab_c_size(n, \
+ sizeof(*(p)->member) + __must_be_array((p)->member),\
+ sizeof(*(p)))
+
+#endif /* __LINUX_OVERFLOW_H */
diff --git a/tools/include/tools/libc_compat.h b/tools/include/tools/libc_compat.h
new file mode 100644
index 000000000000..7bc720f54ef3
--- /dev/null
+++ b/tools/include/tools/libc_compat.h
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2018 Netronome Systems, Inc. */
+
+#ifndef __TOOLS_LIBC_COMPAT_H
+#define __TOOLS_LIBC_COMPAT_H
+
+#include <stdlib.h>
+#include <linux/overflow.h>
+
+/* !defined(_GNU_SOURCE) because e.g. libbpf can't use GNU strerror_r()
+ * for backward compatibility reasons.
+ */
+#if defined(COMPAT_NEED_REALLOCARRAY) || !defined(_GNU_SOURCE)
+static inline void *reallocarray(void *ptr, size_t nmemb, size_t size)
+{
+ size_t bytes;
+
+ if (unlikely(check_mul_overflow(nmemb, size, &bytes)))
+ return NULL;
+ return realloc(ptr, bytes);
+}
+#endif
+#endif
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile
index 5390e7725e43..7a8e4c98ef1a 100644
--- a/tools/lib/bpf/Makefile
+++ b/tools/lib/bpf/Makefile
@@ -66,7 +66,7 @@ ifndef VERBOSE
endif
FEATURE_USER = .libbpf
-FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf
+FEATURE_TESTS = libelf libelf-getphdrnum libelf-mmap bpf reallocarray
FEATURE_DISPLAY = libelf bpf
INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/tools/arch/$(ARCH)/include/uapi -I$(srctree)/tools/include/uapi -I$(srctree)/tools/perf
@@ -120,6 +120,10 @@ ifeq ($(feature-libelf-getphdrnum), 1)
override CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT
endif
+ifeq ($(feature-reallocarray), 0)
+ override CFLAGS += -DCOMPAT_NEED_REALLOCARRAY
+endif
+
# Append required CFLAGS
override CFLAGS += $(EXTRA_WARNINGS)
override CFLAGS += -Werror -Wall
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 5b0e84fbcf71..b653dbb266c7 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -41,6 +41,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/vfs.h>
+#include <tools/libc_compat.h>
#include <libelf.h>
#include <gelf.h>
@@ -369,7 +370,7 @@ bpf_object__add_program(struct bpf_object *obj, void *data, size_t size,
progs = obj->programs;
nr_progs = obj->nr_programs;
- progs = realloc(progs, sizeof(progs[0]) * (nr_progs + 1));
+ progs = reallocarray(progs, nr_progs + 1, sizeof(progs[0]));
if (!progs) {
/*
* In this case the original obj->programs
@@ -870,8 +871,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
continue;
}
- reloc = realloc(reloc,
- sizeof(*obj->efile.reloc) * nr_reloc);
+ reloc = reallocarray(reloc, nr_reloc,
+ sizeof(*obj->efile.reloc));
if (!reloc) {
pr_warning("realloc failed\n");
err = -ENOMEM;
@@ -1163,7 +1164,7 @@ bpf_program__reloc_text(struct bpf_program *prog, struct bpf_object *obj,
return -LIBBPF_ERRNO__RELOC;
}
new_cnt = prog->insns_cnt + text->insns_cnt;
- new_insn = realloc(prog->insns, new_cnt * sizeof(*insn));
+ new_insn = reallocarray(prog->insns, new_cnt, sizeof(*insn));
if (!new_insn) {
pr_warning("oom in prog realloc\n");
return -ENOMEM;
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next v2 09/12] tools: bpftool: reimplement bpf_prog_load() for prog load
From: Jakub Kicinski @ 2018-07-09 17:59 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20180709175944.32265-1-jakub.kicinski@netronome.com>
bpf_prog_load() is a very useful helper but it doesn't give us full
flexibility of modifying the BPF objects before loading. Open code
bpf_prog_load() in bpftool so we can add extra logic in following
commits.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tools/bpf/bpftool/prog.c | 57 ++++++++++++++++++++++++++++++++--------
1 file changed, 46 insertions(+), 11 deletions(-)
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index 7a06fd4c5d27..267d653c93f5 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -43,6 +43,8 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <linux/err.h>
+
#include <bpf.h>
#include <libbpf.h>
@@ -682,12 +684,15 @@ static int do_pin(int argc, char **argv)
static int do_load(int argc, char **argv)
{
- struct bpf_prog_load_attr attr = {
+ enum bpf_attach_type expected_attach_type;
+ struct bpf_object_open_attr attr = {
.prog_type = BPF_PROG_TYPE_UNSPEC,
};
const char *objfile, *pinfile;
+ struct bpf_program *prog;
struct bpf_object *obj;
- int prog_fd;
+ struct bpf_map *map;
+ __u32 ifindex = 0;
int err;
if (!REQ_ARGS(2))
@@ -719,7 +724,7 @@ static int do_load(int argc, char **argv)
strcat(type, "/");
err = libbpf_prog_type_by_string(type, &attr.prog_type,
- &attr.expected_attach_type);
+ &expected_attach_type);
free(type);
if (err < 0) {
p_err("unknown program type '%s'", *argv);
@@ -729,15 +734,15 @@ static int do_load(int argc, char **argv)
} else if (is_prefix(*argv, "dev")) {
NEXT_ARG();
- if (attr.ifindex) {
+ if (ifindex) {
p_err("offload device already specified");
return -1;
}
if (!REQ_ARGS(1))
return -1;
- attr.ifindex = if_nametoindex(*argv);
- if (!attr.ifindex) {
+ ifindex = if_nametoindex(*argv);
+ if (!ifindex) {
p_err("unrecognized netdevice '%s': %s",
*argv, strerror(errno));
return -1;
@@ -750,14 +755,44 @@ static int do_load(int argc, char **argv)
}
}
- attr.file = objfile;
-
- if (bpf_prog_load_xattr(&attr, &obj, &prog_fd)) {
- p_err("failed to load program");
+ obj = bpf_object__open_xattr(objfile, &attr);
+ if (IS_ERR_OR_NULL(obj)) {
+ p_err("failed to open object file");
return -1;
}
- if (do_pin_fd(prog_fd, pinfile))
+ prog = bpf_program__next(NULL, obj);
+ if (!prog) {
+ p_err("object file doesn't contain any bpf program");
+ goto err_close_obj;
+ }
+
+ bpf_program__set_ifindex(prog, ifindex);
+ if (attr.prog_type == BPF_PROG_TYPE_UNSPEC) {
+ const char *sec_name = bpf_program__title(prog, false);
+
+ err = libbpf_prog_type_by_string(sec_name, &attr.prog_type,
+ &expected_attach_type);
+ if (err < 0) {
+ p_err("failed to guess program type based on section name %s\n",
+ sec_name);
+ goto err_close_obj;
+ }
+ }
+ bpf_program__set_type(prog, attr.prog_type);
+ bpf_program__set_expected_attach_type(prog, expected_attach_type);
+
+ bpf_map__for_each(map, obj)
+ if (!bpf_map__is_offload_neutral(map))
+ bpf_map__set_ifindex(map, ifindex);
+
+ err = bpf_object__load(obj);
+ if (err) {
+ p_err("failed to load object file");
+ goto err_close_obj;
+ }
+
+ if (do_pin_fd(bpf_program__fd(prog), pinfile))
goto err_close_obj;
if (json_output)
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next v2 08/12] tools: libbpf: add extended attributes version of bpf_object__open()
From: Jakub Kicinski @ 2018-07-09 17:59 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20180709175944.32265-1-jakub.kicinski@netronome.com>
Similarly to bpf_prog_load() users of bpf_object__open() may need
to specify the expected program type. Program type is needed at
open to avoid the kernel version check for program types which don't
require it.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tools/lib/bpf/libbpf.c | 21 +++++++++++++++++----
tools/lib/bpf/libbpf.h | 6 ++++++
2 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index edc3b0b3737d..5b0e84fbcf71 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -1520,7 +1520,8 @@ __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz,
return ERR_PTR(err);
}
-struct bpf_object *bpf_object__open(const char *path)
+struct bpf_object *bpf_object__open_xattr(const char *path,
+ struct bpf_object_open_attr *attr)
{
/* param validation */
if (!path)
@@ -1528,7 +1529,17 @@ struct bpf_object *bpf_object__open(const char *path)
pr_debug("loading %s\n", path);
- return __bpf_object__open(path, NULL, 0, true);
+ return __bpf_object__open(path, NULL, 0,
+ bpf_prog_type__needs_kver(attr->prog_type));
+}
+
+struct bpf_object *bpf_object__open(const char *path)
+{
+ struct bpf_object_open_attr attr = {
+ .prog_type = BPF_PROG_TYPE_UNSPEC,
+ };
+
+ return bpf_object__open_xattr(path, &attr);
}
struct bpf_object *bpf_object__open_buffer(void *obj_buf,
@@ -2238,6 +2249,9 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type,
int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
struct bpf_object **pobj, int *prog_fd)
{
+ struct bpf_object_open_attr open_attr = {
+ .prog_type = attr->prog_type,
+ };
struct bpf_program *prog, *first_prog = NULL;
enum bpf_attach_type expected_attach_type;
enum bpf_prog_type prog_type;
@@ -2250,8 +2264,7 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
if (!attr->file)
return -EINVAL;
- obj = __bpf_object__open(attr->file, NULL, 0,
- bpf_prog_type__needs_kver(attr->prog_type));
+ obj = bpf_object__open_xattr(attr->file, &open_attr);
if (IS_ERR_OR_NULL(obj))
return -ENOENT;
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 3122d74f2643..60593ac44700 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -66,7 +66,13 @@ void libbpf_set_print(libbpf_print_fn_t warn,
/* Hide internal to user */
struct bpf_object;
+struct bpf_object_open_attr {
+ enum bpf_prog_type prog_type;
+};
+
struct bpf_object *bpf_object__open(const char *path);
+struct bpf_object *bpf_object__open_xattr(const char *path,
+ struct bpf_object_open_attr *attr);
struct bpf_object *bpf_object__open_buffer(void *obj_buf,
size_t obj_buf_sz,
const char *name);
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next v2 07/12] tools: libbpf: recognize offload neutral maps
From: Jakub Kicinski @ 2018-07-09 17:59 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20180709175944.32265-1-jakub.kicinski@netronome.com>
Add helper to libbpf for recognizing maps which should not have
ifindex set when program is loaded. These maps only contain
host metadata and therefore are not marked for offload, e.g.
the perf event map.
Use this helper in bpf_prog_load_xattr().
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tools/lib/bpf/libbpf.c | 8 +++++++-
tools/lib/bpf/libbpf.h | 1 +
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 30f3e58bd563..edc3b0b3737d 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -2154,6 +2154,11 @@ void *bpf_map__priv(struct bpf_map *map)
return map ? map->priv : ERR_PTR(-EINVAL);
}
+bool bpf_map__is_offload_neutral(struct bpf_map *map)
+{
+ return map->def.type == BPF_MAP_TYPE_PERF_EVENT_ARRAY;
+}
+
void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex)
{
map->map_ifindex = ifindex;
@@ -2278,7 +2283,8 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
}
bpf_map__for_each(map, obj) {
- map->map_ifindex = attr->ifindex;
+ if (!bpf_map__is_offload_neutral(map))
+ map->map_ifindex = attr->ifindex;
}
if (!first_prog) {
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 617dacfc6704..3122d74f2643 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -255,6 +255,7 @@ typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
int bpf_map__set_priv(struct bpf_map *map, void *priv,
bpf_map_clear_priv_t clear_priv);
void *bpf_map__priv(struct bpf_map *map);
+bool bpf_map__is_offload_neutral(struct bpf_map *map);
void bpf_map__set_ifindex(struct bpf_map *map, __u32 ifindex);
int bpf_map__pin(struct bpf_map *map, const char *path);
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next v2 06/12] tools: bpftool: allow users to specify program type for prog load
From: Jakub Kicinski @ 2018-07-09 17:59 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20180709175944.32265-1-jakub.kicinski@netronome.com>
Sometimes program section names don't match with libbpf's expectation.
In particular XDP's default section names differ between libbpf and
iproute2. Allow users to pass program type on command line. Name
the types like the libbpf expected section names.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
.../bpftool/Documentation/bpftool-prog.rst | 15 ++++++-
tools/bpf/bpftool/bash-completion/bpftool | 6 +++
tools/bpf/bpftool/prog.c | 44 +++++++++++++++++--
3 files changed, 60 insertions(+), 5 deletions(-)
diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
index 41723c6acaa6..e53e1ad2caf0 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
@@ -24,10 +24,19 @@ MAP COMMANDS
| **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}]
| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}]
| **bpftool** **prog pin** *PROG* *FILE*
-| **bpftool** **prog load** *OBJ* *FILE* [**dev** *NAME*]
+| **bpftool** **prog load** *OBJ* *FILE* [**type** *TYPE*] [**dev** *NAME*]
| **bpftool** **prog help**
|
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
+| *TYPE* := {
+| **socket** | **kprobe** | **kretprobe** | **classifier** | **action** |
+| **tracepoint** | **raw_tracepoint** | **xdp** | **perf_event** | **cgroup/skb** |
+| **cgroup/sock** | **cgroup/dev** | **lwt_in** | **lwt_out** | **lwt_xmit** |
+| **lwt_seg6local** | **sockops** | **sk_skb** | **sk_msg** | **lirc_mode2** |
+| **cgroup/bind4** | **cgroup/bind6** | **cgroup/post_bind4** | **cgroup/post_bind6** |
+| **cgroup/connect4** | **cgroup/connect6** | **cgroup/sendmsg4** | **cgroup/sendmsg6**
+| }
+
DESCRIPTION
===========
@@ -64,8 +73,10 @@ DESCRIPTION
Note: *FILE* must be located in *bpffs* mount.
- **bpftool prog load** *OBJ* *FILE* [**dev** *NAME*]
+ **bpftool prog load** *OBJ* *FILE* [**type** *TYPE*] [**dev** *NAME*]
Load bpf program from binary *OBJ* and pin as *FILE*.
+ **type** is optional, if not specified program type will be
+ inferred from section names.
If **dev** *NAME* is specified program will be loaded onto
given networking device (offload).
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index 238c2f80092a..caf8711993be 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -274,11 +274,17 @@ _bpftool()
fi
case $prev in
+ type)
+ COMPREPLY=( $( compgen -W "socket kprobe kretprobe classifier action tracepoint raw_tracepoint xdp perf_event cgroup/skb cgroup/sock cgroup/dev lwt_in lwt_out lwt_xmit lwt_seg6local sockops sk_skb sk_msg lirc_mode2 cgroup/bind4 cgroup/bind6 cgroup/connect4 cgroup/connect6 cgroup/sendmsg4 cgroup/sendmsg6 cgroup/post_bind4 cgroup/post_bind6" -- \
+ "$cur" ) )
+ return 0
+ ;;
dev)
_sysfs_get_netdevs
return 0
;;
*)
+ _bpftool_once_attr 'type'
_bpftool_once_attr 'dev'
return 0
;;
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index 21c74de7156f..7a06fd4c5d27 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -688,6 +688,7 @@ static int do_load(int argc, char **argv)
const char *objfile, *pinfile;
struct bpf_object *obj;
int prog_fd;
+ int err;
if (!REQ_ARGS(2))
return -1;
@@ -695,7 +696,37 @@ static int do_load(int argc, char **argv)
pinfile = GET_ARG();
while (argc) {
- if (is_prefix(*argv, "dev")) {
+ if (is_prefix(*argv, "type")) {
+ char *type;
+
+ NEXT_ARG();
+
+ if (attr.prog_type != BPF_PROG_TYPE_UNSPEC) {
+ p_err("program type already specified");
+ return -1;
+ }
+ if (!REQ_ARGS(1))
+ return -1;
+
+ /* Put a '/' at the end of type to appease libbpf */
+ type = malloc(strlen(*argv) + 2);
+ if (!type) {
+ p_err("mem alloc failed");
+ return -1;
+ }
+ *type = 0;
+ strcat(type, *argv);
+ strcat(type, "/");
+
+ err = libbpf_prog_type_by_string(type, &attr.prog_type,
+ &attr.expected_attach_type);
+ free(type);
+ if (err < 0) {
+ p_err("unknown program type '%s'", *argv);
+ return err;
+ }
+ NEXT_ARG();
+ } else if (is_prefix(*argv, "dev")) {
NEXT_ARG();
if (attr.ifindex) {
@@ -713,7 +744,7 @@ static int do_load(int argc, char **argv)
}
NEXT_ARG();
} else {
- p_err("expected no more arguments or 'dev', got: '%s'?",
+ p_err("expected no more arguments, 'type' or 'dev', got: '%s'?",
*argv);
return -1;
}
@@ -753,10 +784,17 @@ static int do_help(int argc, char **argv)
" %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n"
" %s %s dump jited PROG [{ file FILE | opcodes }]\n"
" %s %s pin PROG FILE\n"
- " %s %s load OBJ FILE [dev NAME]\n"
+ " %s %s load OBJ FILE [type TYPE] [dev NAME]\n"
" %s %s help\n"
"\n"
" " HELP_SPEC_PROGRAM "\n"
+ " TYPE := { socket | kprobe | kretprobe | classifier | action |\n"
+ " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n"
+ " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n"
+ " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n"
+ " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n"
+ " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n"
+ " cgroup/sendmsg4 | cgroup/sendmsg6 }\n"
" " HELP_SPEC_OPTIONS "\n"
"",
bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next v2 05/12] tools: libbpf: expose the prog type guessing from section name logic
From: Jakub Kicinski @ 2018-07-09 17:59 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20180709175944.32265-1-jakub.kicinski@netronome.com>
libbpf can guess program type based on ELF section names. As libbpf
becomes more popular its association between section name strings and
types becomes more of a standard. Allow libbpf users to use the same
logic for matching strings to types, e.g. when the string originates
from command line.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tools/lib/bpf/libbpf.c | 43 ++++++++++++++++++++++++------------------
tools/lib/bpf/libbpf.h | 3 +++
2 files changed, 28 insertions(+), 18 deletions(-)
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 38ed3e92e393..30f3e58bd563 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -2081,25 +2081,33 @@ static const struct {
#undef BPF_S_PROG_SEC
#undef BPF_SA_PROG_SEC
-static int bpf_program__identify_section(struct bpf_program *prog)
+int libbpf_prog_type_by_string(const char *name, enum bpf_prog_type *prog_type,
+ enum bpf_attach_type *expected_attach_type)
{
int i;
- if (!prog->section_name)
- goto err;
-
- for (i = 0; i < ARRAY_SIZE(section_names); i++)
- if (strncmp(prog->section_name, section_names[i].sec,
- section_names[i].len) == 0)
- return i;
-
-err:
- pr_warning("failed to guess program type based on section name %s\n",
- prog->section_name);
+ if (!name)
+ return -1;
+ for (i = 0; i < ARRAY_SIZE(section_names); i++) {
+ if (strncmp(name, section_names[i].sec, section_names[i].len))
+ continue;
+ *prog_type = section_names[i].prog_type;
+ *expected_attach_type = section_names[i].expected_attach_type;
+ return 0;
+ }
return -1;
}
+static int
+bpf_program__identify_section(struct bpf_program *prog,
+ enum bpf_prog_type *prog_type,
+ enum bpf_attach_type *expected_attach_type)
+{
+ return libbpf_prog_type_by_string(prog->section_name, prog_type,
+ expected_attach_type);
+}
+
int bpf_map__fd(struct bpf_map *map)
{
return map ? map->fd : -EINVAL;
@@ -2230,7 +2238,6 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
enum bpf_prog_type prog_type;
struct bpf_object *obj;
struct bpf_map *map;
- int section_idx;
int err;
if (!attr)
@@ -2252,14 +2259,14 @@ int bpf_prog_load_xattr(const struct bpf_prog_load_attr *attr,
prog->prog_ifindex = attr->ifindex;
expected_attach_type = attr->expected_attach_type;
if (prog_type == BPF_PROG_TYPE_UNSPEC) {
- section_idx = bpf_program__identify_section(prog);
- if (section_idx < 0) {
+ err = bpf_program__identify_section(prog, &prog_type,
+ &expected_attach_type);
+ if (err < 0) {
+ pr_warning("failed to guess program type based on section name %s\n",
+ prog->section_name);
bpf_object__close(obj);
return -EINVAL;
}
- prog_type = section_names[section_idx].prog_type;
- expected_attach_type =
- section_names[section_idx].expected_attach_type;
}
bpf_program__set_type(prog, prog_type);
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 564f4be9bae0..617dacfc6704 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -92,6 +92,9 @@ int bpf_object__set_priv(struct bpf_object *obj, void *priv,
bpf_object_clear_priv_t clear_priv);
void *bpf_object__priv(struct bpf_object *prog);
+int libbpf_prog_type_by_string(const char *name, enum bpf_prog_type *prog_type,
+ enum bpf_attach_type *expected_attach_type);
+
/* Accessors of bpf_program */
struct bpf_program;
struct bpf_program *bpf_program__next(struct bpf_program *prog,
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next v2 04/12] tools: bpftool: add support for loading programs for offload
From: Jakub Kicinski @ 2018-07-09 17:59 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20180709175944.32265-1-jakub.kicinski@netronome.com>
Extend the bpftool prog load command to also accept "dev"
parameter, which will allow us to load programs onto devices.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
.../bpftool/Documentation/bpftool-prog.rst | 6 ++--
tools/bpf/bpftool/bash-completion/bpftool | 23 ++++++++++--
tools/bpf/bpftool/prog.c | 35 +++++++++++++++++--
3 files changed, 58 insertions(+), 6 deletions(-)
diff --git a/tools/bpf/bpftool/Documentation/bpftool-prog.rst b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
index 43d34a5c3ec5..41723c6acaa6 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-prog.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-prog.rst
@@ -24,7 +24,7 @@ MAP COMMANDS
| **bpftool** **prog dump xlated** *PROG* [{**file** *FILE* | **opcodes** | **visual**}]
| **bpftool** **prog dump jited** *PROG* [{**file** *FILE* | **opcodes**}]
| **bpftool** **prog pin** *PROG* *FILE*
-| **bpftool** **prog load** *OBJ* *FILE*
+| **bpftool** **prog load** *OBJ* *FILE* [**dev** *NAME*]
| **bpftool** **prog help**
|
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
@@ -64,8 +64,10 @@ DESCRIPTION
Note: *FILE* must be located in *bpffs* mount.
- **bpftool prog load** *OBJ* *FILE*
+ **bpftool prog load** *OBJ* *FILE* [**dev** *NAME*]
Load bpf program from binary *OBJ* and pin as *FILE*.
+ If **dev** *NAME* is specified program will be loaded onto
+ given networking device (offload).
Note: *FILE* must be located in *bpffs* mount.
diff --git a/tools/bpf/bpftool/bash-completion/bpftool b/tools/bpf/bpftool/bash-completion/bpftool
index ce0bc0cda361..238c2f80092a 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -99,6 +99,12 @@ _bpftool_get_prog_tags()
command sed -n 's/.*"tag": "\(.*\)",$/\1/p' )" -- "$cur" ) )
}
+_sysfs_get_netdevs()
+{
+ COMPREPLY+=( $( compgen -W "$( ls /sys/class/net 2>/dev/null )" -- \
+ "$cur" ) )
+}
+
# For bpftool map update: retrieve type of the map to update.
_bpftool_map_update_map_type()
{
@@ -262,8 +268,21 @@ _bpftool()
return 0
;;
load)
- _filedir
- return 0
+ if [[ ${#words[@]} -lt 6 ]]; then
+ _filedir
+ return 0
+ fi
+
+ case $prev in
+ dev)
+ _sysfs_get_netdevs
+ return 0
+ ;;
+ *)
+ _bpftool_once_attr 'dev'
+ return 0
+ ;;
+ esac
;;
*)
[[ $prev == $object ]] && \
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index a5ef46c59029..21c74de7156f 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -39,6 +39,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <net/if.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -681,6 +682,9 @@ static int do_pin(int argc, char **argv)
static int do_load(int argc, char **argv)
{
+ struct bpf_prog_load_attr attr = {
+ .prog_type = BPF_PROG_TYPE_UNSPEC,
+ };
const char *objfile, *pinfile;
struct bpf_object *obj;
int prog_fd;
@@ -690,7 +694,34 @@ static int do_load(int argc, char **argv)
objfile = GET_ARG();
pinfile = GET_ARG();
- if (bpf_prog_load(objfile, BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) {
+ while (argc) {
+ if (is_prefix(*argv, "dev")) {
+ NEXT_ARG();
+
+ if (attr.ifindex) {
+ p_err("offload device already specified");
+ return -1;
+ }
+ if (!REQ_ARGS(1))
+ return -1;
+
+ attr.ifindex = if_nametoindex(*argv);
+ if (!attr.ifindex) {
+ p_err("unrecognized netdevice '%s': %s",
+ *argv, strerror(errno));
+ return -1;
+ }
+ NEXT_ARG();
+ } else {
+ p_err("expected no more arguments or 'dev', got: '%s'?",
+ *argv);
+ return -1;
+ }
+ }
+
+ attr.file = objfile;
+
+ if (bpf_prog_load_xattr(&attr, &obj, &prog_fd)) {
p_err("failed to load program");
return -1;
}
@@ -722,7 +753,7 @@ static int do_help(int argc, char **argv)
" %s %s dump xlated PROG [{ file FILE | opcodes | visual }]\n"
" %s %s dump jited PROG [{ file FILE | opcodes }]\n"
" %s %s pin PROG FILE\n"
- " %s %s load OBJ FILE\n"
+ " %s %s load OBJ FILE [dev NAME]\n"
" %s %s help\n"
"\n"
" " HELP_SPEC_PROGRAM "\n"
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next v2 03/12] tools: bpftool: refactor argument parsing for prog load
From: Jakub Kicinski @ 2018-07-09 17:59 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20180709175944.32265-1-jakub.kicinski@netronome.com>
Add a new macro for printing more informative message than straight
usage() when parameters are missing, and use it for prog do_load().
Save the object and pin path argument to variables for clarity.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tools/bpf/bpftool/main.h | 15 +++++++++++++++
tools/bpf/bpftool/prog.c | 11 +++++++----
2 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index d39f7ef01d23..15b6c49ae533 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -50,6 +50,21 @@
#define NEXT_ARG() ({ argc--; argv++; if (argc < 0) usage(); })
#define NEXT_ARGP() ({ (*argc)--; (*argv)++; if (*argc < 0) usage(); })
#define BAD_ARG() ({ p_err("what is '%s'?", *argv); -1; })
+#define GET_ARG() ({ argc--; *argv++; })
+#define REQ_ARGS(cnt) \
+ ({ \
+ int _cnt = (cnt); \
+ bool _res; \
+ \
+ if (argc < _cnt) { \
+ p_err("'%s' needs at least %d arguments, %d found", \
+ argv[-1], _cnt, argc); \
+ _res = false; \
+ } else { \
+ _res = true; \
+ } \
+ _res; \
+ })
#define ERR_MAX_LEN 1024
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index a740da99d477..a5ef46c59029 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -681,18 +681,21 @@ static int do_pin(int argc, char **argv)
static int do_load(int argc, char **argv)
{
+ const char *objfile, *pinfile;
struct bpf_object *obj;
int prog_fd;
- if (argc != 2)
- usage();
+ if (!REQ_ARGS(2))
+ return -1;
+ objfile = GET_ARG();
+ pinfile = GET_ARG();
- if (bpf_prog_load(argv[0], BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) {
+ if (bpf_prog_load(objfile, BPF_PROG_TYPE_UNSPEC, &obj, &prog_fd)) {
p_err("failed to load program");
return -1;
}
- if (do_pin_fd(prog_fd, argv[1]))
+ if (do_pin_fd(prog_fd, pinfile))
goto err_close_obj;
if (json_output)
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next v2 02/12] selftests/bpf: add Error: prefix in check_extack helper
From: Jakub Kicinski @ 2018-07-09 17:59 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20180709175944.32265-1-jakub.kicinski@netronome.com>
Currently the test only checks errors, not warnings, so save typing
and prefix the extack messages with "Error:" inside the check helper.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tools/testing/selftests/bpf/test_offload.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py
index a257e4b08392..f8d9bd81d9a4 100755
--- a/tools/testing/selftests/bpf/test_offload.py
+++ b/tools/testing/selftests/bpf/test_offload.py
@@ -547,11 +547,11 @@ netns = [] # net namespaces to be removed
if skip_extack:
return
lines = output.split("\n")
- comp = len(lines) >= 2 and lines[1] == reference
+ comp = len(lines) >= 2 and lines[1] == 'Error: ' + reference
fail(not comp, "Missing or incorrect netlink extack message")
def check_extack_nsim(output, reference, args):
- check_extack(output, "Error: netdevsim: " + reference, args)
+ check_extack(output, "netdevsim: " + reference, args)
def check_no_extack(res, needle):
fail((res[1] + res[2]).count(needle) or (res[1] + res[2]).count("Warning:"),
@@ -654,7 +654,7 @@ netns = []
ret, _, err = sim.cls_bpf_add_filter(obj, skip_sw=True,
fail=False, include_stderr=True)
fail(ret == 0, "TC filter loaded without enabling TC offloads")
- check_extack(err, "Error: TC offload is disabled on net device.", args)
+ check_extack(err, "TC offload is disabled on net device.", args)
sim.wait_for_flush()
sim.set_ethtool_tc_offloads(True)
@@ -694,7 +694,7 @@ netns = []
skip_sw=True,
fail=False, include_stderr=True)
fail(ret == 0, "Offloaded a filter to chain other than 0")
- check_extack(err, "Error: Driver supports only offload of chain 0.", args)
+ check_extack(err, "Driver supports only offload of chain 0.", args)
sim.tc_flush_filters()
start_test("Test TC replace...")
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next v2 01/12] selftests/bpf: remove duplicated word from test offloads
From: Jakub Kicinski @ 2018-07-09 17:59 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: oss-drivers, netdev, Jakub Kicinski
In-Reply-To: <20180709175944.32265-1-jakub.kicinski@netronome.com>
Trivial removal of duplicated "mode" in error message.
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Quentin Monnet <quentin.monnet@netronome.com>
---
tools/testing/selftests/bpf/test_offload.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py
index be800d0e7a84..a257e4b08392 100755
--- a/tools/testing/selftests/bpf/test_offload.py
+++ b/tools/testing/selftests/bpf/test_offload.py
@@ -830,7 +830,7 @@ netns = []
check_extack_nsim(err, "program loaded with different flags.", args)
ret, _, err = sim.unset_xdp("", force=True,
fail=False, include_stderr=True)
- fail(ret == 0, "Removed program with a bad mode mode")
+ fail(ret == 0, "Removed program with a bad mode")
check_extack_nsim(err, "program loaded with different flags.", args)
start_test("Test MTU restrictions...")
--
2.17.1
^ permalink raw reply related
* [PATCH bpf-next v2 00/12] tools: bpf: extend bpftool prog load
From: Jakub Kicinski @ 2018-07-09 17:59 UTC (permalink / raw)
To: alexei.starovoitov, daniel; +Cc: oss-drivers, netdev, Jakub Kicinski
Hi!
This series starts with two minor clean ups to test_offload.py
selftest script.
The next 9 patches extend the abilities of bpftool prog load
beyond the simple cgroup use cases. Three new parameters are
added:
- type - allows specifying program type, independent of how
code sections are named;
- map - allows reusing existing maps, instead of creating a new
map on every program load;
- dev - offload/binding to a device.
A number of changes to libbpf is required to accomplish the task.
The section - program type logic mapping is exposed. We should
probably aim to use the libbpf program section naming everywhere.
For reuse of maps we need to allow users to set FD for bpf map
object in libbpf.
Examples
Load program my_xdp.o and pin it as /sys/fs/bpf/my_xdp, for xdp
program type:
$ bpftool prog load my_xdp.o /sys/fs/bpf/my_xdp \
type xdp
As above but for offload:
$ bpftool prog load my_xdp.o /sys/fs/bpf/my_xdp \
type xdp \
dev netdevsim0
Load program my_maps.o, but for the first map reuse map id 17,
and for the map called "other_map" reuse pinned map /sys/fs/bpf/map0:
$ bpftool prog load my_maps.o /sys/fs/bpf/prog \
map idx 0 id 17 \
map name other_map pinned /sys/fs/bpf/map0
---
v2:
- add compat for reallocarray().
Jakub Kicinski (12):
selftests/bpf: remove duplicated word from test offloads
selftests/bpf: add Error: prefix in check_extack helper
tools: bpftool: refactor argument parsing for prog load
tools: bpftool: add support for loading programs for offload
tools: libbpf: expose the prog type guessing from section name logic
tools: bpftool: allow users to specify program type for prog load
tools: libbpf: recognize offload neutral maps
tools: libbpf: add extended attributes version of bpf_object__open()
tools: bpftool: reimplement bpf_prog_load() for prog load
tools: bpf: make use of reallocarray
tools: libbpf: allow map reuse
tools: bpftool: allow reuse of maps with bpftool prog load
.../bpftool/Documentation/bpftool-prog.rst | 33 ++-
tools/bpf/bpftool/Makefile | 6 +-
tools/bpf/bpftool/bash-completion/bpftool | 96 +++++-
tools/bpf/bpftool/main.h | 19 ++
tools/bpf/bpftool/map.c | 4 +-
tools/bpf/bpftool/prog.c | 245 ++++++++++++++-
tools/bpf/bpftool/xlated_dumper.c | 6 +-
tools/build/feature/Makefile | 4 +
tools/build/feature/test-reallocarray.c | 8 +
tools/include/linux/compiler-gcc.h | 4 +
tools/include/linux/overflow.h | 278 ++++++++++++++++++
tools/include/tools/libc_compat.h | 23 ++
tools/lib/bpf/Makefile | 6 +-
tools/lib/bpf/libbpf.c | 116 ++++++--
tools/lib/bpf/libbpf.h | 11 +
tools/testing/selftests/bpf/test_offload.py | 10 +-
16 files changed, 812 insertions(+), 57 deletions(-)
create mode 100644 tools/build/feature/test-reallocarray.c
create mode 100644 tools/include/linux/overflow.h
create mode 100644 tools/include/tools/libc_compat.h
--
2.17.1
^ permalink raw reply
* [PATCH net-next] tcp: expose both send and receive intervals for rate sample
From: Deepti Raghavan @ 2018-07-09 17:53 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Deepti Raghavan
Congestion control algorithms, which access the rate sample
through the tcp_cong_control function, only have access to the maximum
of the send and receive interval, for cases where the acknowledgment
rate may be inaccurate due to ACK compression or decimation. Algorithms
may want to use send rates and receive rates as separate signals.
Signed-off-by: Deepti Raghavan <deeptir@mit.edu>
---
include/net/tcp.h | 2 ++
net/ipv4/tcp_rate.c | 4 ++++
2 files changed, 6 insertions(+)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index cce3769..f6cb20e 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -954,6 +954,8 @@ struct rate_sample {
u32 prior_delivered; /* tp->delivered at "prior_mstamp" */
s32 delivered; /* number of packets delivered over interval */
long interval_us; /* time for tp->delivered to incr "delivered" */
+ u32 snd_interval_us; /* snd interval for delivered packets */
+ u32 rcv_interval_us; /* rcv interval for delivered packets */
long rtt_us; /* RTT of last (S)ACKed packet (or -1) */
int losses; /* number of packets marked lost upon ACK */
u32 acked_sacked; /* number of packets newly (S)ACKed upon ACK */
diff --git a/net/ipv4/tcp_rate.c b/net/ipv4/tcp_rate.c
index c61240e..4dff40d 100644
--- a/net/ipv4/tcp_rate.c
+++ b/net/ipv4/tcp_rate.c
@@ -146,6 +146,10 @@ void tcp_rate_gen(struct sock *sk, u32 delivered, u32 lost,
rs->prior_mstamp); /* ack phase */
rs->interval_us = max(snd_us, ack_us);
+ /* Record both segment send and ack receive intervals */
+ rs->snd_interval_us = snd_us;
+ rs->rcv_interval_us = ack_us;
+
/* Normally we expect interval_us >= min-rtt.
* Note that rate may still be over-estimated when a spuriously
* retransmistted skb was first (s)acked because "interval_us"
--
2.7.4
^ permalink raw reply related
* [PATCH v2] samples/bpf: Fix tc and ip paths in xdp2skb_meta.sh
From: Taeung Song @ 2018-07-09 17:51 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann
Cc: Jesper Dangaard Brouer, netdev, linux-kernel, Taeung Song
The below path error can occur:
# ./xdp2skb_meta.sh --dev eth0 --list
./xdp2skb_meta.sh: line 61: /usr/sbin/tc: No such file or directory
So just use command names instead of absolute paths of tc and ip.
In addition, it allow callers to redefine $TC and $IP paths
Fixes: 36e04a2d78d9 ("samples/bpf: xdp2skb_meta shows transferring info from XDP to SKB")
Reviewed-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
samples/bpf/xdp2skb_meta.sh | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/samples/bpf/xdp2skb_meta.sh b/samples/bpf/xdp2skb_meta.sh
index b9c9549c4c27..4bde9d066c46 100755
--- a/samples/bpf/xdp2skb_meta.sh
+++ b/samples/bpf/xdp2skb_meta.sh
@@ -16,8 +16,8 @@
BPF_FILE=xdp2skb_meta_kern.o
DIR=$(dirname $0)
-export TC=/usr/sbin/tc
-export IP=/usr/sbin/ip
+[ -z "$TC" ] && TC=tc
+[ -z "$IP" ] && IP=ip
function usage() {
echo ""
@@ -53,7 +53,7 @@ function _call_cmd() {
local allow_fail="$2"
shift 2
if [[ -n "$VERBOSE" ]]; then
- echo "$(basename $cmd) $@"
+ echo "$cmd $@"
fi
if [[ -n "$DRYRUN" ]]; then
return
--
2.17.1
^ permalink raw reply related
* Re: [PATCH] samples/bpf: Fix tc and ip path in xdp2skb_meta.sh
From: Taeung Song @ 2018-07-09 17:44 UTC (permalink / raw)
To: Jesper Dangaard Brouer
Cc: Alexei Starovoitov, Daniel Borkmann, netdev, linux-kernel
In-Reply-To: <20180709174029.3c05e750@redhat.com>
Hi Jesper Dangaard Brouer,
On 07/10/2018 12:40 AM, Jesper Dangaard Brouer wrote:
> On Tue, 10 Jul 2018 00:04:18 +0900
> Taeung Song <treeze.taeung@gmail.com> wrote:
>
>> The below path error can occur:
>>
>> # ./xdp2skb_meta.sh --dev eth0 --list
>> ./xdp2skb_meta.sh: line 61: /usr/sbin/tc: No such file or directory
>>
>> # which tc
>> /sbin/tc
>>
>> So use 'which' command instead of absolute path of tc and ip
>>
>> Fixes: 36e04a2d78d9 ("samples/bpf: xdp2skb_meta shows transferring info from XDP to SKB")
>> Cc: Jesper Dangaard Brouer <brouer@redhat.com>
>> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
>> ---
>> samples/bpf/xdp2skb_meta.sh | 4 ++--
>> 1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/samples/bpf/xdp2skb_meta.sh b/samples/bpf/xdp2skb_meta.sh
>> index b9c9549c4c27..67cf7b5f336d 100755
>> --- a/samples/bpf/xdp2skb_meta.sh
>> +++ b/samples/bpf/xdp2skb_meta.sh
>> @@ -16,8 +16,8 @@
>> BPF_FILE=xdp2skb_meta_kern.o
>> DIR=$(dirname $0)
>>
>> -export TC=/usr/sbin/tc
>> -export IP=/usr/sbin/ip
>> +export TC=`which tc`
>> +export IP=`which ip`
>
> This is not a good solution, as 'which' can return something else.
> E.g. on my system I've aliased 'tc' to 'sudo tc', and `which tc` returns:
>
> $ which tc
> alias tc='sudo tc'
> /usr/bin/sudo
>
> The easiest solution is to simply do:
>
> export TC=tc
> export IP=ip
>
> The more fancy solution is to allow callers to redefine $IP and $TC:
>
> [ -z "$TC" ] && TC=tc
> [ -z "$IP" ] && IP=ip
>
Yep, you are right, I'll change it.
> And then you should also fix the use of 'basename', see below patch...
>
I thought it'd be fine to leave 'basename' as it is,
because if callers redefine TC=/home/taeung/tc and give
the options --verbose or --dry-run, 'basename' can more tidily show outputs.
But it seems to be trivial, I'll resend this patch as v2 based on your
comment !
Thanks,
Taeung
^ permalink raw reply
* Re: [PATCH v3 iproute2 2/3] tc: Add support for the ETF Qdisc
From: David Ahern @ 2018-07-09 17:32 UTC (permalink / raw)
To: Jesus Sanchez-Palencia, netdev
Cc: jhs, xiyou.wangcong, jiri, Vinicius Costa Gomes
In-Reply-To: <a009803c-1036-eae9-c57d-2b95eecd551d@intel.com>
On 7/9/18 9:48 AM, Jesus Sanchez-Palencia wrote:
> Hi David,
>
>
> On 07/06/2018 08:58 AM, David Ahern wrote:
>> On 7/5/18 4:42 PM, Jesus Sanchez-Palencia wrote:
>>
>>> +static int get_clockid(__s32 *val, const char *arg)
>>> +{
>>> + const struct static_clockid {
>>> + const char *name;
>>> + clockid_t clockid;
>>> + } clockids_sysv[] = {
>>> + { "CLOCK_REALTIME", CLOCK_REALTIME },
>>> + { "CLOCK_TAI", CLOCK_TAI },
>>> + { "CLOCK_BOOTTIME", CLOCK_BOOTTIME },
>>> + { "CLOCK_MONOTONIC", CLOCK_MONOTONIC },
>>> + { NULL }
>>> + };
>>> +
>>> + const struct static_clockid *c;
>>> +
>>> + for (c = clockids_sysv; c->name; c++) {
>>> + if (strncasecmp(c->name, arg, 25) == 0) {
>>
>> Why 25?
>
>
> That was just an upper bound giving some room beyond the longest
> clockid name we have today. Should I add a define MAX_CLOCK_NAME ?
why not just strcasecmp? using the 'n' variant with n > strlen of either
argument seems pointless.
>
>
>>
>> be nice to allow shortcuts -- e.g., just REALTIME or realtime.
>
>
> I'd rather just keep it as is and use the names as they are defined for
> everything else (i.e. CLOCK_REALTIME), unless there are some strong objections.
An all caps argument is unnecessary work on the pinky finger and the
CLOCK_ prefix is redundant to the keyword. Really, just a thought on
making it easier for users. A CLI argument does not need to maintain a
1:1 with code names.
^ permalink raw reply
* Re: [PATCH bpf 1/1] bpf: btf: Fix bitfield extraction for big endian
From: Martin KaFai Lau @ 2018-07-09 17:32 UTC (permalink / raw)
To: Okash Khawaja
Cc: Daniel Borkmann, Alexei Starovoitov, Yonghong Song,
Jakub Kicinski, David S. Miller, netdev, kernel-team,
linux-kernel
In-Reply-To: <20180709004002.440153594@fb.com>
On Sun, Jul 08, 2018 at 05:22:03PM -0700, Okash Khawaja wrote:
> When extracting bitfield from a number, btf_int_bits_seq_show() builds
> a mask and accesses least significant byte of the number in a way
> specific to little-endian. This patch fixes that by checking endianness
> of the machine and then shifting left and right the unneeded bits.
>
> Thanks to Martin Lau for the help in navigating potential pitfalls when
> dealing with endianess and for the final solution.
>
> Fixes: b00b8daec828 ("bpf: btf: Add pretty print capability for data with BTF type info")
> Signed-off-by: Okash Khawaja <osk@fb.com>
>
> ---
> kernel/bpf/btf.c | 32 +++++++++++++++-----------------
> 1 file changed, 15 insertions(+), 17 deletions(-)
>
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -162,6 +162,8 @@
> #define BITS_ROUNDDOWN_BYTES(bits) ((bits) >> 3)
> #define BITS_ROUNDUP_BYTES(bits) \
> (BITS_ROUNDDOWN_BYTES(bits) + !!BITS_PER_BYTE_MASKED(bits))
> +const int one = 1;
> +#define is_big_endian() ((*(char *)&one) == 0)
Can the __BIG_ENDIAN be reused here?
>
> #define BTF_INFO_MASK 0x0f00ffff
> #define BTF_INT_MASK 0x0fffffff
> @@ -991,16 +993,13 @@ static void btf_int_bits_seq_show(const
> void *data, u8 bits_offset,
> struct seq_file *m)
> {
> + u8 left_shift_bits, right_shift_bits;
> u32 int_data = btf_type_int(t);
> u16 nr_bits = BTF_INT_BITS(int_data);
> u16 total_bits_offset;
> u16 nr_copy_bytes;
> u16 nr_copy_bits;
> - u8 nr_upper_bits;
> - union {
> - u64 u64_num;
> - u8 u8_nums[8];
> - } print_num;
> + u64 print_num;
>
> total_bits_offset = bits_offset + BTF_INT_OFFSET(int_data);
> data += BITS_ROUNDDOWN_BYTES(total_bits_offset);
> @@ -1008,21 +1007,20 @@ static void btf_int_bits_seq_show(const
> nr_copy_bits = nr_bits + bits_offset;
> nr_copy_bytes = BITS_ROUNDUP_BYTES(nr_copy_bits);
>
> - print_num.u64_num = 0;
> - memcpy(&print_num.u64_num, data, nr_copy_bytes);
> -
> - /* Ditch the higher order bits */
> - nr_upper_bits = BITS_PER_BYTE_MASKED(nr_copy_bits);
> - if (nr_upper_bits) {
> - /* We need to mask out some bits of the upper byte. */
> - u8 mask = (1 << nr_upper_bits) - 1;
> -
> - print_num.u8_nums[nr_copy_bytes - 1] &= mask;
> + print_num = 0;
> + memcpy(&print_num, data, nr_copy_bytes);
> + if (is_big_endian()) {
> + left_shift_bits = bits_offset;
> + right_shift_bits = BITS_PER_U64 - nr_bits;
> + } else {
> + left_shift_bits = BITS_PER_U64 - nr_copy_bits;
> + right_shift_bits = BITS_PER_U64 - nr_bits;
> }
>
> - print_num.u64_num >>= bits_offset;
> + print_num <<= left_shift_bits;
> + print_num >>= right_shift_bits;
>
> - seq_printf(m, "0x%llx", print_num.u64_num);
> + seq_printf(m, "0x%llx", print_num);
> }
>
> static void btf_int_seq_show(const struct btf *btf, const struct btf_type *t,
>
^ permalink raw reply
* Re: [PATCH] net: sched: Fix warnings from xchg() on RCU'd cookie pointer.
From: Vlad Buslov @ 2018-07-09 17:29 UTC (permalink / raw)
To: Marcelo Ricardo Leitner; +Cc: David Miller, netdev, jiri
In-Reply-To: <20180709153012.GA8880@localhost.localdomain>
On Mon 09 Jul 2018 at 15:30, Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> wrote:
> On Sun, Jul 08, 2018 at 05:03:58PM +0900, David Miller wrote:
>>
>> The kbuild test robot reports:
>>
>> >> net/sched/act_api.c:71:15: sparse: incorrect type in initializer (different address spaces) @@ expected struct tc_cookie [noderef] <asn:4>*__ret @@ got [noderef] <asn:4>*__ret @@
>> net/sched/act_api.c:71:15: expected struct tc_cookie [noderef] <asn:4>*__ret
>> net/sched/act_api.c:71:15: got struct tc_cookie *new_cookie
>> >> net/sched/act_api.c:71:13: sparse: incorrect type in assignment (different address spaces) @@ expected struct tc_cookie *old @@ got struct tc_cookie [noderef] <struct tc_cookie *old @@
>> net/sched/act_api.c:71:13: expected struct tc_cookie *old
>> net/sched/act_api.c:71:13: got struct tc_cookie [noderef] <asn:4>*[assigned] __ret
>
> This one:
>
>> >> net/sched/act_api.c:132:48: sparse: dereference of noderef expression
>
> Actually belongs to a different issue, that was reported in the same
> email, but which wasn't handled in this patch.
>
> Marcelo
Thanks,
I've sent the fix.
Vlad
^ permalink raw reply
* [PATCH net-next] net: sched: fix unprotected access to rcu cookie pointer
From: Vlad Buslov @ 2018-07-09 17:26 UTC (permalink / raw)
To: netdev; +Cc: davem, jhs, xiyou.wangcong, jiri, marcelo.leitner, Vlad Buslov
Fix action attribute size calculation function to take rcu read lock and
access act_cookie pointer with rcu dereference.
Fixes: eec94fdb0480 ("net: sched: use rcu for action cookie update")
Reported-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: Vlad Buslov <vladbu@mellanox.com>
---
net/sched/act_api.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 66dc19746c63..148a89ab789b 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -149,10 +149,15 @@ EXPORT_SYMBOL(__tcf_idr_release);
static size_t tcf_action_shared_attrs_size(const struct tc_action *act)
{
+ struct tc_cookie *act_cookie;
u32 cookie_len = 0;
- if (act->act_cookie)
- cookie_len = nla_total_size(act->act_cookie->len);
+ rcu_read_lock();
+ act_cookie = rcu_dereference(act->act_cookie);
+
+ if (act_cookie)
+ cookie_len = nla_total_size(act_cookie->len);
+ rcu_read_unlock();
return nla_total_size(0) /* action number nested */
+ nla_total_size(IFNAMSIZ) /* TCA_ACT_KIND */
--
2.7.5
^ permalink raw reply related
* Re: [PATCH net v2 5/5] Documentation: ip-sysctl.txt: document addr_gen_mode
From: David Ahern @ 2018-07-09 17:25 UTC (permalink / raw)
To: Sabrina Dubroca, netdev; +Cc: Jiri Pirko, Felix Jia
In-Reply-To: <893b7025f6c3d7f7b79fadf7d290da42a83467e9.1531129207.git.sd@queasysnail.net>
On 7/9/18 4:25 AM, Sabrina Dubroca wrote:
> addr_gen_mode was introduced in without documentation, add it now.
>
> Fixes: d35a00b8e33d ("net/ipv6: allow sysctl to change link-local address generation mode")
> Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
> ---
> Documentation/networking/ip-sysctl.txt | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
Reviewed-by: David Ahern <dsahern@gmail.com>
^ permalink raw reply
* Re: [PATCH net v2 4/5] net/ipv6: propagate net.ipv6.conf.all.addr_gen_mode to devices
From: David Ahern @ 2018-07-09 17:24 UTC (permalink / raw)
To: Sabrina Dubroca, netdev; +Cc: Jiri Pirko, Felix Jia
In-Reply-To: <55a3cba92aefc90d3b1837e7fdf4b7e2fea05af4.1531129207.git.sd@queasysnail.net>
On 7/9/18 4:25 AM, Sabrina Dubroca wrote:
> This aligns the addr_gen_mode sysctl with the expected behavior of the
> "all" variant.
>
> Fixes: d35a00b8e33d ("net/ipv6: allow sysctl to change link-local address generation mode")
> Suggested-by: David Ahern <dsahern@gmail.com>
> Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
> ---
> net/ipv6/addrconf.c | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
>
> diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
> index e89bca83e0e4..1659a6b3cf42 100644
> --- a/net/ipv6/addrconf.c
> +++ b/net/ipv6/addrconf.c
> @@ -5926,6 +5926,18 @@ static int addrconf_sysctl_addr_gen_mode(struct ctl_table *ctl, int write,
> idev->cnf.addr_gen_mode = new_val;
> addrconf_dev_config(idev->dev);
> }
> + } else if (&net->ipv6.devconf_all->addr_gen_mode == ctl->data) {
> + struct net_device *dev;
> +
> + net->ipv6.devconf_dflt->addr_gen_mode = new_val;
> + for_each_netdev(net, dev) {
> + idev = __in6_dev_get(dev);
> + if (idev &&
> + idev->cnf.addr_gen_mode != new_val) {
> + idev->cnf.addr_gen_mode = new_val;
> + addrconf_dev_config(idev->dev);
This call is adding a new LL address without removing the previous one:
# ip -6 addr sh dev eth2
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
inet6 2001:db8:2::4/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::e0:f9ff:fe45:6480/64 scope link
valid_lft forever preferred_lft forever
# sysctl -w net.ipv6.conf.eth2.addr_gen_mode=3
net.ipv6.conf.eth2.addr_gen_mode = 3
# ip -6 addr sh dev eth2
4: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
inet6 2001:db8:2::4/64 scope global
valid_lft forever preferred_lft forever
inet6 fe80::bc31:8009:270d:e019/64 scope link stable-privacy
valid_lft forever preferred_lft forever
inet6 fe80::e0:f9ff:fe45:6480/64 scope link
valid_lft forever preferred_lft forever
> + }
> + }
> }
>
> *((u32 *)ctl->data) = new_val;
>
^ permalink raw reply
* Re: [PATCH net v2 1/5] net/ipv6: fix addrconf_sysctl_addr_gen_mode
From: David Ahern @ 2018-07-09 17:20 UTC (permalink / raw)
To: Sabrina Dubroca, netdev; +Cc: Jiri Pirko, Felix Jia
In-Reply-To: <c9860365b10dbd648724a6d65ea0dede8ec56464.1531129207.git.sd@queasysnail.net>
On 7/9/18 4:25 AM, Sabrina Dubroca wrote:
> addrconf_sysctl_addr_gen_mode() has multiple problems. First, it ignores
> the errors returned by proc_dointvec().
>
> addrconf_sysctl_addr_gen_mode() calls proc_dointvec() directly, which
> writes the value to memory, and then checks if it's valid and may return
> EINVAL. If a bad value is given, the value displayed when reading
> net.ipv6.conf.foo.addr_gen_mode next time will be invalid. In case the
> value provided by the user was valid, addrconf_dev_config() won't be
> called since idev->cnf.addr_gen_mode has already been updated.
>
> Fix this in the usual way we deal with values that need to be checked
> after the proc_do*() helper has returned: define a local ctl_table and
> storage, call proc_dointvec() on that temporary area, then check and
> store.
>
> addrconf_sysctl_addr_gen_mode() also writes the new value to the global
> ipv6_devconf_dflt, when we're writing to some netns's default, so that
> new netns will inherit the value that was set by the change occuring in
> any netns. That doesn't make any sense, so let's drop this assignment.
>
> Finally, since addr_gen_mode is a __u32, switch to proc_douintvec().
>
> Fixes: d35a00b8e33d ("net/ipv6: allow sysctl to change link-local address generation mode")
> Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
> ---
> net/ipv6/addrconf.c | 27 ++++++++++++++-------------
> 1 file changed, 14 insertions(+), 13 deletions(-)
>
Reviewed-by: David Ahern <dsahern@gmail.com>
^ permalink raw reply
* Re: KASAN: use-after-free Read in p9_conn_cancel
From: syzbot @ 2018-07-09 17:20 UTC (permalink / raw)
To: davem, ericvh, linux-kernel, lucho, netdev, rminnich,
syzkaller-bugs, v9fs-developer
In-Reply-To: <000000000000d13b2e05708a9ca0@google.com>
syzbot has found a reproducer for the following crash on:
HEAD commit: 1e4b044d2251 Linux 4.18-rc4
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=10d5ba2c400000
kernel config: https://syzkaller.appspot.com/x/.config?x=25856fac4e580aa7
dashboard link: https://syzkaller.appspot.com/bug?extid=f0fdc967350bd580a80b
compiler: gcc (GCC) 8.0.1 20180413 (experimental)
userspace arch: i386
syzkaller repro:https://syzkaller.appspot.com/x/repro.syz?x=179f4f48400000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=12aba452400000
IMPORTANT: if you fix the bug, please add the following tag to the commit:
Reported-by: syzbot+f0fdc967350bd580a80b@syzkaller.appspotmail.com
==================================================================
BUG: KASAN: use-after-free in p9_conn_cancel+0x9de/0xd30
net/9p/trans_fd.c:207
Read of size 4 at addr ffff8801b075c2e8 by task kworker/1:2/4574
CPU: 1 PID: 4574 Comm: kworker/1:2 Not tainted 4.18.0-rc4+ #41
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
Google 01/01/2011
Workqueue: events p9_poll_workfn
Call Trace:
__dump_stack lib/dump_stack.c:77 [inline]
dump_stack+0x1c9/0x2b4 lib/dump_stack.c:113
print_address_description+0x6c/0x20b mm/kasan/report.c:256
kasan_report_error mm/kasan/report.c:354 [inline]
kasan_report.cold.7+0x242/0x2fe mm/kasan/report.c:412
__asan_report_load4_noabort+0x14/0x20 mm/kasan/report.c:432
p9_conn_cancel+0x9de/0xd30 net/9p/trans_fd.c:207
p9_poll_mux net/9p/trans_fd.c:620 [inline]
p9_poll_workfn+0x4b2/0x6d0 net/9p/trans_fd.c:1107
process_one_work+0xc73/0x1ba0 kernel/workqueue.c:2153
worker_thread+0x189/0x13c0 kernel/workqueue.c:2296
kthread+0x345/0x410 kernel/kthread.c:246
ret_from_fork+0x3a/0x50 arch/x86/entry/entry_64.S:412
Allocated by task 4689:
save_stack+0x43/0xd0 mm/kasan/kasan.c:448
set_track mm/kasan/kasan.c:460 [inline]
kasan_kmalloc+0xc4/0xe0 mm/kasan/kasan.c:553
kmem_cache_alloc_trace+0x152/0x780 mm/slab.c:3620
kmalloc include/linux/slab.h:513 [inline]
kzalloc include/linux/slab.h:707 [inline]
p9_fd_open net/9p/trans_fd.c:796 [inline]
p9_fd_create+0x1a7/0x3f0 net/9p/trans_fd.c:1036
p9_client_create+0x915/0x16c9 net/9p/client.c:1062
v9fs_session_init+0x21a/0x1a80 fs/9p/v9fs.c:400
v9fs_mount+0x7c/0x900 fs/9p/vfs_super.c:135
mount_fs+0xae/0x328 fs/super.c:1277
vfs_kern_mount.part.34+0xdc/0x4e0 fs/namespace.c:1037
vfs_kern_mount fs/namespace.c:1027 [inline]
do_new_mount fs/namespace.c:2518 [inline]
do_mount+0x581/0x30e0 fs/namespace.c:2848
__do_compat_sys_mount fs/compat.c:125 [inline]
__se_compat_sys_mount fs/compat.c:92 [inline]
__ia32_compat_sys_mount+0x5d5/0x860 fs/compat.c:92
do_syscall_32_irqs_on arch/x86/entry/common.c:326 [inline]
do_fast_syscall_32+0x34d/0xfb2 arch/x86/entry/common.c:397
entry_SYSENTER_compat+0x70/0x7f arch/x86/entry/entry_64_compat.S:139
Freed by task 4689:
save_stack+0x43/0xd0 mm/kasan/kasan.c:448
set_track mm/kasan/kasan.c:460 [inline]
__kasan_slab_free+0x11a/0x170 mm/kasan/kasan.c:521
kasan_slab_free+0xe/0x10 mm/kasan/kasan.c:528
__cache_free mm/slab.c:3498 [inline]
kfree+0xd9/0x260 mm/slab.c:3813
p9_fd_close+0x416/0x5b0 net/9p/trans_fd.c:893
p9_client_create+0xac2/0x16c9 net/9p/client.c:1076
v9fs_session_init+0x21a/0x1a80 fs/9p/v9fs.c:400
v9fs_mount+0x7c/0x900 fs/9p/vfs_super.c:135
mount_fs+0xae/0x328 fs/super.c:1277
vfs_kern_mount.part.34+0xdc/0x4e0 fs/namespace.c:1037
vfs_kern_mount fs/namespace.c:1027 [inline]
do_new_mount fs/namespace.c:2518 [inline]
do_mount+0x581/0x30e0 fs/namespace.c:2848
__do_compat_sys_mount fs/compat.c:125 [inline]
__se_compat_sys_mount fs/compat.c:92 [inline]
__ia32_compat_sys_mount+0x5d5/0x860 fs/compat.c:92
do_syscall_32_irqs_on arch/x86/entry/common.c:326 [inline]
do_fast_syscall_32+0x34d/0xfb2 arch/x86/entry/common.c:397
entry_SYSENTER_compat+0x70/0x7f arch/x86/entry/entry_64_compat.S:139
The buggy address belongs to the object at ffff8801b075c2c0
which belongs to the cache kmalloc-512 of size 512
The buggy address is located 40 bytes inside of
512-byte region [ffff8801b075c2c0, ffff8801b075c4c0)
The buggy address belongs to the page:
page:ffffea0006c1d700 count:1 mapcount:0 mapping:ffff8801da800940 index:0x0
flags: 0x2fffc0000000100(slab)
raw: 02fffc0000000100 ffffea0006cc1c88 ffffea0006c48288 ffff8801da800940
raw: 0000000000000000 ffff8801b075c040 0000000100000006 0000000000000000
page dumped because: kasan: bad access detected
Memory state around the buggy address:
ffff8801b075c180: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8801b075c200: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc
> ffff8801b075c280: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb
^
ffff8801b075c300: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8801b075c380: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox