On 1/14/21 6:27 AM, Hangbin Liu wrote:
This patch add a xdp program on egress to show that we can modify
the packet on egress. In this sample we will set the pkt's src
mac to egress's mac address. The xdp_prog will be attached when
-X option supplied.

Signed-off-by: Hangbin Liu <liuhang...@gmail.com>

---
v6: no code update, only rebase the code on latest bpf-next

v5:
a) close fd when err out in get_mac_addr()
b) exit program when both -S and -X supplied.

v4:
a) Update get_mac_addr socket create
b) Load dummy prog regardless of 2nd xdp prog on egress

v3:
a) modify the src mac address based on egress mac

v2:
a) use pkt counter instead of IP ttl modification on egress program
b) make the egress program selectable by option -X
---
  samples/bpf/xdp_redirect_map_kern.c |  75 ++++++++++++++--
  samples/bpf/xdp_redirect_map_user.c | 135 +++++++++++++++++++++++-----
  2 files changed, 184 insertions(+), 26 deletions(-)

diff --git a/samples/bpf/xdp_redirect_map_kern.c 
b/samples/bpf/xdp_redirect_map_kern.c
index 6489352ab7a4..8b8e73d25ad6 100644
--- a/samples/bpf/xdp_redirect_map_kern.c
+++ b/samples/bpf/xdp_redirect_map_kern.c
@@ -19,12 +19,22 @@
  #include <linux/ipv6.h>
  #include <bpf/bpf_helpers.h>
+/* The 2nd xdp prog on egress does not support skb mode, so we define two
+ * maps, tx_port_general and tx_port_native.
+ */
  struct {
        __uint(type, BPF_MAP_TYPE_DEVMAP);
        __uint(key_size, sizeof(int));
        __uint(value_size, sizeof(int));
        __uint(max_entries, 100);
-} tx_port SEC(".maps");
+} tx_port_general SEC(".maps");
+
+struct {
+       __uint(type, BPF_MAP_TYPE_DEVMAP);
+       __uint(key_size, sizeof(int));
+       __uint(value_size, sizeof(struct bpf_devmap_val));
+       __uint(max_entries, 100);
+} tx_port_native SEC(".maps");
/* Count RX packets, as XDP bpf_prog doesn't get direct TX-success
   * feedback.  Redirect TX errors can be caught via a tracepoint.
@@ -36,6 +46,14 @@ struct {
        __uint(max_entries, 1);
  } rxcnt SEC(".maps");
+/* map to stroe egress interface mac address */

s/stroe/store

+struct {
+       __uint(type, BPF_MAP_TYPE_ARRAY);
+       __type(key, u32);
+       __type(value, __be64);
+       __uint(max_entries, 1);
+} tx_mac SEC(".maps");
+
  static void swap_src_dst_mac(void *data)
  {
        unsigned short *p = data;
@@ -52,17 +70,16 @@ static void swap_src_dst_mac(void *data)
        p[5] = dst[2];
  }
[...]
  int main(int argc, char **argv)
  {
        struct bpf_prog_load_attr prog_load_attr = {
-               .prog_type      = BPF_PROG_TYPE_XDP,
+               .prog_type      = BPF_PROG_TYPE_UNSPEC,
        };
-       struct bpf_program *prog, *dummy_prog;
+       struct bpf_program *prog, *dummy_prog, *devmap_prog;
+       int devmap_prog_fd_0 = -1, devmap_prog_fd_1 = -1;

The default value is -1 here. I remembered there was a discussion
about the default value here, does default value 0 work here?

+       int prog_fd, dummy_prog_fd;
+       int tx_port_map_fd, tx_mac_map_fd;
+       struct bpf_devmap_val devmap_val;
        struct bpf_prog_info info = {};
        __u32 info_len = sizeof(info);
-       int prog_fd, dummy_prog_fd;
-       const char *optstr = "FSN";
+       const char *optstr = "FSNX";
        struct bpf_object *obj;
        int ret, opt, key = 0;
        char filename[256];
-       int tx_port_map_fd;
while ((opt = getopt(argc, argv, optstr)) != -1) {
                switch (opt) {
@@ -120,14 +154,21 @@ int main(int argc, char **argv)
                case 'F':
                        xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
                        break;
+               case 'X':
+                       xdp_devmap_attached = true;
+                       break;
                default:
                        usage(basename(argv[0]));
                        return 1;
                }
        }
- if (!(xdp_flags & XDP_FLAGS_SKB_MODE))
+       if (!(xdp_flags & XDP_FLAGS_SKB_MODE)) {
                xdp_flags |= XDP_FLAGS_DRV_MODE;
+       } else if (xdp_devmap_attached) {
+               printf("Load xdp program on egress with SKB mode not supported 
yet\n");
+               return 1;
+       }
if (optind == argc) {
                printf("usage: %s <IFNAME|IFINDEX>_IN <IFNAME|IFINDEX>_OUT\n", 
argv[0]);
@@ -150,24 +191,28 @@ int main(int argc, char **argv)
        if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
                return 1;
- prog = bpf_program__next(NULL, obj);
-       dummy_prog = bpf_program__next(prog, obj);
-       if (!prog || !dummy_prog) {
-               printf("finding a prog in obj file failed\n");
-               return 1;
+       if (xdp_flags & XDP_FLAGS_SKB_MODE) {
+               prog = bpf_object__find_program_by_title(obj, 
"xdp_redirect_general");

libbpf supports each section having multiple programs, so bpf_object__find_program_by_title() is not recommended.
Could you change to bpf_object__find_program_by_name()?

+               tx_port_map_fd = bpf_object__find_map_fd_by_name(obj, 
"tx_port_general");
+       } else {
+               prog = bpf_object__find_program_by_title(obj, 
"xdp_redirect_native");
+               tx_port_map_fd = bpf_object__find_map_fd_by_name(obj, 
"tx_port_native");
+       }
+       dummy_prog = bpf_object__find_program_by_title(obj, 
"xdp_redirect_dummy");
+       if (!prog || dummy_prog < 0 || tx_port_map_fd < 0) {
+               printf("finding prog/tx_port_map in obj file failed\n");
+               goto out;
        }
-       /* bpf_prog_load_xattr gives us the pointer to first prog's fd,
-        * so we're missing only the fd for dummy prog
-        */
+       prog_fd = bpf_program__fd(prog);
        dummy_prog_fd = bpf_program__fd(dummy_prog);
-       if (prog_fd < 0 || dummy_prog_fd < 0) {
+       if (prog_fd < 0 || dummy_prog_fd < 0 || tx_port_map_fd < 0) {
                printf("bpf_prog_load_xattr: %s\n", strerror(errno));
                return 1;
        }
- tx_port_map_fd = bpf_object__find_map_fd_by_name(obj, "tx_port");
+       tx_mac_map_fd = bpf_object__find_map_fd_by_name(obj, "tx_mac");
        rxcnt_map_fd = bpf_object__find_map_fd_by_name(obj, "rxcnt");
-       if (tx_port_map_fd < 0 || rxcnt_map_fd < 0) {
+       if (tx_mac_map_fd < 0 || rxcnt_map_fd < 0) {
                printf("bpf_object__find_map_fd_by_name failed\n");
                return 1;
        }
[...]

Reply via email to