Re: [PATCHv6 bpf-next] samples/bpf: add xdp program on egress for xdp_redirect_map

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





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 <liuhangbin@xxxxxxxxx>

---
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;
  	}
[...]



[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux