Commit 37b7c058 authored by Alexei Starovoitov's avatar Alexei Starovoitov

Merge branch 'bpftool-net-attach'

Daniel T. Lee says:

====================
Currently, bpftool net only supports dumping progs attached on the
interface. To attach XDP prog on interface, user must use other tool
(eg. iproute2). By this patch, with `bpftool net attach/detach`, user
can attach/detach XDP prog on interface.

    # bpftool prog
        16: xdp  name xdp_prog1  tag 539ec6ce11b52f98  gpl
        loaded_at 2019-08-07T08:30:17+0900  uid 0
        ...
        20: xdp  name xdp_fwd_prog  tag b9cb69f121e4a274  gpl
        loaded_at 2019-08-07T08:30:17+0900  uid 0

    # bpftool net attach xdpdrv id 16 dev enp6s0np0
    # bpftool net
    xdp:
        enp6s0np0(4) driver id 16

    # bpftool net attach xdpdrv id 20 dev enp6s0np0 overwrite
    # bpftool net
    xdp:
        enp6s0np0(4) driver id 20

    # bpftool net detach xdpdrv dev enp6s0np0
    # bpftool net
    xdp:

While this patch only contains support for XDP, through `net
attach/detach`, bpftool can further support other prog attach types.

XDP attach/detach tested on Mellanox ConnectX-4 and Netronome Agilio.

---
Changes in v5:
  - fix wrong error message, from errno to err with do_attach/detach

Changes in v4:
  - rename variable, attach/detach error message enhancement
  - bash-completion cleanup, doc update with brief description (attach
    types)

Changes in v3:
  - added 'overwrite' option for replacing previously attached XDP prog
  - command argument order has been changed ('ATTACH_TYPE' comes first)
  - add 'dev' keyword in front of <devname>
  - added bash-completion and documentation

Changes in v2:
  - command 'load/unload' changed to 'attach/detach' for the consistency
