[PATCH] samples: bpf: fix: seg fault with NULL pointer arg

2018-12-01 Thread Daniel T. Lee
When NULL pointer accidentally passed to write_kprobe_events,
due to strlen(NULL), segmentation fault happens.
Changed code returns -1 to deal with this situation.

Bug issued with Smatch, static analysis.

Signed-off-by: Daniel T. Lee 
---
 samples/bpf/bpf_load.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index 434ea34a5954..c670bd2200d2 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -58,7 +58,9 @@ static int write_kprobe_events(const char *val)
 {
int fd, ret, flags;
 
-   if ((val != NULL) && (val[0] == '\0'))
+   if (val == NULL)
+   return -1;
+   else if ((val != NULL) && (val[0] == '\0'))
flags = O_WRONLY | O_TRUNC;
else
flags = O_WRONLY | O_APPEND;
-- 
2.17.1



[PATCH v2] samples: bpf: fix: seg fault with NULL pointer arg

2018-12-03 Thread Daniel T. Lee
When NULL pointer accidentally passed to write_kprobe_events,
due to strlen(NULL), segmentation fault happens.
Changed code returns -1 to deal with this situation.

Bug issued with Smatch, static analysis.

Signed-off-by: Daniel T. Lee 
---
 samples/bpf/bpf_load.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index 434ea34a5954..eae7b635343d 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -58,7 +58,9 @@ static int write_kprobe_events(const char *val)
 {
int fd, ret, flags;
 
-   if ((val != NULL) && (val[0] == '\0'))
+   if (val == NULL)
+   return -1;
+   else if (val[0] == '\0')
flags = O_WRONLY | O_TRUNC;
else
flags = O_WRONLY | O_APPEND;
-- 
2.17.1



[PATCH] samples: bpf: fix: error handling regarding kprobe_events

2018-11-21 Thread Daniel T. Lee
Currently, kprobe_events failure won't be handled properly.
Due to calling system() indirectly to write to kprobe_events,
it can't be identified whether an error is derived from kprobe or system.

// buf = "echo '%c:%s %s' >> /s/k/d/t/kprobe_events"
err = system(buf);
if (err < 0) {
printf("failed to create kprobe ..");
return -1;
}

For example, running ./tracex7 sample in ext4 partition,
"echo p:open_ctree open_ctree >> /s/k/d/t/kprobe_events"
gets 256 error code system() failure.
=> The error comes from kprobe, but it's not handled correctly.

According to man of system(3), it's return value
just passes the termination status of the child shell
rather than treating the error as -1. (don't care success)

Which means, currently it's not working as desired.
(According to the upper code snippet)

ex) running ./tracex7 with ext4 env.
# Current Output
sh: echo: I/O error
failed to open event open_ctree

# Desired Output
failed to create kprobe 'open_ctree' error 'No such file or directory'

The problem is, error can't be verified whether from child ps or system.

But using write() directly can verify the command failure,
and it will treat all error as -1.

So I suggest using write() directly to 'kprobe_events'
rather than calling system().

Signed-off-by: Daniel T. Lee 
---
 samples/bpf/bpf_load.c | 33 -
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index e6d7e0fe155b..3e34d733f5f8 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -54,6 +54,23 @@ static int populate_prog_array(const char *event, int 
prog_fd)
return 0;
 }
 
+static int write_kprobe_events(const char *val)
+{
+   int ret, flags;
+
+   if ((val != NULL) && (val[0] == '\0'))
+   flags = O_WRONLY | O_TRUNC;
+   else
+   flags = O_WRONLY | O_APPEND;
+
+   int fd = open("/sys/kernel/debug/tracing/kprobe_events", flags);
+
+   ret = write(fd, val, strlen(val));
+   close(fd);
+
+   return ret;
+}
+
 static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
 {
bool is_socket = strncmp(event, "socket", 6) == 0;
@@ -165,10 +182,9 @@ static int load_and_attach(const char *event, struct 
bpf_insn *prog, int size)
 
 #ifdef __x86_64__
if (strncmp(event, "sys_", 4) == 0) {
-   snprintf(buf, sizeof(buf),
-"echo '%c:__x64_%s __x64_%s' >> 
/sys/kernel/debug/tracing/kprobe_events",
-is_kprobe ? 'p' : 'r', event, event);
-   err = system(buf);
+   snprintf(buf, sizeof(buf), "%c:__x64_%s __x64_%s",
+   is_kprobe ? 'p' : 'r', event, event);
+   err = write_kprobe_events(buf);
if (err >= 0) {
need_normal_check = false;
event_prefix = "__x64_";
@@ -176,10 +192,9 @@ static int load_and_attach(const char *event, struct 
bpf_insn *prog, int size)
}
 #endif
if (need_normal_check) {
-   snprintf(buf, sizeof(buf),
-"echo '%c:%s %s' >> 
/sys/kernel/debug/tracing/kprobe_events",
-is_kprobe ? 'p' : 'r', event, event);
-   err = system(buf);
+   snprintf(buf, sizeof(buf), "%c:%s %s",
+   is_kprobe ? 'p' : 'r', event, event);
+   err = write_kprobe_events(buf);
if (err < 0) {
printf("failed to create kprobe '%s' error 
'%s'\n",
   event, strerror(errno));
@@ -519,7 +534,7 @@ static int do_load_bpf_file(const char *path, fixup_map_cb 
fixup_map)
return 1;
 
/* clear all kprobes */
-   i = system("echo \"\" > /sys/kernel/debug/tracing/kprobe_events");
+   i = write_kprobe_events("");
 
/* scan over all elf sections to get license and map info */
for (i = 1; i < ehdr.e_shnum; i++) {
-- 
2.17.1



[PATCH v2] samples: bpf: fix: error handling regarding kprobe_events

2018-11-22 Thread Daniel T. Lee
Currently, kprobe_events failure won't be handled properly.
Due to calling system() indirectly to write to kprobe_events,
it can't be identified whether an error is derived from kprobe or system.

// buf = "echo '%c:%s %s' >> /s/k/d/t/kprobe_events"
err = system(buf);
if (err < 0) {
printf("failed to create kprobe ..");
return -1;
}

For example, running ./tracex7 sample in ext4 partition,
"echo p:open_ctree open_ctree >> /s/k/d/t/kprobe_events"
gets 256 error code system() failure.
=> The error comes from kprobe, but it's not handled correctly.

According to man of system(3), it's return value
just passes the termination status of the child shell
rather than treating the error as -1. (don't care success)

Which means, currently it's not working as desired.
(According to the upper code snippet)

ex) running ./tracex7 with ext4 env.
# Current Output
sh: echo: I/O error
failed to open event open_ctree

# Desired Output
failed to create kprobe 'open_ctree' error 'No such file or directory'

The problem is, error can't be verified whether from child ps or system.

But using write() directly can verify the command failure,
and it will treat all error as -1.

So I suggest using write() directly to 'kprobe_events'
rather than calling system().

Signed-off-by: Daniel T. Lee 
---
Changes in v2:
  - Fix code style at variable declaration.

 samples/bpf/bpf_load.c | 33 -
 1 file changed, 24 insertions(+), 9 deletions(-)

diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
index e6d7e0fe155b..96783207de4a 100644
--- a/samples/bpf/bpf_load.c
+++ b/samples/bpf/bpf_load.c
@@ -54,6 +54,23 @@ static int populate_prog_array(const char *event, int 
prog_fd)
return 0;
 }
 
+static int write_kprobe_events(const char *val)
+{
+   int fd, ret, flags;
+
+   if ((val != NULL) && (val[0] == '\0'))
+   flags = O_WRONLY | O_TRUNC;
+   else
+   flags = O_WRONLY | O_APPEND;
+
+   fd = open("/sys/kernel/debug/tracing/kprobe_events", flags);
+
+   ret = write(fd, val, strlen(val));
+   close(fd);
+
+   return ret;
+}
+
 static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
 {
bool is_socket = strncmp(event, "socket", 6) == 0;
@@ -165,10 +182,9 @@ static int load_and_attach(const char *event, struct 
bpf_insn *prog, int size)
 
 #ifdef __x86_64__
if (strncmp(event, "sys_", 4) == 0) {
-   snprintf(buf, sizeof(buf),
-"echo '%c:__x64_%s __x64_%s' >> 
/sys/kernel/debug/tracing/kprobe_events",
-is_kprobe ? 'p' : 'r', event, event);
-   err = system(buf);
+   snprintf(buf, sizeof(buf), "%c:__x64_%s __x64_%s",
+   is_kprobe ? 'p' : 'r', event, event);
+   err = write_kprobe_events(buf);
if (err >= 0) {
need_normal_check = false;
event_prefix = "__x64_";
@@ -176,10 +192,9 @@ static int load_and_attach(const char *event, struct 
bpf_insn *prog, int size)
}
 #endif
if (need_normal_check) {
-   snprintf(buf, sizeof(buf),
-"echo '%c:%s %s' >> 
/sys/kernel/debug/tracing/kprobe_events",
-is_kprobe ? 'p' : 'r', event, event);
-   err = system(buf);
+   snprintf(buf, sizeof(buf), "%c:%s %s",
+   is_kprobe ? 'p' : 'r', event, event);
+   err = write_kprobe_events(buf);
if (err < 0) {
printf("failed to create kprobe '%s' error 
'%s'\n",
   event, strerror(errno));
@@ -519,7 +534,7 @@ static int do_load_bpf_file(const char *path, fixup_map_cb 
fixup_map)
return 1;
 
/* clear all kprobes */
-   i = system("echo \"\" > /sys/kernel/debug/tracing/kprobe_events");
+   i = write_kprobe_events("");
 
/* scan over all elf sections to get license and map info */
for (i = 1; i < ehdr.e_shnum; i++) {
-- 
2.17.1



[PATCH] tools: bpftool: add raw_tracepoint_writable prog type to header

2019-07-11 Thread Daniel T. Lee
>From commit 9df1c28bb752 ("bpf: add writable context for raw tracepoints"),
a new type of BPF_PROG, RAW_TRACEPOINT_WRITABLE has been added.

Since this BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE is not listed at
bpftool's header, it causes a segfault when executing 'bpftool feature'.

This commit adds BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE entry to
prog_type_name enum, and will eventually fixes the segfault issue.

Signed-off-by: Daniel T. Lee 
---
 tools/bpf/bpftool/main.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 3ef0d9051e10..7031a4bf87a0 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -74,6 +74,7 @@ static const char * const prog_type_name[] = {
[BPF_PROG_TYPE_SK_REUSEPORT]= "sk_reuseport",
[BPF_PROG_TYPE_FLOW_DISSECTOR]  = "flow_dissector",
[BPF_PROG_TYPE_CGROUP_SYSCTL]   = "cgroup_sysctl",
+   [BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE] = "raw_tracepoint_writable",
[BPF_PROG_TYPE_CGROUP_SOCKOPT]  = "cgroup_sockopt",
 };
 
-- 
2.17.1



[PATCH 0/2] tools: bpftool: add net (un)load command to load XDP

2019-07-30 Thread Daniel T. Lee
Currently, bpftool net only supports dumping progs loaded on the
interface. To load XDP prog on interface, user must use other tool
(eg. iproute2). By this patch, with `bpftool net (un)load`, user can
(un)load XDP prog on interface.

$ ./bpftool prog
...
208: xdp  name xdp_prog1  tag ad822e38b629553f  gpl
  loaded_at 2019-07-28T18:03:11+0900  uid 0
...
$ ./bpftool net load id 208 xdpdrv enp6s0np1
$ ./bpftool net
xdp:
enp6s0np1(5) driver id 208
...
$ ./bpftool net unload xdpdrv enp6s0np1
$ ./bpftool net
xdp:
...

The word 'load' is used instead of 'attach', since XDP program is not
considered as 'bpf_attach_type' and can't be attached with
'BPF_PROG_ATTACH'. In this context, the meaning of 'load' is, prog will
be loaded on interface.

While this patch only contains support for XDP, through `net (un)load`,
bpftool can further support other prog attach types.

XDP (un)load tested on Netronome Agilio.

Daniel T. Lee (2):
  tools: bpftool: add net load command to load XDP on interface
  tools: bpftool: add net unload command to unload XDP on interface

 tools/bpf/bpftool/net.c | 160 +++-
 1 file changed, 159 insertions(+), 1 deletion(-)

-- 
2.20.1



[PATCH 1/2] tools: bpftool: add net load command to load XDP on interface

2019-07-30 Thread Daniel T. Lee
By this commit, using `bpftool net load`, user can load XDP prog on
interface. New type of enum 'net_load_type' has been made, as stated at
cover-letter, the meaning of 'load' is, prog will be loaded on interface.

BPF prog will be loaded through libbpf 'bpf_set_link_xdp_fd'.

Signed-off-by: Daniel T. Lee 
---
 tools/bpf/bpftool/net.c | 107 +++-
 1 file changed, 106 insertions(+), 1 deletion(-)

diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index 67e99c56bc88..d3a4f18b5b95 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_load_type {
+   NET_LOAD_TYPE_XDP,
+   NET_LOAD_TYPE_XDP_GENERIC,
+   NET_LOAD_TYPE_XDP_DRIVE,
+   NET_LOAD_TYPE_XDP_OFFLOAD,
+   __MAX_NET_LOAD_TYPE
+};
+
+static const char * const load_type_strings[] = {
+   [NET_LOAD_TYPE_XDP] = "xdp",
+   [NET_LOAD_TYPE_XDP_GENERIC] = "xdpgeneric",
+   [NET_LOAD_TYPE_XDP_DRIVE] = "xdpdrv",
+   [NET_LOAD_TYPE_XDP_OFFLOAD] = "xdpoffload",
+   [__MAX_NET_LOAD_TYPE] = NULL,
+};
+
+static enum net_load_type parse_load_type(const char *str)
+{
+   enum net_load_type type;
+
+   for (type = 0; type < __MAX_NET_LOAD_TYPE; type++) {
+   if (load_type_strings[type] &&
+  is_prefix(str, load_type_strings[type]))
+   return type;
+   }
+
+   return __MAX_NET_LOAD_TYPE;
+}
+
 static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
 {
struct bpf_netdev_t *netinfo = cookie;
@@ -223,6 +252,77 @@ static int query_flow_dissector(struct bpf_attach_info 
*attach_info)
return 0;
 }
 
+static int parse_load_args(int argc, char **argv, int *progfd,
+  enum net_load_type *load_type, int *ifindex)
+{
+   if (!REQ_ARGS(3))
+   return -EINVAL;
+
+   *progfd = prog_parse_fd(&argc, &argv);
+   if (*progfd < 0)
+   return *progfd;
+
+   *load_type = parse_load_type(*argv);
+   if (*load_type == __MAX_NET_LOAD_TYPE) {
+   p_err("invalid net load/unload type");
+   return -EINVAL;
+   }
+
+   NEXT_ARG();
+   if (!REQ_ARGS(1))
+   return -EINVAL;
+
+   *ifindex = if_nametoindex(*argv);
+   if (!*ifindex) {
+   p_err("Invalid ifname");
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
+static int do_load_unload_xdp(int *progfd, enum net_load_type *load_type,
+ int *ifindex)
+{
+   __u32 flags;
+   int err;
+
+   flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
+   if (*load_type == NET_LOAD_TYPE_XDP_GENERIC)
+   flags |= XDP_FLAGS_SKB_MODE;
+   if (*load_type == NET_LOAD_TYPE_XDP_DRIVE)
+   flags |= XDP_FLAGS_DRV_MODE;
+   if (*load_type == NET_LOAD_TYPE_XDP_OFFLOAD)
+   flags |= XDP_FLAGS_HW_MODE;
+
+   err = bpf_set_link_xdp_fd(*ifindex, *progfd, flags);
+
+   return err;
+}
+
+static int do_load(int argc, char **argv)
+{
+   enum net_load_type load_type;
+   int err, progfd, ifindex;
+
+   err = parse_load_args(argc, argv, &progfd, &load_type, &ifindex);
+   if (err)
+   return err;
+
+   if (is_prefix("xdp", load_type_strings[load_type]))
+   err = do_load_unload_xdp(&progfd, &load_type, &ifindex);
+
+   if (err < 0) {
+   p_err("link set %s failed", load_type_strings[load_type]);
+   return -1;
+   }
+
+   if (json_output)
+   jsonw_null(json_wtr);
+
+   return 0;
+}
+
 static int do_show(int argc, char **argv)
 {
struct bpf_attach_info attach_info = {};
@@ -305,13 +405,17 @@ static int do_help(int argc, char **argv)
 
fprintf(stderr,
"Usage: %s %s { show | list } [dev ]\n"
+   "   %s %s load PROG LOAD_TYPE \n"
"   %s %s help\n"
+   "\n"
+   "   " HELP_SPEC_PROGRAM "\n"
+   "   LOAD_TYPE := { xdp | xdpgeneric | xdpdrv | xdpoffload 
}\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]);
 
return 0;
 }
@@ -319,6 +423,7 @@ static int do_help(int argc, char **argv)
 static const struct cmd cmds[] = {
{ "show",   do_show },
{ "list",   do_show },
+   { "load",   do_load },
{ "help",   do_help },
{ 0 }
 };
-- 
2.20.1



[PATCH 2/2] tools: bpftool: add net unload command to unload XDP on interface

2019-07-30 Thread Daniel T. Lee
By this commit, using `bpftool net unload`, the loaded XDP prog can
be unloaded. Unloading the BPF prog will be done through libbpf
'bpf_set_link_xdp_fd' with the progfd set to -1.

Signed-off-by: Daniel T. Lee 
---
 tools/bpf/bpftool/net.c | 55 -
 1 file changed, 54 insertions(+), 1 deletion(-)

diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index d3a4f18b5b95..9d353b6e7d6d 100644
--- a/tools/bpf/bpftool/net.c
+++ b/tools/bpf/bpftool/net.c
@@ -281,6 +281,31 @@ static int parse_load_args(int argc, char **argv, int 
*progfd,
return 0;
 }
 
+static int parse_unload_args(int argc, char **argv,
+enum net_load_type *load_type, int *ifindex)
+{
+   if (!REQ_ARGS(2))
+   return -EINVAL;
+
+   *load_type = parse_load_type(*argv);
+   if (*load_type == __MAX_NET_LOAD_TYPE) {
+   p_err("invalid net load/unload type");
+   return -EINVAL;
+   }
+
+   NEXT_ARG();
+   if (!REQ_ARGS(1))
+   return -EINVAL;
+
+   *ifindex = if_nametoindex(*argv);
+   if (!*ifindex) {
+   p_err("Invalid ifname");
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
 static int do_load_unload_xdp(int *progfd, enum net_load_type *load_type,
  int *ifindex)
 {
@@ -323,6 +348,31 @@ static int do_load(int argc, char **argv)
return 0;
 }
 
+static int do_unload(int argc, char **argv)
+{
+   enum net_load_type load_type;
+   int err, progfd, ifindex;
+
+   err = parse_unload_args(argc, argv, &load_type, &ifindex);
+   if (err)
+   return err;
+
+   /* to unload xdp prog */
+   progfd = -1;
+   if (is_prefix("xdp", load_type_strings[load_type]))
+   err = do_load_unload_xdp(&progfd, &load_type, &ifindex);
+
+   if (err < 0) {
+   p_err("link set %s failed", load_type_strings[load_type]);
+   return -1;
+   }
+
+   if (json_output)
+   jsonw_null(json_wtr);
+
+   return 0;
+}
+
 static int do_show(int argc, char **argv)
 {
struct bpf_attach_info attach_info = {};
@@ -406,6 +456,7 @@ static int do_help(int argc, char **argv)
fprintf(stderr,
"Usage: %s %s { show | list } [dev ]\n"
"   %s %s load PROG LOAD_TYPE \n"
+   "   %s %s unload LOAD_TYPE \n"
"   %s %s help\n"
"\n"
"   " HELP_SPEC_PROGRAM "\n"
@@ -415,7 +466,8 @@ static int do_help(int argc, char **argv)
"  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],
+   bin_name, argv[-2]);
 
return 0;
 }
@@ -424,6 +476,7 @@ static const struct cmd cmds[] = {
{ "show",   do_show },
{ "list",   do_show },
{ "load",   do_load },
+   { "unload", do_unload },
{ "help",   do_help },
{ 0 }
 };
-- 
2.20.1



Re: [PATCH 1/2] tools: bpftool: add net load command to load XDP on interface

2019-07-31 Thread Daniel T. Lee
On Wed, Jul 31, 2019 at 7:08 PM Jesper Dangaard Brouer
 wrote:
>
> On Wed, 31 Jul 2019 03:48:20 +0900
> "Daniel T. Lee"  wrote:
>
> > By this commit, using `bpftool net load`, user can load XDP prog on
> > interface. New type of enum 'net_load_type' has been made, as stated at
> > cover-letter, the meaning of 'load' is, prog will be loaded on interface.
>
> Why the keyword "load" ?
> Why not "attach" (and "detach")?
>
> For BPF there is a clear distinction between the "load" and "attach"
> steps.  I know this is under subcommand "net", but to follow the
> conversion of other subcommands e.g. "prog" there are both "load" and
> "attach" commands.
>
>
> > BPF prog will be loaded through libbpf 'bpf_set_link_xdp_fd'.
>
> Again this is a "set" operation, not a "load" operation.

>From earlier at cover-letter, I thought using the same word 'load' might give
confusion since XDP program is not considered as 'bpf_attach_type' and can't
be attached with 'BPF_PROG_ATTACH'.

But, according to the feedback from you and Andrii Nakryiko, replacing
the word 'load' as 'attach' would be more clear and more consistent.

> > Signed-off-by: Daniel T. Lee 
>
> [...]
> >  static int do_show(int argc, char **argv)
> >  {
> >   struct bpf_attach_info attach_info = {};
> > @@ -305,13 +405,17 @@ static int do_help(int argc, char **argv)
> >
> >   fprintf(stderr,
> >   "Usage: %s %s { show | list } [dev ]\n"
> > + "   %s %s load PROG LOAD_TYPE \n"
>
> The "PROG" here does it correspond to the 'bpftool prog' syntax?:
>
>  PROG := { id PROG_ID | pinned FILE | tag PROG_TAG }
>

Yes. By using the same 'prog_parse_fd' from 'bpftool prog',
user can 'attach' XDP prog with id, pinned file or tag.

> >   "   %s %s help\n"
> > + "\n"
> > + "   " HELP_SPEC_PROGRAM "\n"
> > + "   LOAD_TYPE := { xdp | xdpgeneric | xdpdrv | xdpoffload 
> > }\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",
>
>
> --
> Best regards,
>   Jesper Dangaard Brouer
>   MSc.CS, Principal Kernel Engineer at Red Hat
>   LinkedIn: http://www.linkedin.com/in/brouer

And about the enum 'NET_LOAD_TYPE_XDP_DRIVE',
'DRIVER' looks more clear to understand.

Will change to it right away.

Thanks for the review.


[v2,0/2] tools: bpftool: add net attach/detach command to attach XDP prog

2019-08-01 Thread Daniel T. Lee
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
...
208: xdp  name xdp_prog1  tag ad822e38b629553f  gpl
  loaded_at 2019-07-28T18:03:11+0900  uid 0
...
$ ./bpftool net attach id 208 xdpdrv enp6s0np1
$ ./bpftool net
xdp:
enp6s0np1(5) driver id 208
...
$ ./bpftool net detach xdpdrv enp6s0np1
$ ./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 v2:
  - command 'load/unload' changed to 'attach/detach' for the consistency

Daniel T. Lee (2):
  tools: bpftool: add net attach command to attach XDP on interface
  tools: bpftool: add net detach command to detach XDP on interface

 tools/bpf/bpftool/net.c | 160 +++-
 1 file changed, 159 insertions(+), 1 deletion(-)

-- 
2.20.1



[v2,1/2] tools: bpftool: add net attach command to attach XDP on interface

2019-08-01 Thread Daniel T. Lee
By this commit, using `bpftool net attach`, user can attach XDP prog on
interface. New type of enum 'net_attach_type' has been made, as stated at
cover-letter, the meaning of 'attach' is, prog will be attached on interface.

BPF prog will be attached through libbpf 'bpf_set_link_xdp_fd'.

Signed-off-by: Daniel T. Lee 
---
Changes in v2:
  - command 'load' changed to 'attach' for the consistency
  - 'NET_ATTACH_TYPE_XDP_DRIVE' changed to 'NET_ATTACH_TYPE_XDP_DRIVER'

 tools/bpf/bpftool/net.c | 107 +++-
 1 file changed, 106 insertions(+), 1 deletion(-)

diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index 67e99c56bc88..f3b57660b303 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,
+   __MAX_NET_ATTACH_TYPE
+};
+
+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",
+   [__MAX_NET_ATTACH_TYPE] = NULL,
+};
+
+static enum net_attach_type parse_attach_type(const char *str)
+{
+   enum net_attach_type type;
+
+   for (type = 0; type < __MAX_NET_ATTACH_TYPE; type++) {
+   if (attach_type_strings[type] &&
+  is_prefix(str, attach_type_strings[type]))
+   return type;
+   }
+
+   return __MAX_NET_ATTACH_TYPE;
+}
+
 static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
 {
struct bpf_netdev_t *netinfo = cookie;
@@ -223,6 +252,77 @@ static int query_flow_dissector(struct bpf_attach_info 
*attach_info)
return 0;
 }
 
+static int parse_attach_args(int argc, char **argv, int *progfd,
+enum net_attach_type *attach_type, int *ifindex)
+{
+   if (!REQ_ARGS(3))
+   return -EINVAL;
+
+   *progfd = prog_parse_fd(&argc, &argv);
+   if (*progfd < 0)
+   return *progfd;
+
+   *attach_type = parse_attach_type(*argv);
+   if (*attach_type == __MAX_NET_ATTACH_TYPE) {
+   p_err("invalid net attach/detach type");
+   return -EINVAL;
+   }
+
+   NEXT_ARG();
+   if (!REQ_ARGS(1))
+   return -EINVAL;
+
+   *ifindex = if_nametoindex(*argv);
+   if (!*ifindex) {
+   p_err("Invalid ifname");
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
+static int do_attach_detach_xdp(int *progfd, enum net_attach_type *attach_type,
+   int *ifindex)
+{
+   __u32 flags;
+   int err;
+
+   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;
+
+   err = bpf_set_link_xdp_fd(*ifindex, *progfd, flags);
+
+   return err;
+}
+
+static int do_attach(int argc, char **argv)
+{
+   enum net_attach_type attach_type;
+   int err, progfd, ifindex;
+
+   err = parse_attach_args(argc, argv, &progfd, &attach_type, &ifindex);
+   if (err)
+   return err;
+
+   if (is_prefix("xdp", attach_type_strings[attach_type]))
+   err = do_attach_detach_xdp(&progfd, &attach_type, &ifindex);
+
+   if (err < 0) {
+   p_err("link set %s failed", attach_type_strings[attach_type]);
+   return -1;
+   }
+
+   if (json_output)
+   jsonw_null(json_wtr);
+
+   return 0;
+}
+
 static int do_show(int argc, char **argv)
 {
struct bpf_attach_info attach_info = {};
@@ -305,13 +405,17 @@ static int do_help(int argc, char **argv)
 
fprintf(stderr,
"Usage: %s %s { show | list } [dev ]\n"
+   "   %s %s attach PROG LOAD_TYPE \n"
"   %s %s help\n"
+   "\n"
+   "   " HELP_SPEC_PROGRAM "\n"
+   "   LOAD_TYPE := { xdp | xdpgeneric | xdpdrv | xdpoffload 
}\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

[v2,2/2] tools: bpftool: add net detach command to detach XDP on interface

2019-08-01 Thread Daniel T. Lee
By this commit, using `bpftool net detach`, the attached XDP prog can
be detached. Detaching the BPF prog will be done through libbpf
'bpf_set_link_xdp_fd' with the progfd set to -1.

Signed-off-by: Daniel T. Lee 
---
Changes in v2:
  - command 'unload' changed to 'detach' for the consistency

 tools/bpf/bpftool/net.c | 55 -
 1 file changed, 54 insertions(+), 1 deletion(-)

diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index f3b57660b303..2ae9a613b05c 100644
--- a/tools/bpf/bpftool/net.c
+++ b/tools/bpf/bpftool/net.c
@@ -281,6 +281,31 @@ static int parse_attach_args(int argc, char **argv, int 
*progfd,
return 0;
 }
 
+static int parse_detach_args(int argc, char **argv,
+enum net_attach_type *attach_type, int *ifindex)
+{
+   if (!REQ_ARGS(2))
+   return -EINVAL;
+
+   *attach_type = parse_attach_type(*argv);
+   if (*attach_type == __MAX_NET_ATTACH_TYPE) {
+   p_err("invalid net attach/detach type");
+   return -EINVAL;
+   }
+
+   NEXT_ARG();
+   if (!REQ_ARGS(1))
+   return -EINVAL;
+
+   *ifindex = if_nametoindex(*argv);
+   if (!*ifindex) {
+   p_err("Invalid ifname");
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
 static int do_attach_detach_xdp(int *progfd, enum net_attach_type *attach_type,
int *ifindex)
 {
@@ -323,6 +348,31 @@ static int do_attach(int argc, char **argv)
return 0;
 }
 
+static int do_detach(int argc, char **argv)
+{
+   enum net_attach_type attach_type;
+   int err, progfd, ifindex;
+
+   err = parse_detach_args(argc, argv, &attach_type, &ifindex);
+   if (err)
+   return err;
+
+   /* to detach xdp prog */
+   progfd = -1;
+   if (is_prefix("xdp", attach_type_strings[attach_type]))
+   err = do_attach_detach_xdp(&progfd, &attach_type, &ifindex);
+
+   if (err < 0) {
+   p_err("link set %s failed", attach_type_strings[attach_type]);
+   return -1;
+   }
+
+   if (json_output)
+   jsonw_null(json_wtr);
+
+   return 0;
+}
+
 static int do_show(int argc, char **argv)
 {
struct bpf_attach_info attach_info = {};
@@ -406,6 +456,7 @@ static int do_help(int argc, char **argv)
fprintf(stderr,
"Usage: %s %s { show | list } [dev ]\n"
"   %s %s attach PROG LOAD_TYPE \n"
+   "   %s %s detach LOAD_TYPE \n"
"   %s %s help\n"
"\n"
"   " HELP_SPEC_PROGRAM "\n"
@@ -415,7 +466,8 @@ static int do_help(int argc, char **argv)
"  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],
+   bin_name, argv[-2]);
 
return 0;
 }
@@ -424,6 +476,7 @@ static const struct cmd cmds[] = {
{ "show",   do_show },
{ "list",   do_show },
{ "attach", do_attach },
+   { "detach", do_detach },
{ "help",   do_help },
{ 0 }
 };
-- 
2.20.1



Re: [v2,1/2] tools: bpftool: add net attach command to attach XDP on interface

2019-08-01 Thread Daniel T. Lee
On Fri, Aug 2, 2019 at 8:36 AM Jakub Kicinski
 wrote:
>
> On Thu,  1 Aug 2019 17:11:32 +0900, Daniel T. Lee wrote:
> > By this commit, using `bpftool net attach`, user can attach XDP prog on
> > interface. New type of enum 'net_attach_type' has been made, as stated at
> > cover-letter, the meaning of 'attach' is, prog will be attached on 
> > interface.
> >
> > BPF prog will be attached through libbpf 'bpf_set_link_xdp_fd'.
> >
> > Signed-off-by: Daniel T. Lee 
> > ---
> > Changes in v2:
> >   - command 'load' changed to 'attach' for the consistency
> >   - 'NET_ATTACH_TYPE_XDP_DRIVE' changed to 'NET_ATTACH_TYPE_XDP_DRIVER'
> >
> >  tools/bpf/bpftool/net.c | 107 +++-
> >  1 file changed, 106 insertions(+), 1 deletion(-)
> >
> > diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
> > index 67e99c56bc88..f3b57660b303 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,
> > + __MAX_NET_ATTACH_TYPE
> > +};
> > +
> > +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",
> > + [__MAX_NET_ATTACH_TYPE] = NULL,
>
> Not sure if the terminator is necessary,
> ARRAY_SIZE(attach_type_strings) should suffice?

Yes, ARRAY_SIZE is fine though. But I was just trying to make below
'parse_attach_type' consistent with 'parse_attach_type' from the 'prog.c'.
At 'prog.c', It has same terminator at 'attach_type_strings'.

Should I change it or keep it?

> > +};
> > +
> > +static enum net_attach_type parse_attach_type(const char *str)
> > +{
> > + enum net_attach_type type;
> > +
> > + for (type = 0; type < __MAX_NET_ATTACH_TYPE; type++) {
> > + if (attach_type_strings[type] &&
> > +is_prefix(str, attach_type_strings[type]))
> > + return type;
> > + }
> > +
> > + return __MAX_NET_ATTACH_TYPE;
> > +}
> > +
> >  static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
> >  {
> >   struct bpf_netdev_t *netinfo = cookie;
> > @@ -223,6 +252,77 @@ static int query_flow_dissector(struct bpf_attach_info 
> > *attach_info)
> >   return 0;
> >  }
> >
> > +static int parse_attach_args(int argc, char **argv, int *progfd,
> > +  enum net_attach_type *attach_type, int *ifindex)
> > +{
> > + if (!REQ_ARGS(3))
> > + return -EINVAL;
> > +
> > + *progfd = prog_parse_fd(&argc, &argv);
> > + if (*progfd < 0)
> > + return *progfd;
> > +
> > + *attach_type = parse_attach_type(*argv);
> > + if (*attach_type == __MAX_NET_ATTACH_TYPE) {
> > + p_err("invalid net attach/detach type");
> > + return -EINVAL;
>
> You should close the progfd on error paths.

I will add 'close(*progfd);' at next version of patch.

>
> > + }
>
> Hm. I'm not too sure about the ordering of arguments, type should
> probably be right after attach.
>
> If we ever add tc attach support or some other hook, that's more
> fundamental part of the command than the program. So I think:
>
> bpftool net attach xdp id xyz dev ethN

I think it is more reasonable than current format.
I'll change the argument order as attach type comes in first.

> > + NEXT_ARG();
> > + if (!REQ_ARGS(1))
> > + return -EINVAL;
>
> Error message needed here.
>

Actually it provides error message like:
Error: 'xdp' needs at least 1 arguments, 0 found

are you suggesting that any additional error message is necessary?

> > + *ifindex = if_nametoindex(*argv);
> > + if (!*ifindex) {
> > + p_err("Invalid ifname");
>
> "ifname" is not mentioned in help, it'd be best to keep this error
> message consistent with bpftool prog load.

I will change it to a 'devname&

Re: [v2,0/2] tools: bpftool: add net attach/detach command to attach XDP prog

2019-08-01 Thread Daniel T. Lee
Thank you for letting me know.
I will add to next version of patch.

And, thank you for the detailed review. :)

On Fri, Aug 2, 2019 at 8:21 AM Jakub Kicinski
 wrote:
>
> On Thu,  1 Aug 2019 17:11:31 +0900, Daniel T. Lee wrote:
> > 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
> > ...
> > 208: xdp  name xdp_prog1  tag ad822e38b629553f  gpl
> >   loaded_at 2019-07-28T18:03:11+0900  uid 0
> > ...
> > $ ./bpftool net attach id 208 xdpdrv enp6s0np1
> > $ ./bpftool net
> > xdp:
> > enp6s0np1(5) driver id 208
> > ...
> > $ ./bpftool net detach xdpdrv enp6s0np1
> > $ ./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.
>
> Please provide documentation for man pages, and bash completions.


Re: [v2,2/2] tools: bpftool: add net detach command to detach XDP on interface

2019-08-02 Thread Daniel T. Lee
On Fri, Aug 2, 2019 at 3:26 PM Y Song  wrote:
>
> On Thu, Aug 1, 2019 at 2:04 AM Daniel T. Lee  wrote:
> >
> > By this commit, using `bpftool net detach`, the attached XDP prog can
> > be detached. Detaching the BPF prog will be done through libbpf
> > 'bpf_set_link_xdp_fd' with the progfd set to -1.
> >
> > Signed-off-by: Daniel T. Lee 
> > ---
> > Changes in v2:
> >   - command 'unload' changed to 'detach' for the consistency
> >
> >  tools/bpf/bpftool/net.c | 55 -
> >  1 file changed, 54 insertions(+), 1 deletion(-)
> >
> > diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
> > index f3b57660b303..2ae9a613b05c 100644
> > --- a/tools/bpf/bpftool/net.c
> > +++ b/tools/bpf/bpftool/net.c
> > @@ -281,6 +281,31 @@ static int parse_attach_args(int argc, char **argv, 
> > int *progfd,
> > return 0;
> >  }
> >
> > +static int parse_detach_args(int argc, char **argv,
> > +enum net_attach_type *attach_type, int 
> > *ifindex)
> > +{
> > +   if (!REQ_ARGS(2))
> > +   return -EINVAL;
> > +
> > +   *attach_type = parse_attach_type(*argv);
> > +   if (*attach_type == __MAX_NET_ATTACH_TYPE) {
> > +   p_err("invalid net attach/detach type");
> > +   return -EINVAL;
> > +   }
> > +
> > +   NEXT_ARG();
> > +   if (!REQ_ARGS(1))
> > +   return -EINVAL;
> > +
> > +   *ifindex = if_nametoindex(*argv);
> > +   if (!*ifindex) {
> > +   p_err("Invalid ifname");
> > +   return -EINVAL;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> >  static int do_attach_detach_xdp(int *progfd, enum net_attach_type 
> > *attach_type,
> > int *ifindex)
> >  {
> > @@ -323,6 +348,31 @@ static int do_attach(int argc, char **argv)
> > return 0;
> >  }
> >
> > +static int do_detach(int argc, char **argv)
> > +{
> > +   enum net_attach_type attach_type;
> > +   int err, progfd, ifindex;
> > +
> > +   err = parse_detach_args(argc, argv, &attach_type, &ifindex);
> > +   if (err)
> > +   return err;
> > +
> > +   /* to detach xdp prog */
> > +   progfd = -1;
> > +   if (is_prefix("xdp", attach_type_strings[attach_type]))
> > +   err = do_attach_detach_xdp(&progfd, &attach_type, &ifindex);
>
> Similar to previous patch, parameters no need to be pointer.
>

I will change the parameter as pass by value.

> > +
> > +   if (err < 0) {
> > +   p_err("link set %s failed", 
> > attach_type_strings[attach_type]);
> > +   return -1;
>
> Maybe "return err"?
>

Hadn't thought of that.
I will change to it!

> > +   }
> > +
> > +   if (json_output)
> > +   jsonw_null(json_wtr);
> > +
> > +   return 0;
> > +}
> > +
> >  static int do_show(int argc, char **argv)
> >  {
> > struct bpf_attach_info attach_info = {};
> > @@ -406,6 +456,7 @@ static int do_help(int argc, char **argv)
> > fprintf(stderr,
> > "Usage: %s %s { show | list } [dev ]\n"
> > "   %s %s attach PROG LOAD_TYPE \n"
> > +   "   %s %s detach LOAD_TYPE \n"
> > "   %s %s help\n"
> > "\n"
> > "   " HELP_SPEC_PROGRAM "\n"
> > @@ -415,7 +466,8 @@ static int do_help(int argc, char **argv)
> > "  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],
> > +   bin_name, argv[-2]);
> >
> > return 0;
> >  }
> > @@ -424,6 +476,7 @@ static const struct cmd cmds[] = {
> > { "show",   do_show },
> > { "list",   do_show },
> > { "attach", do_attach },
> > +   { "detach", do_detach },
> > { "help",   do_help },
> > { 0 }
> >  };
> > --
> > 2.20.1
> >

Thanks for the review!


Re: [v2,1/2] tools: bpftool: add net attach command to attach XDP on interface

2019-08-02 Thread Daniel T. Lee
On Fri, Aug 2, 2019 at 3:23 PM Y Song  wrote:
>
> On Thu, Aug 1, 2019 at 2:04 AM Daniel T. Lee  wrote:
> >
> > By this commit, using `bpftool net attach`, user can attach XDP prog on
> > interface. New type of enum 'net_attach_type' has been made, as stated at
> > cover-letter, the meaning of 'attach' is, prog will be attached on 
> > interface.
> >
> > BPF prog will be attached through libbpf 'bpf_set_link_xdp_fd'.
> >
> > Signed-off-by: Daniel T. Lee 
> > ---
> > Changes in v2:
> >   - command 'load' changed to 'attach' for the consistency
> >   - 'NET_ATTACH_TYPE_XDP_DRIVE' changed to 'NET_ATTACH_TYPE_XDP_DRIVER'
> >
> >  tools/bpf/bpftool/net.c | 107 +++-
> >  1 file changed, 106 insertions(+), 1 deletion(-)
> >
> > diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
> > index 67e99c56bc88..f3b57660b303 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,
> > +   __MAX_NET_ATTACH_TYPE
> > +};
> > +
> > +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",
> > +   [__MAX_NET_ATTACH_TYPE] = NULL,
> > +};
> > +
> > +static enum net_attach_type parse_attach_type(const char *str)
> > +{
> > +   enum net_attach_type type;
> > +
> > +   for (type = 0; type < __MAX_NET_ATTACH_TYPE; type++) {
> > +   if (attach_type_strings[type] &&
> > +  is_prefix(str, attach_type_strings[type]))
> > +   return type;
> > +   }
> > +
> > +   return __MAX_NET_ATTACH_TYPE;
> > +}
> > +
> >  static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
> >  {
> > struct bpf_netdev_t *netinfo = cookie;
> > @@ -223,6 +252,77 @@ static int query_flow_dissector(struct bpf_attach_info 
> > *attach_info)
> > return 0;
> >  }
> >
> > +static int parse_attach_args(int argc, char **argv, int *progfd,
> > +enum net_attach_type *attach_type, int 
> > *ifindex)
> > +{
> > +   if (!REQ_ARGS(3))
> > +   return -EINVAL;
> > +
> > +   *progfd = prog_parse_fd(&argc, &argv);
> > +   if (*progfd < 0)
> > +   return *progfd;
> > +
> > +   *attach_type = parse_attach_type(*argv);
> > +   if (*attach_type == __MAX_NET_ATTACH_TYPE) {
> > +   p_err("invalid net attach/detach type");
> > +   return -EINVAL;
> > +   }
> > +
> > +   NEXT_ARG();
> > +   if (!REQ_ARGS(1))
> > +   return -EINVAL;
> > +
> > +   *ifindex = if_nametoindex(*argv);
> > +   if (!*ifindex) {
> > +   p_err("Invalid ifname");
>
> Do you want to use the full function name "invalid if_nametoindex" here?
>

No. I was trying to fix the message as "Invalid devname", since the
word "devanme"
is mentioned in 'bpftool net help'.

> > +   return -EINVAL;
> > +   }
> > +
> > +   return 0;
> > +}
> > +
> > +static int do_attach_detach_xdp(int *progfd, enum net_attach_type 
> > *attach_type,
> > +   int *ifindex)
>
> You can just use plain int as the argument type here.
>

I will change the parameter as pass by value.

> > +{
> > +   __u32 flags;
> > +   int err;
> > +
> > +   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;
> > +
> > +   err = bpf_set_link_xdp_fd(*ifindex, *progfd, flags);

Re: [v2,1/2] tools: bpftool: add net attach command to attach XDP on interface

2019-08-03 Thread Daniel T. Lee
On Sat, Aug 3, 2019 at 3:39 AM Jakub Kicinski
 wrote:
>
> On Fri, 2 Aug 2019 14:02:29 +0900, Daniel T. Lee wrote:
> > On Fri, Aug 2, 2019 at 8:36 AM Jakub Kicinski  wrote:
> > > On Thu,  1 Aug 2019 17:11:32 +0900, Daniel T. Lee wrote:
> > > > By this commit, using `bpftool net attach`, user can attach XDP prog on
> > > > interface. New type of enum 'net_attach_type' has been made, as stated 
> > > > at
> > > > cover-letter, the meaning of 'attach' is, prog will be attached on 
> > > > interface.
> > > >
> > > > BPF prog will be attached through libbpf 'bpf_set_link_xdp_fd'.
> > > >
> > > > Signed-off-by: Daniel T. Lee 
> > > > ---
> > > > Changes in v2:
> > > >   - command 'load' changed to 'attach' for the consistency
> > > >   - 'NET_ATTACH_TYPE_XDP_DRIVE' changed to 'NET_ATTACH_TYPE_XDP_DRIVER'
> > > >
> > > >  tools/bpf/bpftool/net.c | 107 +++-
> > > >  1 file changed, 106 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
> > > > index 67e99c56bc88..f3b57660b303 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,
> > > > + __MAX_NET_ATTACH_TYPE
> > > > +};
> > > > +
> > > > +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",
> > > > + [__MAX_NET_ATTACH_TYPE] = NULL,
> > >
> > > Not sure if the terminator is necessary,
> > > ARRAY_SIZE(attach_type_strings) should suffice?
> >
> > Yes, ARRAY_SIZE is fine though. But I was just trying to make below
> > 'parse_attach_type' consistent with 'parse_attach_type' from the 'prog.c'.
> > At 'prog.c', It has same terminator at 'attach_type_strings'.
> >
> > Should I change it or keep it?
>
> Oh well, I guess there is some precedent for that :S
>
> Quick grep for const char * const reveals we have around 7 non-NULL
> terminated arrays, and 2 NULL terminated. Plus the NULL-terminated
> don't align the '=' sign, while most do.
>
> it's not a big deal, my preference is for not NULL terminating here,
> and aligning '='.
>

I think following the majority, is better for this case.

Like you mentioned, those 2 NULL-terminated arrays are at 'cgroup.c'
and 'prog.c'
and the strings they are defining are 'bpf_attach_type' which is from
uapi 'bpf.h'.

And, in my guess, the reason for those 2 arrays uses NULL-terminator
is because enum from 'bpf_attach_type' has '__MAX_BPF_ATTACH_TYPE' at
the end.

Actually I was kind of uncomfortable with adding an enum since it's
not used globally and *only* used in 'net.c' context. Instead of using
hacky enum entry, stick to the majority, ARRAY_SIZE, is better to keep
consistency.

I'll update this to next version with '=' alignment.

>
> > > > + NEXT_ARG();
> > > > + if (!REQ_ARGS(1))
> > > > + return -EINVAL;
> > >
> > > Error message needed here.
> > >
> >
> > Actually it provides error message like:
> > Error: 'xdp' needs at least 1 arguments, 0 found
> >
> > are you suggesting that any additional error message is necessary?
>
> Ah, sorry, I missed REQ_ARGS() there!
>
> > > > + return -EINVAL;
> > > > + }
> > >
> > > Please require the dev keyword before the interface name.
> > > That'll make it feel closer to prog load syntax.
> >
> > If adding the dev keyword before interface name, will it be too long to 
> > type in?
>
> I think it's probably muscle memory for most. Plus we have excellent
> bash co

[v3,3/4] tools: bpftool: add bash-completion for net attach/detach

2019-08-06 Thread Daniel T. Lee
This commit adds bash-completion for new "net attach/detach"
subcommand for attaching XDP program on interface.

Signed-off-by: Daniel T. Lee 
---
 tools/bpf/bpftool/bash-completion/bpftool | 64 +++
 1 file changed, 55 insertions(+), 9 deletions(-)

diff --git a/tools/bpf/bpftool/bash-completion/bpftool 
b/tools/bpf/bpftool/bash-completion/bpftool
index c8f42e1fcbc9..1d81cb09d478 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -201,6 +201,10 @@ _bpftool()
 _bpftool_get_prog_tags
 return 0
 ;;
+dev)
+_sysfs_get_netdevs
+return 0
+;;
 file|pinned)
 _filedir
 return 0
@@ -399,10 +403,6 @@ _bpftool()
 _filedir
 return 0
 ;;
-dev)
-_sysfs_get_netdevs
-return 0
-;;
 *)
 COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
 _bpftool_once_attr 'type'
@@ -498,10 +498,6 @@ _bpftool()
 key|value|flags|name|entries)
 return 0
 ;;
-dev)
-_sysfs_get_netdevs
-return 0
-;;
 *)
 _bpftool_once_attr 'type'
 _bpftool_once_attr 'key'
@@ -775,11 +771,61 @@ _bpftool()
 esac
 ;;
 net)
+local PROG_TYPE='id pinned tag'
+local ATTACH_TYPES='xdp xdpgeneric xdpdrv xdpoffload'
 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 ]] && \
 COMPREPLY=( $( compgen -W 'help \
-show list' -- "$cur" ) )
+show list attach detach' -- "$cur" ) )
 ;;
 esac
 ;;
-- 
2.20.1



[v3,2/4] tools: bpftool: add net detach command to detach XDP on interface

2019-08-06 Thread Daniel T. Lee
By this commit, using `bpftool net detach`, the attached XDP prog can
be detached. Detaching the BPF prog will be done through libbpf
'bpf_set_link_xdp_fd' with the progfd set to -1.

Signed-off-by: Daniel T. Lee 
---
 tools/bpf/bpftool/net.c | 42 -
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index c05a3fac5cac..7be96acb08e0 100644
--- a/tools/bpf/bpftool/net.c
+++ b/tools/bpf/bpftool/net.c
@@ -343,6 +343,43 @@ static int do_attach(int argc, char **argv)
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 == max_net_attach_type) {
+   p_err("invalid net attach/detach type");
+   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",
+ attach_type_strings[attach_type]);
+   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 = {};
@@ -419,6 +456,7 @@ static int do_help(int argc, char **argv)
fprintf(stderr,
"Usage: %s %s { show | list } [dev ]\n"
"   %s %s attach ATTACH_TYPE PROG dev  [ overwrite 
]\n"
+   "   %s %s detach ATTACH_TYPE dev \n"
"   %s %s help\n"
"\n"
"   " HELP_SPEC_PROGRAM "\n"
@@ -429,7 +467,8 @@ static int do_help(int argc, char **argv)
"  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],
+   bin_name, argv[-2]);
 
return 0;
 }
@@ -438,6 +477,7 @@ static const struct cmd cmds[] = {
{ "show",   do_show },
{ "list",   do_show },
{ "attach", do_attach },
+   { "detach", do_detach },
{ "help",   do_help },
{ 0 }
 };
-- 
2.20.1



[v3,1/4] tools: bpftool: add net attach command to attach XDP on interface

2019-08-06 Thread Daniel T. Lee
By this commit, using `bpftool net attach`, user can attach XDP prog on
interface. New type of enum 'net_attach_type' has been made, as stated at
cover-letter, the meaning of 'attach' is, prog will be attached on interface.

With 'overwrite' option at argument, attached XDP program could be replaced.
Added new helper 'net_parse_dev' to parse the network device at argument.

BPF prog will be attached through libbpf 'bpf_set_link_xdp_fd'.

Signed-off-by: Daniel T. Lee 
---
 tools/bpf/bpftool/net.c | 141 
 1 file changed, 130 insertions(+), 11 deletions(-)

diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index 67e99c56bc88..c05a3fac5cac 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 max_net_attach_type = 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 < max_net_attach_type; type++) {
+   if (attach_type_strings[type] &&
+  is_prefix(str, attach_type_strings[type]))
+   return type;
+   }
+
+   return max_net_attach_type;
+}
+
 static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
 {
struct bpf_netdev_t *netinfo = cookie;
@@ -223,6 +252,97 @@ 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 == max_net_attach_type) {
+   p_err("invalid net attach/detach type");
+   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",
+ attach_type_strings[attach_type]);
+   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 = {};
@@ -231,17 +351,10 @@ static int do_show(int argc, char **argv)

[v3,0/4] tools: bpftool: add net attach/detach command to attach XDP prog

2019-08-06 Thread Daniel T. Lee
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 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 
  - added bash-completion and documentation

Changes in v2:
  - command 'load/unload' changed to 'attach/detach' for the consistency

Daniel T. Lee (4):
  tools: bpftool: add net attach command to attach XDP on interface
  tools: bpftool: add net detach command to detach XDP on interface
  tools: bpftool: add bash-completion for net attach/detach
  tools: bpftool: add documentation for net attach/detach

 .../bpf/bpftool/Documentation/bpftool-net.rst |  51 -
 tools/bpf/bpftool/bash-completion/bpftool |  64 ++-
 tools/bpf/bpftool/net.c   | 181 --
 3 files changed, 273 insertions(+), 23 deletions(-)

-- 
2.20.1



[v3,4/4] tools: bpftool: add documentation for net attach/detach

2019-08-06 Thread Daniel T. Lee
Since, new sub-command 'net attach/detach' has been added for
attaching XDP program on interface,
this commit documents usage and sample output of `net attach/detach`.

Signed-off-by: Daniel T. Lee 
---
 .../bpf/bpftool/Documentation/bpftool-net.rst | 51 +--
 1 file changed, 48 insertions(+), 3 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst 
b/tools/bpf/bpftool/Documentation/bpftool-net.rst
index d8e5237a2085..4ad1a380e186 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-net.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst
@@ -15,17 +15,22 @@ SYNOPSIS
*OPTIONS* := { [{ **-j** | **--json** }] [{ **-p** | **--pretty** }] }
 
*COMMANDS* :=
-   { **show** | **list** } [ **dev** name ] | **help**
+   { **show** | **list** | **attach** | **detach** | **help** }
 
 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**
+|
+|  *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
+|  *ATTACH_TYPE* := { **xdp** | **xdpgeneric** | **xdpdrv** | 
**xdpoffload** }
 
 DESCRIPTION
 ===
-   **bpftool net { show | list } [ dev name ]**
+   **bpftool net { show | list }** [ **dev** *name* ]
   List bpf program attachments in the kernel networking 
subsystem.
 
   Currently, only device driver xdp attachments and tc filter
@@ -47,6 +52,18 @@ DESCRIPTION
   all bpf programs attached to non clsact qdiscs, and finally 
all
   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, *ATTACH_TYPE* only contains XDP programs.
+
+   **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, *ATTACH_TYPE* only contains XDP programs.
+
**bpftool net help**
  Print short help message.
 
@@ -137,6 +154,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
 
-- 
2.20.1



[v4 2/4] samples: pktgen: fix proc_cmd command result check logic

2019-10-03 Thread Daniel T. Lee
Currently, proc_cmd is used to dispatch command to 'pg_ctrl', 'pg_thread',
'pg_set'. proc_cmd is designed to check command result with grep the
"Result:", but this might fail since this string is only shown in
'pg_thread' and 'pg_set'.

This commit fixes this logic by grep-ing the "Result:" string only when
the command is not for 'pg_ctrl'.

For clarity of an execution flow, 'errexit' flag has been set.

To cleanup pktgen on exit, trap has been added for EXIT signal.

Signed-off-by: Daniel T. Lee 
---
 samples/pktgen/functions.sh | 20 +---
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/samples/pktgen/functions.sh b/samples/pktgen/functions.sh
index 4af4046d71be..e1865660b033 100644
--- a/samples/pktgen/functions.sh
+++ b/samples/pktgen/functions.sh
@@ -5,6 +5,8 @@
 # Author: Jesper Dangaaard Brouer
 # License: GPL
 
+set -o errexit
+
 ## -- General shell logging cmds --
 function err() {
 local exitcode=$1
@@ -58,6 +60,7 @@ function pg_set() {
 function proc_cmd() {
 local result
 local proc_file=$1
+local status=0
 # after shift, the remaining args are contained in $@
 shift
 local proc_ctrl=${PROC_DIR}/$proc_file
@@ -73,13 +76,14 @@ function proc_cmd() {
echo "cmd: $@ > $proc_ctrl"
 fi
 # Quoting of "$@" is important for space expansion
-echo "$@" > "$proc_ctrl"
-local status=$?
-
-result=$(grep "Result: OK:" $proc_ctrl)
-# Due to pgctrl, cannot use exit code $? from grep
-if [[ "$result" == "" ]]; then
-   grep "Result:" $proc_ctrl >&2
+echo "$@" > "$proc_ctrl" || status=$?
+
+if [[ "$proc_file" != "pgctrl" ]]; then
+result=$(grep "Result: OK:" $proc_ctrl) || true
+# Due to pgctrl, cannot use exit code $? from grep
+if [[ "$result" == "" ]]; then
+grep "Result:" $proc_ctrl >&2
+fi
 fi
 if (( $status != 0 )); then
err 5 "Write error($status) occurred cmd: \"$@ > $proc_ctrl\""
@@ -105,6 +109,8 @@ function pgset() {
 fi
 }
 
+trap 'pg_ctrl "reset"' EXIT
+
 ## -- General shell tricks --
 
 function root_check_run_with_sudo() {
-- 
2.20.1



[v4 1/4] samples: pktgen: make variable consistent with option

2019-10-03 Thread Daniel T. Lee
This commit changes variable names that can cause confusion.

For example, variable DST_MIN is quite confusing since the
keyword 'udp_dst_min' and keyword 'dst_min' is used with pg_ctrl.

On the following commit, 'dst_min' will be used to set destination IP,
and the existing variable name DST_MIN should be changed.

Variable names are matched to the exact keyword used with pg_ctrl.

Signed-off-by: Daniel T. Lee 
---
 .../pktgen_bench_xmit_mode_netif_receive.sh  |  8 
 .../pktgen/pktgen_bench_xmit_mode_queue_xmit.sh  |  8 
 samples/pktgen/pktgen_sample01_simple.sh | 16 
 samples/pktgen/pktgen_sample02_multiqueue.sh | 16 
 .../pktgen/pktgen_sample03_burst_single_flow.sh  |  8 
 samples/pktgen/pktgen_sample04_many_flows.sh |  8 
 .../pktgen/pktgen_sample05_flow_per_thread.sh|  8 
 ...en_sample06_numa_awared_queue_irq_affinity.sh | 16 
 8 files changed, 44 insertions(+), 44 deletions(-)

diff --git a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
index e14b1a9144d9..9b74502c58f7 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
@@ -42,8 +42,8 @@ fi
 [ -z "$BURST" ] && BURST=1024
 [ -z "$COUNT" ] && COUNT="1000" # Zero means indefinitely
 if [ -n "$DST_PORT" ]; then
-read -r DST_MIN DST_MAX <<< $(parse_ports $DST_PORT)
-validate_ports $DST_MIN $DST_MAX
+read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
+validate_ports $UDP_DST_MIN $UDP_DST_MAX
 fi
 
 # Base Config
@@ -76,8 +76,8 @@ for ((thread = $F_THREAD; thread <= $L_THREAD; thread++)); do
 if [ -n "$DST_PORT" ]; then
# Single destination port or random port range
pg_set $dev "flag UDPDST_RND"
-   pg_set $dev "udp_dst_min $DST_MIN"
-   pg_set $dev "udp_dst_max $DST_MAX"
+   pg_set $dev "udp_dst_min $UDP_DST_MIN"
+   pg_set $dev "udp_dst_max $UDP_DST_MAX"
 fi
 
 # Inject packet into RX path of stack
diff --git a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
index 82c3e504e056..0f332555b40d 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
@@ -25,8 +25,8 @@ if [[ -n "$BURST" ]]; then
 fi
 [ -z "$COUNT" ] && COUNT="1000" # Zero means indefinitely
 if [ -n "$DST_PORT" ]; then
-read -r DST_MIN DST_MAX <<< $(parse_ports $DST_PORT)
-validate_ports $DST_MIN $DST_MAX
+read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
+validate_ports $UDP_DST_MIN $UDP_DST_MAX
 fi
 
 # Base Config
@@ -59,8 +59,8 @@ for ((thread = $F_THREAD; thread <= $L_THREAD; thread++)); do
 if [ -n "$DST_PORT" ]; then
# Single destination port or random port range
pg_set $dev "flag UDPDST_RND"
-   pg_set $dev "udp_dst_min $DST_MIN"
-   pg_set $dev "udp_dst_max $DST_MAX"
+   pg_set $dev "udp_dst_min $UDP_DST_MIN"
+   pg_set $dev "udp_dst_max $UDP_DST_MAX"
 fi
 
 # Inject packet into TX qdisc egress path of stack
diff --git a/samples/pktgen/pktgen_sample01_simple.sh 
b/samples/pktgen/pktgen_sample01_simple.sh
index d1702fdde8f3..063ec0998906 100755
--- a/samples/pktgen/pktgen_sample01_simple.sh
+++ b/samples/pktgen/pktgen_sample01_simple.sh
@@ -23,16 +23,16 @@ fi
 [ -z "$DST_MAC" ] && usage && err 2 "Must specify -m dst_mac"
 [ -z "$COUNT" ]   && COUNT="10" # Zero means indefinitely
 if [ -n "$DST_PORT" ]; then
-read -r DST_MIN DST_MAX <<< $(parse_ports $DST_PORT)
-validate_ports $DST_MIN $DST_MAX
+read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
+validate_ports $UDP_DST_MIN $UDP_DST_MAX
 fi
 
 # Base Config
 DELAY="0"# Zero means max speed
 
 # Flow variation random source port between min and max
-UDP_MIN=9
-UDP_MAX=109
+UDP_SRC_MIN=9
+UDP_SRC_MAX=109
 
 # General cleanup everything since last run
 # (especially important if other threads were configured by other scripts)
@@ -66,14 +66,14 @@ pg_set $DEV "dst$IP6 $DEST_IP"
 if [ -n "$DST_PORT" ]; then
 # Single destination port or random port range
 pg_set $DEV "flag UDPDST_RND"
-pg_set $DEV "udp_dst_min $DST_MIN"
-pg_set $DEV "udp_dst_max $DST_MAX"
+pg_set $DEV "udp_dst_min $UDP_DST_MIN"
+pg_set $DEV "udp_dst_max $UDP_DST_MAX"
 fi
 
 # Setup random UDP port src range
 pg_set $DEV "flag 

[v4 3/4] samples: pktgen: add helper functions for IP(v4/v6) CIDR parsing

2019-10-03 Thread Daniel T. Lee
This commit adds CIDR parsing and IP validate helper function to parse
single IP or range of IP with CIDR. (e.g. 198.18.0.0/15)

Validating the address should be preceded prior to the parsing.
Helpers will be used in prior to set target address in samples/pktgen.

Signed-off-by: Daniel T. Lee 
---
Changes since v3:
 * Set errexit option to stop script execution on error

Changes since v4:
 * Set errexit option moved to previous commit
 * previously, the reason 'parse_addr' won't exit on error was using 
   here-string which runs on subshell.
 * to avoid this, 'validate_addr' is removed from the 'parse_addr' flow.
 * to remove duplicated comparison, added 'in_between' helper func

samples/pktgen/functions.sh | 137 +++-
 1 file changed, 134 insertions(+), 3 deletions(-)

diff --git a/samples/pktgen/functions.sh b/samples/pktgen/functions.sh
index e1865660b033..a450a0844313 100644
--- a/samples/pktgen/functions.sh
+++ b/samples/pktgen/functions.sh
@@ -169,6 +169,137 @@ function get_node_cpus()
echo $node_cpu_list
 }
 
+# Check $1 is in between $2, $3 ($2 <= $1 <= $3)
+function in_between() { [[ ($1 -ge $2) && ($1 -le $3) ]] ; }
+
+# Extend shrunken IPv6 address.
+# fe80::42:bcff:fe84:e10a => fe80:0:0:0:42:bcff:fe84:e10a
+function extend_addr6()
+{
+local addr=$1
+local sep=: sep2=::
+local sep_cnt=$(tr -cd $sep <<< $1 | wc -c)
+local shrink
+
+# separator count should be (2 <= $sep_cnt <= 7)
+if ! (in_between $sep_cnt 2 7); then
+err 5 "Invalid IP6 address: $1"
+fi
+
+# if shrink '::' occurs multiple, it's malformed.
+shrink=( $(egrep -o "$sep{2,}" <<< $addr) )
+if [[ ${#shrink[@]} -ne 0 ]]; then
+if [[ ${#shrink[@]} -gt 1 || ( ${shrink[0]} != $sep2 ) ]]; then
+err 5 "Invalid IP6 address: $1"
+fi
+fi
+
+# add 0 at begin & end, and extend addr by adding :0
+[[ ${addr:0:1} == $sep ]] && addr=0${addr}
+[[ ${addr: -1} == $sep ]] && addr=${addr}0
+echo "${addr/$sep2/$(printf ':0%.s' $(seq $[8-sep_cnt])):}"
+}
+
+# Given a single IP(v4/v6) address, whether it is valid.
+function validate_addr()
+{
+# check function is called with (funcname)6
+[[ ${FUNCNAME[1]: -1} == 6 ]] && local IP6=6
+local bitlen=$[ IP6 ? 128 : 32 ]
+local len=$[ IP6 ? 8 : 4 ]
+local max=$[ 2**(len*2)-1 ]
+local net prefix
+local addr sep
+
+IFS='/' read net prefix <<< $1
+[[ $IP6 ]] && net=$(extend_addr6 $net)
+
+# if prefix exists, check (0 <= $prefix <= $bitlen)
+if [[ -n $prefix ]]; then
+if ! (in_between $prefix 0 $bitlen); then
+err 5 "Invalid prefix: /$prefix"
+fi
+fi
+
+# set separator for each IP(v4/v6)
+[[ $IP6 ]] && sep=: || sep=.
+IFS=$sep read -a addr <<< $net
+
+# array length
+if [[ ${#addr[@]} != $len ]]; then
+err 5 "Invalid IP$IP6 address: $1"
+fi
+
+# check each digit (0 <= $digit <= $max)
+for digit in "${addr[@]}"; do
+[[ $IP6 ]] && digit=$[ 16#$digit ]
+if ! (in_between $digit 0 $max); then
+err 5 "Invalid IP$IP6 address: $1"
+fi
+done
+
+return 0
+}
+
+function validate_addr6() { validate_addr $@ ; }
+
+# Given a single IP(v4/v6) or CIDR, return minimum and maximum IP addr.
+function parse_addr()
+{
+# check function is called with (funcname)6
+[[ ${FUNCNAME[1]: -1} == 6 ]] && local IP6=6
+local net prefix
+local min_ip max_ip
+
+IFS='/' read net prefix <<< $1
+[[ $IP6 ]] && net=$(extend_addr6 $net)
+
+if [[ -z $prefix ]]; then
+min_ip=$net
+max_ip=$net
+else
+# defining array for converting Decimal 2 Binary
+#  0001 0010 0011 0100 ...
+local d2b='{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}'
+[[ $IP6 ]] && d2b+=$d2b
+eval local D2B=($d2b)
+
+local bitlen=$[ IP6 ? 128 : 32 ]
+local remain=$[ bitlen-prefix ]
+local octet=$[ IP6 ? 16 : 8 ]
+local min_mask max_mask
+local min max
+local ip_bit
+local ip sep
+
+# set separator for each IP(v4/v6)
+[[ $IP6 ]] && sep=: || sep=.
+IFS=$sep read -ra ip <<< $net
+
+min_mask="$(printf '1%.s' $(seq $prefix))$(printf '0%.s' $(seq 
$remain))"
+max_mask="$(printf '0%.s' $(seq $prefix))$(printf '1%.s' $(seq 
$remain))"
+
+# calculate min/max ip with &,| operator
+for i in "${!ip[@]}"; do
+digit=$[ IP6 ? 16#${ip[$i]} : ${ip[$i]} ]
+

[v4 4/4] samples: pktgen: allow to specify destination IP range (CIDR)

2019-10-03 Thread Daniel T. Lee
Currently, kernel pktgen has the feature to specify destination
address range for sending packet. (e.g. pgset "dst_min/dst_max")

But on samples, each pktgen script doesn't have any option to achieve this.

This commit adds the feature to specify the destination address range with CIDR.

-d : ($DEST_IP)   destination IP. CIDR (e.g. 198.18.0.0/15) is also allowed

# ./pktgen_sample01_simple.sh -6 -d fe80::20/126 -p 3000 -n 4
# tcpdump ip6 and udp
05:14:18.082285 IP6 fe80::99.71 > fe80::23.3000: UDP, length 16
05:14:18.082564 IP6 fe80::99.43 > fe80::23.3000: UDP, length 16
05:14:18.083366 IP6 fe80::99.107 > fe80::22.3000: UDP, length 16
05:14:18.083585 IP6 fe80::99.97 > fe80::21.3000: UDP, length 16

Signed-off-by: Daniel T. Lee 
---
Changes since v4:
 * 'validate_addr' is called prior to 'parse_addr'

 samples/pktgen/README.rst  |  2 +-
 samples/pktgen/parameters.sh   |  2 +-
 .../pktgen/pktgen_bench_xmit_mode_netif_receive.sh |  7 ++-
 .../pktgen/pktgen_bench_xmit_mode_queue_xmit.sh|  7 ++-
 samples/pktgen/pktgen_sample01_simple.sh   |  7 ++-
 samples/pktgen/pktgen_sample02_multiqueue.sh   |  7 ++-
 .../pktgen/pktgen_sample03_burst_single_flow.sh|  7 ++-
 samples/pktgen/pktgen_sample04_many_flows.sh   | 14 +++---
 samples/pktgen/pktgen_sample05_flow_per_thread.sh  |  7 ++-
 ...tgen_sample06_numa_awared_queue_irq_affinity.sh |  7 ++-
 10 files changed, 55 insertions(+), 12 deletions(-)

diff --git a/samples/pktgen/README.rst b/samples/pktgen/README.rst
index fd39215db508..3f6483e8b2df 100644
--- a/samples/pktgen/README.rst
+++ b/samples/pktgen/README.rst
@@ -18,7 +18,7 @@ across the sample scripts.  Usage example is printed on 
errors::
  Usage: ./pktgen_sample01_simple.sh [-vx] -i ethX
   -i : ($DEV)   output interface/device (required)
   -s : ($PKT_SIZE)  packet size
-  -d : ($DEST_IP)   destination IP
+  -d : ($DEST_IP)   destination IP. CIDR (e.g. 198.18.0.0/15) is also allowed
   -m : ($DST_MAC)   destination MAC-addr
   -p : ($DST_PORT)  destination PORT range (e.g. 433-444) is also allowed
   -t : ($THREADS)   threads to start
diff --git a/samples/pktgen/parameters.sh b/samples/pktgen/parameters.sh
index a06b00a0c7b6..ff0ed474fee9 100644
--- a/samples/pktgen/parameters.sh
+++ b/samples/pktgen/parameters.sh
@@ -8,7 +8,7 @@ function usage() {
 echo "Usage: $0 [-vx] -i ethX"
 echo "  -i : (\$DEV)   output interface/device (required)"
 echo "  -s : (\$PKT_SIZE)  packet size"
-echo "  -d : (\$DEST_IP)   destination IP"
+echo "  -d : (\$DEST_IP)   destination IP. CIDR (e.g. 198.18.0.0/15) is 
also allowed"
 echo "  -m : (\$DST_MAC)   destination MAC-addr"
 echo "  -p : (\$DST_PORT)  destination PORT range (e.g. 433-444) is also 
allowed"
 echo "  -t : (\$THREADS)   threads to start"
diff --git a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
index 9b74502c58f7..1b6204125d2d 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
@@ -41,6 +41,10 @@ fi
 [ -z "$DST_MAC" ] && DST_MAC="90:e2:ba:ff:ff:ff"
 [ -z "$BURST" ] && BURST=1024
 [ -z "$COUNT" ] && COUNT="1000" # Zero means indefinitely
+if [ -n "$DEST_IP" ]; then
+validate_addr${IP6} $DEST_IP
+read -r DST_MIN DST_MAX <<< $(parse_addr${IP6} $DEST_IP)
+fi
 if [ -n "$DST_PORT" ]; then
 read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
 validate_ports $UDP_DST_MIN $UDP_DST_MAX
@@ -71,7 +75,8 @@ for ((thread = $F_THREAD; thread <= $L_THREAD; thread++)); do
 
 # Destination
 pg_set $dev "dst_mac $DST_MAC"
-pg_set $dev "dst$IP6 $DEST_IP"
+pg_set $dev "dst${IP6}_min $DST_MIN"
+pg_set $dev "dst${IP6}_max $DST_MAX"
 
 if [ -n "$DST_PORT" ]; then
# Single destination port or random port range
diff --git a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
index 0f332555b40d..e607cb369b20 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
@@ -24,6 +24,10 @@ if [[ -n "$BURST" ]]; then
 err 1 "Bursting not supported for this mode"
 fi
 [ -z "$COUNT" ] && COUNT="1000" # Zero means indefinitely
+if [ -n "$DEST_IP" ]; then
+validate_addr${IP6} $DEST_IP
+read -r DST_MIN DST_MAX <<< $(parse_addr${IP6} $DEST_IP)
+fi
 if [ -n "$DST_PORT" ]; then
 read -r UDP_DST_MIN UDP_DST_MAX <<< $

Re: [v4 1/4] samples: pktgen: make variable consistent with option

2019-10-04 Thread Daniel T. Lee
On Fri, Oct 4, 2019 at 9:52 PM Jesper Dangaard Brouer  wrote:
>
>
> On Fri,  4 Oct 2019 10:32:58 +0900 "Daniel T. Lee"  
> wrote:
>
> > [...]
>

Thanks for the review!

> A general comment, you forgot a cover letter for your patchset.
>

At first, I thought the size of the patchset (the feature to enhance)
was small so
I didn't include it with intent, but now it gets bigger and it seems
necessary for cover letter.

When the next version is needed, I'll include it.

> And also forgot the "PATCH" part of subj. but patchwork still found it:
> https://patchwork.ozlabs.org/project/netdev/list/?series=134102&state=2a
>

I'm not sure I'm following.
Are you saying that the word "PATCH" should be included in prefix?
$ git format-patch --subject-prefix="PATCH,v5"
like this?

And again, I really appreciate your time and effort for the review.

Thanks,
Daniel
>
> --
> Best regards,
>   Jesper Dangaard Brouer
>   MSc.CS, Principal Kernel Engineer at Red Hat
>   LinkedIn: http://www.linkedin.com/in/brouer


Re: [v4 1/4] samples: pktgen: make variable consistent with option

2019-10-04 Thread Daniel T. Lee
On Fri, Oct 4, 2019 at 10:41 PM Jesper Dangaard Brouer
 wrote:
>
> On Fri, 4 Oct 2019 22:28:26 +0900
> "Daniel T. Lee"  wrote:
>
> > On Fri, Oct 4, 2019 at 9:52 PM Jesper Dangaard Brouer  
> > wrote:
> > >
> > >
> > > On Fri,  4 Oct 2019 10:32:58 +0900 "Daniel T. Lee" 
> > >  wrote:
> > >
> > > > [...]
> > >
> >
> > Thanks for the review!
> >
> > > A general comment, you forgot a cover letter for your patchset.
> > >
> >
> > At first, I thought the size of the patchset (the feature to enhance)
> > was small so
> > I didn't include it with intent, but now it gets bigger and it seems
> > necessary for cover letter.
> >
> > When the next version is needed, I'll include it.
> >
> > > And also forgot the "PATCH" part of subj. but patchwork still found it:
> > > https://patchwork.ozlabs.org/project/netdev/list/?series=134102&state=2a
> > >
> >
> > I'm not sure I'm following.
> > Are you saying that the word "PATCH" should be included in prefix?
> > $ git format-patch --subject-prefix="PATCH,v5"
> > like this?
>
> I would say "[PATCH net-next v5]" as you should also say which kernel
> tree, in this case net-next.
>
> All the rules are documented here:
>  https://www.kernel.org/doc/html/latest/process/index.html
>  https://www.kernel.org/doc/html/latest/process/submitting-patches.html
>
> This netdev list have it's own extra rules:
>  https://www.kernel.org/doc/html/latest/networking/netdev-FAQ.html
>

Thanks for the confirmation and letting me know.

I'll stick to it!

Thanks,
Daniel

> --
> Best regards,
>   Jesper Dangaard Brouer
>   MSc.CS, Principal Kernel Engineer at Red Hat
>   LinkedIn: http://www.linkedin.com/in/brouer


Re: [v4 2/4] samples: pktgen: fix proc_cmd command result check logic

2019-10-04 Thread Daniel T. Lee
On Fri, Oct 4, 2019 at 10:24 PM Jesper Dangaard Brouer
 wrote:
>
> [...]
>
> Is this comment still relevant?  You just excluded "pgctrl" from
> getting into this section.
>

Oops, will fix it right away.

> > +if [[ "$result" == "" ]]; then
> > +grep "Result:" $proc_ctrl >&2
>
> Missing tap/indention?
>
> > +fi
> >  fi
> >  if (( $status != 0 )); then
> >   err 5 "Write error($status) occurred cmd: \"$@ > $proc_ctrl\""
> > @@ -105,6 +109,8 @@ function pgset() {
> >  fi
> >  }
> >
> > +trap 'pg_ctrl "reset"' EXIT
> > +
>
> This line is activated when I ctrl-C the scripts, but something weird
> happens, it reports:
>
>  ERROR: proc file:/proc/net/pktgen/pgctrl not writable, not root?!
>

Seems, the error is shown when the script is executed without sudo.
By grep-ing the debug info with 'set -x', you can find out that script elevate
itself to sudo by 'root_check_run_with_sudo'.

As you can see, there are three 'pg_ctrl reset'.

First one is called as preparation for packet sending,
Second is called as trap EXIT when sudo elevated script is done and exit.
Last one is also called as trap EXIT, but it is not executed as sudo.



$ ./pktgen_sample01_simple.sh 1>/dev/null 2>out
$ cat out | egrep -A 2 -B 2 'trap|sudo|pg_ctrl reset'
...
++ trap 'pg_ctrl "reset"' EXIT
+ root_check_run_with_sudo
+ '[' 1000 -ne 0 ']'
+ '[' -x ./pktgen_sample01_simple.sh ']'
+ info 'Not root, running with sudo'
+ [[ -n '' ]]
+ sudo ./pktgen_sample01_simple.sh
++ export PROC_DIR=/proc/net/pktgen
++ PROC_DIR=/proc/net/pktgen
++ trap 'pg_ctrl "reset"' EXIT
+ root_check_run_with_sudo
+ '[' 0 -ne 0 ']'
+ source ./parameters.sh
--
+ UDP_SRC_MIN=9
+ UDP_SRC_MAX=109
+ pg_ctrl reset
+ local proc_file=pgctrl
+ proc_cmd pgctrl reset
--
+ echo 'Result device: wlp2s0'
+ cat /proc/net/pktgen/wlp2s0
+ pg_ctrl reset
+ local proc_file=pgctrl
+ proc_cmd pgctrl reset
--
+ ((  0 != 0  ))
+ exit 0
+ pg_ctrl reset
+ local proc_file=pgctrl
+ proc_cmd pgctrl reset


As for solution, only call 'pg_ctrl reset' when it's running as sudo
will solve the problem.
-trap 'pg_ctrl "reset"' EXIT
+trap '[[ $EUID -eq 0 ]] && pg_ctrl "reset"' EXIT

Will apply this at next version of patch.

Thanks,
Daniel

>
> >  ## -- General shell tricks --
> >
> >  function root_check_run_with_sudo() {
>
>
>
> --
> Best regards,
>   Jesper Dangaard Brouer
>   MSc.CS, Principal Kernel Engineer at Red Hat
>   LinkedIn: http://www.linkedin.com/in/brouer


samples/bpf not working?

2019-10-04 Thread Daniel T. Lee
Currently, building the bpf samples isn't working.
Running make from the directory 'samples/bpf' will just shows following
result without compiling any samples.

$ make
make -C ../../ /git/linux/samples/bpf/ BPF_SAMPLES_PATH=/git/linux/samples/bpf
make[1]: Entering directory '/git/linux'
  CALLscripts/checksyscalls.sh
  CALLscripts/atomic/check-atomics.sh
  DESCEND  objtool
make[1]: Leaving directory '/git/linux'
$ ls *kern.o
ls: cannot access '*kern.o': No such file or directory

By using 'git bisect', found the problem is derived from below commit.
commit 394053f4a4b3 ("kbuild: make single targets work more correctly")

> Currently, the single target build directly descends into the directory
> of the target. For example,
>
> $ make foo/bar/baz.o
>
> ... directly descends into foo/bar/.
>
> On the other hand, the normal build usually descends one directory at
> a time, i.e. descends into foo/, and then foo/bar/.
>
> This difference causes some problems.
>
> [...]
>
> This commit fixes those problems by making the single target build
> descend in the same way as the normal build does.

Not familiar with kbuild, so I'm not sure why this led to build failure.
My humble guess is, samples/bpf/Makefile tries to run make from current
directory, 'sample/bpf', but somehow upper commit changed the way it works.

samples/bpf/Makefile:232
# Trick to allow make to be run from this directory
all:
$(MAKE) -C ../../ $(CURDIR)/ BPF_SAMPLES_PATH=$(CURDIR)

I've tried to figure out the problem with 'make --trace', but not sure why
it's not working. Just a hunch with build directory.

Any ideas to fix this problem?


[PATCH net-next v5 0/4] samples: pktgen: allow to specify destination IP range

2019-10-05 Thread Daniel T. Lee
Currently, pktgen script supports specify destination port range.

To further extend the capabilities, this commit allows to specify destination
IP range with CIDR when running pktgen script.

Specifying destination IP range will be useful on various situation such as 
testing RSS/RPS with randomizing n-tuple.

This patchset fixes the problem with checking the command result on proc_cmd,
and add feature to allow destination IP range.

Daniel T. Lee (4):
  samples: pktgen: make variable consistent with option
  samples: pktgen: fix proc_cmd command result check logic
  samples: pktgen: add helper functions for IP(v4/v6) CIDR parsing
  samples: pktgen: allow to specify destination IP range (CIDR)

 samples/pktgen/README.rst |   2 +-
 samples/pktgen/functions.sh   | 154 +-
 samples/pktgen/parameters.sh  |   2 +-
 .../pktgen_bench_xmit_mode_netif_receive.sh   |  15 +-
 .../pktgen_bench_xmit_mode_queue_xmit.sh  |  15 +-
 samples/pktgen/pktgen_sample01_simple.sh  |  23 ++-
 samples/pktgen/pktgen_sample02_multiqueue.sh  |  23 ++-
 .../pktgen_sample03_burst_single_flow.sh  |  15 +-
 samples/pktgen/pktgen_sample04_many_flows.sh  |  22 ++-
 .../pktgen/pktgen_sample05_flow_per_thread.sh |  15 +-
 ...sample06_numa_awared_queue_irq_affinity.sh |  23 ++-
 11 files changed, 244 insertions(+), 65 deletions(-)

-- 
2.20.1



[PATCH net-next v5 2/4] samples: pktgen: fix proc_cmd command result check logic

2019-10-05 Thread Daniel T. Lee


Currently, proc_cmd is used to dispatch command to 'pg_ctrl', 'pg_thread',
'pg_set'. proc_cmd is designed to check command result with grep the
"Result:", but this might fail since this string is only shown in
'pg_thread' and 'pg_set'.

This commit fixes this logic by grep-ing the "Result:" string only when
the command is not for 'pg_ctrl'.

For clarity of an execution flow, 'errexit' flag has been set.

To cleanup pktgen on exit, trap has been added for EXIT signal.

Signed-off-by: Daniel T. Lee 
---
Changes since v5:
 * when script runs sudo, run 'pg_ctrl "reset"' on EXIT with trap

 samples/pktgen/functions.sh | 17 +++--
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/samples/pktgen/functions.sh b/samples/pktgen/functions.sh
index 4af4046d71be..40873a5d1461 100644
--- a/samples/pktgen/functions.sh
+++ b/samples/pktgen/functions.sh
@@ -5,6 +5,8 @@
 # Author: Jesper Dangaaard Brouer
 # License: GPL
 
+set -o errexit
+
 ## -- General shell logging cmds --
 function err() {
 local exitcode=$1
@@ -58,6 +60,7 @@ function pg_set() {
 function proc_cmd() {
 local result
 local proc_file=$1
+local status=0
 # after shift, the remaining args are contained in $@
 shift
 local proc_ctrl=${PROC_DIR}/$proc_file
@@ -73,13 +76,13 @@ function proc_cmd() {
echo "cmd: $@ > $proc_ctrl"
 fi
 # Quoting of "$@" is important for space expansion
-echo "$@" > "$proc_ctrl"
-local status=$?
+echo "$@" > "$proc_ctrl" || status=$?
 
-result=$(grep "Result: OK:" $proc_ctrl)
-# Due to pgctrl, cannot use exit code $? from grep
-if [[ "$result" == "" ]]; then
-   grep "Result:" $proc_ctrl >&2
+if [[ "$proc_file" != "pgctrl" ]]; then
+result=$(grep "Result: OK:" $proc_ctrl) || true
+if [[ "$result" == "" ]]; then
+grep "Result:" $proc_ctrl >&2
+fi
 fi
 if (( $status != 0 )); then
err 5 "Write error($status) occurred cmd: \"$@ > $proc_ctrl\""
@@ -105,6 +108,8 @@ function pgset() {
 fi
 }
 
+[[ $EUID -eq 0 ]] && trap 'pg_ctrl "reset"' EXIT
+
 ## -- General shell tricks --
 
 function root_check_run_with_sudo() {
-- 
2.20.1



[PATCH net-next v5 1/4] samples: pktgen: make variable consistent with option

2019-10-05 Thread Daniel T. Lee
This commit changes variable names that can cause confusion.

For example, variable DST_MIN is quite confusing since the
keyword 'udp_dst_min' and keyword 'dst_min' is used with pg_ctrl.

On the following commit, 'dst_min' will be used to set destination IP,
and the existing variable name DST_MIN should be changed.

Variable names are matched to the exact keyword used with pg_ctrl.

Signed-off-by: Daniel T. Lee 
---
 .../pktgen_bench_xmit_mode_netif_receive.sh  |  8 
 .../pktgen/pktgen_bench_xmit_mode_queue_xmit.sh  |  8 
 samples/pktgen/pktgen_sample01_simple.sh | 16 
 samples/pktgen/pktgen_sample02_multiqueue.sh | 16 
 .../pktgen/pktgen_sample03_burst_single_flow.sh  |  8 
 samples/pktgen/pktgen_sample04_many_flows.sh |  8 
 .../pktgen/pktgen_sample05_flow_per_thread.sh|  8 
 ...en_sample06_numa_awared_queue_irq_affinity.sh | 16 
 8 files changed, 44 insertions(+), 44 deletions(-)

diff --git a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
index e14b1a9144d9..9b74502c58f7 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
@@ -42,8 +42,8 @@ fi
 [ -z "$BURST" ] && BURST=1024
 [ -z "$COUNT" ] && COUNT="1000" # Zero means indefinitely
 if [ -n "$DST_PORT" ]; then
-read -r DST_MIN DST_MAX <<< $(parse_ports $DST_PORT)
-validate_ports $DST_MIN $DST_MAX
+read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
+validate_ports $UDP_DST_MIN $UDP_DST_MAX
 fi
 
 # Base Config
@@ -76,8 +76,8 @@ for ((thread = $F_THREAD; thread <= $L_THREAD; thread++)); do
 if [ -n "$DST_PORT" ]; then
# Single destination port or random port range
pg_set $dev "flag UDPDST_RND"
-   pg_set $dev "udp_dst_min $DST_MIN"
-   pg_set $dev "udp_dst_max $DST_MAX"
+   pg_set $dev "udp_dst_min $UDP_DST_MIN"
+   pg_set $dev "udp_dst_max $UDP_DST_MAX"
 fi
 
 # Inject packet into RX path of stack
diff --git a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
index 82c3e504e056..0f332555b40d 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
@@ -25,8 +25,8 @@ if [[ -n "$BURST" ]]; then
 fi
 [ -z "$COUNT" ] && COUNT="1000" # Zero means indefinitely
 if [ -n "$DST_PORT" ]; then
-read -r DST_MIN DST_MAX <<< $(parse_ports $DST_PORT)
-validate_ports $DST_MIN $DST_MAX
+read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
+validate_ports $UDP_DST_MIN $UDP_DST_MAX
 fi
 
 # Base Config
@@ -59,8 +59,8 @@ for ((thread = $F_THREAD; thread <= $L_THREAD; thread++)); do
 if [ -n "$DST_PORT" ]; then
# Single destination port or random port range
pg_set $dev "flag UDPDST_RND"
-   pg_set $dev "udp_dst_min $DST_MIN"
-   pg_set $dev "udp_dst_max $DST_MAX"
+   pg_set $dev "udp_dst_min $UDP_DST_MIN"
+   pg_set $dev "udp_dst_max $UDP_DST_MAX"
 fi
 
 # Inject packet into TX qdisc egress path of stack
diff --git a/samples/pktgen/pktgen_sample01_simple.sh 
b/samples/pktgen/pktgen_sample01_simple.sh
index d1702fdde8f3..063ec0998906 100755
--- a/samples/pktgen/pktgen_sample01_simple.sh
+++ b/samples/pktgen/pktgen_sample01_simple.sh
@@ -23,16 +23,16 @@ fi
 [ -z "$DST_MAC" ] && usage && err 2 "Must specify -m dst_mac"
 [ -z "$COUNT" ]   && COUNT="10" # Zero means indefinitely
 if [ -n "$DST_PORT" ]; then
-read -r DST_MIN DST_MAX <<< $(parse_ports $DST_PORT)
-validate_ports $DST_MIN $DST_MAX
+read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
+validate_ports $UDP_DST_MIN $UDP_DST_MAX
 fi
 
 # Base Config
 DELAY="0"# Zero means max speed
 
 # Flow variation random source port between min and max
-UDP_MIN=9
-UDP_MAX=109
+UDP_SRC_MIN=9
+UDP_SRC_MAX=109
 
 # General cleanup everything since last run
 # (especially important if other threads were configured by other scripts)
@@ -66,14 +66,14 @@ pg_set $DEV "dst$IP6 $DEST_IP"
 if [ -n "$DST_PORT" ]; then
 # Single destination port or random port range
 pg_set $DEV "flag UDPDST_RND"
-pg_set $DEV "udp_dst_min $DST_MIN"
-pg_set $DEV "udp_dst_max $DST_MAX"
+pg_set $DEV "udp_dst_min $UDP_DST_MIN"
+pg_set $DEV "udp_dst_max $UDP_DST_MAX"
 fi
 
 # Setup random UDP port src range
 pg_set $DEV "flag 

[PATCH net-next v5 3/4] samples: pktgen: add helper functions for IP(v4/v6) CIDR parsing

2019-10-05 Thread Daniel T. Lee
This commit adds CIDR parsing and IP validate helper function to parse
single IP or range of IP with CIDR. (e.g. 198.18.0.0/15)

Validating the address should be preceded prior to the parsing.
Helpers will be used in prior to set target address in samples/pktgen.

Signed-off-by: Daniel T. Lee 
---
Changes since v3:
 * Set errexit option to stop script execution on error

Changes since v4:
 * Set errexit option moved to previous commit
 * previously, the reason 'parse_addr' won't exit on error was using
   here-string which runs on subshell.
 * to avoid this, 'validate_addr' is removed from the 'parse_addr' flow.
 * to remove duplicated comparison, added 'in_between' helper func

 samples/pktgen/functions.sh | 137 +++-
 1 file changed, 134 insertions(+), 3 deletions(-)

diff --git a/samples/pktgen/functions.sh b/samples/pktgen/functions.sh
index 40873a5d1461..858e74ae2279 100644
--- a/samples/pktgen/functions.sh
+++ b/samples/pktgen/functions.sh
@@ -168,6 +168,137 @@ function get_node_cpus()
echo $node_cpu_list
 }
 
+# Check $1 is in between $2, $3 ($2 <= $1 <= $3)
+function in_between() { [[ ($1 -ge $2) && ($1 -le $3) ]] ; }
+
+# Extend shrunken IPv6 address.
+# fe80::42:bcff:fe84:e10a => fe80:0:0:0:42:bcff:fe84:e10a
+function extend_addr6()
+{
+local addr=$1
+local sep=: sep2=::
+local sep_cnt=$(tr -cd $sep <<< $1 | wc -c)
+local shrink
+
+# separator count should be (2 <= $sep_cnt <= 7)
+if ! (in_between $sep_cnt 2 7); then
+err 5 "Invalid IP6 address: $1"
+fi
+
+# if shrink '::' occurs multiple, it's malformed.
+shrink=( $(egrep -o "$sep{2,}" <<< $addr) )
+if [[ ${#shrink[@]} -ne 0 ]]; then
+if [[ ${#shrink[@]} -gt 1 || ( ${shrink[0]} != $sep2 ) ]]; then
+err 5 "Invalid IP6 address: $1"
+fi
+fi
+
+# add 0 at begin & end, and extend addr by adding :0
+[[ ${addr:0:1} == $sep ]] && addr=0${addr}
+[[ ${addr: -1} == $sep ]] && addr=${addr}0
+echo "${addr/$sep2/$(printf ':0%.s' $(seq $[8-sep_cnt])):}"
+}
+
+# Given a single IP(v4/v6) address, whether it is valid.
+function validate_addr()
+{
+# check function is called with (funcname)6
+[[ ${FUNCNAME[1]: -1} == 6 ]] && local IP6=6
+local bitlen=$[ IP6 ? 128 : 32 ]
+local len=$[ IP6 ? 8 : 4 ]
+local max=$[ 2**(len*2)-1 ]
+local net prefix
+local addr sep
+
+IFS='/' read net prefix <<< $1
+[[ $IP6 ]] && net=$(extend_addr6 $net)
+
+# if prefix exists, check (0 <= $prefix <= $bitlen)
+if [[ -n $prefix ]]; then
+if ! (in_between $prefix 0 $bitlen); then
+err 5 "Invalid prefix: /$prefix"
+fi
+fi
+
+# set separator for each IP(v4/v6)
+[[ $IP6 ]] && sep=: || sep=.
+IFS=$sep read -a addr <<< $net
+
+# array length
+if [[ ${#addr[@]} != $len ]]; then
+err 5 "Invalid IP$IP6 address: $1"
+fi
+
+# check each digit (0 <= $digit <= $max)
+for digit in "${addr[@]}"; do
+[[ $IP6 ]] && digit=$[ 16#$digit ]
+if ! (in_between $digit 0 $max); then
+err 5 "Invalid IP$IP6 address: $1"
+fi
+done
+
+return 0
+}
+
+function validate_addr6() { validate_addr $@ ; }
+
+# Given a single IP(v4/v6) or CIDR, return minimum and maximum IP addr.
+function parse_addr()
+{
+# check function is called with (funcname)6
+[[ ${FUNCNAME[1]: -1} == 6 ]] && local IP6=6
+local net prefix
+local min_ip max_ip
+
+IFS='/' read net prefix <<< $1
+[[ $IP6 ]] && net=$(extend_addr6 $net)
+
+if [[ -z $prefix ]]; then
+min_ip=$net
+max_ip=$net
+else
+# defining array for converting Decimal 2 Binary
+#  0001 0010 0011 0100 ...
+local d2b='{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}'
+[[ $IP6 ]] && d2b+=$d2b
+eval local D2B=($d2b)
+
+local bitlen=$[ IP6 ? 128 : 32 ]
+local remain=$[ bitlen-prefix ]
+local octet=$[ IP6 ? 16 : 8 ]
+local min_mask max_mask
+local min max
+local ip_bit
+local ip sep
+
+# set separator for each IP(v4/v6)
+[[ $IP6 ]] && sep=: || sep=.
+IFS=$sep read -ra ip <<< $net
+
+min_mask="$(printf '1%.s' $(seq $prefix))$(printf '0%.s' $(seq 
$remain))"
+max_mask="$(printf '0%.s' $(seq $prefix))$(printf '1%.s' $(seq 
$remain))"
+
+# calculate min/max ip with &,| operator
+for i in "${!ip[@]}"; do
+digit=$[ IP6 ? 16#${ip[$i]} : ${ip[$i]} ]
+

[PATCH net-next v5 4/4] samples: pktgen: allow to specify destination IP range (CIDR)

2019-10-05 Thread Daniel T. Lee
Currently, kernel pktgen has the feature to specify destination
address range for sending packet. (e.g. pgset "dst_min/dst_max")

But on samples, each pktgen script doesn't have any option to achieve this.

This commit adds the feature to specify the destination address range with CIDR.

-d : ($DEST_IP)   destination IP. CIDR (e.g. 198.18.0.0/15) is also allowed

# ./pktgen_sample01_simple.sh -6 -d fe80::20/126 -p 3000 -n 4
# tcpdump ip6 and udp
05:14:18.082285 IP6 fe80::99.71 > fe80::23.3000: UDP, length 16
05:14:18.082564 IP6 fe80::99.43 > fe80::23.3000: UDP, length 16
05:14:18.083366 IP6 fe80::99.107 > fe80::22.3000: UDP, length 16
05:14:18.083585 IP6 fe80::99.97 > fe80::21.3000: UDP, length 16

Signed-off-by: Daniel T. Lee 
---
Changes since v4:
 * 'validate_addr' is called prior to 'parse_addr'

 samples/pktgen/README.rst  |  2 +-
 samples/pktgen/parameters.sh   |  2 +-
 .../pktgen/pktgen_bench_xmit_mode_netif_receive.sh |  7 ++-
 .../pktgen/pktgen_bench_xmit_mode_queue_xmit.sh|  7 ++-
 samples/pktgen/pktgen_sample01_simple.sh   |  7 ++-
 samples/pktgen/pktgen_sample02_multiqueue.sh   |  7 ++-
 .../pktgen/pktgen_sample03_burst_single_flow.sh|  7 ++-
 samples/pktgen/pktgen_sample04_many_flows.sh   | 14 +++---
 samples/pktgen/pktgen_sample05_flow_per_thread.sh  |  7 ++-
 ...tgen_sample06_numa_awared_queue_irq_affinity.sh |  7 ++-
 10 files changed, 55 insertions(+), 12 deletions(-)

diff --git a/samples/pktgen/README.rst b/samples/pktgen/README.rst
index fd39215db508..3f6483e8b2df 100644
--- a/samples/pktgen/README.rst
+++ b/samples/pktgen/README.rst
@@ -18,7 +18,7 @@ across the sample scripts.  Usage example is printed on 
errors::
  Usage: ./pktgen_sample01_simple.sh [-vx] -i ethX
   -i : ($DEV)   output interface/device (required)
   -s : ($PKT_SIZE)  packet size
-  -d : ($DEST_IP)   destination IP
+  -d : ($DEST_IP)   destination IP. CIDR (e.g. 198.18.0.0/15) is also allowed
   -m : ($DST_MAC)   destination MAC-addr
   -p : ($DST_PORT)  destination PORT range (e.g. 433-444) is also allowed
   -t : ($THREADS)   threads to start
diff --git a/samples/pktgen/parameters.sh b/samples/pktgen/parameters.sh
index a06b00a0c7b6..ff0ed474fee9 100644
--- a/samples/pktgen/parameters.sh
+++ b/samples/pktgen/parameters.sh
@@ -8,7 +8,7 @@ function usage() {
 echo "Usage: $0 [-vx] -i ethX"
 echo "  -i : (\$DEV)   output interface/device (required)"
 echo "  -s : (\$PKT_SIZE)  packet size"
-echo "  -d : (\$DEST_IP)   destination IP"
+echo "  -d : (\$DEST_IP)   destination IP. CIDR (e.g. 198.18.0.0/15) is 
also allowed"
 echo "  -m : (\$DST_MAC)   destination MAC-addr"
 echo "  -p : (\$DST_PORT)  destination PORT range (e.g. 433-444) is also 
allowed"
 echo "  -t : (\$THREADS)   threads to start"
diff --git a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
index 9b74502c58f7..1b6204125d2d 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
@@ -41,6 +41,10 @@ fi
 [ -z "$DST_MAC" ] && DST_MAC="90:e2:ba:ff:ff:ff"
 [ -z "$BURST" ] && BURST=1024
 [ -z "$COUNT" ] && COUNT="1000" # Zero means indefinitely
+if [ -n "$DEST_IP" ]; then
+validate_addr${IP6} $DEST_IP
+read -r DST_MIN DST_MAX <<< $(parse_addr${IP6} $DEST_IP)
+fi
 if [ -n "$DST_PORT" ]; then
 read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
 validate_ports $UDP_DST_MIN $UDP_DST_MAX
@@ -71,7 +75,8 @@ for ((thread = $F_THREAD; thread <= $L_THREAD; thread++)); do
 
 # Destination
 pg_set $dev "dst_mac $DST_MAC"
-pg_set $dev "dst$IP6 $DEST_IP"
+pg_set $dev "dst${IP6}_min $DST_MIN"
+pg_set $dev "dst${IP6}_max $DST_MAX"
 
 if [ -n "$DST_PORT" ]; then
# Single destination port or random port range
diff --git a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
index 0f332555b40d..e607cb369b20 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
@@ -24,6 +24,10 @@ if [[ -n "$BURST" ]]; then
 err 1 "Bursting not supported for this mode"
 fi
 [ -z "$COUNT" ] && COUNT="1000" # Zero means indefinitely
+if [ -n "$DEST_IP" ]; then
+validate_addr${IP6} $DEST_IP
+read -r DST_MIN DST_MAX <<< $(parse_addr${IP6} $DEST_IP)
+fi
 if [ -n "$DST_PORT" ]; then
 read -r UDP_DST_MIN UDP_DST_MAX <<< $

[bpf-next v5] samples: bpf: add max_pckt_size option at xdp_adjust_tail

2019-10-06 Thread Daniel T. Lee
Currently, at xdp_adjust_tail_kern.c, MAX_PCKT_SIZE is limited
to 600. To make this size flexible, static global variable
'max_pcktsz' is added.

By updating new packet size from the user space, xdp_adjust_tail_kern.o
will use this value as a new max packet size.

This static global variable can be accesible from .data section with
bpf_object__find_map* from user space, since it is considered as
internal map (accessible with .bss/.data/.rodata suffix).

If no '-P ' option is used, the size of maximum packet
will be 600 as a default.

Changed the way to test prog_fd, map_fd from '!= 0' to '< 0',
since fd could be 0 when stdin is closed.

Signed-off-by: Daniel T. Lee 

---
Changes in v5:
- Change pcktsz map to static global variable
Changes in v4:
- make pckt_size no less than ICMP_TOOBIG_SIZE
- Fix code style
Changes in v2:
- Change the helper to fetch map from 'bpf_map__next' to
'bpf_object__find_map_fd_by_name'.

 samples/bpf/xdp_adjust_tail_kern.c |  7 +--
 samples/bpf/xdp_adjust_tail_user.c | 32 ++
 2 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/samples/bpf/xdp_adjust_tail_kern.c 
b/samples/bpf/xdp_adjust_tail_kern.c
index 411fdb21f8bc..c616508befb9 100644
--- a/samples/bpf/xdp_adjust_tail_kern.c
+++ b/samples/bpf/xdp_adjust_tail_kern.c
@@ -25,6 +25,9 @@
 #define ICMP_TOOBIG_SIZE 98
 #define ICMP_TOOBIG_PAYLOAD_SIZE 92
 
+/* volatile to prevent compiler optimizations */
+static volatile __u32 max_pcktsz = MAX_PCKT_SIZE;
+
 struct bpf_map_def SEC("maps") icmpcnt = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
@@ -92,7 +95,7 @@ static __always_inline int send_icmp4_too_big(struct xdp_md 
*xdp)
orig_iph = data + off;
icmp_hdr->type = ICMP_DEST_UNREACH;
icmp_hdr->code = ICMP_FRAG_NEEDED;
-   icmp_hdr->un.frag.mtu = htons(MAX_PCKT_SIZE-sizeof(struct ethhdr));
+   icmp_hdr->un.frag.mtu = htons(max_pcktsz - sizeof(struct ethhdr));
icmp_hdr->checksum = 0;
ipv4_csum(icmp_hdr, ICMP_TOOBIG_PAYLOAD_SIZE, &csum);
icmp_hdr->checksum = csum;
@@ -121,7 +124,7 @@ static __always_inline int handle_ipv4(struct xdp_md *xdp)
int pckt_size = data_end - data;
int offset;
 
-   if (pckt_size > MAX_PCKT_SIZE) {
+   if (pckt_size > max(max_pcktsz, ICMP_TOOBIG_SIZE)) {
offset = pckt_size - ICMP_TOOBIG_SIZE;
if (bpf_xdp_adjust_tail(xdp, 0 - offset))
return XDP_PASS;
diff --git a/samples/bpf/xdp_adjust_tail_user.c 
b/samples/bpf/xdp_adjust_tail_user.c
index a3596b617c4c..bcdebd3be83e 100644
--- a/samples/bpf/xdp_adjust_tail_user.c
+++ b/samples/bpf/xdp_adjust_tail_user.c
@@ -23,6 +23,7 @@
 #include "libbpf.h"
 
 #define STATS_INTERVAL_S 2U
+#define MAX_PCKT_SIZE 600
 
 static int ifindex = -1;
 static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
@@ -72,6 +73,7 @@ static void usage(const char *cmd)
printf("Usage: %s [...]\n", cmd);
printf("-i  Interface\n");
printf("-T  Default: 0 (forever)\n");
+   printf("-P  Default: %u\n", MAX_PCKT_SIZE);
printf("-S use skb-mode\n");
printf("-N enforce native mode\n");
printf("-F force loading prog\n");
@@ -85,13 +87,14 @@ int main(int argc, char **argv)
.prog_type  = BPF_PROG_TYPE_XDP,
};
unsigned char opt_flags[256] = {};
-   const char *optstr = "i:T:SNFh";
+   const char *optstr = "i:T:P:SNFh";
struct bpf_prog_info info = {};
__u32 info_len = sizeof(info);
unsigned int kill_after_s = 0;
int i, prog_fd, map_fd, opt;
struct bpf_object *obj;
-   struct bpf_map *map;
+   __u32 max_pckt_size = 0;
+   __u32 key = 0;
char filename[256];
int err;
 
@@ -110,6 +113,9 @@ int main(int argc, char **argv)
case 'T':
kill_after_s = atoi(optarg);
break;
+   case 'P':
+   max_pckt_size = atoi(optarg);
+   break;
case 'S':
xdp_flags |= XDP_FLAGS_SKB_MODE;
break;
@@ -150,15 +156,25 @@ int main(int argc, char **argv)
if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
return 1;
 
-   map = bpf_map__next(NULL, obj);
-   if (!map) {
-   printf("finding a map in obj file failed\n");
+   if (prog_fd < 0) {
+   printf("load_bpf_file: %s\n", strerror(errno));
return 1;
}
-   map_fd = bpf_map__fd(map);
 
-   if (!prog_fd) {
-  

Re: [bpf-next v5] samples: bpf: add max_pckt_size option at xdp_adjust_tail

2019-10-07 Thread Daniel T. Lee
On Mon, Oct 7, 2019 at 12:37 PM Andrii Nakryiko
 wrote:
>
> On Sun, Oct 6, 2019 at 4:58 AM Daniel T. Lee  wrote:
> >
> > Currently, at xdp_adjust_tail_kern.c, MAX_PCKT_SIZE is limited
> > to 600. To make this size flexible, static global variable
> > 'max_pcktsz' is added.
> >
> > By updating new packet size from the user space, xdp_adjust_tail_kern.o
> > will use this value as a new max packet size.
> >
> > This static global variable can be accesible from .data section with
> > bpf_object__find_map* from user space, since it is considered as
> > internal map (accessible with .bss/.data/.rodata suffix).
> >
> > If no '-P ' option is used, the size of maximum packet
> > will be 600 as a default.
> >
> > Changed the way to test prog_fd, map_fd from '!= 0' to '< 0',
> > since fd could be 0 when stdin is closed.
> >
> > Signed-off-by: Daniel T. Lee 
> >
> > ---
>
> See nit below, but otherwise looks good.
>
> Acked-by: Andrii Nakryiko 
>
> > Changes in v5:
> > - Change pcktsz map to static global variable
> > Changes in v4:
> > - make pckt_size no less than ICMP_TOOBIG_SIZE
> > - Fix code style
> > Changes in v2:
> > - Change the helper to fetch map from 'bpf_map__next' to
> > 'bpf_object__find_map_fd_by_name'.
> >
> >  samples/bpf/xdp_adjust_tail_kern.c |  7 +--
> >  samples/bpf/xdp_adjust_tail_user.c | 32 ++
> >  2 files changed, 29 insertions(+), 10 deletions(-)
> >
> > diff --git a/samples/bpf/xdp_adjust_tail_kern.c 
> > b/samples/bpf/xdp_adjust_tail_kern.c
> > index 411fdb21f8bc..c616508befb9 100644
> > --- a/samples/bpf/xdp_adjust_tail_kern.c
> > +++ b/samples/bpf/xdp_adjust_tail_kern.c
> > @@ -25,6 +25,9 @@
> >  #define ICMP_TOOBIG_SIZE 98
> >  #define ICMP_TOOBIG_PAYLOAD_SIZE 92
> >
> > +/* volatile to prevent compiler optimizations */
> > +static volatile __u32 max_pcktsz = MAX_PCKT_SIZE;
> > +
> >  struct bpf_map_def SEC("maps") icmpcnt = {
> > .type = BPF_MAP_TYPE_ARRAY,
> > .key_size = sizeof(__u32),
> > @@ -92,7 +95,7 @@ static __always_inline int send_icmp4_too_big(struct 
> > xdp_md *xdp)
> > orig_iph = data + off;
> > icmp_hdr->type = ICMP_DEST_UNREACH;
> > icmp_hdr->code = ICMP_FRAG_NEEDED;
> > -   icmp_hdr->un.frag.mtu = htons(MAX_PCKT_SIZE-sizeof(struct ethhdr));
> > +   icmp_hdr->un.frag.mtu = htons(max_pcktsz - sizeof(struct ethhdr));
> > icmp_hdr->checksum = 0;
> > ipv4_csum(icmp_hdr, ICMP_TOOBIG_PAYLOAD_SIZE, &csum);
> > icmp_hdr->checksum = csum;
> > @@ -121,7 +124,7 @@ static __always_inline int handle_ipv4(struct xdp_md 
> > *xdp)
> > int pckt_size = data_end - data;
> > int offset;
> >
> > -   if (pckt_size > MAX_PCKT_SIZE) {
> > +   if (pckt_size > max(max_pcktsz, ICMP_TOOBIG_SIZE)) {
> > offset = pckt_size - ICMP_TOOBIG_SIZE;
> > if (bpf_xdp_adjust_tail(xdp, 0 - offset))
> > return XDP_PASS;
> > diff --git a/samples/bpf/xdp_adjust_tail_user.c 
> > b/samples/bpf/xdp_adjust_tail_user.c
> > index a3596b617c4c..bcdebd3be83e 100644
> > --- a/samples/bpf/xdp_adjust_tail_user.c
> > +++ b/samples/bpf/xdp_adjust_tail_user.c
> > @@ -23,6 +23,7 @@
> >  #include "libbpf.h"
> >
> >  #define STATS_INTERVAL_S 2U
> > +#define MAX_PCKT_SIZE 600
> >
> >  static int ifindex = -1;
> >  static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
> > @@ -72,6 +73,7 @@ static void usage(const char *cmd)
> > printf("Usage: %s [...]\n", cmd);
> > printf("-i  Interface\n");
> > printf("-T  Default: 0 (forever)\n");
> > +   printf("-P  Default: %u\n", MAX_PCKT_SIZE);
> > printf("-S use skb-mode\n");
> > printf("-N enforce native mode\n");
> > printf("-F force loading prog\n");
> > @@ -85,13 +87,14 @@ int main(int argc, char **argv)
> > .prog_type  = BPF_PROG_TYPE_XDP,
> > };
> > unsigned char opt_flags[256] = {};
> > -   const char *optstr = "i:T:SNFh";
> > +   const char *optstr = "i:T:P:SNFh";
> > struct bpf_prog_info info = {};
> > __u32 info_len = sizeof(info);
> >   

Re: [PATCH net-next v5 2/4] samples: pktgen: fix proc_cmd command result check logic

2019-10-07 Thread Daniel T. Lee
On Mon, Oct 7, 2019 at 5:15 PM Jesper Dangaard Brouer  wrote:
>
> On Sat,  5 Oct 2019 17:25:07 +0900
> "Daniel T. Lee"  wrote:
>
> > Currently, proc_cmd is used to dispatch command to 'pg_ctrl', 'pg_thread',
> > 'pg_set'. proc_cmd is designed to check command result with grep the
> > "Result:", but this might fail since this string is only shown in
> > 'pg_thread' and 'pg_set'.
> >
> > This commit fixes this logic by grep-ing the "Result:" string only when
> > the command is not for 'pg_ctrl'.
> >
> > For clarity of an execution flow, 'errexit' flag has been set.
> >
> > To cleanup pktgen on exit, trap has been added for EXIT signal.
> >
> > Signed-off-by: Daniel T. Lee 
> > ---
>
> Acked-by: Jesper Dangaard Brouer 
>
> > Changes since v5:
> >  * when script runs sudo, run 'pg_ctrl "reset"' on EXIT with trap
> >
> >  samples/pktgen/functions.sh | 17 +++--
> >  1 file changed, 11 insertions(+), 6 deletions(-)
> >
> > diff --git a/samples/pktgen/functions.sh b/samples/pktgen/functions.sh
> > index 4af4046d71be..40873a5d1461 100644
> > --- a/samples/pktgen/functions.sh
> > +++ b/samples/pktgen/functions.sh
> > @@ -5,6 +5,8 @@
> >  # Author: Jesper Dangaaard Brouer
> >  # License: GPL
> >
> > +set -o errexit
> > +
> >  ## -- General shell logging cmds --
> >  function err() {
> >  local exitcode=$1
> > @@ -58,6 +60,7 @@ function pg_set() {
> >  function proc_cmd() {
> >  local result
> >  local proc_file=$1
> > +local status=0
> >  # after shift, the remaining args are contained in $@
> >  shift
> >  local proc_ctrl=${PROC_DIR}/$proc_file
> > @@ -73,13 +76,13 @@ function proc_cmd() {
> >   echo "cmd: $@ > $proc_ctrl"
> >  fi
> >  # Quoting of "$@" is important for space expansion
> > -echo "$@" > "$proc_ctrl"
> > -local status=$?
> > +echo "$@" > "$proc_ctrl" || status=$?
> >
> > -result=$(grep "Result: OK:" $proc_ctrl)
> > -# Due to pgctrl, cannot use exit code $? from grep
> > -if [[ "$result" == "" ]]; then
> > - grep "Result:" $proc_ctrl >&2
> > +if [[ "$proc_file" != "pgctrl" ]]; then
> > +result=$(grep "Result: OK:" $proc_ctrl) || true
> > +if [[ "$result" == "" ]]; then
> > +grep "Result:" $proc_ctrl >&2
> > +fi
> >  fi
> >  if (( $status != 0 )); then
> >   err 5 "Write error($status) occurred cmd: \"$@ > $proc_ctrl\""
> > @@ -105,6 +108,8 @@ function pgset() {
> >  fi
> >  }
> >
> > +[[ $EUID -eq 0 ]] && trap 'pg_ctrl "reset"' EXIT
> > +
>
> This is fine, but you could have placed the 'trap' handler in
> parameters.sh file, as all scripts first source functions.sh and then
> call root_check_run_with_sudo, before sourcing parameters.sh.
>

Yes, this will work since 'parameters.sh' is only sourced when it is
on root, but I've thought this file only focuses on parsing parameters
not the general workflow of the pktgen script.

So I thought 'functions.sh' is more suitable place to add trap rather
than 'paramters.sh'.

What do you think?

Thanks for the review.

Thanks,
Daniel

> >  ## -- General shell tricks --
> >
> >  function root_check_run_with_sudo() {
>
>
>
> --
> Best regards,
>   Jesper Dangaard Brouer
>   MSc.CS, Principal Kernel Engineer at Red Hat
>   LinkedIn: http://www.linkedin.com/in/brouer


[PATCH bpf-next v6] samples: bpf: add max_pckt_size option at xdp_adjust_tail

2019-10-07 Thread Daniel T. Lee
Currently, at xdp_adjust_tail_kern.c, MAX_PCKT_SIZE is limited
to 600. To make this size flexible, static global variable
'max_pcktsz' is added.

By updating new packet size from the user space, xdp_adjust_tail_kern.o
will use this value as a new max packet size.

This static global variable can be accesible from .data section with
bpf_object__find_map* from user space, since it is considered as
internal map (accessible with .bss/.data/.rodata suffix).

If no '-P ' option is used, the size of maximum packet
will be 600 as a default.

Changed the way to test prog_fd, map_fd from '!= 0' to '< 0',
since fd could be 0 when stdin is closed.

Signed-off-by: Daniel T. Lee 

---
Changes in v6:
- Remove redundant error message
Changes in v5:
- Change pcktsz map to static global variable
Changes in v4:
- make pckt_size no less than ICMP_TOOBIG_SIZE
- Fix code style
Changes in v2:
- Change the helper to fetch map from 'bpf_map__next' to
'bpf_object__find_map_fd_by_name'.

 samples/bpf/xdp_adjust_tail_kern.c |  7 +--
 samples/bpf/xdp_adjust_tail_user.c | 29 -
 2 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/samples/bpf/xdp_adjust_tail_kern.c 
b/samples/bpf/xdp_adjust_tail_kern.c
index 411fdb21f8bc..c616508befb9 100644
--- a/samples/bpf/xdp_adjust_tail_kern.c
+++ b/samples/bpf/xdp_adjust_tail_kern.c
@@ -25,6 +25,9 @@
 #define ICMP_TOOBIG_SIZE 98
 #define ICMP_TOOBIG_PAYLOAD_SIZE 92
 
+/* volatile to prevent compiler optimizations */
+static volatile __u32 max_pcktsz = MAX_PCKT_SIZE;
+
 struct bpf_map_def SEC("maps") icmpcnt = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
@@ -92,7 +95,7 @@ static __always_inline int send_icmp4_too_big(struct xdp_md 
*xdp)
orig_iph = data + off;
icmp_hdr->type = ICMP_DEST_UNREACH;
icmp_hdr->code = ICMP_FRAG_NEEDED;
-   icmp_hdr->un.frag.mtu = htons(MAX_PCKT_SIZE-sizeof(struct ethhdr));
+   icmp_hdr->un.frag.mtu = htons(max_pcktsz - sizeof(struct ethhdr));
icmp_hdr->checksum = 0;
ipv4_csum(icmp_hdr, ICMP_TOOBIG_PAYLOAD_SIZE, &csum);
icmp_hdr->checksum = csum;
@@ -121,7 +124,7 @@ static __always_inline int handle_ipv4(struct xdp_md *xdp)
int pckt_size = data_end - data;
int offset;
 
-   if (pckt_size > MAX_PCKT_SIZE) {
+   if (pckt_size > max(max_pcktsz, ICMP_TOOBIG_SIZE)) {
offset = pckt_size - ICMP_TOOBIG_SIZE;
if (bpf_xdp_adjust_tail(xdp, 0 - offset))
return XDP_PASS;
diff --git a/samples/bpf/xdp_adjust_tail_user.c 
b/samples/bpf/xdp_adjust_tail_user.c
index a3596b617c4c..d86e9ad0356b 100644
--- a/samples/bpf/xdp_adjust_tail_user.c
+++ b/samples/bpf/xdp_adjust_tail_user.c
@@ -23,6 +23,7 @@
 #include "libbpf.h"
 
 #define STATS_INTERVAL_S 2U
+#define MAX_PCKT_SIZE 600
 
 static int ifindex = -1;
 static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
@@ -72,6 +73,7 @@ static void usage(const char *cmd)
printf("Usage: %s [...]\n", cmd);
printf("-i  Interface\n");
printf("-T  Default: 0 (forever)\n");
+   printf("-P  Default: %u\n", MAX_PCKT_SIZE);
printf("-S use skb-mode\n");
printf("-N enforce native mode\n");
printf("-F force loading prog\n");
@@ -85,13 +87,14 @@ int main(int argc, char **argv)
.prog_type  = BPF_PROG_TYPE_XDP,
};
unsigned char opt_flags[256] = {};
-   const char *optstr = "i:T:SNFh";
+   const char *optstr = "i:T:P:SNFh";
struct bpf_prog_info info = {};
__u32 info_len = sizeof(info);
unsigned int kill_after_s = 0;
int i, prog_fd, map_fd, opt;
struct bpf_object *obj;
-   struct bpf_map *map;
+   __u32 max_pckt_size = 0;
+   __u32 key = 0;
char filename[256];
int err;
 
@@ -110,6 +113,9 @@ int main(int argc, char **argv)
case 'T':
kill_after_s = atoi(optarg);
break;
+   case 'P':
+   max_pckt_size = atoi(optarg);
+   break;
case 'S':
xdp_flags |= XDP_FLAGS_SKB_MODE;
break;
@@ -150,15 +156,20 @@ int main(int argc, char **argv)
if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
return 1;
 
-   map = bpf_map__next(NULL, obj);
-   if (!map) {
-   printf("finding a map in obj file failed\n");
-   return 1;
+   /* static global var 'max_pcktsz' is accessible from .data section */
+   if (max_pckt_size) {
+   map_fd = bpf_object__find_map_fd

Re: [PATCH bpf-next v6] samples: bpf: add max_pckt_size option at xdp_adjust_tail

2019-10-07 Thread Daniel T. Lee
On Tue, Oct 8, 2019 at 1:41 AM Andrii Nakryiko
 wrote:
>
> On Mon, Oct 7, 2019 at 9:06 AM Daniel T. Lee  wrote:
> >
> > Currently, at xdp_adjust_tail_kern.c, MAX_PCKT_SIZE is limited
> > to 600. To make this size flexible, static global variable
> > 'max_pcktsz' is added.
> >
> > By updating new packet size from the user space, xdp_adjust_tail_kern.o
> > will use this value as a new max packet size.
> >
> > This static global variable can be accesible from .data section with
> > bpf_object__find_map* from user space, since it is considered as
> > internal map (accessible with .bss/.data/.rodata suffix).
> >
> > If no '-P ' option is used, the size of maximum packet
> > will be 600 as a default.
> >
> > Changed the way to test prog_fd, map_fd from '!= 0' to '< 0',
> > since fd could be 0 when stdin is closed.
> >
> > Signed-off-by: Daniel T. Lee 
> >
> > ---
> > Changes in v6:
> > - Remove redundant error message
> > Changes in v5:
> > - Change pcktsz map to static global variable
> > Changes in v4:
> > - make pckt_size no less than ICMP_TOOBIG_SIZE
> > - Fix code style
> > Changes in v2:
> > - Change the helper to fetch map from 'bpf_map__next' to
> > 'bpf_object__find_map_fd_by_name'.
>
>
> This should go into commit message, that's netdev preference.
>
> Otherwise looks good!
>
> Acked-by: Andrii Nakryiko 
>

Thanks for the feedback!

Will send the next patch with the modified commit message right away!

Thanks,
Daniel

> >
> >  samples/bpf/xdp_adjust_tail_kern.c |  7 +--
> >  samples/bpf/xdp_adjust_tail_user.c | 29 -
> >  2 files changed, 25 insertions(+), 11 deletions(-)
> >
> > diff --git a/samples/bpf/xdp_adjust_tail_kern.c 
> > b/samples/bpf/xdp_adjust_tail_kern.c
> > index 411fdb21f8bc..c616508befb9 100644
> > --- a/samples/bpf/xdp_adjust_tail_kern.c
> > +++ b/samples/bpf/xdp_adjust_tail_kern.c
> > @@ -25,6 +25,9 @@
> >  #define ICMP_TOOBIG_SIZE 98
> >  #define ICMP_TOOBIG_PAYLOAD_SIZE 92
> >
>
> [...]


[PATCH bpf-next v7] samples: bpf: add max_pckt_size option at xdp_adjust_tail

2019-10-07 Thread Daniel T. Lee
Currently, at xdp_adjust_tail_kern.c, MAX_PCKT_SIZE is limited
to 600. To make this size flexible, static global variable
'max_pcktsz' is added.

By updating new packet size from the user space, xdp_adjust_tail_kern.o
will use this value as a new max packet size.

This static global variable can be accesible from .data section with
bpf_object__find_map* from user space, since it is considered as
internal map (accessible with .bss/.data/.rodata suffix).

If no '-P ' option is used, the size of maximum packet
will be 600 as a default.

For clarity, change the helper to fetch map from 'bpf_map__next'
to 'bpf_object__find_map_fd_by_name'. Also, changed the way to
test prog_fd, map_fd from '!= 0' to '< 0', since fd could be 0
when stdin is closed.

Signed-off-by: Daniel T. Lee 

---
Changes in v6:
- Remove redundant error message
Changes in v5:
- Change pcktsz map to static global variable
Changes in v4:
- make pckt_size no less than ICMP_TOOBIG_SIZE
- Fix code style

 samples/bpf/xdp_adjust_tail_kern.c |  7 +--
 samples/bpf/xdp_adjust_tail_user.c | 29 -
 2 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/samples/bpf/xdp_adjust_tail_kern.c 
b/samples/bpf/xdp_adjust_tail_kern.c
index 411fdb21f8bc..c616508befb9 100644
--- a/samples/bpf/xdp_adjust_tail_kern.c
+++ b/samples/bpf/xdp_adjust_tail_kern.c
@@ -25,6 +25,9 @@
 #define ICMP_TOOBIG_SIZE 98
 #define ICMP_TOOBIG_PAYLOAD_SIZE 92
 
+/* volatile to prevent compiler optimizations */
+static volatile __u32 max_pcktsz = MAX_PCKT_SIZE;
+
 struct bpf_map_def SEC("maps") icmpcnt = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
@@ -92,7 +95,7 @@ static __always_inline int send_icmp4_too_big(struct xdp_md 
*xdp)
orig_iph = data + off;
icmp_hdr->type = ICMP_DEST_UNREACH;
icmp_hdr->code = ICMP_FRAG_NEEDED;
-   icmp_hdr->un.frag.mtu = htons(MAX_PCKT_SIZE-sizeof(struct ethhdr));
+   icmp_hdr->un.frag.mtu = htons(max_pcktsz - sizeof(struct ethhdr));
icmp_hdr->checksum = 0;
ipv4_csum(icmp_hdr, ICMP_TOOBIG_PAYLOAD_SIZE, &csum);
icmp_hdr->checksum = csum;
@@ -121,7 +124,7 @@ static __always_inline int handle_ipv4(struct xdp_md *xdp)
int pckt_size = data_end - data;
int offset;
 
-   if (pckt_size > MAX_PCKT_SIZE) {
+   if (pckt_size > max(max_pcktsz, ICMP_TOOBIG_SIZE)) {
offset = pckt_size - ICMP_TOOBIG_SIZE;
if (bpf_xdp_adjust_tail(xdp, 0 - offset))
return XDP_PASS;
diff --git a/samples/bpf/xdp_adjust_tail_user.c 
b/samples/bpf/xdp_adjust_tail_user.c
index a3596b617c4c..d86e9ad0356b 100644
--- a/samples/bpf/xdp_adjust_tail_user.c
+++ b/samples/bpf/xdp_adjust_tail_user.c
@@ -23,6 +23,7 @@
 #include "libbpf.h"
 
 #define STATS_INTERVAL_S 2U
+#define MAX_PCKT_SIZE 600
 
 static int ifindex = -1;
 static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
@@ -72,6 +73,7 @@ static void usage(const char *cmd)
printf("Usage: %s [...]\n", cmd);
printf("-i  Interface\n");
printf("-T  Default: 0 (forever)\n");
+   printf("-P  Default: %u\n", MAX_PCKT_SIZE);
printf("-S use skb-mode\n");
printf("-N enforce native mode\n");
printf("-F force loading prog\n");
@@ -85,13 +87,14 @@ int main(int argc, char **argv)
.prog_type  = BPF_PROG_TYPE_XDP,
};
unsigned char opt_flags[256] = {};
-   const char *optstr = "i:T:SNFh";
+   const char *optstr = "i:T:P:SNFh";
struct bpf_prog_info info = {};
__u32 info_len = sizeof(info);
unsigned int kill_after_s = 0;
int i, prog_fd, map_fd, opt;
struct bpf_object *obj;
-   struct bpf_map *map;
+   __u32 max_pckt_size = 0;
+   __u32 key = 0;
char filename[256];
int err;
 
@@ -110,6 +113,9 @@ int main(int argc, char **argv)
case 'T':
kill_after_s = atoi(optarg);
break;
+   case 'P':
+   max_pckt_size = atoi(optarg);
+   break;
case 'S':
xdp_flags |= XDP_FLAGS_SKB_MODE;
break;
@@ -150,15 +156,20 @@ int main(int argc, char **argv)
if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
return 1;
 
-   map = bpf_map__next(NULL, obj);
-   if (!map) {
-   printf("finding a map in obj file failed\n");
-   return 1;
+   /* static global var 'max_pcktsz' is accessible from .data section */
+   if (max_pckt_size) {
+   map_fd = bpf_object__find_map_fd_by_name(

Re: [PATCH bpf-next v7] samples: bpf: add max_pckt_size option at xdp_adjust_tail

2019-10-07 Thread Daniel T. Lee
On Tue, Oct 8, 2019 at 12:24 PM Alexei Starovoitov
 wrote:
>
> On Mon, Oct 7, 2019 at 10:21 AM Daniel T. Lee  wrote:
> >
> > Currently, at xdp_adjust_tail_kern.c, MAX_PCKT_SIZE is limited
> > to 600. To make this size flexible, static global variable
> > 'max_pcktsz' is added.
> >
> > By updating new packet size from the user space, xdp_adjust_tail_kern.o
> > will use this value as a new max packet size.
> >
> > This static global variable can be accesible from .data section with
> > bpf_object__find_map* from user space, since it is considered as
> > internal map (accessible with .bss/.data/.rodata suffix).
> >
> > If no '-P ' option is used, the size of maximum packet
> > will be 600 as a default.
> >
> > For clarity, change the helper to fetch map from 'bpf_map__next'
> > to 'bpf_object__find_map_fd_by_name'. Also, changed the way to
> > test prog_fd, map_fd from '!= 0' to '< 0', since fd could be 0
> > when stdin is closed.
> >
> > Signed-off-by: Daniel T. Lee 
> >
> > ---
> > Changes in v6:
> > - Remove redundant error message
>
> Applied.
> Please keep Acks if you're only doing minor tweaks between versions.

Thank you for your time and effort for the review.

I will keep that in mind for the future.

Thanks,
Daniel


[PATCH] samples: bpf: make the use of xdp samples consistent

2019-06-24 Thread Daniel T. Lee
Currently, each xdp samples are inconsistent in the use.
Most of the samples fetch the interface with it's name.
(ex. xdp1, xdp2skb, xdp_redirect, xdp_sample_pkts, etc.)

But only xdp_adjst_tail and xdp_tx_iptunnel fetch the interface with
ifindex by command argument.

This commit enables those two samples to fetch interface with it's name
without changing the original index interface fetching.
( fetching in the same way as xdp_sample_pkts_user.c does.)

Signed-off-by: Daniel T. Lee 
---
 samples/bpf/xdp_adjust_tail_user.c | 12 ++--
 samples/bpf/xdp_tx_iptunnel_user.c | 12 ++--
 2 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/samples/bpf/xdp_adjust_tail_user.c 
b/samples/bpf/xdp_adjust_tail_user.c
index 586ff751aba9..a3596b617c4c 100644
--- a/samples/bpf/xdp_adjust_tail_user.c
+++ b/samples/bpf/xdp_adjust_tail_user.c
@@ -13,6 +13,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -69,7 +70,7 @@ static void usage(const char *cmd)
printf("Start a XDP prog which send ICMP \"packet too big\" \n"
"messages if ingress packet is bigger then MAX_SIZE bytes\n");
printf("Usage: %s [...]\n", cmd);
-   printf("-i  Interface Index\n");
+   printf("-i  Interface\n");
printf("-T  Default: 0 (forever)\n");
printf("-S use skb-mode\n");
printf("-N enforce native mode\n");
@@ -102,7 +103,9 @@ int main(int argc, char **argv)
 
switch (opt) {
case 'i':
-   ifindex = atoi(optarg);
+   ifindex = if_nametoindex(optarg);
+   if (!ifindex)
+   ifindex = atoi(optarg);
break;
case 'T':
kill_after_s = atoi(optarg);
@@ -136,6 +139,11 @@ int main(int argc, char **argv)
return 1;
}
 
+   if (!ifindex) {
+   fprintf(stderr, "Invalid ifname\n");
+   return 1;
+   }
+
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
prog_load_attr.file = filename;
 
diff --git a/samples/bpf/xdp_tx_iptunnel_user.c 
b/samples/bpf/xdp_tx_iptunnel_user.c
index 394896430712..dfb68582e243 100644
--- a/samples/bpf/xdp_tx_iptunnel_user.c
+++ b/samples/bpf/xdp_tx_iptunnel_user.c
@@ -9,6 +9,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -83,7 +84,7 @@ static void usage(const char *cmd)
   "in an IPv4/v6 header and XDP_TX it out.  The dst \n"
   "is used to select packets to encapsulate\n\n");
printf("Usage: %s [...]\n", cmd);
-   printf("-i  Interface Index\n");
+   printf("-i  Interface\n");
printf("-a  IPv4 or IPv6\n");
printf("-p  A port range (e.g. 433-444) is also 
allowed\n");
printf("-s  Used in the IPTunnel header\n");
@@ -181,7 +182,9 @@ int main(int argc, char **argv)
 
switch (opt) {
case 'i':
-   ifindex = atoi(optarg);
+   ifindex = if_nametoindex(optarg);
+   if (!ifindex)
+   ifindex = atoi(optarg);
break;
case 'a':
vip.family = parse_ipstr(optarg, vip.daddr.v6);
@@ -253,6 +256,11 @@ int main(int argc, char **argv)
return 1;
}
 
+   if (!ifindex) {
+   fprintf(stderr, "Invalid ifname\n");
+   return 1;
+   }
+
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
prog_load_attr.file = filename;
 
-- 
2.17.1



Re: [PATCH] samples: bpf: make the use of xdp samples consistent

2019-06-24 Thread Daniel T. Lee
Will do right away! :)

On Tue, Jun 25, 2019 at 3:24 AM Toke Høiland-Jørgensen  wrote:
>
> "Daniel T. Lee"  writes:
>
> > Currently, each xdp samples are inconsistent in the use.
> > Most of the samples fetch the interface with it's name.
> > (ex. xdp1, xdp2skb, xdp_redirect, xdp_sample_pkts, etc.)
>
> The xdp_redirect and xdp_redirect_map also only accept ifindexes, not
> interface names. Care to fix those while you're at it? :)
>
> -Toke


[PATCH v2] samples: bpf: make the use of xdp samples consistent

2019-06-24 Thread Daniel T. Lee
Currently, each xdp samples are inconsistent in the use.
Most of the samples fetch the interface with it's name.
(ex. xdp1, xdp2skb, xdp_redirect_cpu, xdp_sample_pkts, etc.)

But some of the xdp samples are fetching the interface with
ifindex by command argument.

This commit enables xdp samples to fetch interface with it's name
without changing the original index interface fetching.
( fetching in the same way as xdp_sample_pkts_user.c does.)

Signed-off-by: Daniel T. Lee 
---
Changes in v2:
  - added xdp_redirect_user.c, xdp_redirect_map_user.c 

 samples/bpf/xdp_adjust_tail_user.c  | 12 ++--
 samples/bpf/xdp_redirect_map_user.c | 15 +++
 samples/bpf/xdp_redirect_user.c | 15 +++
 samples/bpf/xdp_tx_iptunnel_user.c  | 12 ++--
 4 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/samples/bpf/xdp_adjust_tail_user.c 
b/samples/bpf/xdp_adjust_tail_user.c
index 586ff751aba9..a3596b617c4c 100644
--- a/samples/bpf/xdp_adjust_tail_user.c
+++ b/samples/bpf/xdp_adjust_tail_user.c
@@ -13,6 +13,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -69,7 +70,7 @@ static void usage(const char *cmd)
printf("Start a XDP prog which send ICMP \"packet too big\" \n"
"messages if ingress packet is bigger then MAX_SIZE bytes\n");
printf("Usage: %s [...]\n", cmd);
-   printf("-i  Interface Index\n");
+   printf("-i  Interface\n");
printf("-T  Default: 0 (forever)\n");
printf("-S use skb-mode\n");
printf("-N enforce native mode\n");
@@ -102,7 +103,9 @@ int main(int argc, char **argv)
 
switch (opt) {
case 'i':
-   ifindex = atoi(optarg);
+   ifindex = if_nametoindex(optarg);
+   if (!ifindex)
+   ifindex = atoi(optarg);
break;
case 'T':
kill_after_s = atoi(optarg);
@@ -136,6 +139,11 @@ int main(int argc, char **argv)
return 1;
}
 
+   if (!ifindex) {
+   fprintf(stderr, "Invalid ifname\n");
+   return 1;
+   }
+
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
prog_load_attr.file = filename;
 
diff --git a/samples/bpf/xdp_redirect_map_user.c 
b/samples/bpf/xdp_redirect_map_user.c
index 15bb6f67f9c3..f70ee33907fd 100644
--- a/samples/bpf/xdp_redirect_map_user.c
+++ b/samples/bpf/xdp_redirect_map_user.c
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -85,7 +86,7 @@ static void poll_stats(int interval, int ifindex)
 static void usage(const char *prog)
 {
fprintf(stderr,
-   "usage: %s [OPTS] IFINDEX_IN IFINDEX_OUT\n\n"
+   "usage: %s [OPTS] _IN _OUT\n\n"
"OPTS:\n"
"-Suse skb-mode\n"
"-Nenforce native mode\n"
@@ -127,7 +128,7 @@ int main(int argc, char **argv)
}
 
if (optind == argc) {
-   printf("usage: %s IFINDEX_IN IFINDEX_OUT\n", argv[0]);
+   printf("usage: %s _IN _OUT\n", 
argv[0]);
return 1;
}
 
@@ -136,8 +137,14 @@ int main(int argc, char **argv)
return 1;
}
 
-   ifindex_in = strtoul(argv[optind], NULL, 0);
-   ifindex_out = strtoul(argv[optind + 1], NULL, 0);
+   ifindex_in = if_nametoindex(argv[optind]);
+   if (!ifindex_in)
+   ifindex_in = strtoul(argv[optind], NULL, 0);
+
+   ifindex_out = if_nametoindex(argv[optind + 1]);
+   if (!ifindex_out)
+   ifindex_out = strtoul(argv[optind + 1], NULL, 0);
+
printf("input: %d output: %d\n", ifindex_in, ifindex_out);
 
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
diff --git a/samples/bpf/xdp_redirect_user.c b/samples/bpf/xdp_redirect_user.c
index ce71be187205..39de06f3ec25 100644
--- a/samples/bpf/xdp_redirect_user.c
+++ b/samples/bpf/xdp_redirect_user.c
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -85,7 +86,7 @@ static void poll_stats(int interval, int ifindex)
 static void usage(const char *prog)
 {
fprintf(stderr,
-   "usage: %s [OPTS] IFINDEX_IN IFINDEX_OUT\n\n"
+   "usage: %s [OPTS] _IN _OUT\n\n"
"OPTS:\n"
"-Suse skb-mode\n"
"-Nenforce native mode\n"
@@ -128,7 +129,7 @@ int main(int argc, char **argv)
}
 
if (optind == argc) {
-   printf("usage: %s IFINDEX_IN IFINDEX_OUT\n", a

[PATCH v2] samples: bpf: make the use of xdp samples consistent

2019-06-24 Thread Daniel T. Lee
Currently, each xdp samples are inconsistent in the use.
Most of the samples fetch the interface with it's name.
(ex. xdp1, xdp2skb, xdp_redirect_cpu, xdp_sample_pkts, etc.)

But some of the xdp samples are fetching the interface with
ifindex by command argument.

This commit enables xdp samples to fetch interface with it's name
without changing the original index interface fetching.
( fetching in the same way as xdp_sample_pkts_user.c does.)

Signed-off-by: Daniel T. Lee 
---
Changes in v2:
  - added xdp_redirect_user.c, xdp_redirect_map_user.c 

 samples/bpf/xdp_adjust_tail_user.c  | 12 ++--
 samples/bpf/xdp_redirect_map_user.c | 15 +++
 samples/bpf/xdp_redirect_user.c | 15 +++
 samples/bpf/xdp_tx_iptunnel_user.c  | 12 ++--
 4 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/samples/bpf/xdp_adjust_tail_user.c 
b/samples/bpf/xdp_adjust_tail_user.c
index 586ff751aba9..a3596b617c4c 100644
--- a/samples/bpf/xdp_adjust_tail_user.c
+++ b/samples/bpf/xdp_adjust_tail_user.c
@@ -13,6 +13,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -69,7 +70,7 @@ static void usage(const char *cmd)
printf("Start a XDP prog which send ICMP \"packet too big\" \n"
"messages if ingress packet is bigger then MAX_SIZE bytes\n");
printf("Usage: %s [...]\n", cmd);
-   printf("-i  Interface Index\n");
+   printf("-i  Interface\n");
printf("-T  Default: 0 (forever)\n");
printf("-S use skb-mode\n");
printf("-N enforce native mode\n");
@@ -102,7 +103,9 @@ int main(int argc, char **argv)
 
switch (opt) {
case 'i':
-   ifindex = atoi(optarg);
+   ifindex = if_nametoindex(optarg);
+   if (!ifindex)
+   ifindex = atoi(optarg);
break;
case 'T':
kill_after_s = atoi(optarg);
@@ -136,6 +139,11 @@ int main(int argc, char **argv)
return 1;
}
 
+   if (!ifindex) {
+   fprintf(stderr, "Invalid ifname\n");
+   return 1;
+   }
+
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
prog_load_attr.file = filename;
 
diff --git a/samples/bpf/xdp_redirect_map_user.c 
b/samples/bpf/xdp_redirect_map_user.c
index 15bb6f67f9c3..f70ee33907fd 100644
--- a/samples/bpf/xdp_redirect_map_user.c
+++ b/samples/bpf/xdp_redirect_map_user.c
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -85,7 +86,7 @@ static void poll_stats(int interval, int ifindex)
 static void usage(const char *prog)
 {
fprintf(stderr,
-   "usage: %s [OPTS] IFINDEX_IN IFINDEX_OUT\n\n"
+   "usage: %s [OPTS] _IN _OUT\n\n"
"OPTS:\n"
"-Suse skb-mode\n"
"-Nenforce native mode\n"
@@ -127,7 +128,7 @@ int main(int argc, char **argv)
}
 
if (optind == argc) {
-   printf("usage: %s IFINDEX_IN IFINDEX_OUT\n", argv[0]);
+   printf("usage: %s _IN _OUT\n", 
argv[0]);
return 1;
}
 
@@ -136,8 +137,14 @@ int main(int argc, char **argv)
return 1;
}
 
-   ifindex_in = strtoul(argv[optind], NULL, 0);
-   ifindex_out = strtoul(argv[optind + 1], NULL, 0);
+   ifindex_in = if_nametoindex(argv[optind]);
+   if (!ifindex_in)
+   ifindex_in = strtoul(argv[optind], NULL, 0);
+
+   ifindex_out = if_nametoindex(argv[optind + 1]);
+   if (!ifindex_out)
+   ifindex_out = strtoul(argv[optind + 1], NULL, 0);
+
printf("input: %d output: %d\n", ifindex_in, ifindex_out);
 
snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
diff --git a/samples/bpf/xdp_redirect_user.c b/samples/bpf/xdp_redirect_user.c
index ce71be187205..39de06f3ec25 100644
--- a/samples/bpf/xdp_redirect_user.c
+++ b/samples/bpf/xdp_redirect_user.c
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -85,7 +86,7 @@ static void poll_stats(int interval, int ifindex)
 static void usage(const char *prog)
 {
fprintf(stderr,
-   "usage: %s [OPTS] IFINDEX_IN IFINDEX_OUT\n\n"
+   "usage: %s [OPTS] _IN _OUT\n\n"
"OPTS:\n"
"-Suse skb-mode\n"
"-Nenforce native mode\n"
@@ -128,7 +129,7 @@ int main(int argc, char **argv)
}
 
if (optind == argc) {
-   printf("usage: %s IFINDEX_IN IFINDEX_OUT\n", a

[PATCH 2/2] samples: pktgen: allow to specify destination port

2019-06-29 Thread Daniel T. Lee
Currently, kernel pktgen has the feature to specify udp destination port
for sending packet. (e.g. pgset "udp_dst_min 9")

But on samples, each of the scripts doesn't have any option to achieve this.

This commit adds the DST_PORT option to specify the target port(s) in the 
script.

-p : ($DST_PORT)  destination PORT range (e.g. 433-444) is also allowed

Signed-off-by: Daniel T. Lee 
---
 samples/pktgen/README.rst|  1 +
 samples/pktgen/parameters.sh |  7 ++-
 .../pktgen/pktgen_bench_xmit_mode_netif_receive.sh   | 11 +++
 samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh  | 11 +++
 samples/pktgen/pktgen_sample01_simple.sh | 11 +++
 samples/pktgen/pktgen_sample02_multiqueue.sh | 11 +++
 samples/pktgen/pktgen_sample03_burst_single_flow.sh  | 11 +++
 samples/pktgen/pktgen_sample04_many_flows.sh | 11 +++
 samples/pktgen/pktgen_sample05_flow_per_thread.sh| 12 +++-
 ...pktgen_sample06_numa_awared_queue_irq_affinity.sh | 11 +++
 10 files changed, 95 insertions(+), 2 deletions(-)

diff --git a/samples/pktgen/README.rst b/samples/pktgen/README.rst
index ff8929da61c5..fd39215db508 100644
--- a/samples/pktgen/README.rst
+++ b/samples/pktgen/README.rst
@@ -20,6 +20,7 @@ across the sample scripts.  Usage example is printed on 
errors::
   -s : ($PKT_SIZE)  packet size
   -d : ($DEST_IP)   destination IP
   -m : ($DST_MAC)   destination MAC-addr
+  -p : ($DST_PORT)  destination PORT range (e.g. 433-444) is also allowed
   -t : ($THREADS)   threads to start
   -f : ($F_THREAD)  index of first thread (zero indexed CPU number)
   -c : ($SKB_CLONE) SKB clones send before alloc new SKB
diff --git a/samples/pktgen/parameters.sh b/samples/pktgen/parameters.sh
index 72fc562876e2..a06b00a0c7b6 100644
--- a/samples/pktgen/parameters.sh
+++ b/samples/pktgen/parameters.sh
@@ -10,6 +10,7 @@ function usage() {
 echo "  -s : (\$PKT_SIZE)  packet size"
 echo "  -d : (\$DEST_IP)   destination IP"
 echo "  -m : (\$DST_MAC)   destination MAC-addr"
+echo "  -p : (\$DST_PORT)  destination PORT range (e.g. 433-444) is also 
allowed"
 echo "  -t : (\$THREADS)   threads to start"
 echo "  -f : (\$F_THREAD)  index of first thread (zero indexed CPU number)"
 echo "  -c : (\$SKB_CLONE) SKB clones send before alloc new SKB"
@@ -23,7 +24,7 @@ function usage() {
 
 ##  --- Parse command line arguments / parameters ---
 ## echo "Commandline options:"
-while getopts "s:i:d:m:f:t:c:n:b:vxh6" option; do
+while getopts "s:i:d:m:p:f:t:c:n:b:vxh6" option; do
 case $option in
 i) # interface
   export DEV=$OPTARG
@@ -41,6 +42,10 @@ while getopts "s:i:d:m:f:t:c:n:b:vxh6" option; do
   export DST_MAC=$OPTARG
  info "Destination MAC set to: DST_MAC=$DST_MAC"
   ;;
+p) # PORT
+  export DST_PORT=$OPTARG
+ info "Destination PORT set to: DST_PORT=$DST_PORT"
+  ;;
 f)
  export F_THREAD=$OPTARG
  info "Index of first thread (zero indexed CPU number): $F_THREAD"
diff --git a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
index 2839f7d315cf..e14b1a9144d9 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
@@ -41,6 +41,10 @@ fi
 [ -z "$DST_MAC" ] && DST_MAC="90:e2:ba:ff:ff:ff"
 [ -z "$BURST" ] && BURST=1024
 [ -z "$COUNT" ] && COUNT="1000" # Zero means indefinitely
+if [ -n "$DST_PORT" ]; then
+read -r DST_MIN DST_MAX <<< $(parse_ports $DST_PORT)
+validate_ports $DST_MIN $DST_MAX
+fi
 
 # Base Config
 DELAY="0"# Zero means max speed
@@ -69,6 +73,13 @@ for ((thread = $F_THREAD; thread <= $L_THREAD; thread++)); do
 pg_set $dev "dst_mac $DST_MAC"
 pg_set $dev "dst$IP6 $DEST_IP"
 
+if [ -n "$DST_PORT" ]; then
+   # Single destination port or random port range
+   pg_set $dev "flag UDPDST_RND"
+   pg_set $dev "udp_dst_min $DST_MIN"
+   pg_set $dev "udp_dst_max $DST_MAX"
+fi
+
 # Inject packet into RX path of stack
 pg_set $dev "xmit_mode netif_receive"
 
diff --git a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
index e1ee54465def..82c3e504e056 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
@@ -24,6 +24,10 @@ if [[ -n "$BURST" ]]; then
 err 1 "Bursting not supported for this mode"
 fi
 [ -z "$C

[PATCH 1/2] samples: pktgen: add some helper functions for port parsing

2019-06-29 Thread Daniel T. Lee
This commit adds port parsing and port validate helper function to parse
single or range of port(s) from a given string. (e.g. 1234, 443-444)

Helpers will be used in prior to set target port(s) in samples/pktgen.

Signed-off-by: Daniel T. Lee 
---
 samples/pktgen/functions.sh | 34 ++
 1 file changed, 34 insertions(+)

diff --git a/samples/pktgen/functions.sh b/samples/pktgen/functions.sh
index f8bb3cd0f4ce..4af4046d71be 100644
--- a/samples/pktgen/functions.sh
+++ b/samples/pktgen/functions.sh
@@ -162,3 +162,37 @@ function get_node_cpus()
 
echo $node_cpu_list
 }
+
+# Given a single or range of port(s), return minimum and maximum port number.
+function parse_ports()
+{
+local port_str=$1
+local port_list
+local min_port
+local max_port
+
+IFS="-" read -ra port_list <<< $port_str
+
+min_port=${port_list[0]}
+max_port=${port_list[1]:-$min_port}
+
+echo $min_port $max_port
+}
+
+# Given a minimum and maximum port, verify port number.
+function validate_ports()
+{
+local min_port=$1
+local max_port=$2
+
+# 0 < port < 65536
+if [[ $min_port -gt 0 && $min_port -lt 65536 ]]; then
+   if [[ $max_port -gt 0 && $max_port -lt 65536 ]]; then
+   if [[ $min_port -le $max_port ]]; then
+   return 0
+   fi
+   fi
+fi
+
+err 5 "Invalid port(s): $min_port-$max_port"
+}
-- 
2.17.1



Re: [PATCH 2/2] samples: pktgen: allow to specify destination port

2019-07-01 Thread Daniel T. Lee
Thanks for the review!

About the equivalent port in the same burst thing, I didn't realize it
would work in
that way. It doesn't matter in my use-case, but thank you for letting me know!

On Tue, Jul 2, 2019 at 12:08 AM Jesper Dangaard Brouer
 wrote:
>
> On Sat, 29 Jun 2019 22:33:58 +0900
> "Daniel T. Lee"  wrote:
>
> > Currently, kernel pktgen has the feature to specify udp destination port
> > for sending packet. (e.g. pgset "udp_dst_min 9")
> >
> > But on samples, each of the scripts doesn't have any option to achieve this.
> >
> > This commit adds the DST_PORT option to specify the target port(s) in the 
> > script.
> >
> > -p : ($DST_PORT)  destination PORT range (e.g. 433-444) is also allowed
> >
> > Signed-off-by: Daniel T. Lee 
>
> Nice feature, this look very usable for testing.  I think my QA asked
> me for something similar.
>
> One nitpick is that script named pktgen_sample03_burst_single_flow.sh
> implies this is a single flow, but by specifying a port-range this will
> be more flows.  I'm okay with adding this, as the end-user specifying a
> port-range should realize this.  Thus, you get my ACK.
>
> Acked-by: Jesper Dangaard Brouer 
>
> Another thing you should realize (but you/we cannot do anything about)
> is that when the scripts use burst or clone, then the port (UDPDST_RND)
> will be the same for all packets in the same burst.  I don't know if it
> matters for your use-case.
>
> --
> Best regards,
>   Jesper Dangaard Brouer
>   MSc.CS, Principal Kernel Engineer at Red Hat
>   LinkedIn: http://www.linkedin.com/in/brouer


[PATCH bpf-next 1/3] samples: bpf: Refactor xdp_monitor with libbpf

2020-10-09 Thread Daniel T. Lee
To avoid confusion caused by the increasing fragmentation of the BPF
Loader program, this commit would like to change to the libbpf loader
instead of using the bpf_load.

Thanks to libbpf's bpf_link interface, managing the tracepoint BPF
program is much easier. bpf_program__attach_tracepoint manages the
enable of tracepoint event and attach of BPF programs to it with a
single interface bpf_link, so there is no need to manage event_fd and
prog_fd separately.

This commit refactors xdp_monitor with using this libbpf API, and the
bpf_load is removed and migrated to libbpf.

Signed-off-by: Daniel T. Lee 
---
 samples/bpf/Makefile   |   2 +-
 samples/bpf/xdp_monitor_user.c | 144 -
 2 files changed, 108 insertions(+), 38 deletions(-)

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 4f1ed0e3cf9f..0cee2aa8970f 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -99,7 +99,7 @@ per_socket_stats_example-objs := cookie_uid_helper_example.o
 xdp_redirect-objs := xdp_redirect_user.o
 xdp_redirect_map-objs := xdp_redirect_map_user.o
 xdp_redirect_cpu-objs := bpf_load.o xdp_redirect_cpu_user.o
-xdp_monitor-objs := bpf_load.o xdp_monitor_user.o
+xdp_monitor-objs := xdp_monitor_user.o
 xdp_rxq_info-objs := xdp_rxq_info_user.o
 syscall_tp-objs := syscall_tp_user.o
 cpustat-objs := cpustat_user.o
diff --git a/samples/bpf/xdp_monitor_user.c b/samples/bpf/xdp_monitor_user.c
index ef53b93db573..c627c53d6ada 100644
--- a/samples/bpf/xdp_monitor_user.c
+++ b/samples/bpf/xdp_monitor_user.c
@@ -26,12 +26,36 @@ static const char *__doc_err_only__=
 #include 
 #include 
 
+#include 
 #include 
-#include "bpf_load.h"
+#include 
 #include "bpf_util.h"
 
+enum map_type {
+   REDIRECT_ERR_CNT,
+   EXCEPTION_CNT,
+   CPUMAP_ENQUEUE_CNT,
+   CPUMAP_KTHREAD_CNT,
+   DEVMAP_XMIT_CNT,
+};
+
+static const char *const map_type_strings[] = {
+   [REDIRECT_ERR_CNT] = "redirect_err_cnt",
+   [EXCEPTION_CNT] = "exception_cnt",
+   [CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt",
+   [CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt",
+   [DEVMAP_XMIT_CNT] = "devmap_xmit_cnt",
+};
+
+#define NUM_MAP 5
+#define NUM_TP 8
+
+static int tp_cnt;
+static int map_cnt;
 static int verbose = 1;
 static bool debug = false;
+struct bpf_map *map_data[NUM_MAP] = { 0 };
+struct bpf_link *tp_links[NUM_TP] = { 0 };
 
 static const struct option long_options[] = {
{"help",no_argument,NULL, 'h' },
@@ -41,6 +65,15 @@ static const struct option long_options[] = {
{0, 0, NULL,  0 }
 };
 
+static void int_exit(int sig)
+{
+   /* Detach tracepoints */
+   while (tp_cnt)
+   bpf_link__destroy(tp_links[--tp_cnt]);
+
+   exit(0);
+}
+
 /* C standard specifies two constants, EXIT_SUCCESS(0) and EXIT_FAILURE(1) */
 #define EXIT_FAIL_MEM  5
 
@@ -483,23 +516,23 @@ static bool stats_collect(struct stats_record *rec)
 * this can happen by someone running perf-record -e
 */
 
-   fd = map_data[0].fd; /* map0: redirect_err_cnt */
+   fd = bpf_map__fd(map_data[REDIRECT_ERR_CNT]);
for (i = 0; i < REDIR_RES_MAX; i++)
map_collect_record_u64(fd, i, &rec->xdp_redirect[i]);
 
-   fd = map_data[1].fd; /* map1: exception_cnt */
+   fd = bpf_map__fd(map_data[EXCEPTION_CNT]);
for (i = 0; i < XDP_ACTION_MAX; i++) {
map_collect_record_u64(fd, i, &rec->xdp_exception[i]);
}
 
-   fd = map_data[2].fd; /* map2: cpumap_enqueue_cnt */
+   fd = bpf_map__fd(map_data[CPUMAP_ENQUEUE_CNT]);
for (i = 0; i < MAX_CPUS; i++)
map_collect_record(fd, i, &rec->xdp_cpumap_enqueue[i]);
 
-   fd = map_data[3].fd; /* map3: cpumap_kthread_cnt */
+   fd = bpf_map__fd(map_data[CPUMAP_KTHREAD_CNT]);
map_collect_record(fd, 0, &rec->xdp_cpumap_kthread);
 
-   fd = map_data[4].fd; /* map4: devmap_xmit_cnt */
+   fd = bpf_map__fd(map_data[DEVMAP_XMIT_CNT]);
map_collect_record(fd, 0, &rec->xdp_devmap_xmit);
 
return true;
@@ -598,8 +631,8 @@ static void stats_poll(int interval, bool err_only)
 
/* TODO Need more advanced stats on error types */
if (verbose) {
-   printf(" - Stats map0: %s\n", map_data[0].name);
-   printf(" - Stats map1: %s\n", map_data[1].name);
+   printf(" - Stats map0: %s\n", bpf_map__name(map_data[0]));
+   printf(" - Stats map1: %s\n", bpf_map__name(map_data[1]));
printf("\n");
}
fflush(stdout);
@@ -616,46 +649,52 @@ static void stats_poll(int interval, bool err_only)
free_stats_record(prev);
 }
 
-static void print_bpf_prog_info(void)
+static void print_bpf_prog_info(struct bpf_object *obj)
 {
-

[PATCH bpf-next 0/3] samples: bpf: Refactor XDP programs with libbpf

2020-10-09 Thread Daniel T. Lee
To avoid confusion caused by the increasing fragmentation of the BPF
Loader program, this commit would like to convert the previous bpf_load
loader with the libbpf loader.

Thanks to libbpf's bpf_link interface, managing the tracepoint BPF
program is much easier. bpf_program__attach_tracepoint manages the
enable of tracepoint event and attach of BPF programs to it with a
single interface bpf_link, so there is no need to manage event_fd and
prog_fd separately.

And due to addition of generic bpf_program__attach() to libbpf, it is
now possible to attach BPF programs with __attach() instead of
explicitly calling __attach_().

This patchset refactors xdp_monitor with using this libbpf API, and the
bpf_load is removed and migrated to libbpf. Also, attach_tracepoint()
is replaced with the generic __attach() method in xdp_redirect_cpu.
Moreover, maps in kern program have been converted to BTF-defined map.

Daniel T. Lee (3):
  samples: bpf: Refactor xdp_monitor with libbpf
  samples: bpf: Replace attach_tracepoint() to attach() in
xdp_redirect_cpu
  samples: bpf: refactor XDP kern program maps with BTF-defined map

 samples/bpf/Makefile|   4 +-
 samples/bpf/xdp_monitor_kern.c  |  60 ++--
 samples/bpf/xdp_monitor_user.c  | 144 +---
 samples/bpf/xdp_redirect_cpu_user.c | 138 +-
 samples/bpf/xdp_sample_pkts_kern.c  |  14 ++-
 samples/bpf/xdp_sample_pkts_user.c  |   1 -
 6 files changed, 211 insertions(+), 150 deletions(-)

-- 
2.25.1



[PATCH bpf-next 3/3] samples: bpf: refactor XDP kern program maps with BTF-defined map

2020-10-09 Thread Daniel T. Lee
Most of the samples were converted to use the new BTF-defined MAP as
they moved to libbpf, but some of the samples were missing.

Instead of using the previous BPF MAP definition, this commit refactors
xdp_monitor and xdp_sample_pkts_kern MAP definition with the new
BTF-defined MAP format.

Also, this commit removes the max_entries attribute at PERF_EVENT_ARRAY
map type. The libbpf's bpf_object__create_map() will automatically
set max_entries to the maximum configured number of CPUs on the host.

Signed-off-by: Daniel T. Lee 
---
 samples/bpf/xdp_monitor_kern.c | 60 +++---
 samples/bpf/xdp_sample_pkts_kern.c | 14 +++
 samples/bpf/xdp_sample_pkts_user.c |  1 -
 3 files changed, 36 insertions(+), 39 deletions(-)

diff --git a/samples/bpf/xdp_monitor_kern.c b/samples/bpf/xdp_monitor_kern.c
index 3d33cca2d48a..5c955b812c47 100644
--- a/samples/bpf/xdp_monitor_kern.c
+++ b/samples/bpf/xdp_monitor_kern.c
@@ -6,21 +6,21 @@
 #include 
 #include 
 
-struct bpf_map_def SEC("maps") redirect_err_cnt = {
-   .type = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size = sizeof(u32),
-   .value_size = sizeof(u64),
-   .max_entries = 2,
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, u64);
+   __uint(max_entries, 2);
/* TODO: have entries for all possible errno's */
-};
+} redirect_err_cnt SEC(".maps");
 
 #define XDP_UNKNOWNXDP_REDIRECT + 1
-struct bpf_map_def SEC("maps") exception_cnt = {
-   .type   = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size   = sizeof(u32),
-   .value_size = sizeof(u64),
-   .max_entries= XDP_UNKNOWN + 1,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, u64);
+   __uint(max_entries, XDP_UNKNOWN + 1);
+} exception_cnt SEC(".maps");
 
 /* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_redirect/format
  * Code in:kernel/include/trace/events/xdp.h
@@ -129,19 +129,19 @@ struct datarec {
 };
 #define MAX_CPUS 64
 
-struct bpf_map_def SEC("maps") cpumap_enqueue_cnt = {
-   .type   = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size   = sizeof(u32),
-   .value_size = sizeof(struct datarec),
-   .max_entries= MAX_CPUS,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, struct datarec);
+   __uint(max_entries, MAX_CPUS);
+} cpumap_enqueue_cnt SEC(".maps");
 
-struct bpf_map_def SEC("maps") cpumap_kthread_cnt = {
-   .type   = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size   = sizeof(u32),
-   .value_size = sizeof(struct datarec),
-   .max_entries= 1,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, struct datarec);
+   __uint(max_entries, 1);
+} cpumap_kthread_cnt SEC(".maps");
 
 /* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_enqueue/format
  * Code in: kernel/include/trace/events/xdp.h
@@ -210,12 +210,12 @@ int trace_xdp_cpumap_kthread(struct cpumap_kthread_ctx 
*ctx)
return 0;
 }
 
-struct bpf_map_def SEC("maps") devmap_xmit_cnt = {
-   .type   = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size   = sizeof(u32),
-   .value_size = sizeof(struct datarec),
-   .max_entries= 1,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, struct datarec);
+   __uint(max_entries, 1);
+} devmap_xmit_cnt SEC(".maps");
 
 /* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_devmap_xmit/format
  * Code in: kernel/include/trace/events/xdp.h
diff --git a/samples/bpf/xdp_sample_pkts_kern.c 
b/samples/bpf/xdp_sample_pkts_kern.c
index 33377289e2a8..2fc3ecc9d9aa 100644
--- a/samples/bpf/xdp_sample_pkts_kern.c
+++ b/samples/bpf/xdp_sample_pkts_kern.c
@@ -5,14 +5,12 @@
 #include 
 
 #define SAMPLE_SIZE 64ul
-#define MAX_CPUS 128
-
-struct bpf_map_def SEC("maps") my_map = {
-   .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
-   .key_size = sizeof(int),
-   .value_size = sizeof(u32),
-   .max_entries = MAX_CPUS,
-};
+
+struct {
+   __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
+   __type(key, int);
+   __type(value, u32);
+} my_map SEC(".maps");
 
 SEC("xdp_sample")
 int xdp_sample_prog(struct xdp_md *ctx)
diff --git a/samples/bpf/xdp_sample_pkts_user.c 
b/samples/bpf/xdp_sample_pkts_user.c
index 991ef6f0880b..4b2a300c750c 100644
--- a/samples/bpf/xdp_sample_pkts_user.c
+++ b/samples/bpf/xdp_sample_pkts_user.c
@@ -18,7 +18,6 @@
 
 #include "perf-sys.h"
 
-#define MAX_CPUS 128
 static int if_idx;
 static char *if_name;
 static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
-- 
2.25.1



[PATCH bpf-next 2/3] samples: bpf: Replace attach_tracepoint() to attach() in xdp_redirect_cpu

2020-10-09 Thread Daniel T. Lee
>From commit d7a18ea7e8b6 ("libbpf: Add generic bpf_program__attach()"),
for some BPF programs, it is now possible to attach BPF programs
with __attach() instead of explicitly calling __attach_().

This commit refactors the __attach_tracepoint() with libbpf's generic
__attach() method. In addition, this refactors the logic of setting
the map FD to simplify the code. Also, the missing removal of
bpf_load.o in Makefile has been fixed.

Signed-off-by: Daniel T. Lee 
---
 samples/bpf/Makefile|   2 +-
 samples/bpf/xdp_redirect_cpu_user.c | 138 +---
 2 files changed, 67 insertions(+), 73 deletions(-)

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 0cee2aa8970f..ac9175705b2f 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -98,7 +98,7 @@ test_map_in_map-objs := test_map_in_map_user.o
 per_socket_stats_example-objs := cookie_uid_helper_example.o
 xdp_redirect-objs := xdp_redirect_user.o
 xdp_redirect_map-objs := xdp_redirect_map_user.o
-xdp_redirect_cpu-objs := bpf_load.o xdp_redirect_cpu_user.o
+xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o
 xdp_monitor-objs := xdp_monitor_user.o
 xdp_rxq_info-objs := xdp_rxq_info_user.o
 syscall_tp-objs := syscall_tp_user.o
diff --git a/samples/bpf/xdp_redirect_cpu_user.c 
b/samples/bpf/xdp_redirect_cpu_user.c
index 3dd366e9474d..805b5df5e47b 100644
--- a/samples/bpf/xdp_redirect_cpu_user.c
+++ b/samples/bpf/xdp_redirect_cpu_user.c
@@ -37,18 +37,35 @@ static __u32 prog_id;
 
 static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
 static int n_cpus;
-static int cpu_map_fd;
-static int rx_cnt_map_fd;
-static int redirect_err_cnt_map_fd;
-static int cpumap_enqueue_cnt_map_fd;
-static int cpumap_kthread_cnt_map_fd;
-static int cpus_available_map_fd;
-static int cpus_count_map_fd;
-static int cpus_iterator_map_fd;
-static int exception_cnt_map_fd;
+
+enum map_type {
+   CPU_MAP,
+   RX_CNT,
+   REDIRECT_ERR_CNT,
+   CPUMAP_ENQUEUE_CNT,
+   CPUMAP_KTHREAD_CNT,
+   CPUS_AVAILABLE,
+   CPUS_COUNT,
+   CPUS_ITERATOR,
+   EXCEPTION_CNT,
+};
+
+static const char *const map_type_strings[] = {
+   [CPU_MAP] = "cpu_map",
+   [RX_CNT] = "rx_cnt",
+   [REDIRECT_ERR_CNT] = "redirect_err_cnt",
+   [CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt",
+   [CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt",
+   [CPUS_AVAILABLE] = "cpus_available",
+   [CPUS_COUNT] = "cpus_count",
+   [CPUS_ITERATOR] = "cpus_iterator",
+   [EXCEPTION_CNT] = "exception_cnt",
+};
 
 #define NUM_TP 5
+#define NUM_MAP 9
 struct bpf_link *tp_links[NUM_TP] = { 0 };
+static int map_fds[NUM_MAP];
 static int tp_cnt = 0;
 
 /* Exit return codes */
@@ -527,20 +544,20 @@ static void stats_collect(struct stats_record *rec)
 {
int fd, i;
 
-   fd = rx_cnt_map_fd;
+   fd = map_fds[RX_CNT];
map_collect_percpu(fd, 0, &rec->rx_cnt);
 
-   fd = redirect_err_cnt_map_fd;
+   fd = map_fds[REDIRECT_ERR_CNT];
map_collect_percpu(fd, 1, &rec->redir_err);
 
-   fd = cpumap_enqueue_cnt_map_fd;
+   fd = map_fds[CPUMAP_ENQUEUE_CNT];
for (i = 0; i < n_cpus; i++)
map_collect_percpu(fd, i, &rec->enq[i]);
 
-   fd = cpumap_kthread_cnt_map_fd;
+   fd = map_fds[CPUMAP_KTHREAD_CNT];
map_collect_percpu(fd, 0, &rec->kthread);
 
-   fd = exception_cnt_map_fd;
+   fd = map_fds[EXCEPTION_CNT];
map_collect_percpu(fd, 0, &rec->exception);
 }
 
@@ -565,7 +582,7 @@ static int create_cpu_entry(__u32 cpu, struct 
bpf_cpumap_val *value,
/* Add a CPU entry to cpumap, as this allocate a cpu entry in
 * the kernel for the cpu.
 */
-   ret = bpf_map_update_elem(cpu_map_fd, &cpu, value, 0);
+   ret = bpf_map_update_elem(map_fds[CPU_MAP], &cpu, value, 0);
if (ret) {
fprintf(stderr, "Create CPU entry failed (err:%d)\n", ret);
exit(EXIT_FAIL_BPF);
@@ -574,21 +591,21 @@ static int create_cpu_entry(__u32 cpu, struct 
bpf_cpumap_val *value,
/* Inform bpf_prog's that a new CPU is available to select
 * from via some control maps.
 */
-   ret = bpf_map_update_elem(cpus_available_map_fd, &avail_idx, &cpu, 0);
+   ret = bpf_map_update_elem(map_fds[CPUS_AVAILABLE], &avail_idx, &cpu, 0);
if (ret) {
fprintf(stderr, "Add to avail CPUs failed\n");
exit(EXIT_FAIL_BPF);
}
 
/* When not replacing/updating existing entry, bump the count */
-   ret = bpf_map_lookup_elem(cpus_count_map_fd, &key, &curr_cpus_count);
+   ret = bpf_map_lookup_elem(map_fds[CPUS_COUNT], &key, &curr_cpus_count);
if (ret) {
fprintf(stderr, "Failed reading curr cpus_count\n"

Re: [PATCH bpf-next 1/3] samples: bpf: Refactor xdp_monitor with libbpf

2020-10-10 Thread Daniel T. Lee
On Sat, Oct 10, 2020 at 3:17 AM Andrii Nakryiko
 wrote:
>
> On Fri, Oct 9, 2020 at 9:04 AM Daniel T. Lee  wrote:
> >
> > To avoid confusion caused by the increasing fragmentation of the BPF
> > Loader program, this commit would like to change to the libbpf loader
> > instead of using the bpf_load.
> >
> > Thanks to libbpf's bpf_link interface, managing the tracepoint BPF
> > program is much easier. bpf_program__attach_tracepoint manages the
> > enable of tracepoint event and attach of BPF programs to it with a
> > single interface bpf_link, so there is no need to manage event_fd and
> > prog_fd separately.
> >
> > This commit refactors xdp_monitor with using this libbpf API, and the
> > bpf_load is removed and migrated to libbpf.
> >
> > Signed-off-by: Daniel T. Lee 
> > ---
> >  samples/bpf/Makefile   |   2 +-
> >  samples/bpf/xdp_monitor_user.c | 144 -
> >  2 files changed, 108 insertions(+), 38 deletions(-)
> >
>
> [...]
>
> > +static int tp_cnt;
> > +static int map_cnt;
> >  static int verbose = 1;
> >  static bool debug = false;
> > +struct bpf_map *map_data[NUM_MAP] = { 0 };
> > +struct bpf_link *tp_links[NUM_TP] = { 0 };
>
> this syntax means "initialize *only the first element* to 0
> (explicitly) and the rest of elements to default (which is also 0)".
> So it's just misleading, use ` = {}`.
>

Thanks for the great review!

Come to think of it, it could be confusing as you mentioned. I will
remove the unnecessary initializer in the next patch and resend it.

> >
> >  static const struct option long_options[] = {
> > {"help",no_argument,NULL, 'h' },
> > @@ -41,6 +65,15 @@ static const struct option long_options[] = {
> > {0, 0, NULL,  0 }
> >  };
> >
> > +static void int_exit(int sig)
> > +{
> > +   /* Detach tracepoints */
> > +   while (tp_cnt)
> > +   bpf_link__destroy(tp_links[--tp_cnt]);
> > +
>
> see below about proper cleanup
>
> > +   exit(0);
> > +}
> > +
> >  /* C standard specifies two constants, EXIT_SUCCESS(0) and EXIT_FAILURE(1) 
> > */
> >  #define EXIT_FAIL_MEM  5
> >
>
> [...]
>
> >
> > -static void print_bpf_prog_info(void)
> > +static void print_bpf_prog_info(struct bpf_object *obj)
> >  {
> > -   int i;
> > +   struct bpf_program *prog;
> > +   struct bpf_map *map;
> > +   int i = 0;
> >
> > /* Prog info */
> > -   printf("Loaded BPF prog have %d bpf program(s)\n", prog_cnt);
> > -   for (i = 0; i < prog_cnt; i++) {
> > -   printf(" - prog_fd[%d] = fd(%d)\n", i, prog_fd[i]);
> > +   printf("Loaded BPF prog have %d bpf program(s)\n", tp_cnt);
> > +   bpf_object__for_each_program(prog, obj) {
> > +   printf(" - prog_fd[%d] = fd(%d)\n", i++, 
> > bpf_program__fd(prog));
> > }
> >
> > +   i = 0;
> > /* Maps info */
> > -   printf("Loaded BPF prog have %d map(s)\n", map_data_count);
> > -   for (i = 0; i < map_data_count; i++) {
> > -   char *name = map_data[i].name;
> > -   int fd = map_data[i].fd;
> > +   printf("Loaded BPF prog have %d map(s)\n", map_cnt);
> > +   bpf_object__for_each_map(map, obj) {
> > +   const char *name = bpf_map__name(map);
> > +   int fd   = bpf_map__fd(map);
> >
> > -   printf(" - map_data[%d] = fd(%d) name:%s\n", i, fd, name);
> > +   printf(" - map_data[%d] = fd(%d) name:%s\n", i++, fd, name);
>
> please move out increment into a separate statement, no need to
> confuse readers unnecessarily
>

I will fix it at the following patch.

> > }
> >
> > /* Event info */
> > -   printf("Searching for (max:%d) event file descriptor(s)\n", 
> > prog_cnt);
> > -   for (i = 0; i < prog_cnt; i++) {
> > -   if (event_fd[i] != -1)
> > -   printf(" - event_fd[%d] = fd(%d)\n", i, 
> > event_fd[i]);
> > +   printf("Searching for (max:%d) event file descriptor(s)\n", tp_cnt);
> > +   for (i = 0; i < tp_cnt; i++) {
> > +   int fd = bpf_link__fd(tp_links[i]);
> > +
> > +   if (fd != -1)
> > +   pri

Re: [PATCH bpf-next 3/3] samples: bpf: refactor XDP kern program maps with BTF-defined map

2020-10-10 Thread Daniel T. Lee
On Sat, Oct 10, 2020 at 3:25 AM Andrii Nakryiko
 wrote:
>
> On Fri, Oct 9, 2020 at 9:04 AM Daniel T. Lee  wrote:
> >
> > Most of the samples were converted to use the new BTF-defined MAP as
> > they moved to libbpf, but some of the samples were missing.
> >
> > Instead of using the previous BPF MAP definition, this commit refactors
> > xdp_monitor and xdp_sample_pkts_kern MAP definition with the new
> > BTF-defined MAP format.
> >
> > Also, this commit removes the max_entries attribute at PERF_EVENT_ARRAY
> > map type. The libbpf's bpf_object__create_map() will automatically
> > set max_entries to the maximum configured number of CPUs on the host.
> >
> > Signed-off-by: Daniel T. Lee 
> > ---
> >  samples/bpf/xdp_monitor_kern.c | 60 +++---
> >  samples/bpf/xdp_sample_pkts_kern.c | 14 +++
> >  samples/bpf/xdp_sample_pkts_user.c |  1 -
> >  3 files changed, 36 insertions(+), 39 deletions(-)
> >
>
> [...]
>
> > --- a/samples/bpf/xdp_sample_pkts_kern.c
> > +++ b/samples/bpf/xdp_sample_pkts_kern.c
> > @@ -5,14 +5,12 @@
> >  #include 
> >
> >  #define SAMPLE_SIZE 64ul
> > -#define MAX_CPUS 128
> > -
> > -struct bpf_map_def SEC("maps") my_map = {
> > -   .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
> > -   .key_size = sizeof(int),
> > -   .value_size = sizeof(u32),
> > -   .max_entries = MAX_CPUS,
> > -};
> > +
> > +struct {
> > +   __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
> > +   __type(key, int);
> > +   __type(value, u32);
>
>
> this actually will generate unnecessary libbpf warnings, because
> PERF_EVENT_ARRAY doesn't support BTF types for key/value. So use
> __uint(key_size, sizeof(int)) and __uint(value_size, sizeof(u32))
> instead.
>

Thanks for the great review!
I'll fix it right away and send the next version of patch.


> > +} my_map SEC(".maps");
> >
> >  SEC("xdp_sample")
> >  int xdp_sample_prog(struct xdp_md *ctx)
> > diff --git a/samples/bpf/xdp_sample_pkts_user.c 
> > b/samples/bpf/xdp_sample_pkts_user.c
> > index 991ef6f0880b..4b2a300c750c 100644
> > --- a/samples/bpf/xdp_sample_pkts_user.c
> > +++ b/samples/bpf/xdp_sample_pkts_user.c
> > @@ -18,7 +18,6 @@
> >
> >  #include "perf-sys.h"
> >
> > -#define MAX_CPUS 128
> >  static int if_idx;
> >  static char *if_name;
> >  static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
> > --
> > 2.25.1
> >


[PATCH bpf-next v2 2/3] samples: bpf: Replace attach_tracepoint() to attach() in xdp_redirect_cpu

2020-10-10 Thread Daniel T. Lee
>From commit d7a18ea7e8b6 ("libbpf: Add generic bpf_program__attach()"),
for some BPF programs, it is now possible to attach BPF programs
with __attach() instead of explicitly calling __attach_().

This commit refactors the __attach_tracepoint() with libbpf's generic
__attach() method. In addition, this refactors the logic of setting
the map FD to simplify the code. Also, the missing removal of
bpf_load.o in Makefile has been fixed.

Signed-off-by: Daniel T. Lee 

---
Changes in v2:
 - program section match with bpf_program__is_ instead of strncmp
 - refactor pointer array initialization
 - error code cleanup

 samples/bpf/Makefile|   2 +-
 samples/bpf/xdp_redirect_cpu_user.c | 153 +---
 2 files changed, 73 insertions(+), 82 deletions(-)

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 0cee2aa8970f..ac9175705b2f 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -98,7 +98,7 @@ test_map_in_map-objs := test_map_in_map_user.o
 per_socket_stats_example-objs := cookie_uid_helper_example.o
 xdp_redirect-objs := xdp_redirect_user.o
 xdp_redirect_map-objs := xdp_redirect_map_user.o
-xdp_redirect_cpu-objs := bpf_load.o xdp_redirect_cpu_user.o
+xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o
 xdp_monitor-objs := xdp_monitor_user.o
 xdp_rxq_info-objs := xdp_rxq_info_user.o
 syscall_tp-objs := syscall_tp_user.o
diff --git a/samples/bpf/xdp_redirect_cpu_user.c 
b/samples/bpf/xdp_redirect_cpu_user.c
index 3dd366e9474d..6fb8dbde62c5 100644
--- a/samples/bpf/xdp_redirect_cpu_user.c
+++ b/samples/bpf/xdp_redirect_cpu_user.c
@@ -37,18 +37,35 @@ static __u32 prog_id;
 
 static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
 static int n_cpus;
-static int cpu_map_fd;
-static int rx_cnt_map_fd;
-static int redirect_err_cnt_map_fd;
-static int cpumap_enqueue_cnt_map_fd;
-static int cpumap_kthread_cnt_map_fd;
-static int cpus_available_map_fd;
-static int cpus_count_map_fd;
-static int cpus_iterator_map_fd;
-static int exception_cnt_map_fd;
+
+enum map_type {
+   CPU_MAP,
+   RX_CNT,
+   REDIRECT_ERR_CNT,
+   CPUMAP_ENQUEUE_CNT,
+   CPUMAP_KTHREAD_CNT,
+   CPUS_AVAILABLE,
+   CPUS_COUNT,
+   CPUS_ITERATOR,
+   EXCEPTION_CNT,
+};
+
+static const char *const map_type_strings[] = {
+   [CPU_MAP] = "cpu_map",
+   [RX_CNT] = "rx_cnt",
+   [REDIRECT_ERR_CNT] = "redirect_err_cnt",
+   [CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt",
+   [CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt",
+   [CPUS_AVAILABLE] = "cpus_available",
+   [CPUS_COUNT] = "cpus_count",
+   [CPUS_ITERATOR] = "cpus_iterator",
+   [EXCEPTION_CNT] = "exception_cnt",
+};
 
 #define NUM_TP 5
-struct bpf_link *tp_links[NUM_TP] = { 0 };
+#define NUM_MAP 9
+struct bpf_link *tp_links[NUM_TP] = {};
+static int map_fds[NUM_MAP];
 static int tp_cnt = 0;
 
 /* Exit return codes */
@@ -527,20 +544,20 @@ static void stats_collect(struct stats_record *rec)
 {
int fd, i;
 
-   fd = rx_cnt_map_fd;
+   fd = map_fds[RX_CNT];
map_collect_percpu(fd, 0, &rec->rx_cnt);
 
-   fd = redirect_err_cnt_map_fd;
+   fd = map_fds[REDIRECT_ERR_CNT];
map_collect_percpu(fd, 1, &rec->redir_err);
 
-   fd = cpumap_enqueue_cnt_map_fd;
+   fd = map_fds[CPUMAP_ENQUEUE_CNT];
for (i = 0; i < n_cpus; i++)
map_collect_percpu(fd, i, &rec->enq[i]);
 
-   fd = cpumap_kthread_cnt_map_fd;
+   fd = map_fds[CPUMAP_KTHREAD_CNT];
map_collect_percpu(fd, 0, &rec->kthread);
 
-   fd = exception_cnt_map_fd;
+   fd = map_fds[EXCEPTION_CNT];
map_collect_percpu(fd, 0, &rec->exception);
 }
 
@@ -565,7 +582,7 @@ static int create_cpu_entry(__u32 cpu, struct 
bpf_cpumap_val *value,
/* Add a CPU entry to cpumap, as this allocate a cpu entry in
 * the kernel for the cpu.
 */
-   ret = bpf_map_update_elem(cpu_map_fd, &cpu, value, 0);
+   ret = bpf_map_update_elem(map_fds[CPU_MAP], &cpu, value, 0);
if (ret) {
fprintf(stderr, "Create CPU entry failed (err:%d)\n", ret);
exit(EXIT_FAIL_BPF);
@@ -574,21 +591,21 @@ static int create_cpu_entry(__u32 cpu, struct 
bpf_cpumap_val *value,
/* Inform bpf_prog's that a new CPU is available to select
 * from via some control maps.
 */
-   ret = bpf_map_update_elem(cpus_available_map_fd, &avail_idx, &cpu, 0);
+   ret = bpf_map_update_elem(map_fds[CPUS_AVAILABLE], &avail_idx, &cpu, 0);
if (ret) {
fprintf(stderr, "Add to avail CPUs failed\n");
exit(EXIT_FAIL_BPF);
}
 
/* When not replacing/updating existing entry, bump the count */
-   ret = bpf_map_lookup_elem(cpus_count_map_fd, &key, &curr_cpus_count);

[PATCH bpf-next v2 0/3] samples: bpf: Refactor XDP programs with libbpf

2020-10-10 Thread Daniel T. Lee
To avoid confusion caused by the increasing fragmentation of the BPF
Loader program, this commit would like to convert the previous bpf_load
loader with the libbpf loader.

Thanks to libbpf's bpf_link interface, managing the tracepoint BPF
program is much easier. bpf_program__attach_tracepoint manages the
enable of tracepoint event and attach of BPF programs to it with a
single interface bpf_link, so there is no need to manage event_fd and
prog_fd separately.

And due to addition of generic bpf_program__attach() to libbpf, it is
now possible to attach BPF programs with __attach() instead of
explicitly calling __attach_().

This patchset refactors xdp_monitor with using this libbpf API, and the
bpf_load is removed and migrated to libbpf. Also, attach_tracepoint()
is replaced with the generic __attach() method in xdp_redirect_cpu.
Moreover, maps in kern program have been converted to BTF-defined map.

---
Changes in v2:
 - added cleanup logic for bpf_link and bpf_object in xdp_monitor
 - program section match with bpf_program__is_ instead of strncmp
 - revert BTF key/val type to default of BPF_MAP_TYPE_PERF_EVENT_ARRAY
 - split increment into seperate satement
 - refactor pointer array initialization
 - error code cleanup

Daniel T. Lee (3):
  samples: bpf: Refactor xdp_monitor with libbpf
  samples: bpf: Replace attach_tracepoint() to attach() in
xdp_redirect_cpu
  samples: bpf: refactor XDP kern program maps with BTF-defined map

 samples/bpf/Makefile|   4 +-
 samples/bpf/xdp_monitor_kern.c  |  60 +--
 samples/bpf/xdp_monitor_user.c  | 159 +---
 samples/bpf/xdp_redirect_cpu_user.c | 153 +-
 samples/bpf/xdp_sample_pkts_kern.c  |  14 ++-
 samples/bpf/xdp_sample_pkts_user.c  |   1 -
 6 files changed, 230 insertions(+), 161 deletions(-)

-- 
2.25.1



[PATCH bpf-next v2 2/3] samples: bpf: Replace attach_tracepoint() to attach() in xdp_redirect_cpu

2020-10-10 Thread Daniel T. Lee
>From commit d7a18ea7e8b6 ("libbpf: Add generic bpf_program__attach()"),
for some BPF programs, it is now possible to attach BPF programs
with __attach() instead of explicitly calling __attach_().

This commit refactors the __attach_tracepoint() with libbpf's generic
__attach() method. In addition, this refactors the logic of setting
the map FD to simplify the code. Also, the missing removal of
bpf_load.o in Makefile has been fixed.

Signed-off-by: Daniel T. Lee 

---
Changes in v2:
 - program section match with bpf_program__is_ instead of strncmp
 - refactor pointer array initialization
 - error code cleanup

 samples/bpf/Makefile|   2 +-
 samples/bpf/xdp_redirect_cpu_user.c | 153 +---
 2 files changed, 73 insertions(+), 82 deletions(-)

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 0cee2aa8970f..ac9175705b2f 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -98,7 +98,7 @@ test_map_in_map-objs := test_map_in_map_user.o
 per_socket_stats_example-objs := cookie_uid_helper_example.o
 xdp_redirect-objs := xdp_redirect_user.o
 xdp_redirect_map-objs := xdp_redirect_map_user.o
-xdp_redirect_cpu-objs := bpf_load.o xdp_redirect_cpu_user.o
+xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o
 xdp_monitor-objs := xdp_monitor_user.o
 xdp_rxq_info-objs := xdp_rxq_info_user.o
 syscall_tp-objs := syscall_tp_user.o
diff --git a/samples/bpf/xdp_redirect_cpu_user.c 
b/samples/bpf/xdp_redirect_cpu_user.c
index 3dd366e9474d..6fb8dbde62c5 100644
--- a/samples/bpf/xdp_redirect_cpu_user.c
+++ b/samples/bpf/xdp_redirect_cpu_user.c
@@ -37,18 +37,35 @@ static __u32 prog_id;
 
 static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
 static int n_cpus;
-static int cpu_map_fd;
-static int rx_cnt_map_fd;
-static int redirect_err_cnt_map_fd;
-static int cpumap_enqueue_cnt_map_fd;
-static int cpumap_kthread_cnt_map_fd;
-static int cpus_available_map_fd;
-static int cpus_count_map_fd;
-static int cpus_iterator_map_fd;
-static int exception_cnt_map_fd;
+
+enum map_type {
+   CPU_MAP,
+   RX_CNT,
+   REDIRECT_ERR_CNT,
+   CPUMAP_ENQUEUE_CNT,
+   CPUMAP_KTHREAD_CNT,
+   CPUS_AVAILABLE,
+   CPUS_COUNT,
+   CPUS_ITERATOR,
+   EXCEPTION_CNT,
+};
+
+static const char *const map_type_strings[] = {
+   [CPU_MAP] = "cpu_map",
+   [RX_CNT] = "rx_cnt",
+   [REDIRECT_ERR_CNT] = "redirect_err_cnt",
+   [CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt",
+   [CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt",
+   [CPUS_AVAILABLE] = "cpus_available",
+   [CPUS_COUNT] = "cpus_count",
+   [CPUS_ITERATOR] = "cpus_iterator",
+   [EXCEPTION_CNT] = "exception_cnt",
+};
 
 #define NUM_TP 5
-struct bpf_link *tp_links[NUM_TP] = { 0 };
+#define NUM_MAP 9
+struct bpf_link *tp_links[NUM_TP] = {};
+static int map_fds[NUM_MAP];
 static int tp_cnt = 0;
 
 /* Exit return codes */
@@ -527,20 +544,20 @@ static void stats_collect(struct stats_record *rec)
 {
int fd, i;
 
-   fd = rx_cnt_map_fd;
+   fd = map_fds[RX_CNT];
map_collect_percpu(fd, 0, &rec->rx_cnt);
 
-   fd = redirect_err_cnt_map_fd;
+   fd = map_fds[REDIRECT_ERR_CNT];
map_collect_percpu(fd, 1, &rec->redir_err);
 
-   fd = cpumap_enqueue_cnt_map_fd;
+   fd = map_fds[CPUMAP_ENQUEUE_CNT];
for (i = 0; i < n_cpus; i++)
map_collect_percpu(fd, i, &rec->enq[i]);
 
-   fd = cpumap_kthread_cnt_map_fd;
+   fd = map_fds[CPUMAP_KTHREAD_CNT];
map_collect_percpu(fd, 0, &rec->kthread);
 
-   fd = exception_cnt_map_fd;
+   fd = map_fds[EXCEPTION_CNT];
map_collect_percpu(fd, 0, &rec->exception);
 }
 
@@ -565,7 +582,7 @@ static int create_cpu_entry(__u32 cpu, struct 
bpf_cpumap_val *value,
/* Add a CPU entry to cpumap, as this allocate a cpu entry in
 * the kernel for the cpu.
 */
-   ret = bpf_map_update_elem(cpu_map_fd, &cpu, value, 0);
+   ret = bpf_map_update_elem(map_fds[CPU_MAP], &cpu, value, 0);
if (ret) {
fprintf(stderr, "Create CPU entry failed (err:%d)\n", ret);
exit(EXIT_FAIL_BPF);
@@ -574,21 +591,21 @@ static int create_cpu_entry(__u32 cpu, struct 
bpf_cpumap_val *value,
/* Inform bpf_prog's that a new CPU is available to select
 * from via some control maps.
 */
-   ret = bpf_map_update_elem(cpus_available_map_fd, &avail_idx, &cpu, 0);
+   ret = bpf_map_update_elem(map_fds[CPUS_AVAILABLE], &avail_idx, &cpu, 0);
if (ret) {
fprintf(stderr, "Add to avail CPUs failed\n");
exit(EXIT_FAIL_BPF);
}
 
/* When not replacing/updating existing entry, bump the count */
-   ret = bpf_map_lookup_elem(cpus_count_map_fd, &key, &curr_cpus_count);

Re: [PATCH bpf-next 2/3] samples: bpf: Replace attach_tracepoint() to attach() in xdp_redirect_cpu

2020-10-10 Thread Daniel T. Lee
On Sat, Oct 10, 2020 at 3:23 AM Andrii Nakryiko
 wrote:
>
> On Fri, Oct 9, 2020 at 9:04 AM Daniel T. Lee  wrote:
> >
> > From commit d7a18ea7e8b6 ("libbpf: Add generic bpf_program__attach()"),
> > for some BPF programs, it is now possible to attach BPF programs
> > with __attach() instead of explicitly calling __attach_().
> >
> > This commit refactors the __attach_tracepoint() with libbpf's generic
> > __attach() method. In addition, this refactors the logic of setting
> > the map FD to simplify the code. Also, the missing removal of
> > bpf_load.o in Makefile has been fixed.
> >
> > Signed-off-by: Daniel T. Lee 
> > ---
> >  samples/bpf/Makefile|   2 +-
> >  samples/bpf/xdp_redirect_cpu_user.c | 138 +---
> >  2 files changed, 67 insertions(+), 73 deletions(-)
> >
>
> [...]
>
> >  #define NUM_TP 5
> > +#define NUM_MAP 9
> >  struct bpf_link *tp_links[NUM_TP] = { 0 };
>
> = {}
>
> > +static int map_fds[NUM_MAP];
> >  static int tp_cnt = 0;
> >
> >  /* Exit return codes */
>
> [...]
>
> > -static struct bpf_link * attach_tp(struct bpf_object *obj,
> > -  const char *tp_category,
> > -  const char* tp_name)
> > +static int init_tracepoints(struct bpf_object *obj)
> >  {
> > +   char *tp_section = "tracepoint/";
> > struct bpf_program *prog;
> > -   struct bpf_link *link;
> > -   char sec_name[PATH_MAX];
> > -   int len;
> > +   const char *section;
> >
> > -   len = snprintf(sec_name, PATH_MAX, "tracepoint/%s/%s",
> > -  tp_category, tp_name);
> > -   if (len < 0)
> > -   exit(EXIT_FAIL);
> > +   bpf_object__for_each_program(prog, obj) {
> > +   section = bpf_program__section_name(prog);
> > +   if (strncmp(section, tp_section, strlen(tp_section)) != 0)
> > +   continue;
>
> that's a convoluted and error-prone way (you can also use "tp/bla/bla"
> for tracepoint programs, for example). Use
> bpf_program__is_tracepoint() check.
>

Thanks for the review!
I think that's a much better way. I will send the next patch with applying
that method.

> >
> > -   prog = bpf_object__find_program_by_title(obj, sec_name);
> > -   if (!prog) {
> > -   fprintf(stderr, "ERR: finding progsec: %s\n", sec_name);
> > -   exit(EXIT_FAIL_BPF);
> > +   tp_links[tp_cnt] = bpf_program__attach(prog);
> > +   if (libbpf_get_error(tp_links[tp_cnt])) {
> > +   tp_links[tp_cnt] = NULL;
> > +   return -EINVAL;
> > +   }
> > +   tp_cnt++;
> > }
> >
>
> [...]


Re: [PATCH bpf-next 0/3] samples: bpf: Refactor XDP programs with libbpf

2020-10-10 Thread Daniel T. Lee
On Sat, Oct 10, 2020 at 3:30 AM Andrii Nakryiko
 wrote:
>
> On Fri, Oct 9, 2020 at 9:04 AM Daniel T. Lee  wrote:
> >
> > To avoid confusion caused by the increasing fragmentation of the BPF
> > Loader program, this commit would like to convert the previous bpf_load
> > loader with the libbpf loader.
> >
> > Thanks to libbpf's bpf_link interface, managing the tracepoint BPF
> > program is much easier. bpf_program__attach_tracepoint manages the
> > enable of tracepoint event and attach of BPF programs to it with a
> > single interface bpf_link, so there is no need to manage event_fd and
> > prog_fd separately.
> >
> > And due to addition of generic bpf_program__attach() to libbpf, it is
> > now possible to attach BPF programs with __attach() instead of
> > explicitly calling __attach_().
> >
> > This patchset refactors xdp_monitor with using this libbpf API, and the
> > bpf_load is removed and migrated to libbpf. Also, attach_tracepoint()
> > is replaced with the generic __attach() method in xdp_redirect_cpu.
> > Moreover, maps in kern program have been converted to BTF-defined map.
> >
> > Daniel T. Lee (3):
> >   samples: bpf: Refactor xdp_monitor with libbpf
> >   samples: bpf: Replace attach_tracepoint() to attach() in
> > xdp_redirect_cpu
> >   samples: bpf: refactor XDP kern program maps with BTF-defined map
> >
> >  samples/bpf/Makefile|   4 +-
> >  samples/bpf/xdp_monitor_kern.c  |  60 ++--
> >  samples/bpf/xdp_monitor_user.c  | 144 +---
> >  samples/bpf/xdp_redirect_cpu_user.c | 138 +-
> >  samples/bpf/xdp_sample_pkts_kern.c  |  14 ++-
> >  samples/bpf/xdp_sample_pkts_user.c  |   1 -
> >  6 files changed, 211 insertions(+), 150 deletions(-)
> >
> > --
> > 2.25.1
> >
>
> Thanks for this clean up, Daniel! It's great! I left a few nits here
> and there in the appropriate patches.
>
> There still seem to be a bunch of users of bpf_load.c, which would be
> nice to get rid of completely. But before you go do that, consider
> integrating BPF skeleton into samples/bpf Makefile. That way instead
> of all those look ups of maps/programs by name, you'd be writing a
> straightforward skel->maps.my_map and similar short and non-failing
> code. This should make the overall time spent on conversion much
> smaller (and more pleasant, IMO).
>
> You've dealt with a lot of samples/bpf reworking, so it should be too
> hard for you to figure out the best way to do this, but check
> selftests/bpf's Makefile, if you need some ideas. Or just ask for
> help. Thanks!

Thanks for the great feedback!

Thank you for letting me know about the BPF features that I can apply.
Currently, I'm not familiar with the BPF skeleton yet, but I'll take a good
look at the BPF skeleton to apply it in a more advanced form.

Thank you for your time and effort for the review.

-- 
Best,
Daniel T. Lee


[PATCH bpf-next v2 3/3] samples: bpf: refactor XDP kern program maps with BTF-defined map

2020-10-10 Thread Daniel T. Lee
Most of the samples were converted to use the new BTF-defined MAP as
they moved to libbpf, but some of the samples were missing.

Instead of using the previous BPF MAP definition, this commit refactors
xdp_monitor and xdp_sample_pkts_kern MAP definition with the new
BTF-defined MAP format.

Also, this commit removes the max_entries attribute at PERF_EVENT_ARRAY
map type. The libbpf's bpf_object__create_map() will automatically
set max_entries to the maximum configured number of CPUs on the host.

Signed-off-by: Daniel T. Lee 

---
Changes in v2:
 - revert BTF key/val type to default of BPF_MAP_TYPE_PERF_EVENT_ARRAY

 samples/bpf/xdp_monitor_kern.c | 60 +++---
 samples/bpf/xdp_sample_pkts_kern.c | 14 +++
 samples/bpf/xdp_sample_pkts_user.c |  1 -
 3 files changed, 36 insertions(+), 39 deletions(-)

diff --git a/samples/bpf/xdp_monitor_kern.c b/samples/bpf/xdp_monitor_kern.c
index 3d33cca2d48a..5c955b812c47 100644
--- a/samples/bpf/xdp_monitor_kern.c
+++ b/samples/bpf/xdp_monitor_kern.c
@@ -6,21 +6,21 @@
 #include 
 #include 
 
-struct bpf_map_def SEC("maps") redirect_err_cnt = {
-   .type = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size = sizeof(u32),
-   .value_size = sizeof(u64),
-   .max_entries = 2,
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, u64);
+   __uint(max_entries, 2);
/* TODO: have entries for all possible errno's */
-};
+} redirect_err_cnt SEC(".maps");
 
 #define XDP_UNKNOWNXDP_REDIRECT + 1
-struct bpf_map_def SEC("maps") exception_cnt = {
-   .type   = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size   = sizeof(u32),
-   .value_size = sizeof(u64),
-   .max_entries= XDP_UNKNOWN + 1,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, u64);
+   __uint(max_entries, XDP_UNKNOWN + 1);
+} exception_cnt SEC(".maps");
 
 /* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_redirect/format
  * Code in:kernel/include/trace/events/xdp.h
@@ -129,19 +129,19 @@ struct datarec {
 };
 #define MAX_CPUS 64
 
-struct bpf_map_def SEC("maps") cpumap_enqueue_cnt = {
-   .type   = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size   = sizeof(u32),
-   .value_size = sizeof(struct datarec),
-   .max_entries= MAX_CPUS,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, struct datarec);
+   __uint(max_entries, MAX_CPUS);
+} cpumap_enqueue_cnt SEC(".maps");
 
-struct bpf_map_def SEC("maps") cpumap_kthread_cnt = {
-   .type   = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size   = sizeof(u32),
-   .value_size = sizeof(struct datarec),
-   .max_entries= 1,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, struct datarec);
+   __uint(max_entries, 1);
+} cpumap_kthread_cnt SEC(".maps");
 
 /* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_enqueue/format
  * Code in: kernel/include/trace/events/xdp.h
@@ -210,12 +210,12 @@ int trace_xdp_cpumap_kthread(struct cpumap_kthread_ctx 
*ctx)
return 0;
 }
 
-struct bpf_map_def SEC("maps") devmap_xmit_cnt = {
-   .type   = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size   = sizeof(u32),
-   .value_size = sizeof(struct datarec),
-   .max_entries= 1,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, struct datarec);
+   __uint(max_entries, 1);
+} devmap_xmit_cnt SEC(".maps");
 
 /* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_devmap_xmit/format
  * Code in: kernel/include/trace/events/xdp.h
diff --git a/samples/bpf/xdp_sample_pkts_kern.c 
b/samples/bpf/xdp_sample_pkts_kern.c
index 33377289e2a8..9cf76b340dd7 100644
--- a/samples/bpf/xdp_sample_pkts_kern.c
+++ b/samples/bpf/xdp_sample_pkts_kern.c
@@ -5,14 +5,12 @@
 #include 
 
 #define SAMPLE_SIZE 64ul
-#define MAX_CPUS 128
-
-struct bpf_map_def SEC("maps") my_map = {
-   .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
-   .key_size = sizeof(int),
-   .value_size = sizeof(u32),
-   .max_entries = MAX_CPUS,
-};
+
+struct {
+   __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
+   __uint(key_size, sizeof(int));
+   __uint(value_size, sizeof(u32));
+} my_map SEC(".maps");
 
 SEC("xdp_sample")
 int xdp_sample_prog(struct xdp_md *ctx)
diff --git a/samples/bpf/xdp_sample_pkts_user.c 
b/samples/bpf/xdp_sample_pkts_user.c
index 991ef6f0880b..4b2a300c750c 100644
--- a/samples/bpf/xdp_sample_pkts_user.c
+++ b/samples/bpf/xdp_sample_pkts_user.c
@@ -18,7 +18,6 @@
 
 #include "perf-sys.h"
 
-#define MAX_CPUS 128
 static int if_idx;
 static char *if_name;
 static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
-- 
2.25.1



[PATCH bpf-next v2 0/3] samples: bpf: Refactor XDP programs with libbpf

2020-10-10 Thread Daniel T. Lee
To avoid confusion caused by the increasing fragmentation of the BPF
Loader program, this commit would like to convert the previous bpf_load
loader with the libbpf loader.

Thanks to libbpf's bpf_link interface, managing the tracepoint BPF
program is much easier. bpf_program__attach_tracepoint manages the
enable of tracepoint event and attach of BPF programs to it with a
single interface bpf_link, so there is no need to manage event_fd and
prog_fd separately.

And due to addition of generic bpf_program__attach() to libbpf, it is
now possible to attach BPF programs with __attach() instead of
explicitly calling __attach_().

This patchset refactors xdp_monitor with using this libbpf API, and the
bpf_load is removed and migrated to libbpf. Also, attach_tracepoint()
is replaced with the generic __attach() method in xdp_redirect_cpu.
Moreover, maps in kern program have been converted to BTF-defined map.

---
Changes in v2:
 - added cleanup logic for bpf_link and bpf_object in xdp_monitor
 - program section match with bpf_program__is_ instead of strncmp
 - revert BTF key/val type to default of BPF_MAP_TYPE_PERF_EVENT_ARRAY
 - split increment into seperate satement
 - refactor pointer array initialization
 - error code cleanup

Daniel T. Lee (3):
  samples: bpf: Refactor xdp_monitor with libbpf
  samples: bpf: Replace attach_tracepoint() to attach() in
xdp_redirect_cpu
  samples: bpf: refactor XDP kern program maps with BTF-defined map

 samples/bpf/Makefile|   4 +-
 samples/bpf/xdp_monitor_kern.c  |  60 +--
 samples/bpf/xdp_monitor_user.c  | 159 +---
 samples/bpf/xdp_redirect_cpu_user.c | 153 +-
 samples/bpf/xdp_sample_pkts_kern.c  |  14 ++-
 samples/bpf/xdp_sample_pkts_user.c  |   1 -
 6 files changed, 230 insertions(+), 161 deletions(-)

-- 
2.25.1



[PATCH bpf-next v2 1/3] samples: bpf: Refactor xdp_monitor with libbpf

2020-10-10 Thread Daniel T. Lee
To avoid confusion caused by the increasing fragmentation of the BPF
Loader program, this commit would like to change to the libbpf loader
instead of using the bpf_load.

Thanks to libbpf's bpf_link interface, managing the tracepoint BPF
program is much easier. bpf_program__attach_tracepoint manages the
enable of tracepoint event and attach of BPF programs to it with a
single interface bpf_link, so there is no need to manage event_fd and
prog_fd separately.

This commit refactors xdp_monitor with using this libbpf API, and the
bpf_load is removed and migrated to libbpf.

Signed-off-by: Daniel T. Lee 

---
Changes in v2:
 - added cleanup logic for bpf_link and bpf_object
 - split increment into seperate satement
 - refactor pointer array initialization

 samples/bpf/Makefile   |   2 +-
 samples/bpf/xdp_monitor_user.c | 159 +
 2 files changed, 121 insertions(+), 40 deletions(-)

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 4f1ed0e3cf9f..0cee2aa8970f 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -99,7 +99,7 @@ per_socket_stats_example-objs := cookie_uid_helper_example.o
 xdp_redirect-objs := xdp_redirect_user.o
 xdp_redirect_map-objs := xdp_redirect_map_user.o
 xdp_redirect_cpu-objs := bpf_load.o xdp_redirect_cpu_user.o
-xdp_monitor-objs := bpf_load.o xdp_monitor_user.o
+xdp_monitor-objs := xdp_monitor_user.o
 xdp_rxq_info-objs := xdp_rxq_info_user.o
 syscall_tp-objs := syscall_tp_user.o
 cpustat-objs := cpustat_user.o
diff --git a/samples/bpf/xdp_monitor_user.c b/samples/bpf/xdp_monitor_user.c
index ef53b93db573..03d0a182913f 100644
--- a/samples/bpf/xdp_monitor_user.c
+++ b/samples/bpf/xdp_monitor_user.c
@@ -26,12 +26,37 @@ static const char *__doc_err_only__=
 #include 
 #include 
 
+#include 
 #include 
-#include "bpf_load.h"
+#include 
 #include "bpf_util.h"
 
+enum map_type {
+   REDIRECT_ERR_CNT,
+   EXCEPTION_CNT,
+   CPUMAP_ENQUEUE_CNT,
+   CPUMAP_KTHREAD_CNT,
+   DEVMAP_XMIT_CNT,
+};
+
+static const char *const map_type_strings[] = {
+   [REDIRECT_ERR_CNT] = "redirect_err_cnt",
+   [EXCEPTION_CNT] = "exception_cnt",
+   [CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt",
+   [CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt",
+   [DEVMAP_XMIT_CNT] = "devmap_xmit_cnt",
+};
+
+#define NUM_MAP 5
+#define NUM_TP 8
+
+static int tp_cnt;
+static int map_cnt;
 static int verbose = 1;
 static bool debug = false;
+struct bpf_map *map_data[NUM_MAP] = {};
+struct bpf_link *tp_links[NUM_TP] = {};
+struct bpf_object *obj;
 
 static const struct option long_options[] = {
{"help",no_argument,NULL, 'h' },
@@ -41,6 +66,16 @@ static const struct option long_options[] = {
{0, 0, NULL,  0 }
 };
 
+static void int_exit(int sig)
+{
+   /* Detach tracepoints */
+   while (tp_cnt)
+   bpf_link__destroy(tp_links[--tp_cnt]);
+
+   bpf_object__close(obj);
+   exit(0);
+}
+
 /* C standard specifies two constants, EXIT_SUCCESS(0) and EXIT_FAILURE(1) */
 #define EXIT_FAIL_MEM  5
 
@@ -483,23 +518,23 @@ static bool stats_collect(struct stats_record *rec)
 * this can happen by someone running perf-record -e
 */
 
-   fd = map_data[0].fd; /* map0: redirect_err_cnt */
+   fd = bpf_map__fd(map_data[REDIRECT_ERR_CNT]);
for (i = 0; i < REDIR_RES_MAX; i++)
map_collect_record_u64(fd, i, &rec->xdp_redirect[i]);
 
-   fd = map_data[1].fd; /* map1: exception_cnt */
+   fd = bpf_map__fd(map_data[EXCEPTION_CNT]);
for (i = 0; i < XDP_ACTION_MAX; i++) {
map_collect_record_u64(fd, i, &rec->xdp_exception[i]);
}
 
-   fd = map_data[2].fd; /* map2: cpumap_enqueue_cnt */
+   fd = bpf_map__fd(map_data[CPUMAP_ENQUEUE_CNT]);
for (i = 0; i < MAX_CPUS; i++)
map_collect_record(fd, i, &rec->xdp_cpumap_enqueue[i]);
 
-   fd = map_data[3].fd; /* map3: cpumap_kthread_cnt */
+   fd = bpf_map__fd(map_data[CPUMAP_KTHREAD_CNT]);
map_collect_record(fd, 0, &rec->xdp_cpumap_kthread);
 
-   fd = map_data[4].fd; /* map4: devmap_xmit_cnt */
+   fd = bpf_map__fd(map_data[DEVMAP_XMIT_CNT]);
map_collect_record(fd, 0, &rec->xdp_devmap_xmit);
 
return true;
@@ -598,8 +633,8 @@ static void stats_poll(int interval, bool err_only)
 
/* TODO Need more advanced stats on error types */
if (verbose) {
-   printf(" - Stats map0: %s\n", map_data[0].name);
-   printf(" - Stats map1: %s\n", map_data[1].name);
+   printf(" - Stats map0: %s\n", bpf_map__name(map_data[0]));
+   printf(" - Stats map1: %s\n", bpf_map__name(map_data[1]));
printf("\n");
}
fflush(stdout);
@@ -618,44 +653,51 @

[PATCH bpf-next v2 3/3] samples: bpf: refactor XDP kern program maps with BTF-defined map

2020-10-10 Thread Daniel T. Lee
Most of the samples were converted to use the new BTF-defined MAP as
they moved to libbpf, but some of the samples were missing.

Instead of using the previous BPF MAP definition, this commit refactors
xdp_monitor and xdp_sample_pkts_kern MAP definition with the new
BTF-defined MAP format.

Also, this commit removes the max_entries attribute at PERF_EVENT_ARRAY
map type. The libbpf's bpf_object__create_map() will automatically
set max_entries to the maximum configured number of CPUs on the host.

Signed-off-by: Daniel T. Lee 

---
Changes in v2:
 - revert BTF key/val type to default of BPF_MAP_TYPE_PERF_EVENT_ARRAY

 samples/bpf/xdp_monitor_kern.c | 60 +++---
 samples/bpf/xdp_sample_pkts_kern.c | 14 +++
 samples/bpf/xdp_sample_pkts_user.c |  1 -
 3 files changed, 36 insertions(+), 39 deletions(-)

diff --git a/samples/bpf/xdp_monitor_kern.c b/samples/bpf/xdp_monitor_kern.c
index 3d33cca2d48a..5c955b812c47 100644
--- a/samples/bpf/xdp_monitor_kern.c
+++ b/samples/bpf/xdp_monitor_kern.c
@@ -6,21 +6,21 @@
 #include 
 #include 
 
-struct bpf_map_def SEC("maps") redirect_err_cnt = {
-   .type = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size = sizeof(u32),
-   .value_size = sizeof(u64),
-   .max_entries = 2,
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, u64);
+   __uint(max_entries, 2);
/* TODO: have entries for all possible errno's */
-};
+} redirect_err_cnt SEC(".maps");
 
 #define XDP_UNKNOWNXDP_REDIRECT + 1
-struct bpf_map_def SEC("maps") exception_cnt = {
-   .type   = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size   = sizeof(u32),
-   .value_size = sizeof(u64),
-   .max_entries= XDP_UNKNOWN + 1,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, u64);
+   __uint(max_entries, XDP_UNKNOWN + 1);
+} exception_cnt SEC(".maps");
 
 /* Tracepoint format: /sys/kernel/debug/tracing/events/xdp/xdp_redirect/format
  * Code in:kernel/include/trace/events/xdp.h
@@ -129,19 +129,19 @@ struct datarec {
 };
 #define MAX_CPUS 64
 
-struct bpf_map_def SEC("maps") cpumap_enqueue_cnt = {
-   .type   = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size   = sizeof(u32),
-   .value_size = sizeof(struct datarec),
-   .max_entries= MAX_CPUS,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, struct datarec);
+   __uint(max_entries, MAX_CPUS);
+} cpumap_enqueue_cnt SEC(".maps");
 
-struct bpf_map_def SEC("maps") cpumap_kthread_cnt = {
-   .type   = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size   = sizeof(u32),
-   .value_size = sizeof(struct datarec),
-   .max_entries= 1,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, struct datarec);
+   __uint(max_entries, 1);
+} cpumap_kthread_cnt SEC(".maps");
 
 /* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_cpumap_enqueue/format
  * Code in: kernel/include/trace/events/xdp.h
@@ -210,12 +210,12 @@ int trace_xdp_cpumap_kthread(struct cpumap_kthread_ctx 
*ctx)
return 0;
 }
 
-struct bpf_map_def SEC("maps") devmap_xmit_cnt = {
-   .type   = BPF_MAP_TYPE_PERCPU_ARRAY,
-   .key_size   = sizeof(u32),
-   .value_size = sizeof(struct datarec),
-   .max_entries= 1,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
+   __type(key, u32);
+   __type(value, struct datarec);
+   __uint(max_entries, 1);
+} devmap_xmit_cnt SEC(".maps");
 
 /* Tracepoint: /sys/kernel/debug/tracing/events/xdp/xdp_devmap_xmit/format
  * Code in: kernel/include/trace/events/xdp.h
diff --git a/samples/bpf/xdp_sample_pkts_kern.c 
b/samples/bpf/xdp_sample_pkts_kern.c
index 33377289e2a8..9cf76b340dd7 100644
--- a/samples/bpf/xdp_sample_pkts_kern.c
+++ b/samples/bpf/xdp_sample_pkts_kern.c
@@ -5,14 +5,12 @@
 #include 
 
 #define SAMPLE_SIZE 64ul
-#define MAX_CPUS 128
-
-struct bpf_map_def SEC("maps") my_map = {
-   .type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
-   .key_size = sizeof(int),
-   .value_size = sizeof(u32),
-   .max_entries = MAX_CPUS,
-};
+
+struct {
+   __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
+   __uint(key_size, sizeof(int));
+   __uint(value_size, sizeof(u32));
+} my_map SEC(".maps");
 
 SEC("xdp_sample")
 int xdp_sample_prog(struct xdp_md *ctx)
diff --git a/samples/bpf/xdp_sample_pkts_user.c 
b/samples/bpf/xdp_sample_pkts_user.c
index 991ef6f0880b..4b2a300c750c 100644
--- a/samples/bpf/xdp_sample_pkts_user.c
+++ b/samples/bpf/xdp_sample_pkts_user.c
@@ -18,7 +18,6 @@
 
 #include "perf-sys.h"
 
-#define MAX_CPUS 128
 static int if_idx;
 static char *if_name;
 static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
-- 
2.25.1



[PATCH bpf-next v2 1/3] samples: bpf: Refactor xdp_monitor with libbpf

2020-10-10 Thread Daniel T. Lee
To avoid confusion caused by the increasing fragmentation of the BPF
Loader program, this commit would like to change to the libbpf loader
instead of using the bpf_load.

Thanks to libbpf's bpf_link interface, managing the tracepoint BPF
program is much easier. bpf_program__attach_tracepoint manages the
enable of tracepoint event and attach of BPF programs to it with a
single interface bpf_link, so there is no need to manage event_fd and
prog_fd separately.

This commit refactors xdp_monitor with using this libbpf API, and the
bpf_load is removed and migrated to libbpf.

Signed-off-by: Daniel T. Lee 

---
Changes in v2:
 - added cleanup logic for bpf_link and bpf_object
 - split increment into seperate satement
 - refactor pointer array initialization

 samples/bpf/Makefile   |   2 +-
 samples/bpf/xdp_monitor_user.c | 159 +
 2 files changed, 121 insertions(+), 40 deletions(-)

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 4f1ed0e3cf9f..0cee2aa8970f 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -99,7 +99,7 @@ per_socket_stats_example-objs := cookie_uid_helper_example.o
 xdp_redirect-objs := xdp_redirect_user.o
 xdp_redirect_map-objs := xdp_redirect_map_user.o
 xdp_redirect_cpu-objs := bpf_load.o xdp_redirect_cpu_user.o
-xdp_monitor-objs := bpf_load.o xdp_monitor_user.o
+xdp_monitor-objs := xdp_monitor_user.o
 xdp_rxq_info-objs := xdp_rxq_info_user.o
 syscall_tp-objs := syscall_tp_user.o
 cpustat-objs := cpustat_user.o
diff --git a/samples/bpf/xdp_monitor_user.c b/samples/bpf/xdp_monitor_user.c
index ef53b93db573..03d0a182913f 100644
--- a/samples/bpf/xdp_monitor_user.c
+++ b/samples/bpf/xdp_monitor_user.c
@@ -26,12 +26,37 @@ static const char *__doc_err_only__=
 #include 
 #include 
 
+#include 
 #include 
-#include "bpf_load.h"
+#include 
 #include "bpf_util.h"
 
+enum map_type {
+   REDIRECT_ERR_CNT,
+   EXCEPTION_CNT,
+   CPUMAP_ENQUEUE_CNT,
+   CPUMAP_KTHREAD_CNT,
+   DEVMAP_XMIT_CNT,
+};
+
+static const char *const map_type_strings[] = {
+   [REDIRECT_ERR_CNT] = "redirect_err_cnt",
+   [EXCEPTION_CNT] = "exception_cnt",
+   [CPUMAP_ENQUEUE_CNT] = "cpumap_enqueue_cnt",
+   [CPUMAP_KTHREAD_CNT] = "cpumap_kthread_cnt",
+   [DEVMAP_XMIT_CNT] = "devmap_xmit_cnt",
+};
+
+#define NUM_MAP 5
+#define NUM_TP 8
+
+static int tp_cnt;
+static int map_cnt;
 static int verbose = 1;
 static bool debug = false;
+struct bpf_map *map_data[NUM_MAP] = {};
+struct bpf_link *tp_links[NUM_TP] = {};
+struct bpf_object *obj;
 
 static const struct option long_options[] = {
{"help",no_argument,NULL, 'h' },
@@ -41,6 +66,16 @@ static const struct option long_options[] = {
{0, 0, NULL,  0 }
 };
 
+static void int_exit(int sig)
+{
+   /* Detach tracepoints */
+   while (tp_cnt)
+   bpf_link__destroy(tp_links[--tp_cnt]);
+
+   bpf_object__close(obj);
+   exit(0);
+}
+
 /* C standard specifies two constants, EXIT_SUCCESS(0) and EXIT_FAILURE(1) */
 #define EXIT_FAIL_MEM  5
 
@@ -483,23 +518,23 @@ static bool stats_collect(struct stats_record *rec)
 * this can happen by someone running perf-record -e
 */
 
-   fd = map_data[0].fd; /* map0: redirect_err_cnt */
+   fd = bpf_map__fd(map_data[REDIRECT_ERR_CNT]);
for (i = 0; i < REDIR_RES_MAX; i++)
map_collect_record_u64(fd, i, &rec->xdp_redirect[i]);
 
-   fd = map_data[1].fd; /* map1: exception_cnt */
+   fd = bpf_map__fd(map_data[EXCEPTION_CNT]);
for (i = 0; i < XDP_ACTION_MAX; i++) {
map_collect_record_u64(fd, i, &rec->xdp_exception[i]);
}
 
-   fd = map_data[2].fd; /* map2: cpumap_enqueue_cnt */
+   fd = bpf_map__fd(map_data[CPUMAP_ENQUEUE_CNT]);
for (i = 0; i < MAX_CPUS; i++)
map_collect_record(fd, i, &rec->xdp_cpumap_enqueue[i]);
 
-   fd = map_data[3].fd; /* map3: cpumap_kthread_cnt */
+   fd = bpf_map__fd(map_data[CPUMAP_KTHREAD_CNT]);
map_collect_record(fd, 0, &rec->xdp_cpumap_kthread);
 
-   fd = map_data[4].fd; /* map4: devmap_xmit_cnt */
+   fd = bpf_map__fd(map_data[DEVMAP_XMIT_CNT]);
map_collect_record(fd, 0, &rec->xdp_devmap_xmit);
 
return true;
@@ -598,8 +633,8 @@ static void stats_poll(int interval, bool err_only)
 
/* TODO Need more advanced stats on error types */
if (verbose) {
-   printf(" - Stats map0: %s\n", map_data[0].name);
-   printf(" - Stats map1: %s\n", map_data[1].name);
+   printf(" - Stats map0: %s\n", bpf_map__name(map_data[0]));
+   printf(" - Stats map1: %s\n", bpf_map__name(map_data[1]));
printf("\n");
}
fflush(stdout);
@@ -618,44 +653,51 @

[PATCH 1/3] samples: bpf: fix bpf programs with kprobe/sys_connect event

2020-06-26 Thread Daniel T. Lee
Currently, BPF programs with kprobe/sys_connect does not work properly.

Commit 34745aed515c ("samples/bpf: fix kprobe attachment issue on x64")
This commit modifies the bpf_load behavior of kprobe events in the x64
architecture. If the current kprobe event target starts with "sys_*",
add the prefix "__x64_" to the front of the event.

Appending "__x64_" prefix with kprobe/sys_* event was appropriate as a
solution to most of the problems caused by the commit below.

commit d5a00528b58c ("syscalls/core, syscalls/x86: Rename struct
pt_regs-based sys_*() to __x64_sys_*()")

However, there is a problem with the sys_connect kprobe event that does
not work properly. For __sys_connect event, parameters can be fetched
normally, but for __x64_sys_connect, parameters cannot be fetched.

Because of this problem, this commit fixes the sys_connect event by
specifying the __sys_connect directly and this will bypass the
"__x64_" appending rule of bpf_load.

Fixes: 34745aed515c ("samples/bpf: fix kprobe attachment issue on x64")
Signed-off-by: Daniel T. Lee 
---
 samples/bpf/map_perf_test_kern.c | 2 +-
 samples/bpf/test_map_in_map_kern.c   | 2 +-
 samples/bpf/test_probe_write_user_kern.c | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/samples/bpf/map_perf_test_kern.c b/samples/bpf/map_perf_test_kern.c
index 1bb1fdb9cdf8..69ecd717d998 100644
--- a/samples/bpf/map_perf_test_kern.c
+++ b/samples/bpf/map_perf_test_kern.c
@@ -159,7 +159,7 @@ int stress_percpu_hmap_alloc(struct pt_regs *ctx)
return 0;
 }
 
-SEC("kprobe/sys_connect")
+SEC("kprobe/__sys_connect")
 int stress_lru_hmap_alloc(struct pt_regs *ctx)
 {
char fmt[] = "Failed at stress_lru_hmap_alloc. ret:%dn";
diff --git a/samples/bpf/test_map_in_map_kern.c 
b/samples/bpf/test_map_in_map_kern.c
index 6cee61e8ce9b..b1562ba2f025 100644
--- a/samples/bpf/test_map_in_map_kern.c
+++ b/samples/bpf/test_map_in_map_kern.c
@@ -102,7 +102,7 @@ static __always_inline int do_inline_hash_lookup(void 
*inner_map, u32 port)
return result ? *result : -ENOENT;
 }
 
-SEC("kprobe/sys_connect")
+SEC("kprobe/__sys_connect")
 int trace_sys_connect(struct pt_regs *ctx)
 {
struct sockaddr_in6 *in6;
diff --git a/samples/bpf/test_probe_write_user_kern.c 
b/samples/bpf/test_probe_write_user_kern.c
index 6579639a83b2..9b3c3918c37d 100644
--- a/samples/bpf/test_probe_write_user_kern.c
+++ b/samples/bpf/test_probe_write_user_kern.c
@@ -26,7 +26,7 @@ struct {
  * This example sits on a syscall, and the syscall ABI is relatively stable
  * of course, across platforms, and over time, the ABI may change.
  */
-SEC("kprobe/sys_connect")
+SEC("kprobe/__sys_connect")
 int bpf_prog1(struct pt_regs *ctx)
 {
struct sockaddr_in new_addr, orig_addr = {};
-- 
2.25.1



[PATCH 3/3] samples: bpf: refactor BPF map in map test with libbpf

2020-06-26 Thread Daniel T. Lee
>From commit 646f02ffdd49 ("libbpf: Add BTF-defined map-in-map
support"), a way to define internal map in BTF-defined map has been
added.

Instead of using previous 'inner_map_idx' definition, the structure to
be used for the inner map can be directly defined using array directive.

__array(values, struct inner_map)

This commit refactors map in map test program with libbpf by explicitly
defining inner map with BTF-defined format.

Signed-off-by: Daniel T. Lee 
---
 samples/bpf/Makefile   |  2 +-
 samples/bpf/test_map_in_map_kern.c | 85 +++---
 samples/bpf/test_map_in_map_user.c | 53 +--
 3 files changed, 91 insertions(+), 49 deletions(-)

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index ffd0fda536da..78678d4e6842 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -93,7 +93,7 @@ sampleip-objs := sampleip_user.o $(TRACE_HELPERS)
 tc_l2_redirect-objs := bpf_load.o tc_l2_redirect_user.o
 lwt_len_hist-objs := bpf_load.o lwt_len_hist_user.o
 xdp_tx_iptunnel-objs := xdp_tx_iptunnel_user.o
-test_map_in_map-objs := bpf_load.o test_map_in_map_user.o
+test_map_in_map-objs := test_map_in_map_user.o
 per_socket_stats_example-objs := cookie_uid_helper_example.o
 xdp_redirect-objs := xdp_redirect_user.o
 xdp_redirect_map-objs := xdp_redirect_map_user.o
diff --git a/samples/bpf/test_map_in_map_kern.c 
b/samples/bpf/test_map_in_map_kern.c
index b1562ba2f025..d3f56ed78541 100644
--- a/samples/bpf/test_map_in_map_kern.c
+++ b/samples/bpf/test_map_in_map_kern.c
@@ -11,66 +11,65 @@
 #include 
 #include 
 #include 
-#include "bpf_legacy.h"
 #include 
 
 #define MAX_NR_PORTS 65536
 
 /* map #0 */
-struct bpf_map_def_legacy SEC("maps") port_a = {
-   .type = BPF_MAP_TYPE_ARRAY,
-   .key_size = sizeof(u32),
-   .value_size = sizeof(int),
-   .max_entries = MAX_NR_PORTS,
-};
+struct inner_a {
+   __uint(type, BPF_MAP_TYPE_ARRAY);
+   __type(key, u32);
+   __type(value, int);
+   __uint(max_entries, MAX_NR_PORTS);
+} port_a SEC(".maps");
 
 /* map #1 */
-struct bpf_map_def_legacy SEC("maps") port_h = {
-   .type = BPF_MAP_TYPE_HASH,
-   .key_size = sizeof(u32),
-   .value_size = sizeof(int),
-   .max_entries = 1,
-};
+struct inner_h {
+   __uint(type, BPF_MAP_TYPE_HASH);
+   __type(key, u32);
+   __type(value, int);
+   __uint(max_entries, 1);
+} port_h SEC(".maps");
 
 /* map #2 */
-struct bpf_map_def_legacy SEC("maps") reg_result_h = {
-   .type = BPF_MAP_TYPE_HASH,
-   .key_size = sizeof(u32),
-   .value_size = sizeof(int),
-   .max_entries = 1,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_HASH);
+   __type(key, u32);
+   __type(value, int);
+   __uint(max_entries, 1);
+} reg_result_h SEC(".maps");
 
 /* map #3 */
-struct bpf_map_def_legacy SEC("maps") inline_result_h = {
-   .type = BPF_MAP_TYPE_HASH,
-   .key_size = sizeof(u32),
-   .value_size = sizeof(int),
-   .max_entries = 1,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_HASH);
+   __type(key, u32);
+   __type(value, int);
+   __uint(max_entries, 1);
+} inline_result_h SEC(".maps");
 
 /* map #4 */ /* Test case #0 */
-struct bpf_map_def_legacy SEC("maps") a_of_port_a = {
-   .type = BPF_MAP_TYPE_ARRAY_OF_MAPS,
-   .key_size = sizeof(u32),
-   .inner_map_idx = 0, /* map_fd[0] is port_a */
-   .max_entries = MAX_NR_PORTS,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
+   __uint(max_entries, MAX_NR_PORTS);
+   __uint(key_size, sizeof(u32));
+   __array(values, struct inner_a); /* use inner_a as inner map */
+} a_of_port_a SEC(".maps");
 
 /* map #5 */ /* Test case #1 */
-struct bpf_map_def_legacy SEC("maps") h_of_port_a = {
-   .type = BPF_MAP_TYPE_HASH_OF_MAPS,
-   .key_size = sizeof(u32),
-   .inner_map_idx = 0, /* map_fd[0] is port_a */
-   .max_entries = 1,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
+   __uint(max_entries, 1);
+   __uint(key_size, sizeof(u32));
+   __array(values, struct inner_a); /* use inner_a as inner map */
+} h_of_port_a SEC(".maps");
 
 /* map #6 */ /* Test case #2 */
-struct bpf_map_def_legacy SEC("maps") h_of_port_h = {
-   .type = BPF_MAP_TYPE_HASH_OF_MAPS,
-   .key_size = sizeof(u32),
-   .inner_map_idx = 1, /* map_fd[1] is port_h */
-   .max_entries = 1,
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_HASH_OF_MAPS);
+   __uint(max_entries, 1);
+   __uint(key_size, sizeof(u32));
+   __array(values, struct inner_h); /* use inner_h as inner map */
+} h_of_port_h SEC(".maps");
 
 static __always_inline int do_reg_lookup(void *inner_map, u32 port)
 {
diff --git a/samples/bpf/test_map_in_map_user.c 
b/samples/bpf/test_map_in_map_user.c
index eb2

[PATCH 2/3] samples: bpf: cleanup pointer error check with libbpf

2020-06-26 Thread Daniel T. Lee
Libbpf has its own helper function to check for errors in the bpf
data structure (pointer). And Some codes do not use this libbbpf
helper function and check the pointer's error directly.

This commit clean up the existing pointer error check logic with
libbpf.

Signed-off-by: Daniel T. Lee 
---
 samples/bpf/sampleip_user.c| 2 +-
 samples/bpf/trace_event_user.c | 2 +-
 samples/bpf/tracex1_user.c | 2 +-
 samples/bpf/tracex5_user.c | 2 +-
 samples/bpf/tracex7_user.c | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/samples/bpf/sampleip_user.c b/samples/bpf/sampleip_user.c
index 921c505bb567..554dfa1cb34d 100644
--- a/samples/bpf/sampleip_user.c
+++ b/samples/bpf/sampleip_user.c
@@ -186,7 +186,7 @@ int main(int argc, char **argv)
}
 
prog = bpf_object__find_program_by_name(obj, "do_sample");
-   if (!prog) {
+   if (libbpf_get_error(prog)) {
fprintf(stderr, "ERROR: finding a prog in obj file failed\n");
goto cleanup;
}
diff --git a/samples/bpf/trace_event_user.c b/samples/bpf/trace_event_user.c
index ac1ba368195c..8bcb9b4bfbe6 100644
--- a/samples/bpf/trace_event_user.c
+++ b/samples/bpf/trace_event_user.c
@@ -318,7 +318,7 @@ int main(int argc, char **argv)
}
 
prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
-   if (!prog) {
+   if (libbpf_get_error(prog)) {
printf("finding a prog in obj file failed\n");
goto cleanup;
}
diff --git a/samples/bpf/tracex1_user.c b/samples/bpf/tracex1_user.c
index 9d4adb7fd834..d3e01807dcd0 100644
--- a/samples/bpf/tracex1_user.c
+++ b/samples/bpf/tracex1_user.c
@@ -20,7 +20,7 @@ int main(int ac, char **argv)
}
 
prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
-   if (!prog) {
+   if (libbpf_get_error(prog)) {
fprintf(stderr, "ERROR: finding a prog in obj file failed\n");
goto cleanup;
}
diff --git a/samples/bpf/tracex5_user.c b/samples/bpf/tracex5_user.c
index 98dad57a96c4..65c753b30121 100644
--- a/samples/bpf/tracex5_user.c
+++ b/samples/bpf/tracex5_user.c
@@ -53,7 +53,7 @@ int main(int ac, char **argv)
}
 
prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
-   if (!prog) {
+   if (libbpf_get_error(prog)) {
printf("finding a prog in obj file failed\n");
goto cleanup;
}
diff --git a/samples/bpf/tracex7_user.c b/samples/bpf/tracex7_user.c
index fdcd6580dd73..10c896732139 100644
--- a/samples/bpf/tracex7_user.c
+++ b/samples/bpf/tracex7_user.c
@@ -22,7 +22,7 @@ int main(int argc, char **argv)
}
 
prog = bpf_object__find_program_by_name(obj, "bpf_prog1");
-   if (!prog) {
+   if (libbpf_get_error(prog)) {
fprintf(stderr, "ERROR: finding a prog in obj file failed\n");
goto cleanup;
}
-- 
2.25.1



Re: [PATCH bpf-next v2 1/7] samples: bpf: refactor hbm program with libbpf

2020-11-24 Thread Daniel T. Lee
Sorry for the late reply.

On Sat, Nov 21, 2020 at 11:34 AM Martin KaFai Lau  wrote:
>
> On Thu, Nov 19, 2020 at 03:06:11PM +, Daniel T. Lee wrote:
> [ ... ]
>
> >  static int run_bpf_prog(char *prog, int cg_id)
> > [ ... ]
> >   if (!outFlag)
> > - type = BPF_CGROUP_INET_INGRESS;
> > - if (bpf_prog_attach(bpfprog_fd, cg1, type, 0)) {
> > - printf("ERROR: bpf_prog_attach fails!\n");
> > - log_err("Attaching prog");
> > + bpf_program__set_expected_attach_type(bpf_prog, 
> > BPF_CGROUP_INET_INGRESS);
> > +
> > + link = bpf_program__attach_cgroup(bpf_prog, cg1);
> > + if (libbpf_get_error(link)) {
> > + fprintf(stderr, "ERROR: bpf_program__attach_cgroup failed\n");
> > + link = NULL;
> Again, this is not needed.  bpf_link__destroy() can
> handle both NULL and error pointer.  Please take a look
> at the bpf_link__destroy() in libbpf.c
>
> > + goto err;
> > + }
> > [ ... ]

> > @@ -398,10 +400,10 @@ static int run_bpf_prog(char *prog, int cg_id)
> >  err:
> >   rc = 1;
> >
> > - if (cg1)
> > - close(cg1);
> > + bpf_link__destroy(link);
> > + close(cg1);
> >   cleanup_cgroup_environment();
> > -
> > + bpf_object__close(obj);
> The bpf_* cleanup condition still looks wrong.
>
> I can understand why it does not want to cleanup_cgroup_environment()
> on the success case because the sh script may want to run test under this
> cgroup.
>
> However, the bpf_link__destroy(), bpf_object__close(), and
> even close(cg1) should be done in both success and error
> cases.
>
> The cg1 test still looks wrong also.  The cg1 should
> be init to -1 and then test for "if (cg1 == -1)".

Thanks for pointing this out.
I'll remove NULL initialize and fix this on the next patch.


--
Best,
Daniel T. Lee


[PATCH bpf-next v3 0/7] bpf: remove bpf_load loader completely

2020-11-24 Thread Daniel T. Lee
Numerous refactoring that rewrites BPF programs written with bpf_load
to use the libbpf loader was finally completed, resulting in BPF
programs using bpf_load within the kernel being completely no longer
present.

This patchset refactors remaining bpf programs with libbpf and
completely removes bpf_load, an outdated bpf loader that is difficult
to keep up with the latest kernel BPF and causes confusion.

Changes in v2:
 - drop 'move tracing helpers to trace_helper' patch
 - add link pinning to prevent cleaning up on process exit
 - add static at global variable and remove unused variable
 - change to destroy link even after link__pin()
 - fix return error code on exit
 - merge commit with changing Makefile

Changes in v3:
 - cleanup bpf_link, bpf_object and cgroup fd both on success and error

Daniel T. Lee (7):
  samples: bpf: refactor hbm program with libbpf
  samples: bpf: refactor test_cgrp2_sock2 program with libbpf
  samples: bpf: refactor task_fd_query program with libbpf
  samples: bpf: refactor ibumad program with libbpf
  samples: bpf: refactor test_overhead program with libbpf
  samples: bpf: fix lwt_len_hist reusing previous BPF map
  samples: bpf: remove bpf_load loader completely

 samples/bpf/.gitignore   |   3 +
 samples/bpf/Makefile |  20 +-
 samples/bpf/bpf_load.c   | 667 ---
 samples/bpf/bpf_load.h   |  57 ---
 samples/bpf/do_hbm_test.sh   |  32 +-
 samples/bpf/hbm.c| 111 ++---
 samples/bpf/hbm_kern.h   |   2 +-
 samples/bpf/ibumad_kern.c|  26 +-
 samples/bpf/ibumad_user.c|  71 +++-
 samples/bpf/lwt_len_hist.sh  |   2 +
 samples/bpf/task_fd_query_user.c | 101 +++--
 samples/bpf/test_cgrp2_sock2.c   |  61 ++-
 samples/bpf/test_cgrp2_sock2.sh  |  21 +-
 samples/bpf/test_lwt_bpf.sh  |   0
 samples/bpf/test_overhead_user.c |  82 ++--
 samples/bpf/xdp2skb_meta_kern.c  |   2 +-
 16 files changed, 350 insertions(+), 908 deletions(-)
 delete mode 100644 samples/bpf/bpf_load.c
 delete mode 100644 samples/bpf/bpf_load.h
 mode change 100644 => 100755 samples/bpf/lwt_len_hist.sh
 mode change 100644 => 100755 samples/bpf/test_lwt_bpf.sh

-- 
2.25.1



[PATCH bpf-next v3 2/7] samples: bpf: refactor test_cgrp2_sock2 program with libbpf

2020-11-24 Thread Daniel T. Lee
This commit refactors the existing cgroup program with libbpf bpf
loader. The original test_cgrp2_sock2 has keeped the bpf program
attached to the cgroup hierarchy even after the exit of user program.
To implement the same functionality with libbpf, this commit uses the
BPF_LINK_PINNING to pin the link attachment even after it is closed.

Since this uses LINK instead of ATTACH, detach of bpf program from
cgroup with 'test_cgrp2_sock' is not used anymore.

The code to mount the bpf was added to the .sh file in case the bpff
was not mounted on /sys/fs/bpf. Additionally, to fix the problem that
shell script cannot find the binary object from the current path,
relative path './' has been added in front of binary.

Fixes: 554ae6e792ef3 ("samples/bpf: add userspace example for prohibiting 
sockets")
Signed-off-by: Daniel T. Lee 
---
Changes in v2:
 - change to destroy link even after link__pin()
 - enhance error message
 
 samples/bpf/Makefile|  2 +-
 samples/bpf/test_cgrp2_sock2.c  | 61 -
 samples/bpf/test_cgrp2_sock2.sh | 21 +---
 3 files changed, 62 insertions(+), 22 deletions(-)

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 7c61118525f7..d31e082c369e 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -82,7 +82,7 @@ test_overhead-objs := bpf_load.o test_overhead_user.o
 test_cgrp2_array_pin-objs := test_cgrp2_array_pin.o
 test_cgrp2_attach-objs := test_cgrp2_attach.o
 test_cgrp2_sock-objs := test_cgrp2_sock.o
-test_cgrp2_sock2-objs := bpf_load.o test_cgrp2_sock2.o
+test_cgrp2_sock2-objs := test_cgrp2_sock2.o
 xdp1-objs := xdp1_user.o
 # reuse xdp1 source intentionally
 xdp2-objs := xdp1_user.o
diff --git a/samples/bpf/test_cgrp2_sock2.c b/samples/bpf/test_cgrp2_sock2.c
index a9277b118c33..e7060aaa2f5a 100644
--- a/samples/bpf/test_cgrp2_sock2.c
+++ b/samples/bpf/test_cgrp2_sock2.c
@@ -20,9 +20,9 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "bpf_insn.h"
-#include "bpf_load.h"
 
 static int usage(const char *argv0)
 {
@@ -32,37 +32,64 @@ static int usage(const char *argv0)
 
 int main(int argc, char **argv)
 {
-   int cg_fd, ret, filter_id = 0;
+   int cg_fd, err, ret = EXIT_FAILURE, filter_id = 0, prog_cnt = 0;
+   const char *link_pin_path = "/sys/fs/bpf/test_cgrp2_sock2";
+   struct bpf_link *link = NULL;
+   struct bpf_program *progs[2];
+   struct bpf_program *prog;
+   struct bpf_object *obj;
 
if (argc < 3)
return usage(argv[0]);
 
+   if (argc > 3)
+   filter_id = atoi(argv[3]);
+
cg_fd = open(argv[1], O_DIRECTORY | O_RDONLY);
if (cg_fd < 0) {
printf("Failed to open cgroup path: '%s'\n", strerror(errno));
-   return EXIT_FAILURE;
+   return ret;
}
 
-   if (load_bpf_file(argv[2]))
-   return EXIT_FAILURE;
-
-   printf("Output from kernel verifier:\n%s\n---\n", bpf_log_buf);
+   obj = bpf_object__open_file(argv[2], NULL);
+   if (libbpf_get_error(obj)) {
+   printf("ERROR: opening BPF object file failed\n");
+   return ret;
+   }
 
-   if (argc > 3)
-   filter_id = atoi(argv[3]);
+   bpf_object__for_each_program(prog, obj) {
+   progs[prog_cnt] = prog;
+   prog_cnt++;
+   }
 
if (filter_id >= prog_cnt) {
printf("Invalid program id; program not found in file\n");
-   return EXIT_FAILURE;
+   goto cleanup;
+   }
+
+   /* load BPF program */
+   if (bpf_object__load(obj)) {
+   printf("ERROR: loading BPF object file failed\n");
+   goto cleanup;
}
 
-   ret = bpf_prog_attach(prog_fd[filter_id], cg_fd,
- BPF_CGROUP_INET_SOCK_CREATE, 0);
-   if (ret < 0) {
-   printf("Failed to attach prog to cgroup: '%s'\n",
-  strerror(errno));
-   return EXIT_FAILURE;
+   link = bpf_program__attach_cgroup(progs[filter_id], cg_fd);
+   if (libbpf_get_error(link)) {
+   printf("ERROR: bpf_program__attach failed\n");
+   link = NULL;
+   goto cleanup;
}
 
-   return EXIT_SUCCESS;
+   err = bpf_link__pin(link, link_pin_path);
+   if (err < 0) {
+   printf("ERROR: bpf_link__pin failed: %d\n", err);
+   goto cleanup;
+   }
+
+   ret = EXIT_SUCCESS;
+
+cleanup:
+   bpf_link__destroy(link);
+   bpf_object__close(obj);
+   return ret;
 }
diff --git a/samples/bpf/test_cgrp2_sock2.sh b/samples/bpf/test_cgrp2_sock2.sh
index 0f396a86e0cb..6a3dbe642b2b 100755
--- a/samples/bpf/test_cgrp2_sock2.sh
+++ b/samples/bpf/test_cgrp2_sock2.sh
@@ -1,6 +1,9 @

[PATCH bpf-next v3 5/7] samples: bpf: refactor test_overhead program with libbpf

2020-11-24 Thread Daniel T. Lee
This commit refactors the existing program with libbpf bpf loader.
Since the kprobe, tracepoint and raw_tracepoint bpf program can be
attached with single bpf_program__attach() interface, so the
corresponding function of libbpf is used here.

Rather than specifying the number of cpus inside the code, this commit
uses the number of available cpus with _SC_NPROCESSORS_ONLN.

Signed-off-by: Daniel T. Lee 
Acked-by: Andrii Nakryiko 
---
Changes in v2:
 - add static at global variable and drop {}
 
 samples/bpf/Makefile |  2 +-
 samples/bpf/test_overhead_user.c | 82 +++-
 2 files changed, 60 insertions(+), 24 deletions(-)

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 09a249477554..25380e04897e 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -78,7 +78,7 @@ lathist-objs := lathist_user.o
 offwaketime-objs := offwaketime_user.o $(TRACE_HELPERS)
 spintest-objs := spintest_user.o $(TRACE_HELPERS)
 map_perf_test-objs := map_perf_test_user.o
-test_overhead-objs := bpf_load.o test_overhead_user.o
+test_overhead-objs := test_overhead_user.o
 test_cgrp2_array_pin-objs := test_cgrp2_array_pin.o
 test_cgrp2_attach-objs := test_cgrp2_attach.o
 test_cgrp2_sock-objs := test_cgrp2_sock.o
diff --git a/samples/bpf/test_overhead_user.c b/samples/bpf/test_overhead_user.c
index 94f74112a20e..819a6fe86f89 100644
--- a/samples/bpf/test_overhead_user.c
+++ b/samples/bpf/test_overhead_user.c
@@ -18,10 +18,14 @@
 #include 
 #include 
 #include 
-#include "bpf_load.h"
+#include 
 
 #define MAX_CNT 100
 
+static struct bpf_link *links[2];
+static struct bpf_object *obj;
+static int cnt;
+
 static __u64 time_get_ns(void)
 {
struct timespec ts;
@@ -115,20 +119,54 @@ static void run_perf_test(int tasks, int flags)
}
 }
 
+static int load_progs(char *filename)
+{
+   struct bpf_program *prog;
+   int err = 0;
+
+   obj = bpf_object__open_file(filename, NULL);
+   err = libbpf_get_error(obj);
+   if (err < 0) {
+   fprintf(stderr, "ERROR: opening BPF object file failed\n");
+   return err;
+   }
+
+   /* load BPF program */
+   err = bpf_object__load(obj);
+   if (err < 0) {
+   fprintf(stderr, "ERROR: loading BPF object file failed\n");
+   return err;
+   }
+
+   bpf_object__for_each_program(prog, obj) {
+   links[cnt] = bpf_program__attach(prog);
+   err = libbpf_get_error(links[cnt]);
+   if (err < 0) {
+   fprintf(stderr, "ERROR: bpf_program__attach failed\n");
+   links[cnt] = NULL;
+   return err;
+   }
+   cnt++;
+   }
+
+   return err;
+}
+
 static void unload_progs(void)
 {
-   close(prog_fd[0]);
-   close(prog_fd[1]);
-   close(event_fd[0]);
-   close(event_fd[1]);
+   while (cnt)
+   bpf_link__destroy(links[--cnt]);
+
+   bpf_object__close(obj);
 }
 
 int main(int argc, char **argv)
 {
struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
-   char filename[256];
-   int num_cpu = 8;
+   int num_cpu = sysconf(_SC_NPROCESSORS_ONLN);
int test_flags = ~0;
+   char filename[256];
+   int err = 0;
 
setrlimit(RLIMIT_MEMLOCK, &r);
 
@@ -145,38 +183,36 @@ int main(int argc, char **argv)
if (test_flags & 0xC) {
snprintf(filename, sizeof(filename),
 "%s_kprobe_kern.o", argv[0]);
-   if (load_bpf_file(filename)) {
-   printf("%s", bpf_log_buf);
-   return 1;
-   }
+
printf("w/KPROBE\n");
-   run_perf_test(num_cpu, test_flags >> 2);
+   err = load_progs(filename);
+   if (!err)
+   run_perf_test(num_cpu, test_flags >> 2);
+
unload_progs();
}
 
if (test_flags & 0x30) {
snprintf(filename, sizeof(filename),
 "%s_tp_kern.o", argv[0]);
-   if (load_bpf_file(filename)) {
-   printf("%s", bpf_log_buf);
-   return 1;
-   }
printf("w/TRACEPOINT\n");
-   run_perf_test(num_cpu, test_flags >> 4);
+   err = load_progs(filename);
+   if (!err)
+   run_perf_test(num_cpu, test_flags >> 4);
+
unload_progs();
}
 
if (test_flags & 0xC0) {
snprintf(filename, sizeof(filename),
 "%s_raw_tp_kern.o", argv[0]);
-   if (load_bpf_file(filename)) {
-   printf("%s", bpf_log_buf);
-   return 1;
-   }
  

[PATCH bpf-next v3 4/7] samples: bpf: refactor ibumad program with libbpf

2020-11-24 Thread Daniel T. Lee
This commit refactors the existing ibumad program with libbpf bpf
loader. Attach/detach of Tracepoint bpf programs has been managed
with the generic bpf_program__attach() and bpf_link__destroy() from
the libbpf.

Also, instead of using the previous BPF MAP definition, this commit
refactors ibumad MAP definition with the new BTF-defined MAP format.

To verify that this bpf program works without an infiniband device,
try loading ib_umad kernel module and test the program as follows:

# modprobe ib_umad
# ./ibumad

Moreover, TRACE_HELPERS has been removed from the Makefile since it is
not used on this program.

Signed-off-by: Daniel T. Lee 
---
Changes in v2:
 - add static at global variable and drop {}
 - fix return error code on exit
 
 samples/bpf/Makefile  |  2 +-
 samples/bpf/ibumad_kern.c | 26 +++---
 samples/bpf/ibumad_user.c | 71 +--
 3 files changed, 68 insertions(+), 31 deletions(-)

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 3bffd42e1482..09a249477554 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -109,7 +109,7 @@ xsk_fwd-objs := xsk_fwd.o
 xdp_fwd-objs := xdp_fwd_user.o
 task_fd_query-objs := task_fd_query_user.o $(TRACE_HELPERS)
 xdp_sample_pkts-objs := xdp_sample_pkts_user.o $(TRACE_HELPERS)
-ibumad-objs := bpf_load.o ibumad_user.o $(TRACE_HELPERS)
+ibumad-objs := ibumad_user.o
 hbm-objs := hbm.o $(CGROUP_HELPERS)
 
 # Tell kbuild to always build the programs
diff --git a/samples/bpf/ibumad_kern.c b/samples/bpf/ibumad_kern.c
index 3a91b4c1989a..26dcd4dde946 100644
--- a/samples/bpf/ibumad_kern.c
+++ b/samples/bpf/ibumad_kern.c
@@ -16,19 +16,19 @@
 #include 
 
 
-struct bpf_map_def SEC("maps") read_count = {
-   .type= BPF_MAP_TYPE_ARRAY,
-   .key_size= sizeof(u32), /* class; u32 required */
-   .value_size  = sizeof(u64), /* count of mads read */
-   .max_entries = 256, /* Room for all Classes */
-};
-
-struct bpf_map_def SEC("maps") write_count = {
-   .type= BPF_MAP_TYPE_ARRAY,
-   .key_size= sizeof(u32), /* class; u32 required */
-   .value_size  = sizeof(u64), /* count of mads written */
-   .max_entries = 256, /* Room for all Classes */
-};
+struct {
+   __uint(type, BPF_MAP_TYPE_ARRAY);
+   __type(key, u32); /* class; u32 required */
+   __type(value, u64); /* count of mads read */
+   __uint(max_entries, 256); /* Room for all Classes */
+} read_count SEC(".maps");
+
+struct {
+   __uint(type, BPF_MAP_TYPE_ARRAY);
+   __type(key, u32); /* class; u32 required */
+   __type(value, u64); /* count of mads written */
+   __uint(max_entries, 256); /* Room for all Classes */
+} write_count SEC(".maps");
 
 #undef DEBUG
 #ifndef DEBUG
diff --git a/samples/bpf/ibumad_user.c b/samples/bpf/ibumad_user.c
index fa06eef31a84..d83d8102f489 100644
--- a/samples/bpf/ibumad_user.c
+++ b/samples/bpf/ibumad_user.c
@@ -23,10 +23,15 @@
 #include 
 #include 
 
-#include "bpf_load.h"
+#include 
 #include "bpf_util.h"
 #include 
 
+static struct bpf_link *tp_links[3];
+static struct bpf_object *obj;
+static int map_fd[2];
+static int tp_cnt;
+
 static void dump_counts(int fd)
 {
__u32 key;
@@ -53,6 +58,11 @@ static void dump_all_counts(void)
 static void dump_exit(int sig)
 {
dump_all_counts();
+   /* Detach tracepoints */
+   while (tp_cnt)
+   bpf_link__destroy(tp_links[--tp_cnt]);
+
+   bpf_object__close(obj);
exit(0);
 }
 
@@ -73,19 +83,11 @@ static void usage(char *cmd)
 
 int main(int argc, char **argv)
 {
+   struct bpf_program *prog;
unsigned long delay = 5;
+   char filename[256];
int longindex = 0;
-   int opt;
-   char bpf_file[256];
-
-   /* Create the eBPF kernel code path name.
-* This follows the pattern of all of the other bpf samples
-*/
-   snprintf(bpf_file, sizeof(bpf_file), "%s_kern.o", argv[0]);
-
-   /* Do one final dump when exiting */
-   signal(SIGINT, dump_exit);
-   signal(SIGTERM, dump_exit);
+   int opt, err = -1;
 
while ((opt = getopt_long(argc, argv, "hd:rSw",
  long_options, &longindex)) != -1) {
@@ -107,16 +109,51 @@ int main(int argc, char **argv)
}
}
 
-   if (load_bpf_file(bpf_file)) {
-   fprintf(stderr, "ERROR: failed to load eBPF from file : %s\n",
-   bpf_file);
-   return 1;
+   /* Do one final dump when exiting */
+   signal(SIGINT, dump_exit);
+   signal(SIGTERM, dump_exit);
+
+   snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
+   obj = bpf_object__open_file(filename, NULL);
+   if (libbpf_get_error(obj)) {
+   fprintf(stderr, "ERROR: opening BPF object file failed\n");
+   return err;
+   

[PATCH bpf-next v3 6/7] samples: bpf: fix lwt_len_hist reusing previous BPF map

2020-11-24 Thread Daniel T. Lee
Currently, lwt_len_hist's map lwt_len_hist_map is uses pinning, and the
map isn't cleared on test end. This leds to reuse of that map for
each test, which prevents the results of the test from being accurate.

This commit fixes the problem by removing of pinned map from bpffs.
Also, this commit add the executable permission to shell script
files.

Fixes: f74599f7c5309 ("bpf: Add tests and samples for LWT-BPF")
Signed-off-by: Daniel T. Lee 
---
 samples/bpf/lwt_len_hist.sh | 2 ++
 samples/bpf/test_lwt_bpf.sh | 0
 2 files changed, 2 insertions(+)
 mode change 100644 => 100755 samples/bpf/lwt_len_hist.sh
 mode change 100644 => 100755 samples/bpf/test_lwt_bpf.sh

diff --git a/samples/bpf/lwt_len_hist.sh b/samples/bpf/lwt_len_hist.sh
old mode 100644
new mode 100755
index 090b96eaf7f7..0eda9754f50b
--- a/samples/bpf/lwt_len_hist.sh
+++ b/samples/bpf/lwt_len_hist.sh
@@ -8,6 +8,8 @@ VETH1=tst_lwt1b
 TRACE_ROOT=/sys/kernel/debug/tracing
 
 function cleanup {
+   # To reset saved histogram, remove pinned map
+   rm /sys/fs/bpf/tc/globals/lwt_len_hist_map
ip route del 192.168.253.2/32 dev $VETH0 2> /dev/null
ip link del $VETH0 2> /dev/null
ip link del $VETH1 2> /dev/null
diff --git a/samples/bpf/test_lwt_bpf.sh b/samples/bpf/test_lwt_bpf.sh
old mode 100644
new mode 100755
-- 
2.25.1



[PATCH bpf-next v3 3/7] samples: bpf: refactor task_fd_query program with libbpf

2020-11-24 Thread Daniel T. Lee
This commit refactors the existing kprobe program with libbpf bpf
loader. To attach bpf program, this uses generic bpf_program__attach()
approach rather than using bpf_load's load_bpf_file().

To attach bpf to perf_event, instead of using previous ioctl method,
this commit uses bpf_program__attach_perf_event since it manages the
enable of perf_event and attach of BPF programs to it, which is much
more intuitive way to achieve.

Also, explicit close(fd) has been removed since event will be closed
inside bpf_link__destroy() automatically.

Furthermore, to prevent conflict of same named uprobe events, O_TRUNC
flag has been used to clear 'uprobe_events' interface.

Signed-off-by: Daniel T. Lee 
---
Changes in v2:
 - add static at global variable and drop {}
 - fix return error code on exit
 - restore DEBUGFS macro to absolute string path
 
 samples/bpf/Makefile |   2 +-
 samples/bpf/task_fd_query_user.c | 101 ++-
 2 files changed, 75 insertions(+), 28 deletions(-)

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index d31e082c369e..3bffd42e1482 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -107,7 +107,7 @@ xdp_adjust_tail-objs := xdp_adjust_tail_user.o
 xdpsock-objs := xdpsock_user.o
 xsk_fwd-objs := xsk_fwd.o
 xdp_fwd-objs := xdp_fwd_user.o
-task_fd_query-objs := bpf_load.o task_fd_query_user.o $(TRACE_HELPERS)
+task_fd_query-objs := task_fd_query_user.o $(TRACE_HELPERS)
 xdp_sample_pkts-objs := xdp_sample_pkts_user.o $(TRACE_HELPERS)
 ibumad-objs := bpf_load.o ibumad_user.o $(TRACE_HELPERS)
 hbm-objs := hbm.o $(CGROUP_HELPERS)
diff --git a/samples/bpf/task_fd_query_user.c b/samples/bpf/task_fd_query_user.c
index b68bd2f8fdc9..f6b772faa348 100644
--- a/samples/bpf/task_fd_query_user.c
+++ b/samples/bpf/task_fd_query_user.c
@@ -15,12 +15,15 @@
 #include 
 #include 
 
+#include 
 #include 
-#include "bpf_load.h"
 #include "bpf_util.h"
 #include "perf-sys.h"
 #include "trace_helpers.h"
 
+static struct bpf_program *progs[2];
+static struct bpf_link *links[2];
+
 #define CHECK_PERROR_RET(condition) ({ \
int __ret = !!(condition);  \
if (__ret) {\
@@ -86,21 +89,22 @@ static int bpf_get_retprobe_bit(const char *event_type)
return ret;
 }
 
-static int test_debug_fs_kprobe(int prog_fd_idx, const char *fn_name,
+static int test_debug_fs_kprobe(int link_idx, const char *fn_name,
__u32 expected_fd_type)
 {
__u64 probe_offset, probe_addr;
__u32 len, prog_id, fd_type;
+   int err, event_fd;
char buf[256];
-   int err;
 
len = sizeof(buf);
-   err = bpf_task_fd_query(getpid(), event_fd[prog_fd_idx], 0, buf, &len,
+   event_fd = bpf_link__fd(links[link_idx]);
+   err = bpf_task_fd_query(getpid(), event_fd, 0, buf, &len,
&prog_id, &fd_type, &probe_offset,
&probe_addr);
if (err < 0) {
printf("FAIL: %s, for event_fd idx %d, fn_name %s\n",
-  __func__, prog_fd_idx, fn_name);
+  __func__, link_idx, fn_name);
perror(":");
return -1;
}
@@ -108,7 +112,7 @@ static int test_debug_fs_kprobe(int prog_fd_idx, const char 
*fn_name,
fd_type != expected_fd_type ||
probe_offset != 0x0 || probe_addr != 0x0) {
printf("FAIL: bpf_trace_event_query(event_fd[%d]):\n",
-  prog_fd_idx);
+  link_idx);
printf("buf: %s, fd_type: %u, probe_offset: 0x%llx,"
   " probe_addr: 0x%llx\n",
   buf, fd_type, probe_offset, probe_addr);
@@ -125,12 +129,13 @@ static int test_nondebug_fs_kuprobe_common(const char 
*event_type,
int is_return_bit = bpf_get_retprobe_bit(event_type);
int type = bpf_find_probe_type(event_type);
struct perf_event_attr attr = {};
-   int fd;
+   struct bpf_link *link;
+   int fd, err = -1;
 
if (type < 0 || is_return_bit < 0) {
printf("FAIL: %s incorrect type (%d) or is_return_bit (%d)\n",
__func__, type, is_return_bit);
-   return -1;
+   return err;
}
 
attr.sample_period = 1;
@@ -149,14 +154,21 @@ static int test_nondebug_fs_kuprobe_common(const char 
*event_type,
attr.type = type;
 
fd = sys_perf_event_open(&attr, -1, 0, -1, 0);
-   CHECK_PERROR_RET(fd < 0);
+   link = bpf_program__attach_perf_event(progs[0], fd);
+   if (libbpf_get_error(link)) {
+   printf("ERROR: bpf_program__attach_perf_event failed\n");
+   link = NULL;
+   close(fd);
+

[PATCH bpf-next v3 7/7] samples: bpf: remove bpf_load loader completely

2020-11-24 Thread Daniel T. Lee
Numerous refactoring that rewrites BPF programs written with bpf_load
to use the libbpf loader was finally completed, resulting in BPF
programs using bpf_load within the kernel being completely no longer
present.

This commit removes bpf_load, an outdated bpf loader that is difficult
to keep up with the latest kernel BPF and causes confusion.

Also, this commit removes the unused trace_helper and bpf_load from
samples/bpf target objects from Makefile.

Signed-off-by: Daniel T. Lee 
Acked-by: Jesper Dangaard Brouer 
Acked-by: Andrii Nakryiko 
---
Changes in v2:
 - merge commit with changing Makefile
 
 samples/bpf/Makefile|  10 +-
 samples/bpf/bpf_load.c  | 667 
 samples/bpf/bpf_load.h  |  57 ---
 samples/bpf/xdp2skb_meta_kern.c |   2 +-
 4 files changed, 5 insertions(+), 731 deletions(-)
 delete mode 100644 samples/bpf/bpf_load.c
 delete mode 100644 samples/bpf/bpf_load.h

diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 25380e04897e..05db041f8b18 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -73,7 +73,7 @@ tracex5-objs := tracex5_user.o $(TRACE_HELPERS)
 tracex6-objs := tracex6_user.o
 tracex7-objs := tracex7_user.o
 test_probe_write_user-objs := test_probe_write_user_user.o
-trace_output-objs := trace_output_user.o $(TRACE_HELPERS)
+trace_output-objs := trace_output_user.o
 lathist-objs := lathist_user.o
 offwaketime-objs := offwaketime_user.o $(TRACE_HELPERS)
 spintest-objs := spintest_user.o $(TRACE_HELPERS)
@@ -91,8 +91,8 @@ test_current_task_under_cgroup-objs := $(CGROUP_HELPERS) \
   test_current_task_under_cgroup_user.o
 trace_event-objs := trace_event_user.o $(TRACE_HELPERS)
 sampleip-objs := sampleip_user.o $(TRACE_HELPERS)
-tc_l2_redirect-objs := bpf_load.o tc_l2_redirect_user.o
-lwt_len_hist-objs := bpf_load.o lwt_len_hist_user.o
+tc_l2_redirect-objs := tc_l2_redirect_user.o
+lwt_len_hist-objs := lwt_len_hist_user.o
 xdp_tx_iptunnel-objs := xdp_tx_iptunnel_user.o
 test_map_in_map-objs := test_map_in_map_user.o
 per_socket_stats_example-objs := cookie_uid_helper_example.o
@@ -108,7 +108,7 @@ xdpsock-objs := xdpsock_user.o
 xsk_fwd-objs := xsk_fwd.o
 xdp_fwd-objs := xdp_fwd_user.o
 task_fd_query-objs := task_fd_query_user.o $(TRACE_HELPERS)
-xdp_sample_pkts-objs := xdp_sample_pkts_user.o $(TRACE_HELPERS)
+xdp_sample_pkts-objs := xdp_sample_pkts_user.o
 ibumad-objs := ibumad_user.o
 hbm-objs := hbm.o $(CGROUP_HELPERS)
 
@@ -197,8 +197,6 @@ TPROGS_CFLAGS += --sysroot=$(SYSROOT)
 TPROGS_LDFLAGS := -L$(SYSROOT)/usr/lib
 endif
 
-TPROGCFLAGS_bpf_load.o += -Wno-unused-variable
-
 TPROGS_LDLIBS  += $(LIBBPF) -lelf -lz
 TPROGLDLIBS_tracex4+= -lrt
 TPROGLDLIBS_trace_output   += -lrt
diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c
deleted file mode 100644
index c5ad528f046e..
--- a/samples/bpf/bpf_load.c
+++ /dev/null
@@ -1,667 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include "bpf_load.h"
-#include "perf-sys.h"
-
-#define DEBUGFS "/sys/kernel/debug/tracing/"
-
-static char license[128];
-static int kern_version;
-static bool processed_sec[128];
-char bpf_log_buf[BPF_LOG_BUF_SIZE];
-int map_fd[MAX_MAPS];
-int prog_fd[MAX_PROGS];
-int event_fd[MAX_PROGS];
-int prog_cnt;
-int prog_array_fd = -1;
-
-struct bpf_map_data map_data[MAX_MAPS];
-int map_data_count;
-
-static int populate_prog_array(const char *event, int prog_fd)
-{
-   int ind = atoi(event), err;
-
-   err = bpf_map_update_elem(prog_array_fd, &ind, &prog_fd, BPF_ANY);
-   if (err < 0) {
-   printf("failed to store prog_fd in prog_array\n");
-   return -1;
-   }
-   return 0;
-}
-
-static int write_kprobe_events(const char *val)
-{
-   int fd, ret, flags;
-
-   if (val == NULL)
-   return -1;
-   else if (val[0] == '\0')
-   flags = O_WRONLY | O_TRUNC;
-   else
-   flags = O_WRONLY | O_APPEND;
-
-   fd = open(DEBUGFS "kprobe_events", flags);
-
-   ret = write(fd, val, strlen(val));
-   close(fd);
-
-   return ret;
-}
-
-static int load_and_attach(const char *event, struct bpf_insn *prog, int size)
-{
-   bool is_socket = strncmp(event, "socket", 6) == 0;
-   bool is_kprobe = strncmp(event, "kprobe/", 7) == 0;
-   bool is_kretprobe = strncmp(event, "kretprobe/", 10) == 0;
-   bool is_tracepoint = strncmp(event, "tracepoint/", 11) == 0;
-   bool is_raw_tracepoint = strncmp(event, "raw_tracepoint/", 15) == 0;
-   bool is_xdp = strncmp(event,

[PATCH bpf-next v3 1/7] samples: bpf: refactor hbm program with libbpf

2020-11-24 Thread Daniel T. Lee
This commit refactors the existing cgroup programs with libbpf
bpf loader. Since bpf_program__attach doesn't support cgroup program
attachment, this explicitly attaches cgroup bpf program with
bpf_program__attach_cgroup(bpf_prog, cg1).

Also, to change attach_type of bpf program, this uses libbpf's
bpf_program__set_expected_attach_type helper to switch EGRESS to
INGRESS. To keep bpf program attached to the cgroup hierarchy even
after the exit, this commit uses the BPF_LINK_PINNING to pin the link
attachment even after it is closed.

Besides, this program was broken due to the typo of BPF MAP definition.
But this commit solves the problem by fixing this from 'queue_stats' map
struct hvm_queue_stats -> hbm_queue_stats.

Fixes: 36b5d471135c ("selftests/bpf: samples/bpf: Split off legacy stuff from 
bpf_helpers.h")
Signed-off-by: Daniel T. Lee 
---
Changes in v2:
 - restore read_trace_pipe2
 - remove unnecessary return code and cgroup fd compare
 - add static at global variable and remove unused variable
 - change cgroup path with unified controller (/unified/)
 - add link pinning to prevent cleaning up on process exit

Changes in v3:
 - cleanup bpf_link, bpf_object and cgroup fd both on success and error
 - remove link NULL cleanup since __destroy() can handle
 - fix cgroup test on cgroup fd cleanup
 
 samples/bpf/.gitignore |   3 +
 samples/bpf/Makefile   |   2 +-
 samples/bpf/do_hbm_test.sh |  32 +--
 samples/bpf/hbm.c  | 111 -
 samples/bpf/hbm_kern.h |   2 +-
 5 files changed, 78 insertions(+), 72 deletions(-)

diff --git a/samples/bpf/.gitignore b/samples/bpf/.gitignore
index b2f29bc8dc43..0b9548ea8477 100644
--- a/samples/bpf/.gitignore
+++ b/samples/bpf/.gitignore
@@ -52,3 +52,6 @@ xdp_tx_iptunnel
 xdpsock
 xsk_fwd
 testfile.img
+hbm_out.log
+iperf.*
+*.out
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index aeebf5d12f32..7c61118525f7 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -110,7 +110,7 @@ xdp_fwd-objs := xdp_fwd_user.o
 task_fd_query-objs := bpf_load.o task_fd_query_user.o $(TRACE_HELPERS)
 xdp_sample_pkts-objs := xdp_sample_pkts_user.o $(TRACE_HELPERS)
 ibumad-objs := bpf_load.o ibumad_user.o $(TRACE_HELPERS)
-hbm-objs := bpf_load.o hbm.o $(CGROUP_HELPERS)
+hbm-objs := hbm.o $(CGROUP_HELPERS)
 
 # Tell kbuild to always build the programs
 always-y := $(tprogs-y)
diff --git a/samples/bpf/do_hbm_test.sh b/samples/bpf/do_hbm_test.sh
index ffe4c0607341..21790ea5c460 100755
--- a/samples/bpf/do_hbm_test.sh
+++ b/samples/bpf/do_hbm_test.sh
@@ -91,6 +91,16 @@ qdisc=""
 flags=""
 do_stats=0
 
+BPFFS=/sys/fs/bpf
+function config_bpffs () {
+   if mount | grep $BPFFS > /dev/null; then
+   echo "bpffs already mounted"
+   else
+   echo "bpffs not mounted. Mounting..."
+   mount -t bpf none $BPFFS
+   fi
+}
+
 function start_hbm () {
   rm -f hbm.out
   echo "./hbm $dir -n $id -r $rate -t $dur $flags $dbg $prog" > hbm.out
@@ -192,6 +202,7 @@ processArgs () {
 }
 
 processArgs
+config_bpffs
 
 if [ $debug_flag -eq 1 ] ; then
   rm -f hbm_out.log
@@ -201,7 +212,7 @@ hbm_pid=$(start_hbm)
 usleep 10
 
 host=`hostname`
-cg_base_dir=/sys/fs/cgroup
+cg_base_dir=/sys/fs/cgroup/unified
 cg_dir="$cg_base_dir/cgroup-test-work-dir/hbm$id"
 
 echo $$ >> $cg_dir/cgroup.procs
@@ -411,23 +422,8 @@ fi
 
 sleep 1
 
-# Detach any BPF programs that may have lingered
-ttx=`bpftool cgroup tree | grep hbm`
-v=2
-for x in $ttx ; do
-if [ "${x:0:36}" == "/sys/fs/cgroup/cgroup-test-work-dir/" ] ; then
-   cg=$x ; v=0
-else
-   if [ $v -eq 0 ] ; then
-   id=$x ; v=1
-   else
-   if [ $v -eq 1 ] ; then
-   type=$x ; bpftool cgroup detach $cg $type id $id
-   v=0
-   fi
-   fi
-fi
-done
+# Detach any pinned BPF programs that may have lingered
+rm -rf $BPFFS/hbm*
 
 if [ $use_netperf -ne 0 ] ; then
   if [ "$server" == "" ] ; then
diff --git a/samples/bpf/hbm.c b/samples/bpf/hbm.c
index 400e741a56eb..b0c18efe7928 100644
--- a/samples/bpf/hbm.c
+++ b/samples/bpf/hbm.c
@@ -46,7 +46,6 @@
 #include 
 #include 
 
-#include "bpf_load.h"
 #include "bpf_rlimit.h"
 #include "cgroup_helpers.h"
 #include "hbm.h"
@@ -70,9 +69,9 @@ static void do_error(char *msg, bool errno_flag);
 
 #define DEBUGFS "/sys/kernel/debug/tracing/"
 
-struct bpf_object *obj;
-int bpfprog_fd;
-int cgroup_storage_fd;
+static struct bpf_program *bpf_prog;
+static struct bpf_object *obj;
+static int queue_stats_fd;
 
 static void read_trace_pipe2(void)
 {
@@ -121,56 +120,50 @@ static void do_error(char *msg, bool errno_flag)
 
 static int prog_load(char *prog)
 {
-   struct bpf_prog_load_attr prog_load_attr = {
-   .prog_type = BPF_PROG_TYPE_CGROUP

Re: [v3,1/4] tools: bpftool: add net attach command to attach XDP on interface

2019-08-08 Thread Daniel T. Lee
On Thu, Aug 8, 2019 at 5:42 AM Jakub Kicinski
 wrote:
>
> On Wed,  7 Aug 2019 11:25:06 +0900, Daniel T. Lee wrote:
> > By this commit, using `bpftool net attach`, user can attach XDP prog on
> > interface. New type of enum 'net_attach_type' has been made, as stated at
> > cover-letter, the meaning of 'attach' is, prog will be attached on 
> > interface.
> >
> > With 'overwrite' option at argument, attached XDP program could be replaced.
> > Added new helper 'net_parse_dev' to parse the network device at argument.
> >
> > BPF prog will be attached through libbpf 'bpf_set_link_xdp_fd'.
> >
> > Signed-off-by: Daniel T. Lee 
> > ---
> >  tools/bpf/bpftool/net.c | 141 
> >  1 file changed, 130 insertions(+), 11 deletions(-)
> >
> > diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
> > index 67e99c56bc88..c05a3fac5cac 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 max_net_attach_type = ARRAY_SIZE(attach_type_strings);
>
> Nit: in practice max_.._type is num_types - 1, so perhaps rename this
> to num_.. or such?
>

I can see at 'map.c', it declares ARRAY_SIZE with '_size' suffix.
 const size_t map_type_name_size = ARRAY_SIZE(map_type_name);

I'll change this variable name 'max_net_attach_type' to 'net_attach_type_size'.

> > +static enum net_attach_type parse_attach_type(const char *str)
> > +{
> > + enum net_attach_type type;
> > +
> > + for (type = 0; type < max_net_attach_type; type++) {
> > + if (attach_type_strings[type] &&
> > +is_prefix(str, attach_type_strings[type]))
>
>^
> this is misaligned by one space
>
> Please try checkpatch with the --strict option to catch these.
>

I didn't know checkpatch has strict option.
Thanks for letting me know!

> > + return type;
> > + }
> > +
> > + return max_net_attach_type;
> > +}
> > +
> >  static int dump_link_nlmsg(void *cookie, void *msg, struct nlattr **tb)
> >  {
> >   struct bpf_netdev_t *netinfo = cookie;
> > @@ -223,6 +252,97 @@ 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 = fa

Re: [v3,1/4] tools: bpftool: add net attach command to attach XDP on interface

2019-08-08 Thread Daniel T. Lee
On Fri, Aug 9, 2019 at 2:50 AM Jakub Kicinski
 wrote:
>
> On Thu, 8 Aug 2019 07:15:22 +0900, Daniel T. Lee wrote:
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + NEXT_ARG();
> > >
> > > nit: the new line should be before NEXT_ARG(), IOV NEXT_ARG() belongs
> > > to the code which consumed the argument
> > >
> >
> > I'm not sure I'm following.
> > Are you saying that, at here the newline shouldn't be necessary?
>
> I mean this is better:
>
> if (!is_prefix(*argv, "bla-bla"))
> return -EINVAL;
> NEXT_ARG();
>
> if (!is_prefix(*argv, "bla-bla"))
> return -EINVAL;
> NEXT_ARG();
>
> Than this:
>
> if (!is_prefix(*argv, "bla-bla"))
> return -EINVAL;
>
> NEXT_ARG();
> if (!is_prefix(*argv, "bla-bla"))
> return -EINVAL;
>
> NEXT_ARG();
>
> Because the NEXT_ARG() "belongs" to the code that "consumed" the option.
>
> So instead of this:
>
>  attach_type = parse_attach_type(*argv);
>  if (attach_type == max_net_attach_type) {
>  p_err("invalid net attach/detach type");
>  return -EINVAL;
>  }
>
>  NEXT_ARG();
>  progfd = prog_parse_fd(&argc, &argv);
>  if (progfd < 0)
>  return -EINVAL;
>
> This seems more logical to me:
>
>  attach_type = parse_attach_type(*argv);
>  if (attach_type == max_net_attach_type) {
>  p_err("invalid net attach/detach type");
>  return -EINVAL;
>  }
>  NEXT_ARG();
>
>  progfd = prog_parse_fd(&argc, &argv);
>  if (progfd < 0)
>  return -EINVAL;

Oh. I see.
I'll update NEXT_ARG line stick to the code which "consumes" the option.

Thanks for the review! :)


Re: [v3,3/4] tools: bpftool: add bash-completion for net attach/detach

2019-08-08 Thread Daniel T. Lee
On Fri, Aug 9, 2019 at 1:48 AM Quentin Monnet
 wrote:
>
> 2019-08-07 11:25 UTC+0900 ~ Daniel T. Lee 
> > This commit adds bash-completion for new "net attach/detach"
> > subcommand for attaching XDP program on interface.
> >
> > Signed-off-by: Daniel T. Lee 
> > ---
> >  tools/bpf/bpftool/bash-completion/bpftool | 64 +++
> >  1 file changed, 55 insertions(+), 9 deletions(-)
> >
> > diff --git a/tools/bpf/bpftool/bash-completion/bpftool 
> > b/tools/bpf/bpftool/bash-completion/bpftool
> > index c8f42e1fcbc9..1d81cb09d478 100644
> > --- a/tools/bpf/bpftool/bash-completion/bpftool
> > +++ b/tools/bpf/bpftool/bash-completion/bpftool
> > @@ -201,6 +201,10 @@ _bpftool()
> >  _bpftool_get_prog_tags
> >  return 0
> >  ;;
> > +dev)
> > +_sysfs_get_netdevs
> > +return 0
> > +;;
>
> Makes sense to have this for "dev", thanks! But it seems you missed one
> place where it was used, for "bpftool feature probe" (We have "[[ $prev
> == "dev" ]] && _sysfs_get_netdevs && return 0"). Could you also remove
> that one please?
>
> Other than this looks good, thanks:
>
> Reviewed-by: Quentin Monnet 

My bad. Thanks for letting me know.
I'll update it with the next version of patch.

Thank you for your review.
I really appreciate it.


Re: [v3,4/4] tools: bpftool: add documentation for net attach/detach

2019-08-08 Thread Daniel T. Lee
On Fri, Aug 9, 2019 at 1:48 AM Quentin Monnet
 wrote:
>
> 2019-08-07 11:25 UTC+0900 ~ Daniel T. Lee 
> > Since, new sub-command 'net attach/detach' has been added for
> > attaching XDP program on interface,
> > this commit documents usage and sample output of `net attach/detach`.
> >
> > Signed-off-by: Daniel T. Lee 
> > ---
> >  .../bpf/bpftool/Documentation/bpftool-net.rst | 51 +--
> >  1 file changed, 48 insertions(+), 3 deletions(-)
> >
> > diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst 
> > b/tools/bpf/bpftool/Documentation/bpftool-net.rst
> > index d8e5237a2085..4ad1a380e186 100644
> > --- a/tools/bpf/bpftool/Documentation/bpftool-net.rst
> > +++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst
> > @@ -15,17 +15,22 @@ SYNOPSIS
> >   *OPTIONS* := { [{ **-j** | **--json** }] [{ **-p** | **--pretty** }] }
> >
> >   *COMMANDS* :=
> > - { **show** | **list** } [ **dev** name ] | **help**
> > + { **show** | **list** | **attach** | **detach** | **help** }
> >
> >  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*
>
> Nit: Could we have "name" in capital letters (everywhere in the file),
> to make this file consistent with the formatting used for
> bpftool-prog.rst and bpftool-map.rst?
>

I'll update all "name" with capital "NAME" at next version of patch.

> >  |**bpftool** **net help**
> > +|
> > +|*PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* 
> > }
> > +|*ATTACH_TYPE* := { **xdp** | **xdpgeneric** | **xdpdrv** | 
> > **xdpoffload** }
> >
> >  DESCRIPTION
> >  ===
> > - **bpftool net { show | list } [ dev name ]**
> > + **bpftool net { show | list }** [ **dev** *name* ]
> >List bpf program attachments in the kernel networking 
> > subsystem.
> >
> >Currently, only device driver xdp attachments and tc 
> > filter
> > @@ -47,6 +52,18 @@ DESCRIPTION
> >all bpf programs attached to non clsact qdiscs, and 
> > finally all
> >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, *ATTACH_TYPE* only contains XDP programs.
>
> Other nit: "ATTACH_TYPE only contains XDP programs" sounds odd to me.
> Could we maybe phrase this something like: "Currently, only XDP-related
> modes are supported for ATTACH_TYPE"?
>
> Also, could you please provide a brief description of the different
> attach types? In particular, explaining what "xdp" alone stands for
> might be useful.
>

I'll replace the phrase and add brief description about the attach types.

> Thanks,
> Quentin
>
> > +
> > + **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, *ATTACH_TYPE* only contains XDP programs.

Thank you for taking your time for the review.


[v4,1/4] tools: bpftool: add net attach command to attach XDP on interface

2019-08-09 Thread Daniel T. Lee
By this commit, using `bpftool net attach`, user can attach XDP prog on
interface. New type of enum 'net_attach_type' has been made, as stated at
cover-letter, the meaning of 'attach' is, prog will be attached on interface.

With 'overwrite' option at argument, attached XDP program could be replaced.
Added new helper 'net_parse_dev' to parse the network device at argument.

BPF prog will be attached through libbpf 'bpf_set_link_xdp_fd'.

Signed-off-by: Daniel T. Lee 
---
 tools/bpf/bpftool/net.c | 136 +---
 1 file changed, 129 insertions(+), 7 deletions(-)

diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index 67e99c56bc88..74cc346c36cd 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;
@@ -223,6 +252,97 @@ 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(errno));
+   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 +352,9 @@ static int do_show(in

[v4,0/4] tools: bpftool: add net attach/detach command to attach XDP prog

2019-08-09 Thread Daniel T. Lee
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 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 
  - added bash-completion and documentation

Changes in v2:
  - command 'load/unload' changed to 'attach/detach' for the consistency

Daniel T. Lee (4):
  tools: bpftool: add net attach command to attach XDP on interface
  tools: bpftool: add net detach command to detach XDP on interface
  tools: bpftool: add bash-completion for net attach/detach
  tools: bpftool: add documentation for net attach/detach

 .../bpf/bpftool/Documentation/bpftool-net.rst |  57 +-
 tools/bpf/bpftool/bash-completion/bpftool |  65 ++-
 tools/bpf/bpftool/net.c   | 176 +-
 3 files changed, 278 insertions(+), 20 deletions(-)

-- 
2.20.1



[v4,3/4] tools: bpftool: add bash-completion for net attach/detach

2019-08-09 Thread Daniel T. Lee
This commit adds bash-completion for new "net attach/detach"
subcommand for attaching XDP program on interface.

Signed-off-by: Daniel T. Lee 
---
 tools/bpf/bpftool/bash-completion/bpftool | 65 +++
 1 file changed, 55 insertions(+), 10 deletions(-)

diff --git a/tools/bpf/bpftool/bash-completion/bpftool 
b/tools/bpf/bpftool/bash-completion/bpftool
index c8f42e1fcbc9..dbfcf50d8215 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -201,6 +201,10 @@ _bpftool()
 _bpftool_get_prog_tags
 return 0
 ;;
+dev)
+_sysfs_get_netdevs
+return 0
+;;
 file|pinned)
 _filedir
 return 0
@@ -399,10 +403,6 @@ _bpftool()
 _filedir
 return 0
 ;;
-dev)
-_sysfs_get_netdevs
-return 0
-;;
 *)
 COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
 _bpftool_once_attr 'type'
@@ -498,10 +498,6 @@ _bpftool()
 key|value|flags|name|entries)
 return 0
 ;;
-dev)
-_sysfs_get_netdevs
-return 0
-;;
 *)
 _bpftool_once_attr 'type'
 _bpftool_once_attr 'key'
@@ -775,18 +771,67 @@ _bpftool()
 esac
 ;;
 net)
+local PROG_TYPE='id pinned tag'
+local ATTACH_TYPES='xdp xdpgeneric xdpdrv xdpoffload'
 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 ]] && \
 COMPREPLY=( $( compgen -W 'help \
-show list' -- "$cur" ) )
+show list attach detach' -- "$cur" ) )
 ;;
 esac
 ;;
 feature)
 case $command in
 probe)
-[[ $prev == "dev" ]] && _sysfs_get_netdevs && return 0
 [[ $prev == "prefix" ]] && return 0
 if _bpftool_search_list 'macros'; then
 COMPREPLY+=( $( compgen -W 'prefix' -- "$cur" ) )
-- 
2.20.1



[v4,4/4] tools: bpftool: add documentation for net attach/detach

2019-08-09 Thread Daniel T. Lee
Since, new sub-command 'net attach/detach' has been added for
attaching XDP program on interface,
this commit documents usage and sample output of `net attach/detach`.

Signed-off-by: Daniel T. Lee 
---
 .../bpf/bpftool/Documentation/bpftool-net.rst | 57 ++-
 1 file changed, 54 insertions(+), 3 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst 
b/tools/bpf/bpftool/Documentation/bpftool-net.rst
index d8e5237a2085..8651b00b81ea 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-net.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst
@@ -15,17 +15,22 @@ SYNOPSIS
*OPTIONS* := { [{ **-j** | **--json** }] [{ **-p** | **--pretty** }] }
 
*COMMANDS* :=
-   { **show** | **list** } [ **dev** name ] | **help**
+   { **show** | **list** | **attach** | **detach** | **help** }
 
 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**
+|
+|  *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
+|  *ATTACH_TYPE* := { **xdp** | **xdpgeneric** | **xdpdrv** | 
**xdpoffload** }
 
 DESCRIPTION
 ===
-   **bpftool net { show | list } [ dev name ]**
+   **bpftool net { show | list }** [ **dev** *NAME* ]
   List bpf program attachments in the kernel networking 
subsystem.
 
   Currently, only device driver xdp attachments and tc filter
@@ -47,6 +52,24 @@ DESCRIPTION
   all bpf programs attached to non clsact qdiscs, and finally 
all
   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**
  Print short help message.
 
@@ -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
 
-- 
2.20.1



[v4,2/4] tools: bpftool: add net detach command to detach XDP on interface

2019-08-09 Thread Daniel T. Lee
By this commit, using `bpftool net detach`, the attached XDP prog can
be detached. Detaching the BPF prog will be done through libbpf
'bpf_set_link_xdp_fd' with the progfd set to -1.

Signed-off-by: Daniel T. Lee 
---
 tools/bpf/bpftool/net.c | 42 -
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index 74cc346c36cd..ef1e576c6dba 100644
--- a/tools/bpf/bpftool/net.c
+++ b/tools/bpf/bpftool/net.c
@@ -343,6 +343,43 @@ static int do_attach(int argc, char **argv)
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(errno));
+   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 = {};
@@ -422,6 +459,7 @@ static int do_help(int argc, char **argv)
fprintf(stderr,
"Usage: %s %s { show | list } [dev ]\n"
"   %s %s attach ATTACH_TYPE PROG dev  [ overwrite 
]\n"
+   "   %s %s detach ATTACH_TYPE dev \n"
"   %s %s help\n"
"\n"
"   " HELP_SPEC_PROGRAM "\n"
@@ -432,7 +470,8 @@ static int do_help(int argc, char **argv)
"  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],
+   bin_name, argv[-2]);
 
return 0;
 }
@@ -441,6 +480,7 @@ static const struct cmd cmds[] = {
{ "show",   do_show },
{ "list",   do_show },
{ "attach", do_attach },
+   { "detach", do_detach },
{ "help",   do_help },
{ 0 }
 };
-- 
2.20.1



Re: [v4,1/4] tools: bpftool: add net attach command to attach XDP on interface

2019-08-12 Thread Daniel T. Lee
On Mon, Aug 12, 2019 at 9:27 AM Y Song  wrote:
>
> On Fri, Aug 9, 2019 at 6:35 AM Daniel T. Lee  wrote:
> >
> > By this commit, using `bpftool net attach`, user can attach XDP prog on
> > interface. New type of enum 'net_attach_type' has been made, as stated at
> > cover-letter, the meaning of 'attach' is, prog will be attached on 
> > interface.
> >
> > With 'overwrite' option at argument, attached XDP program could be replaced.
> > Added new helper 'net_parse_dev' to parse the network device at argument.
> >
> > BPF prog will be attached through libbpf 'bpf_set_link_xdp_fd'.
> >
> > Signed-off-by: Daniel T. Lee 
> > ---
> >  tools/bpf/bpftool/net.c | 136 +---
> >  1 file changed, 129 insertions(+), 7 deletions(-)
> >
> > diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
> > index 67e99c56bc88..74cc346c36cd 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;
> > @@ -223,6 +252,97 @@ 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 = p

[v5,2/4] tools: bpftool: add net detach command to detach XDP on interface

2019-08-12 Thread Daniel T. Lee
By this commit, using `bpftool net detach`, the attached XDP prog can
be detached. Detaching the BPF prog will be done through libbpf
'bpf_set_link_xdp_fd' with the progfd set to -1.

Acked-by: Yonghong Song 
Signed-off-by: Daniel T. Lee 
---
 tools/bpf/bpftool/net.c | 42 -
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index 33222ca1060e..a213a9b7f69c 100644
--- a/tools/bpf/bpftool/net.c
+++ b/tools/bpf/bpftool/net.c
@@ -343,6 +343,43 @@ static int do_attach(int argc, char **argv)
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 = {};
@@ -422,6 +459,7 @@ static int do_help(int argc, char **argv)
fprintf(stderr,
"Usage: %s %s { show | list } [dev ]\n"
"   %s %s attach ATTACH_TYPE PROG dev  [ overwrite 
]\n"
+   "   %s %s detach ATTACH_TYPE dev \n"
"   %s %s help\n"
"\n"
"   " HELP_SPEC_PROGRAM "\n"
@@ -432,7 +470,8 @@ static int do_help(int argc, char **argv)
"  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],
+   bin_name, argv[-2]);
 
return 0;
 }
@@ -441,6 +480,7 @@ static const struct cmd cmds[] = {
{ "show",   do_show },
{ "list",   do_show },
{ "attach", do_attach },
+   { "detach", do_detach },
{ "help",   do_help },
{ 0 }
 };
-- 
2.20.1



[v5,0/4] tools: bpftool: add net attach/detach command to attach XDP prog

2019-08-12 Thread Daniel T. Lee
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 
  - added bash-completion and documentation

Changes in v2:
  - command 'load/unload' changed to 'attach/detach' for the consistency

Daniel T. Lee (4):
  tools: bpftool: add net attach command to attach XDP on interface
  tools: bpftool: add net detach command to detach XDP on interface
  tools: bpftool: add bash-completion for net attach/detach
  tools: bpftool: add documentation for net attach/detach

 .../bpf/bpftool/Documentation/bpftool-net.rst |  57 +-
 tools/bpf/bpftool/bash-completion/bpftool |  65 ++-
 tools/bpf/bpftool/net.c   | 176 +-
 3 files changed, 278 insertions(+), 20 deletions(-)

-- 
2.20.1



[v5,3/4] tools: bpftool: add bash-completion for net attach/detach

2019-08-12 Thread Daniel T. Lee
This commit adds bash-completion for new "net attach/detach"
subcommand for attaching XDP program on interface.

Signed-off-by: Daniel T. Lee 
---
 tools/bpf/bpftool/bash-completion/bpftool | 65 +++
 1 file changed, 55 insertions(+), 10 deletions(-)

diff --git a/tools/bpf/bpftool/bash-completion/bpftool 
b/tools/bpf/bpftool/bash-completion/bpftool
index c8f42e1fcbc9..dbfcf50d8215 100644
--- a/tools/bpf/bpftool/bash-completion/bpftool
+++ b/tools/bpf/bpftool/bash-completion/bpftool
@@ -201,6 +201,10 @@ _bpftool()
 _bpftool_get_prog_tags
 return 0
 ;;
+dev)
+_sysfs_get_netdevs
+return 0
+;;
 file|pinned)
 _filedir
 return 0
@@ -399,10 +403,6 @@ _bpftool()
 _filedir
 return 0
 ;;
-dev)
-_sysfs_get_netdevs
-return 0
-;;
 *)
 COMPREPLY=( $( compgen -W "map" -- "$cur" ) )
 _bpftool_once_attr 'type'
@@ -498,10 +498,6 @@ _bpftool()
 key|value|flags|name|entries)
 return 0
 ;;
-dev)
-_sysfs_get_netdevs
-return 0
-;;
 *)
 _bpftool_once_attr 'type'
 _bpftool_once_attr 'key'
@@ -775,18 +771,67 @@ _bpftool()
 esac
 ;;
 net)
+local PROG_TYPE='id pinned tag'
+local ATTACH_TYPES='xdp xdpgeneric xdpdrv xdpoffload'
 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 ]] && \
 COMPREPLY=( $( compgen -W 'help \
-show list' -- "$cur" ) )
+show list attach detach' -- "$cur" ) )
 ;;
 esac
 ;;
 feature)
 case $command in
 probe)
-[[ $prev == "dev" ]] && _sysfs_get_netdevs && return 0
 [[ $prev == "prefix" ]] && return 0
 if _bpftool_search_list 'macros'; then
 COMPREPLY+=( $( compgen -W 'prefix' -- "$cur" ) )
-- 
2.20.1



[v5,4/4] tools: bpftool: add documentation for net attach/detach

2019-08-12 Thread Daniel T. Lee
Since, new sub-command 'net attach/detach' has been added for
attaching XDP program on interface,
this commit documents usage and sample output of `net attach/detach`.

Signed-off-by: Daniel T. Lee 
---
 .../bpf/bpftool/Documentation/bpftool-net.rst | 57 ++-
 1 file changed, 54 insertions(+), 3 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-net.rst 
b/tools/bpf/bpftool/Documentation/bpftool-net.rst
index d8e5237a2085..8651b00b81ea 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-net.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-net.rst
@@ -15,17 +15,22 @@ SYNOPSIS
*OPTIONS* := { [{ **-j** | **--json** }] [{ **-p** | **--pretty** }] }
 
*COMMANDS* :=
-   { **show** | **list** } [ **dev** name ] | **help**
+   { **show** | **list** | **attach** | **detach** | **help** }
 
 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**
+|
+|  *PROG* := { **id** *PROG_ID* | **pinned** *FILE* | **tag** *PROG_TAG* }
+|  *ATTACH_TYPE* := { **xdp** | **xdpgeneric** | **xdpdrv** | 
**xdpoffload** }
 
 DESCRIPTION
 ===
-   **bpftool net { show | list } [ dev name ]**
+   **bpftool net { show | list }** [ **dev** *NAME* ]
   List bpf program attachments in the kernel networking 
subsystem.
 
   Currently, only device driver xdp attachments and tc filter
@@ -47,6 +52,24 @@ DESCRIPTION
   all bpf programs attached to non clsact qdiscs, and finally 
all
   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**
  Print short help message.
 
@@ -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
 
-- 
2.20.1



[v5,1/4] tools: bpftool: add net attach command to attach XDP on interface

2019-08-12 Thread Daniel T. Lee
By this commit, using `bpftool net attach`, user can attach XDP prog on
interface. New type of enum 'net_attach_type' has been made, as stat ted at
cover-letter, the meaning of 'attach' is, prog will be attached on interface.

With 'overwrite' option at argument, attached XDP program could be replaced.
Added new helper 'net_parse_dev' to parse the network device at argument.

BPF prog will be attached through libbpf 'bpf_set_link_xdp_fd'.

Acked-by: Yonghong Song 
Signed-off-by: Daniel T. Lee 
---
 tools/bpf/bpftool/net.c | 136 +---
 1 file changed, 129 insertions(+), 7 deletions(-)

diff --git a/tools/bpf/bpftool/net.c b/tools/bpf/bpftool/net.c
index 67e99c56bc88..33222ca1060e 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;
@@ -223,6 +252,97 @@ 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_show(int argc, char **argv)
 {
struct bpf_attach_info attach_info = {};
@@ 

Re: [v5,0/4] tools: bpftool: add net attach/detach command to attach XDP prog

2019-08-14 Thread Daniel T. Lee
On Wed, Aug 14, 2019 at 6:43 AM Jakub Kicinski
 wrote:
>
> On Tue, 13 Aug 2019 11:46:17 +0900, Daniel T. Lee wrote:
> > 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
>
> The inconsistency in libbpf's error reporting is generally troubling,
> but a problem of this set, so:
>
> Reviewed-by: Jakub Kicinski 
>
> In the future please keep review tags if you have only made minor
> changes to the code.

Thank you for the review.
Sorry to bother you. I'll keep that in mind.

Thanks!


[PATCH] samples: bpf: add max_pckt_size option at xdp_adjust_tail

2019-08-26 Thread Daniel T. Lee
Currently, at xdp_adjust_tail_kern.c, MAX_PCKT_SIZE is limited
to 600. To make this size flexible, a new map 'pcktsz' is added.

By updating new packet size to this map from the userland,
xdp_adjust_tail_kern.o will use this value as a new max_pckt_size.

If no '-P ' option is used, the size of maximum packet
will be 600 as a default.

Signed-off-by: Daniel T. Lee 
---
 samples/bpf/xdp_adjust_tail_kern.c | 23 +++
 samples/bpf/xdp_adjust_tail_user.c | 21 +++--
 2 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/samples/bpf/xdp_adjust_tail_kern.c 
b/samples/bpf/xdp_adjust_tail_kern.c
index 411fdb21f8bc..4d53af370b68 100644
--- a/samples/bpf/xdp_adjust_tail_kern.c
+++ b/samples/bpf/xdp_adjust_tail_kern.c
@@ -25,6 +25,13 @@
 #define ICMP_TOOBIG_SIZE 98
 #define ICMP_TOOBIG_PAYLOAD_SIZE 92
 
+struct bpf_map_def SEC("maps") pcktsz = {
+   .type = BPF_MAP_TYPE_ARRAY,
+   .key_size = sizeof(__u32),
+   .value_size = sizeof(__u32),
+   .max_entries = 1,
+};
+
 struct bpf_map_def SEC("maps") icmpcnt = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
@@ -64,7 +71,8 @@ static __always_inline void ipv4_csum(void *data_start, int 
data_size,
*csum = csum_fold_helper(*csum);
 }
 
-static __always_inline int send_icmp4_too_big(struct xdp_md *xdp)
+static __always_inline int send_icmp4_too_big(struct xdp_md *xdp,
+ __u32 max_pckt_size)
 {
int headroom = (int)sizeof(struct iphdr) + (int)sizeof(struct icmphdr);
 
@@ -92,7 +100,7 @@ static __always_inline int send_icmp4_too_big(struct xdp_md 
*xdp)
orig_iph = data + off;
icmp_hdr->type = ICMP_DEST_UNREACH;
icmp_hdr->code = ICMP_FRAG_NEEDED;
-   icmp_hdr->un.frag.mtu = htons(MAX_PCKT_SIZE-sizeof(struct ethhdr));
+   icmp_hdr->un.frag.mtu = htons(max_pckt_size - sizeof(struct ethhdr));
icmp_hdr->checksum = 0;
ipv4_csum(icmp_hdr, ICMP_TOOBIG_PAYLOAD_SIZE, &csum);
icmp_hdr->checksum = csum;
@@ -118,14 +126,21 @@ static __always_inline int handle_ipv4(struct xdp_md *xdp)
 {
void *data_end = (void *)(long)xdp->data_end;
void *data = (void *)(long)xdp->data;
+   __u32 max_pckt_size = MAX_PCKT_SIZE;
+   __u32 *pckt_sz;
+   __u32 key = 0;
int pckt_size = data_end - data;
int offset;
 
-   if (pckt_size > MAX_PCKT_SIZE) {
+   pckt_sz = bpf_map_lookup_elem(&pcktsz, &key);
+   if (pckt_sz && *pckt_sz)
+   max_pckt_size = *pckt_sz;
+
+   if (pckt_size > max_pckt_size) {
offset = pckt_size - ICMP_TOOBIG_SIZE;
if (bpf_xdp_adjust_tail(xdp, 0 - offset))
return XDP_PASS;
-   return send_icmp4_too_big(xdp);
+   return send_icmp4_too_big(xdp, max_pckt_size);
}
return XDP_PASS;
 }
diff --git a/samples/bpf/xdp_adjust_tail_user.c 
b/samples/bpf/xdp_adjust_tail_user.c
index a3596b617c4c..dd3befa5e1fe 100644
--- a/samples/bpf/xdp_adjust_tail_user.c
+++ b/samples/bpf/xdp_adjust_tail_user.c
@@ -72,6 +72,7 @@ static void usage(const char *cmd)
printf("Usage: %s [...]\n", cmd);
printf("-i  Interface\n");
printf("-T  Default: 0 (forever)\n");
+   printf("-P  Default: 600\n");
printf("-S use skb-mode\n");
printf("-N enforce native mode\n");
printf("-F force loading prog\n");
@@ -85,9 +86,11 @@ int main(int argc, char **argv)
.prog_type  = BPF_PROG_TYPE_XDP,
};
unsigned char opt_flags[256] = {};
-   const char *optstr = "i:T:SNFh";
+   const char *optstr = "i:T:P:SNFh";
struct bpf_prog_info info = {};
__u32 info_len = sizeof(info);
+   __u32 max_pckt_size = 0;
+   __u32 key = 0;
unsigned int kill_after_s = 0;
int i, prog_fd, map_fd, opt;
struct bpf_object *obj;
@@ -110,6 +113,9 @@ int main(int argc, char **argv)
case 'T':
kill_after_s = atoi(optarg);
break;
+   case 'P':
+   max_pckt_size = atoi(optarg);
+   break;
case 'S':
xdp_flags |= XDP_FLAGS_SKB_MODE;
break;
@@ -150,9 +156,20 @@ int main(int argc, char **argv)
if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
return 1;
 
+   /* update pcktsz map */
map = bpf_map__next(NULL, obj);
if (!map) {
-   printf("finding a map in obj file failed\n");
+   printf("finding a pcktsz map in obj file failed\n");
+   retur

[bpf-next, v2] samples: bpf: add max_pckt_size option at xdp_adjust_tail

2019-08-26 Thread Daniel T. Lee
Currently, at xdp_adjust_tail_kern.c, MAX_PCKT_SIZE is limited
to 600. To make this size flexible, a new map 'pcktsz' is added.

By updating new packet size to this map from the userland,
xdp_adjust_tail_kern.o will use this value as a new max_pckt_size.

If no '-P ' option is used, the size of maximum packet
will be 600 as a default.

Signed-off-by: Daniel T. Lee 

---
Changes in v2:
- Change the helper to fetch map from 'bpf_map__next' to 
'bpf_object__find_map_fd_by_name'.

 samples/bpf/xdp_adjust_tail_kern.c | 23 +++
 samples/bpf/xdp_adjust_tail_user.c | 27 +--
 2 files changed, 40 insertions(+), 10 deletions(-)

diff --git a/samples/bpf/xdp_adjust_tail_kern.c 
b/samples/bpf/xdp_adjust_tail_kern.c
index 411fdb21f8bc..d6d84ffe6a7a 100644
--- a/samples/bpf/xdp_adjust_tail_kern.c
+++ b/samples/bpf/xdp_adjust_tail_kern.c
@@ -25,6 +25,13 @@
 #define ICMP_TOOBIG_SIZE 98
 #define ICMP_TOOBIG_PAYLOAD_SIZE 92
 
+struct bpf_map_def SEC("maps") pcktsz = {
+   .type = BPF_MAP_TYPE_ARRAY,
+   .key_size = sizeof(__u32),
+   .value_size = sizeof(__u32),
+   .max_entries = 1,
+};
+
 struct bpf_map_def SEC("maps") icmpcnt = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
@@ -64,7 +71,8 @@ static __always_inline void ipv4_csum(void *data_start, int 
data_size,
*csum = csum_fold_helper(*csum);
 }
 
-static __always_inline int send_icmp4_too_big(struct xdp_md *xdp)
+static __always_inline int send_icmp4_too_big(struct xdp_md *xdp,
+ __u32 max_pckt_size)
 {
int headroom = (int)sizeof(struct iphdr) + (int)sizeof(struct icmphdr);
 
@@ -92,7 +100,7 @@ static __always_inline int send_icmp4_too_big(struct xdp_md 
*xdp)
orig_iph = data + off;
icmp_hdr->type = ICMP_DEST_UNREACH;
icmp_hdr->code = ICMP_FRAG_NEEDED;
-   icmp_hdr->un.frag.mtu = htons(MAX_PCKT_SIZE-sizeof(struct ethhdr));
+   icmp_hdr->un.frag.mtu = htons(max_pckt_size - sizeof(struct ethhdr));
icmp_hdr->checksum = 0;
ipv4_csum(icmp_hdr, ICMP_TOOBIG_PAYLOAD_SIZE, &csum);
icmp_hdr->checksum = csum;
@@ -118,14 +126,21 @@ static __always_inline int handle_ipv4(struct xdp_md *xdp)
 {
void *data_end = (void *)(long)xdp->data_end;
void *data = (void *)(long)xdp->data;
+   __u32 max_pckt_size = MAX_PCKT_SIZE;
+   __u32 *pckt_sz;
+   __u32 key = 0;
int pckt_size = data_end - data;
int offset;
 
-   if (pckt_size > MAX_PCKT_SIZE) {
+   pckt_sz = bpf_map_lookup_elem(&pcktsz, &key);
+   if (pckt_sz && *pckt_sz)
+   max_pckt_size = *pckt_sz;
+
+   if (pckt_size > max_pckt_size) {
offset = pckt_size - ICMP_TOOBIG_SIZE;
if (bpf_xdp_adjust_tail(xdp, 0 - offset))
return XDP_PASS;
-   return send_icmp4_too_big(xdp);
+   return send_icmp4_too_big(xdp, max_pckt_size);
}
return XDP_PASS;
 }
diff --git a/samples/bpf/xdp_adjust_tail_user.c 
b/samples/bpf/xdp_adjust_tail_user.c
index a3596b617c4c..29ade7caf841 100644
--- a/samples/bpf/xdp_adjust_tail_user.c
+++ b/samples/bpf/xdp_adjust_tail_user.c
@@ -72,6 +72,7 @@ static void usage(const char *cmd)
printf("Usage: %s [...]\n", cmd);
printf("-i  Interface\n");
printf("-T  Default: 0 (forever)\n");
+   printf("-P  Default: 600\n");
printf("-S use skb-mode\n");
printf("-N enforce native mode\n");
printf("-F force loading prog\n");
@@ -85,13 +86,14 @@ int main(int argc, char **argv)
.prog_type  = BPF_PROG_TYPE_XDP,
};
unsigned char opt_flags[256] = {};
-   const char *optstr = "i:T:SNFh";
+   const char *optstr = "i:T:P:SNFh";
struct bpf_prog_info info = {};
__u32 info_len = sizeof(info);
+   __u32 max_pckt_size = 0;
+   __u32 key = 0;
unsigned int kill_after_s = 0;
int i, prog_fd, map_fd, opt;
struct bpf_object *obj;
-   struct bpf_map *map;
char filename[256];
int err;
 
@@ -110,6 +112,9 @@ int main(int argc, char **argv)
case 'T':
kill_after_s = atoi(optarg);
break;
+   case 'P':
+   max_pckt_size = atoi(optarg);
+   break;
case 'S':
xdp_flags |= XDP_FLAGS_SKB_MODE;
break;
@@ -150,12 +155,22 @@ int main(int argc, char **argv)
if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
return 1;
 
-   map = bpf_map__next(NULL, obj);
-

Re: [PATCH] samples: bpf: add max_pckt_size option at xdp_adjust_tail

2019-08-26 Thread Daniel T. Lee
On Tue, Aug 27, 2019 at 12:54 AM Maciej Fijalkowski
 wrote:
>
> On Mon, 26 Aug 2019 18:57:22 +0900
> "Daniel T. Lee"  wrote:
>
> > Currently, at xdp_adjust_tail_kern.c, MAX_PCKT_SIZE is limited
> > to 600. To make this size flexible, a new map 'pcktsz' is added.
> >
> > By updating new packet size to this map from the userland,
> > xdp_adjust_tail_kern.o will use this value as a new max_pckt_size.
> >
> > If no '-P ' option is used, the size of maximum packet
> > will be 600 as a default.
> >
> > Signed-off-by: Daniel T. Lee 
> > ---
> >  samples/bpf/xdp_adjust_tail_kern.c | 23 +++
> >  samples/bpf/xdp_adjust_tail_user.c | 21 +++--
> >  2 files changed, 38 insertions(+), 6 deletions(-)
> >
> > diff --git a/samples/bpf/xdp_adjust_tail_kern.c 
> > b/samples/bpf/xdp_adjust_tail_kern.c
> > index 411fdb21f8bc..4d53af370b68 100644
> > --- a/samples/bpf/xdp_adjust_tail_kern.c
> > +++ b/samples/bpf/xdp_adjust_tail_kern.c
> > @@ -25,6 +25,13 @@
> >  #define ICMP_TOOBIG_SIZE 98
> >  #define ICMP_TOOBIG_PAYLOAD_SIZE 92
> >
> > +struct bpf_map_def SEC("maps") pcktsz = {
> > + .type = BPF_MAP_TYPE_ARRAY,
> > + .key_size = sizeof(__u32),
> > + .value_size = sizeof(__u32),
> > + .max_entries = 1,
> > +};
> > +
> >  struct bpf_map_def SEC("maps") icmpcnt = {
> >   .type = BPF_MAP_TYPE_ARRAY,
> >   .key_size = sizeof(__u32),
> > @@ -64,7 +71,8 @@ static __always_inline void ipv4_csum(void *data_start, 
> > int data_size,
> >   *csum = csum_fold_helper(*csum);
> >  }
> >
> > -static __always_inline int send_icmp4_too_big(struct xdp_md *xdp)
> > +static __always_inline int send_icmp4_too_big(struct xdp_md *xdp,
> > +   __u32 max_pckt_size)
> >  {
> >   int headroom = (int)sizeof(struct iphdr) + (int)sizeof(struct 
> > icmphdr);
> >
> > @@ -92,7 +100,7 @@ static __always_inline int send_icmp4_too_big(struct 
> > xdp_md *xdp)
> >   orig_iph = data + off;
> >   icmp_hdr->type = ICMP_DEST_UNREACH;
> >   icmp_hdr->code = ICMP_FRAG_NEEDED;
> > - icmp_hdr->un.frag.mtu = htons(MAX_PCKT_SIZE-sizeof(struct ethhdr));
> > + icmp_hdr->un.frag.mtu = htons(max_pckt_size - sizeof(struct ethhdr));
> >   icmp_hdr->checksum = 0;
> >   ipv4_csum(icmp_hdr, ICMP_TOOBIG_PAYLOAD_SIZE, &csum);
> >   icmp_hdr->checksum = csum;
> > @@ -118,14 +126,21 @@ static __always_inline int handle_ipv4(struct xdp_md 
> > *xdp)
> >  {
> >   void *data_end = (void *)(long)xdp->data_end;
> >   void *data = (void *)(long)xdp->data;
> > + __u32 max_pckt_size = MAX_PCKT_SIZE;
> > + __u32 *pckt_sz;
> > + __u32 key = 0;
> >   int pckt_size = data_end - data;
> >   int offset;
> >
> > - if (pckt_size > MAX_PCKT_SIZE) {
> > + pckt_sz = bpf_map_lookup_elem(&pcktsz, &key);
> > + if (pckt_sz && *pckt_sz)
> > + max_pckt_size = *pckt_sz;
> > +
> > + if (pckt_size > max_pckt_size) {
> >   offset = pckt_size - ICMP_TOOBIG_SIZE;
> >   if (bpf_xdp_adjust_tail(xdp, 0 - offset))
> >   return XDP_PASS;
> > - return send_icmp4_too_big(xdp);
> > + return send_icmp4_too_big(xdp, max_pckt_size);
> >   }
> >   return XDP_PASS;
> >  }
> > diff --git a/samples/bpf/xdp_adjust_tail_user.c 
> > b/samples/bpf/xdp_adjust_tail_user.c
> > index a3596b617c4c..dd3befa5e1fe 100644
> > --- a/samples/bpf/xdp_adjust_tail_user.c
> > +++ b/samples/bpf/xdp_adjust_tail_user.c
> > @@ -72,6 +72,7 @@ static void usage(const char *cmd)
> >   printf("Usage: %s [...]\n", cmd);
> >   printf("-i  Interface\n");
> >   printf("-T  Default: 0 (forever)\n");
> > + printf("-P  Default: 600\n");
> >   printf("-S use skb-mode\n");
> >   printf("-N enforce native mode\n");
> >   printf("-F force loading prog\n");
> > @@ -85,9 +86,11 @@ int main(int argc, char **argv)
> >   .prog_type  = BPF_PROG_TYPE_XDP,
> >   };
> >   unsigned char opt_flags[256] = {};
> > - const char *optstr = "i:T:SNFh";
> > + const char *optstr = "i:T:P:SNFh";
> >   struct bpf_prog_info info = {};
>

[PATCH 3/3] samples: pktgen: allow to specify destination IP range (CIDR)

2019-08-28 Thread Daniel T. Lee
Currently, kernel pktgen has the feature to specify destination
address range for sending packet. (e.g. pgset "dst_min/dst_max")

But on samples, each of them doesn't have any option to achieve this.

The commit adds feature to specify destination address range with CIDR.

-d : ($DEST_IP)   destination IP. CIDR (e.g. 198.18.0.0/15) is also allowed

# ./pktgen_sample01_simple.sh -6 -d fe80::20/126 -p 3000 -n 4
# tcpdump ip6 and udp
05:14:18.082285 IP6 fe80::99.71 > fe80::23.3000: UDP, length 16
05:14:18.082564 IP6 fe80::99.43 > fe80::23.3000: UDP, length 16
05:14:18.083366 IP6 fe80::99.107 > fe80::22.3000: UDP, length 16
05:14:18.083585 IP6 fe80::99.97 > fe80::21.3000: UDP, length 16

Signed-off-by: Daniel T. Lee 
---
 samples/pktgen/README.rst |  2 +-
 samples/pktgen/parameters.sh  |  2 +-
 .../pktgen/pktgen_bench_xmit_mode_netif_receive.sh|  4 +++-
 samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh   |  4 +++-
 samples/pktgen/pktgen_sample01_simple.sh  |  4 +++-
 samples/pktgen/pktgen_sample02_multiqueue.sh  |  4 +++-
 samples/pktgen/pktgen_sample03_burst_single_flow.sh   |  4 +++-
 samples/pktgen/pktgen_sample04_many_flows.sh  | 11 ---
 samples/pktgen/pktgen_sample05_flow_per_thread.sh |  4 +++-
 .../pktgen_sample06_numa_awared_queue_irq_affinity.sh |  4 +++-
 10 files changed, 31 insertions(+), 12 deletions(-)

diff --git a/samples/pktgen/README.rst b/samples/pktgen/README.rst
index fd39215db508..3f6483e8b2df 100644
--- a/samples/pktgen/README.rst
+++ b/samples/pktgen/README.rst
@@ -18,7 +18,7 @@ across the sample scripts.  Usage example is printed on 
errors::
  Usage: ./pktgen_sample01_simple.sh [-vx] -i ethX
   -i : ($DEV)   output interface/device (required)
   -s : ($PKT_SIZE)  packet size
-  -d : ($DEST_IP)   destination IP
+  -d : ($DEST_IP)   destination IP. CIDR (e.g. 198.18.0.0/15) is also allowed
   -m : ($DST_MAC)   destination MAC-addr
   -p : ($DST_PORT)  destination PORT range (e.g. 433-444) is also allowed
   -t : ($THREADS)   threads to start
diff --git a/samples/pktgen/parameters.sh b/samples/pktgen/parameters.sh
index a06b00a0c7b6..ff0ed474fee9 100644
--- a/samples/pktgen/parameters.sh
+++ b/samples/pktgen/parameters.sh
@@ -8,7 +8,7 @@ function usage() {
 echo "Usage: $0 [-vx] -i ethX"
 echo "  -i : (\$DEV)   output interface/device (required)"
 echo "  -s : (\$PKT_SIZE)  packet size"
-echo "  -d : (\$DEST_IP)   destination IP"
+echo "  -d : (\$DEST_IP)   destination IP. CIDR (e.g. 198.18.0.0/15) is 
also allowed"
 echo "  -m : (\$DST_MAC)   destination MAC-addr"
 echo "  -p : (\$DST_PORT)  destination PORT range (e.g. 433-444) is also 
allowed"
 echo "  -t : (\$THREADS)   threads to start"
diff --git a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
index 9b74502c58f7..da6cb711b7f4 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
@@ -41,6 +41,7 @@ fi
 [ -z "$DST_MAC" ] && DST_MAC="90:e2:ba:ff:ff:ff"
 [ -z "$BURST" ] && BURST=1024
 [ -z "$COUNT" ] && COUNT="1000" # Zero means indefinitely
+[ -n "$DEST_IP" ] && read -r DST_MIN DST_MAX <<< $(parse_addr${IP6} $DEST_IP)
 if [ -n "$DST_PORT" ]; then
 read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
 validate_ports $UDP_DST_MIN $UDP_DST_MAX
@@ -71,7 +72,8 @@ for ((thread = $F_THREAD; thread <= $L_THREAD; thread++)); do
 
 # Destination
 pg_set $dev "dst_mac $DST_MAC"
-pg_set $dev "dst$IP6 $DEST_IP"
+pg_set $dev "dst${IP6}_min $DST_MIN"
+pg_set $dev "dst${IP6}_max $DST_MAX"
 
 if [ -n "$DST_PORT" ]; then
# Single destination port or random port range
diff --git a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
index 0f332555b40d..355937787364 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
@@ -24,6 +24,7 @@ if [[ -n "$BURST" ]]; then
 err 1 "Bursting not supported for this mode"
 fi
 [ -z "$COUNT" ] && COUNT="1000" # Zero means indefinitely
+[ -n "$DEST_IP" ] && read -r DST_MIN DST_MAX <<< $(parse_addr${IP6} $DEST_IP)
 if [ -n "$DST_PORT" ]; then
 read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
 validate_ports $UDP_DST_MIN $UDP_DST_MAX
@@ -54,7 +55,8 @@ for ((thread = $F_THREAD; thread <= $L_THREAD; thread++)); do
 
 # Destination
 pg_set 

[PATCH 1/3] samples: pktgen: make variable consistent with option

2019-08-28 Thread Daniel T. Lee
This commit changes variable names that can cause confusion.

For example, variable DST_MIN is quite confusing since the
keyword 'udp_dst_min' and keyword 'dst_min' is used with pg_ctrl.

On the following commit, 'dst_min' will be used to set destination IP,
and the existing variable name DST_MIN should be changed.

Variable names are matched to the exact keyword used with pg_ctrl.

Signed-off-by: Daniel T. Lee 
---
 .../pktgen_bench_xmit_mode_netif_receive.sh  |  8 
 .../pktgen/pktgen_bench_xmit_mode_queue_xmit.sh  |  8 
 samples/pktgen/pktgen_sample01_simple.sh | 16 
 samples/pktgen/pktgen_sample02_multiqueue.sh | 16 
 .../pktgen/pktgen_sample03_burst_single_flow.sh  |  8 
 samples/pktgen/pktgen_sample04_many_flows.sh |  8 
 .../pktgen/pktgen_sample05_flow_per_thread.sh|  8 
 ...en_sample06_numa_awared_queue_irq_affinity.sh | 16 
 8 files changed, 44 insertions(+), 44 deletions(-)

diff --git a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
index e14b1a9144d9..9b74502c58f7 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_netif_receive.sh
@@ -42,8 +42,8 @@ fi
 [ -z "$BURST" ] && BURST=1024
 [ -z "$COUNT" ] && COUNT="1000" # Zero means indefinitely
 if [ -n "$DST_PORT" ]; then
-read -r DST_MIN DST_MAX <<< $(parse_ports $DST_PORT)
-validate_ports $DST_MIN $DST_MAX
+read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
+validate_ports $UDP_DST_MIN $UDP_DST_MAX
 fi
 
 # Base Config
@@ -76,8 +76,8 @@ for ((thread = $F_THREAD; thread <= $L_THREAD; thread++)); do
 if [ -n "$DST_PORT" ]; then
# Single destination port or random port range
pg_set $dev "flag UDPDST_RND"
-   pg_set $dev "udp_dst_min $DST_MIN"
-   pg_set $dev "udp_dst_max $DST_MAX"
+   pg_set $dev "udp_dst_min $UDP_DST_MIN"
+   pg_set $dev "udp_dst_max $UDP_DST_MAX"
 fi
 
 # Inject packet into RX path of stack
diff --git a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh 
b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
index 82c3e504e056..0f332555b40d 100755
--- a/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
+++ b/samples/pktgen/pktgen_bench_xmit_mode_queue_xmit.sh
@@ -25,8 +25,8 @@ if [[ -n "$BURST" ]]; then
 fi
 [ -z "$COUNT" ] && COUNT="1000" # Zero means indefinitely
 if [ -n "$DST_PORT" ]; then
-read -r DST_MIN DST_MAX <<< $(parse_ports $DST_PORT)
-validate_ports $DST_MIN $DST_MAX
+read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
+validate_ports $UDP_DST_MIN $UDP_DST_MAX
 fi
 
 # Base Config
@@ -59,8 +59,8 @@ for ((thread = $F_THREAD; thread <= $L_THREAD; thread++)); do
 if [ -n "$DST_PORT" ]; then
# Single destination port or random port range
pg_set $dev "flag UDPDST_RND"
-   pg_set $dev "udp_dst_min $DST_MIN"
-   pg_set $dev "udp_dst_max $DST_MAX"
+   pg_set $dev "udp_dst_min $UDP_DST_MIN"
+   pg_set $dev "udp_dst_max $UDP_DST_MAX"
 fi
 
 # Inject packet into TX qdisc egress path of stack
diff --git a/samples/pktgen/pktgen_sample01_simple.sh 
b/samples/pktgen/pktgen_sample01_simple.sh
index d1702fdde8f3..063ec0998906 100755
--- a/samples/pktgen/pktgen_sample01_simple.sh
+++ b/samples/pktgen/pktgen_sample01_simple.sh
@@ -23,16 +23,16 @@ fi
 [ -z "$DST_MAC" ] && usage && err 2 "Must specify -m dst_mac"
 [ -z "$COUNT" ]   && COUNT="10" # Zero means indefinitely
 if [ -n "$DST_PORT" ]; then
-read -r DST_MIN DST_MAX <<< $(parse_ports $DST_PORT)
-validate_ports $DST_MIN $DST_MAX
+read -r UDP_DST_MIN UDP_DST_MAX <<< $(parse_ports $DST_PORT)
+validate_ports $UDP_DST_MIN $UDP_DST_MAX
 fi
 
 # Base Config
 DELAY="0"# Zero means max speed
 
 # Flow variation random source port between min and max
-UDP_MIN=9
-UDP_MAX=109
+UDP_SRC_MIN=9
+UDP_SRC_MAX=109
 
 # General cleanup everything since last run
 # (especially important if other threads were configured by other scripts)
@@ -66,14 +66,14 @@ pg_set $DEV "dst$IP6 $DEST_IP"
 if [ -n "$DST_PORT" ]; then
 # Single destination port or random port range
 pg_set $DEV "flag UDPDST_RND"
-pg_set $DEV "udp_dst_min $DST_MIN"
-pg_set $DEV "udp_dst_max $DST_MAX"
+pg_set $DEV "udp_dst_min $UDP_DST_MIN"
+pg_set $DEV "udp_dst_max $UDP_DST_MAX"
 fi
 
 # Setup random UDP port src range
 pg_set $DEV "flag 

[PATCH 2/3] samples: pktgen: add helper functions for IP(v4/v6) CIDR parsing

2019-08-28 Thread Daniel T. Lee
This commit adds CIDR parsing and IP validate helper function to parse
single IP or range of IP with CIDR. (e.g. 198.18.0.0/15)

Helpers will be used in prior to set target address in samples/pktgen.

Signed-off-by: Daniel T. Lee 
---
 samples/pktgen/functions.sh | 134 
 1 file changed, 134 insertions(+)

diff --git a/samples/pktgen/functions.sh b/samples/pktgen/functions.sh
index 4af4046d71be..eb1c52e25018 100644
--- a/samples/pktgen/functions.sh
+++ b/samples/pktgen/functions.sh
@@ -163,6 +163,140 @@ function get_node_cpus()
echo $node_cpu_list
 }
 
+# Extend shrunken IPv6 address.
+# fe80::42:bcff:fe84:e10a => fe80:0:0:0:42:bcff:fe84:e10a
+function extend_addr6()
+{
+local addr=$1
+local sep=:
+local sep2=::
+local sep_cnt=$(tr -cd $sep <<< $1 | wc -c)
+local shrink
+
+# separator count : should be between 2, 7.
+if [[ $sep_cnt -lt 2 || $sep_cnt -gt 7 ]]; then
+err 5 "Invalid IP6 address sep: $1"
+fi
+
+# if shrink '::' occurs multiple, it's malformed.
+shrink=( $(egrep -o "$sep{2,}" <<< $addr) )
+if [[ ${#shrink[@]} -ne 0 ]]; then
+if [[ ${#shrink[@]} -gt 1 || ( ${shrink[0]} != $sep2 ) ]]; then
+err 5 "Invalid IP$IP6 address shr: $1"
+fi
+fi
+
+# add 0 at begin & end, and extend addr by adding :0
+[[ ${addr:0:1} == $sep ]] && addr=0${addr}
+[[ ${addr: -1} == $sep ]] && addr=${addr}0
+echo "${addr/$sep2/$(printf ':0%.s' $(seq $[8-sep_cnt])):}"
+}
+
+
+# Given a single IP(v4/v6) address, whether it is valid.
+function validate_addr()
+{
+# check function is called with (funcname)6
+[[ ${FUNCNAME[1]: -1} == 6 ]] && local IP6=6
+local len=$[ IP6 ? 8 : 4 ]
+local max=$[ 2**(len*2)-1 ]
+local addr
+local sep
+
+# set separator for each IP(v4/v6)
+[[ $IP6 ]] && sep=: || sep=.
+IFS=$sep read -a addr <<< $1
+
+# array length
+if [[ ${#addr[@]} != $len ]]; then
+err 5 "Invalid IP$IP6 address: $1"
+fi
+
+# check each digit between 0, $max
+for digit in "${addr[@]}"; do
+[[ $IP6 ]] && digit=$[ 16#$digit ]
+if [[ $digit -lt 0 || $digit -gt $max ]]; then
+err 5 "Invalid IP$IP6 address: $1"
+fi
+done
+
+return 0
+}
+
+function validate_addr6() { validate_addr $@ ; }
+
+# Given a single IP(v4/v6) or CIDR, return minimum and maximum IP addr.
+function parse_addr()
+{
+# check function is called with (funcname)6
+[[ ${FUNCNAME[1]: -1} == 6 ]] && local IP6=6
+local bitlen=$[ IP6 ? 128 : 32 ]
+
+local addr=$1
+local net
+local prefix
+local min_ip
+local max_ip
+
+IFS='/' read net prefix <<< $addr
+[[ $IP6 ]] && net=$(extend_addr6 $net)
+validate_addr$IP6 $net
+
+if [[ $prefix -gt $bitlen ]]; then
+err 5 "Invalid prefix: $prefix"
+elif [[ -z $prefix ]]; then
+min_ip=$net
+max_ip=$net
+else
+# defining array for converting Decimal 2 Binary
+#  0001 0010 0011 0100 ...
+local d2b='{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}'
+[[ $IP6 ]] && d2b+=$d2b
+eval local D2B=($d2b)
+
+local shift=$[ bitlen-prefix ]
+local ip_bit
+local ip
+local sep
+
+# set separator for each IP(v4/v6)
+[[ $IP6 ]] && sep=: || sep=.
+IFS=$sep read -ra ip <<< $net
+
+# build full size bit
+for digit in "${ip[@]}"; do
+[[ $IP6 ]] && digit=$[ 16#$digit ]
+ip_bit+=${D2B[$digit]}
+done
+
+# fill 0 or 1 by $shift
+base_bit=${ip_bit::$prefix}
+min_bit="$base_bit$(printf '0%.s' $(seq $shift))"
+max_bit="$base_bit$(printf '1%.s' $(seq $shift))"
+
+bit2addr() {
+local step=$[ IP6 ? 16 : 8 ]
+local max=$[ bitlen-step ]
+local result
+local fmt
+[[ $IP6 ]] && fmt='%X' || fmt='%d'
+
+for i in $(seq 0 $step $max); do
+result+=$(printf $fmt $[ 2#${1:$i:$step} ])
+[[ $i != $max ]] && result+=$sep
+done
+echo $result
+}
+
+min_ip=$(bit2addr $min_bit)
+max_ip=$(bit2addr $max_bit)
+fi
+
+echo $min_ip $max_ip
+}
+
+function parse_addr6() { parse_addr $@ ; }
+
 # Given a single or range of port(s), return minimum and maximum port number.
 function parse_ports()
 {
-- 
2.20.1



Re: [bpf-next, v2] samples: bpf: add max_pckt_size option at xdp_adjust_tail

2019-08-29 Thread Daniel T. Lee
On Fri, Aug 30, 2019 at 5:42 AM Song Liu  wrote:
>
> On Mon, Aug 26, 2019 at 9:52 AM Daniel T. Lee  wrote:
> >
> > Currently, at xdp_adjust_tail_kern.c, MAX_PCKT_SIZE is limited
> > to 600. To make this size flexible, a new map 'pcktsz' is added.
> >
> > By updating new packet size to this map from the userland,
> > xdp_adjust_tail_kern.o will use this value as a new max_pckt_size.
> >
> > If no '-P ' option is used, the size of maximum packet
> > will be 600 as a default.
>
> Please also cc b...@vger.kernel.org for bpf patches.
>

I'll make sure to have it included next time.

> >
> > Signed-off-by: Daniel T. Lee 
>
> Acked-by: Song Liu 
>
> With a nit below.
>
> [...]
>
> > diff --git a/samples/bpf/xdp_adjust_tail_user.c 
> > b/samples/bpf/xdp_adjust_tail_user.c
> > index a3596b617c4c..29ade7caf841 100644
> > --- a/samples/bpf/xdp_adjust_tail_user.c
> > +++ b/samples/bpf/xdp_adjust_tail_user.c
> > @@ -72,6 +72,7 @@ static void usage(const char *cmd)
> > printf("Usage: %s [...]\n", cmd);
> > printf("-i  Interface\n");
> > printf("-T  Default: 0 (forever)\n");
> > +   printf("-P  Default: 600\n");
>
> nit: printf("-P  Default: %u\n", MAX_PCKT_SIZE);

With all due respect, I'm afraid that MAX_PCKT_SIZE constant is only
defined at '_kern.c'.
Are you saying that it should be defined at '_user.c' either?

Thanks for the review!


  1   2   3   >