diff options
Diffstat (limited to 'tools/bpf/bpftool/net.c')
| -rw-r--r-- | tools/bpf/bpftool/net.c | 178 | 
1 files changed, 170 insertions, 8 deletions
diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c index 67e99c56bc88..4f52d3151616 100644 --- a/tools/bpf/bpftool/net.c +++ b/tools/bpf/bpftool/net.c @@ -55,6 +55,35 @@ struct bpf_attach_info {  	__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)  {  	struct bpf_netdev_t *netinfo = cookie; @@ -197,7 +226,7 @@ static int query_flow_dissector(struct bpf_attach_info *attach_info)  	fd = open("/proc/self/ns/net", O_RDONLY);  	if (fd < 0) { -		p_err("can't open /proc/self/ns/net: %d", +		p_err("can't open /proc/self/ns/net: %s",  		      strerror(errno));  		return -1;  	} @@ -223,6 +252,134 @@ static int query_flow_dissector(struct bpf_attach_info *attach_info)  	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)  {  	struct bpf_attach_info attach_info = {}; @@ -232,13 +389,9 @@ static int do_show(int argc, char **argv)  	char err_buf[256];  	if (argc == 2) { -		if (strcmp(argv[0], "dev") != 0) -			usage(); -		filter_idx = if_nametoindex(argv[1]); -		if (filter_idx == 0) { -			fprintf(stderr, "invalid dev name %s\n", argv[1]); +		filter_idx = net_parse_dev(&argc, &argv); +		if (filter_idx < 1)  			return -1; -		}  	} else if (argc != 0) {  		usage();  	} @@ -305,13 +458,20 @@ static int do_help(int argc, char **argv)  	fprintf(stderr,  		"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" +		"\n" +		"       " HELP_SPEC_PROGRAM "\n" +		"       ATTACH_TYPE := { xdp | xdpgeneric | xdpdrv | xdpoffload }\n" +		"\n"  		"Note: Only xdp and tc attachments are supported now.\n"  		"      For progs attached to cgroups, use \"bpftool cgroup\"\n"  		"      to dump program attachments. For program types\n"  		"      sk_{filter,skb,msg,reuseport} and lwt/seg6, please\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;  } @@ -319,6 +479,8 @@ static int do_help(int argc, char **argv)  static const struct cmd cmds[] = {  	{ "show",	do_show },  	{ "list",	do_show }, +	{ "attach",	do_attach }, +	{ "detach",	do_detach },  	{ "help",	do_help },  	{ 0 }  };  |