====================
Reviewed-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents a9436dca cb9d9968
...@@ -15,17 +15,22 @@ SYNOPSIS ...@@ -15,17 +15,22 @@ SYNOPSIS
*OPTIONS* := { [{ **-j** | **--json** }] [{ **-p** | **--pretty** }] } *OPTIONS* := { [{ **-j** | **--json** }] [{ **-p** | **--pretty** }] }
*COMMANDS* := *COMMANDS* :=
{ **show** | **list** } [ **dev** name ] | **help** { **show** | **list** | **attach** | **detach** | **help** }
NET COMMANDS NET COMMANDS
============ ============
| **bpftool** **net { show | list } [ dev name ]** | **bpftool** **net { show | list }** [ **dev** *NAME* ]
| **bpftool** **net attach** *ATTACH_TYPE* *PROG* **dev** *NAME* [ **overwrite** ]
| **bpftool** **net detach** *ATTACH_TYPE* **dev** *NAME*
| **bpftool** **net help** | **bpftool** **net help**
|
| *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
| *ATTACH_TYPE* := { **xdp** | **xdpgeneric** | **xdpdrv** | **xdpoffload** }
DESCRIPTION DESCRIPTION
=========== ===========
**bpftool net { show | list } [ dev name ]** **bpftool net { show | list }** [ **dev** *NAME* ]
List bpf program attachments in the kernel networking subsystem. List bpf program attachments in the kernel networking subsystem.
Currently, only device driver xdp attachments and tc filter Currently, only device driver xdp attachments and tc filter
...@@ -47,6 +52,24 @@ DESCRIPTION ...@@ -47,6 +52,24 @@ DESCRIPTION
all bpf programs attached to non clsact qdiscs, and finally all all bpf programs attached to non clsact qdiscs, and finally all
bpf programs attached to root and clsact qdisc. bpf programs attached to root and clsact qdisc.
**bpftool** **net attach** *ATTACH_TYPE* *PROG* **dev** *NAME* [ **overwrite** ]
Attach bpf program *PROG* to network interface *NAME* with
type specified by *ATTACH_TYPE*. Previously attached bpf program
can be replaced by the command used with **overwrite** option.
Currently, only XDP-related modes are supported for *ATTACH_TYPE*.
*ATTACH_TYPE* can be of:
**xdp** - try native XDP and fallback to generic XDP if NIC driver does not support it;
**xdpgeneric** - Generic XDP. runs at generic XDP hook when packet already enters receive path as skb;
**xdpdrv** - Native XDP. runs earliest point in driver's receive path;
**xdpoffload** - Offload XDP. runs directly on NIC on each packet reception;
**bpftool** **net detach** *ATTACH_TYPE* **dev** *NAME*
Detach bpf program attached to network interface *NAME* with
type specified by *ATTACH_TYPE*. To detach bpf program, same
*ATTACH_TYPE* previously used for attach must be specified.
Currently, only XDP-related modes are supported for *ATTACH_TYPE*.
**bpftool net help** **bpftool net help**
Print short help message. Print short help message.
...@@ -137,6 +160,34 @@ EXAMPLES ...@@ -137,6 +160,34 @@ EXAMPLES
} }
] ]
|
| **# bpftool net attach xdpdrv id 16 dev enp6s0np0**
| **# bpftool net**
::
xdp:
enp6s0np0(4) driver id 16
|
| **# bpftool net attach xdpdrv id 16 dev enp6s0np0**
| **# bpftool net attach xdpdrv id 20 dev enp6s0np0 overwrite**
| **# bpftool net**
::
xdp:
enp6s0np0(4) driver id 20
|
| **# bpftool net attach xdpdrv id 16 dev enp6s0np0**
| **# bpftool net detach xdpdrv dev enp6s0np0**
| **# bpftool net**
::
xdp:
SEE ALSO SEE ALSO
======== ========
......
...@@ -201,6 +201,10 @@ _bpftool() ...@@ -201,6 +201,10 @@ _bpftool()
_bpftool_get_prog_tags _bpftool_get_prog_tags
return 0 return 0
;; ;;
dev)
_sysfs_get_netdevs
return 0
;;
file|pinned) file|pinned)
_filedir _filedir
return 0 return 0
...@@ -399,10 +403,6 @@ _bpftool() ...@@ -399,10 +403,6 @@ _bpftool()
_filedir _filedir
return 0 return 0
;; ;;
dev)
_sysfs_get_netdevs
return 0
;;
*) *)
COMPREPLY=( $( compgen -W "map" -- "$cur" ) ) COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
_bpftool_once_attr 'type' _bpftool_once_attr 'type'
...@@ -498,10 +498,6 @@ _bpftool() ...@@ -498,10 +498,6 @@ _bpftool()
key|value|flags|name|entries) key|value|flags|name|entries)
return 0 return 0
;; ;;
dev)
_sysfs_get_netdevs
return 0
;;
*) *)
_bpftool_once_attr 'type' _bpftool_once_attr 'type'
_bpftool_once_attr 'key' _bpftool_once_attr 'key'
...@@ -778,18 +774,67 @@ _bpftool() ...@@ -778,18 +774,67 @@ _bpftool()
esac esac
;; ;;
net) net)
local PROG_TYPE='id pinned tag'
local ATTACH_TYPES='xdp xdpgeneric xdpdrv xdpoffload'
case $command in case $command in
show|list)
[[ $prev != "$command" ]] && return 0
COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
return 0
;;
attach)
case $cword in
3)
COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- "$cur" ) )
return 0
;;
4)
COMPREPLY=( $( compgen -W "$PROG_TYPE" -- "$cur" ) )
return 0
;;
5)
case $prev in
id)
_bpftool_get_prog_ids
;;
pinned)
_filedir
;;
esac
return 0
;;
6)
COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
return 0
;;
8)
_bpftool_once_attr 'overwrite'
return 0
;;
esac
;;
detach)
case $cword in
3)
COMPREPLY=( $( compgen -W "$ATTACH_TYPES" -- "$cur" ) )
return 0
;;
4)
COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) )
return 0
;;
esac
;;
*) *)
[[ $prev == $object ]] && \ [[ $prev == $object ]] && \
COMPREPLY=( $( compgen -W 'help \ COMPREPLY=( $( compgen -W 'help \
show list' -- "$cur" ) ) show list attach detach' -- "$cur" ) )
;; ;;
esac esac
;; ;;
feature) feature)
case $command in case $command in
probe) probe)
[[ $prev == "dev" ]] && _sysfs_get_netdevs && return 0
[[ $prev == "prefix" ]] && return 0 [[ $prev == "prefix" ]] && return 0
if _bpftool_search_list 'macros'; then if _bpftool_search_list 'macros'; then
COMPREPLY+=( $( compgen -W 'prefix' -- "$cur" ) ) COMPREPLY+=( $( compgen -W 'prefix' -- "$cur" ) )
......
...@@ -55,6 +55,35 @@ struct bpf_attach_info { ...@@ -55,6 +55,35 @@ struct bpf_attach_info {
__u32 flow_dissector_id; __u32 flow_dissector_id;
}; };
enum net_attach_type {
NET_ATTACH_TYPE_XDP,
NET_ATTACH_TYPE_XDP_GENERIC,
NET_ATTACH_TYPE_XDP_DRIVER,
NET_ATTACH_TYPE_XDP_OFFLOAD,
};
static const char * const attach_type_strings[] = {
[NET_ATTACH_TYPE_XDP] = "xdp",
[NET_ATTACH_TYPE_XDP_GENERIC] = "xdpgeneric",
[NET_ATTACH_TYPE_XDP_DRIVER] = "xdpdrv",
[NET_ATTACH_TYPE_XDP_OFFLOAD] = "xdpoffload",
};
const size_t net_attach_type_size = ARRAY_SIZE(attach_type_strings);
static enum net_attach_type parse_attach_type(const char *str)
{
enum net_attach_type type;
for (type = 0; type < net_attach_type_size; type++) {
if (attach_type_strings[type] &&
is_prefix(str, attach_type_strings[type]))
return type;
}
return net_attach_type_size;
}
static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb) static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
{ {
struct bpf_netdev_t *netinfo = cookie; struct bpf_netdev_t *netinfo = cookie;
...@@ -223,6 +252,134 @@ static int query_flow_dissector(struct bpf_attach_info *attach_info) ...@@ -223,6 +252,134 @@ static int query_flow_dissector(struct bpf_attach_info *attach_info)
return 0; return 0;
} }
static int net_parse_dev(int *argc, char ***argv)
{
int ifindex;
if (is_prefix(**argv, "dev")) {
NEXT_ARGP();
ifindex = if_nametoindex(**argv);
if (!ifindex)
p_err("invalid devname %s", **argv);
NEXT_ARGP();
} else {
p_err("expected 'dev', got: '%s'?", **argv);
return -1;
}
return ifindex;
}
static int do_attach_detach_xdp(int progfd, enum net_attach_type attach_type,
int ifindex, bool overwrite)
{
__u32 flags = 0;
if (!overwrite)
flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
if (attach_type == NET_ATTACH_TYPE_XDP_GENERIC)
flags |= XDP_FLAGS_SKB_MODE;
if (attach_type == NET_ATTACH_TYPE_XDP_DRIVER)
flags |= XDP_FLAGS_DRV_MODE;
if (attach_type == NET_ATTACH_TYPE_XDP_OFFLOAD)
flags |= XDP_FLAGS_HW_MODE;
return bpf_set_link_xdp_fd(ifindex, progfd, flags);
}
static int do_attach(int argc, char **argv)
{
enum net_attach_type attach_type;
int progfd, ifindex, err = 0;
bool overwrite = false;
/* parse attach args */
if (!REQ_ARGS(5))
return -EINVAL;
attach_type = parse_attach_type(*argv);
if (attach_type == net_attach_type_size) {
p_err("invalid net attach/detach type: %s", *argv);
return -EINVAL;
}
NEXT_ARG();
progfd = prog_parse_fd(&argc, &argv);
if (progfd < 0)
return -EINVAL;
ifindex = net_parse_dev(&argc, &argv);
if (ifindex < 1) {
close(progfd);
return -EINVAL;
}
if (argc) {
if (is_prefix(*argv, "overwrite")) {
overwrite = true;
} else {
p_err("expected 'overwrite', got: '%s'?", *argv);
close(progfd);
return -EINVAL;
}
}
/* attach xdp prog */
if (is_prefix("xdp", attach_type_strings[attach_type]))
err = do_attach_detach_xdp(progfd, attach_type, ifindex,
overwrite);
if (err < 0) {
p_err("interface %s attach failed: %s",
attach_type_strings[attach_type], strerror(-err));
return err;
}
if (json_output)
jsonw_null(json_wtr);
return 0;
}
static int do_detach(int argc, char **argv)
{
enum net_attach_type attach_type;
int progfd, ifindex, err = 0;
/* parse detach args */
if (!REQ_ARGS(3))
return -EINVAL;
attach_type = parse_attach_type(*argv);
if (attach_type == net_attach_type_size) {
p_err("invalid net attach/detach type: %s", *argv);
return -EINVAL;
}
NEXT_ARG();
ifindex = net_parse_dev(&argc, &argv);
if (ifindex < 1)
return -EINVAL;
/* detach xdp prog */
progfd = -1;
if (is_prefix("xdp", attach_type_strings[attach_type]))
err = do_attach_detach_xdp(progfd, attach_type, ifindex, NULL);
if (err < 0) {
p_err("interface %s detach failed: %s",
attach_type_strings[attach_type], strerror(-err));
return err;
}
if (json_output)
jsonw_null(json_wtr);
return 0;
}
static int do_show(int argc, char **argv) static int do_show(int argc, char **argv)
{ {
struct bpf_attach_info attach_info = {}; struct bpf_attach_info attach_info = {};
...@@ -232,13 +389,9 @@ static int do_show(int argc, char **argv) ...@@ -232,13 +389,9 @@ static int do_show(int argc, char **argv)
char err_buf[256]; char err_buf[256];
if (argc == 2) { if (argc == 2) {
if (strcmp(argv[0], "dev") != 0) filter_idx = net_parse_dev(&argc, &argv);
usage(); if (filter_idx < 1)
filter_idx = if_nametoindex(argv[1]);
if (filter_idx == 0) {
fprintf(stderr, "invalid dev name %s\n", argv[1]);
return -1; return -1;
}
} else if (argc != 0) { } else if (argc != 0) {
usage(); usage();
} }
...@@ -305,13 +458,20 @@ static int do_help(int argc, char **argv) ...@@ -305,13 +458,20 @@ static int do_help(int argc, char **argv)
fprintf(stderr, fprintf(stderr,
"Usage: %s %s { show | list } [dev <devname>]\n" "Usage: %s %s { show | list } [dev <devname>]\n"
" %s %s attach ATTACH_TYPE PROG dev <devname> [ overwrite ]\n"
" %s %s detach ATTACH_TYPE dev <devname>\n"
" %s %s help\n" " %s %s help\n"
"\n"
" " HELP_SPEC_PROGRAM "\n"
" ATTACH_TYPE := { xdp | xdpgeneric | xdpdrv | xdpoffload }\n"
"\n"
"Note: Only xdp and tc attachments are supported now.\n" "Note: Only xdp and tc attachments are supported now.\n"
" For progs attached to cgroups, use \"bpftool cgroup\"\n" " For progs attached to cgroups, use \"bpftool cgroup\"\n"
" to dump program attachments. For program types\n" " to dump program attachments. For program types\n"
" sk_{filter,skb,msg,reuseport} and lwt/seg6, please\n" " sk_{filter,skb,msg,reuseport} and lwt/seg6, please\n"
" consult iproute2.\n", " consult iproute2.\n",
bin_name, argv[-2], bin_name, argv[-2]); bin_name, argv[-2], bin_name, argv[-2], bin_name, argv[-2],
bin_name, argv[-2]);
return 0; return 0;
} }
...@@ -319,6 +479,8 @@ static int do_help(int argc, char **argv) ...@@ -319,6 +479,8 @@ static int do_help(int argc, char **argv)
static const struct cmd cmds[] = { static const struct cmd cmds[] = {
{ "show", do_show }, { "show", do_show },
{ "list", do_show }, { "list", do_show },
{ "attach", do_attach },
{ "detach", do_detach },
{ "help", do_help }, { "help", do_help },
{ 0 } { 0 }
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment