From c8c5144fd8e9b18bdfd5c3405b755203b988a827 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Wed, 21 Jul 2021 18:30:42 -0400 Subject: [PATCH 1/8] uapi: add metadata flag to xdp flags Second approach to inform driver about metadata. Let user decide if metadata should be supported or not. Add this flag to allow user to inform driver that metadata is used. Set flag is sent to driver via exsisting ndo_bpf call in flag field. Signed-off-by: Michal Swiatkowski --- include/uapi/linux/if_link.h | 4 +++- tools/include/uapi/linux/if_link.h | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index eebd3894fe89a0..4326237c7ba1e8 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -1182,11 +1182,13 @@ enum { #define XDP_FLAGS_DRV_MODE (1U << 2) #define XDP_FLAGS_HW_MODE (1U << 3) #define XDP_FLAGS_REPLACE (1U << 4) +#define XDP_FLAGS_USE_METADATA (1U << 5) #define XDP_FLAGS_MODES (XDP_FLAGS_SKB_MODE | \ XDP_FLAGS_DRV_MODE | \ XDP_FLAGS_HW_MODE) #define XDP_FLAGS_MASK (XDP_FLAGS_UPDATE_IF_NOEXIST | \ - XDP_FLAGS_MODES | XDP_FLAGS_REPLACE) + XDP_FLAGS_MODES | XDP_FLAGS_REPLACE | \ + XDP_FLAGS_USE_METADATA) /* These are stored into IFLA_XDP_ATTACHED on dump. */ enum { diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index b3610fdd1feec3..595e238d489b71 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -969,11 +969,13 @@ enum { #define XDP_FLAGS_DRV_MODE (1U << 2) #define XDP_FLAGS_HW_MODE (1U << 3) #define XDP_FLAGS_REPLACE (1U << 4) +#define XDP_FLAGS_USE_METADATA (1U << 5) #define XDP_FLAGS_MODES (XDP_FLAGS_SKB_MODE | \ XDP_FLAGS_DRV_MODE | \ XDP_FLAGS_HW_MODE) #define XDP_FLAGS_MASK (XDP_FLAGS_UPDATE_IF_NOEXIST | \ - XDP_FLAGS_MODES | XDP_FLAGS_REPLACE) + XDP_FLAGS_MODES | XDP_FLAGS_REPLACE | \ + XDP_FLAGS_USE_METADATA) /* These are stored into IFLA_XDP_ATTACHED on dump. */ enum { From 92adc5dbc74ad07d9ed0b75ab1f4c804e6a54793 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Mon, 9 Aug 2021 20:25:18 -0400 Subject: [PATCH 2/8] net: include xdp generic metadata definition Definition is only a proposal. There should be free place for 8B of tx timestamp. Signed-off-by: Michal Swiatkowski --- include/net/xdp.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/include/net/xdp.h b/include/net/xdp.h index ad5b02dcb6f4c4..9c4d3c9ddc7de9 100644 --- a/include/net/xdp.h +++ b/include/net/xdp.h @@ -76,6 +76,24 @@ struct xdp_buff { u32 frame_sz; /* frame size to deduce data_hard_end/reserved tailroom*/ }; +struct xdp_meta_generic { + // Tx part + u32 flags; + u16 free_slot; + u16 csum_off; + u16 txcvid; + + // Rx part + u16 rxcvid; + u32 csum; + u32 hash; + u64 tstamp; + + // BTF ID + u32 btf_id; +} __packed __aligned(8); +static_assert(sizeof(struct xdp_meta_generic) == 32); + static __always_inline void xdp_init_buff(struct xdp_buff *xdp, u32 frame_sz, struct xdp_rxq_info *rxq) { From aef5c237b842bc5541b919e917c203c871538e4e Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Mon, 9 Aug 2021 23:21:15 -0400 Subject: [PATCH 3/8] ice: use xdp generic metadata As starting point add vlan id and rss hash if xdp metadata is supported. Add xd_metadata_support field in VSI to allow easy passing this value to ring configuration. Signed-off-by: Michal Swiatkowski --- drivers/net/ethernet/intel/ice/ice.h | 2 ++ drivers/net/ethernet/intel/ice/ice_main.c | 20 +++++++++++++++++-- drivers/net/ethernet/intel/ice/ice_txrx.c | 3 +++ drivers/net/ethernet/intel/ice/ice_txrx.h | 3 +++ drivers/net/ethernet/intel/ice/ice_txrx_lib.h | 10 ++++++++++ 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index eadcb99583464f..d2441c8192919c 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -349,6 +349,8 @@ struct ice_vsi { u16 num_xdp_txq; /* Used XDP queues */ u8 xdp_mapping_mode; /* ICE_MAP_MODE_[CONTIG|SCATTER] */ + bool xdp_metadata_support; /* true if VSI should support xdp meta */ + /* setup back reference, to which aggregator node this VSI * corresponds to */ diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 0d6c143f665327..50a3b9adc1d447 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2419,6 +2419,17 @@ static void ice_vsi_assign_bpf_prog(struct ice_vsi *vsi, struct bpf_prog *prog) WRITE_ONCE(vsi->rx_rings[i]->xdp_prog, vsi->xdp_prog); } +static void ice_xdp_rings_set_metadata(struct ice_vsi *vsi) +{ + int i; + + ice_for_each_rxq(vsi, i) + vsi->rx_rings[i]->xdp_metadata_support = vsi->xdp_metadata_support; + + for (i = 0; i < vsi->num_xdp_txq; i++) + vsi->xdp_rings[i]->xdp_metadata_support = vsi->xdp_metadata_support; +} + /** * ice_prepare_xdp_rings - Allocate, configure and setup Tx rings for XDP * @vsi: VSI to bring up Tx rings used by XDP @@ -2458,6 +2469,8 @@ int ice_prepare_xdp_rings(struct ice_vsi *vsi, struct bpf_prog *prog) if (ice_xdp_alloc_setup_rings(vsi)) goto clear_xdp_rings; + ice_xdp_rings_set_metadata(vsi); + /* follow the logic from ice_vsi_map_rings_to_vectors */ ice_for_each_q_vector(vsi, v_idx) { struct ice_q_vector *q_vector = vsi->q_vectors[v_idx]; @@ -2613,7 +2626,7 @@ static void ice_vsi_rx_napi_schedule(struct ice_vsi *vsi) */ static int ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog, - struct netlink_ext_ack *extack) + struct netlink_ext_ack *extack, u32 flags) { int frame_size = vsi->netdev->mtu + ICE_ETH_PKT_HDR_PAD; bool if_running = netif_running(vsi->netdev); @@ -2633,6 +2646,9 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog, } } + if (flags & XDP_FLAGS_USE_METADATA) + vsi->xdp_metadata_support = true; + if (!ice_is_xdp_ena_vsi(vsi) && prog) { vsi->num_xdp_txq = vsi->alloc_rxq; xdp_ring_err = ice_prepare_xdp_rings(vsi, prog); @@ -2686,7 +2702,7 @@ static int ice_xdp(struct net_device *dev, struct netdev_bpf *xdp) switch (xdp->command) { case XDP_SETUP_PROG: - return ice_xdp_setup_prog(vsi, xdp->prog, xdp->extack); + return ice_xdp_setup_prog(vsi, xdp->prog, xdp->extack, xdp->flags); case XDP_SETUP_XSK_POOL: return ice_xsk_pool_setup(vsi, xdp->xsk.pool, xdp->xsk.queue_id); diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 6ee8e0032d52cb..128fd49383439a 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -1135,6 +1135,9 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget) hard_start = page_address(rx_buf->page) + rx_buf->page_offset - offset; xdp_prepare_buff(&xdp, hard_start, offset, size, true); + + if (likely(rx_ring->xdp_metadata_support)) + ice_xdp_set_meta(&xdp, rx_desc); #if (PAGE_SIZE > 4096) /* At larger PAGE_SIZE, frame_sz depend on len size */ xdp.frame_sz = ice_rx_frame_truesize(rx_ring, size); diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index 1e46e80f3d6f89..b43923ddf883cf 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -276,6 +276,7 @@ struct ice_ring { u16 q_handle; /* Queue handle per TC */ u8 ring_active:1; /* is ring online or not */ + u8 xdp_metadata_support:1; /* is xdp metadata support */ u16 count; /* Number of descriptors */ u16 reg_idx; /* HW register index of the ring */ @@ -301,6 +302,8 @@ struct ice_ring { /* CL3 - 3rd cacheline starts here */ struct xdp_rxq_info xdp_rxq; struct sk_buff *skb; + + /* CLX - the below items are only accessed infrequently and should be * in their own cache line if possible */ diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h index 05ac3075290260..d77bc7686b61bd 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h @@ -46,6 +46,16 @@ static inline void ice_xdp_ring_update_tail(struct ice_ring *xdp_ring) writel_relaxed(xdp_ring->next_to_use, xdp_ring->tail); } +static inline void ice_xdp_set_meta(struct xdp_buff *xdp, union ice_32b_rx_flex_desc *desc) +{ + struct ice_32b_rx_flex_desc_nic *flex = (struct ice_32b_rx_flex_desc_nic *)desc; + struct xdp_meta_generic *md = xdp->data - sizeof(struct xdp_meta_generic); + + xdp->data_meta = md; + md->rxcvid = le16_to_cpu(flex->flex_ts.flex.vlan_id); + md->hash = le32_to_cpu(flex->rss_hash); +} + void ice_finalize_xdp_rx(struct ice_ring *rx_ring, unsigned int xdp_res); int ice_xmit_xdp_buff(struct xdp_buff *xdp, struct ice_ring *xdp_ring); int ice_xmit_xdp_ring(void *data, u16 size, struct ice_ring *xdp_ring); From f40e089a292f6b310d978952d16e6fb48d81ffc9 Mon Sep 17 00:00:00 2001 From: Michal Swiatkowski Date: Thu, 23 Sep 2021 18:40:43 -0400 Subject: [PATCH 4/8] btf: ice: implement finding BTF type id Function btf_get_type_id is needed to get correct BTF id to fill metadata by driver. BTF id is obtained while loading XDP program and saved in ring structure to be available in irq. Calling btf_get_type_id with null pointer as module will result in searching for BTF id in vmlinux. Signed-off-by: Ederson de Souza Signed-off-by: Michal Swiatkowski Signed-off-by: Larysa Zaremba --- drivers/net/ethernet/intel/ice/ice.h | 2 + drivers/net/ethernet/intel/ice/ice_main.c | 12 ++++-- drivers/net/ethernet/intel/ice/ice_txrx.c | 3 +- drivers/net/ethernet/intel/ice/ice_txrx.h | 1 + drivers/net/ethernet/intel/ice/ice_txrx_lib.h | 14 ++++++- include/linux/btf.h | 1 + kernel/bpf/btf.c | 37 +++++++++++++++++++ 7 files changed, 64 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index d2441c8192919c..a73f500c9be82f 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -350,6 +351,7 @@ struct ice_vsi { u8 xdp_mapping_mode; /* ICE_MAP_MODE_[CONTIG|SCATTER] */ bool xdp_metadata_support; /* true if VSI should support xdp meta */ + s32 btf_id; /* setup back reference, to which aggregator node this VSI * corresponds to diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 50a3b9adc1d447..e81f2944b1ab80 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -2423,11 +2423,15 @@ static void ice_xdp_rings_set_metadata(struct ice_vsi *vsi) { int i; - ice_for_each_rxq(vsi, i) + ice_for_each_rxq(vsi, i) { vsi->rx_rings[i]->xdp_metadata_support = vsi->xdp_metadata_support; + vsi->rx_rings[i]->btf_id = vsi->btf_id; + } - for (i = 0; i < vsi->num_xdp_txq; i++) + for (i = 0; i < vsi->num_xdp_txq; i++) { vsi->xdp_rings[i]->xdp_metadata_support = vsi->xdp_metadata_support; + vsi->xdp_rings[i]->btf_id = vsi->btf_id; + } } /** @@ -2646,8 +2650,10 @@ ice_xdp_setup_prog(struct ice_vsi *vsi, struct bpf_prog *prog, } } - if (flags & XDP_FLAGS_USE_METADATA) + if (flags & XDP_FLAGS_USE_METADATA) { vsi->xdp_metadata_support = true; + vsi->btf_id = btf_get_type_id(THIS_MODULE, "xdp_meta_generic", BTF_KIND_STRUCT); + } if (!ice_is_xdp_ena_vsi(vsi) && prog) { vsi->num_xdp_txq = vsi->alloc_rxq; diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.c b/drivers/net/ethernet/intel/ice/ice_txrx.c index 128fd49383439a..f52ab7b2e3258f 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.c +++ b/drivers/net/ethernet/intel/ice/ice_txrx.c @@ -1137,7 +1137,8 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget) xdp_prepare_buff(&xdp, hard_start, offset, size, true); if (likely(rx_ring->xdp_metadata_support)) - ice_xdp_set_meta(&xdp, rx_desc); + ice_xdp_set_meta(&xdp, rx_desc, rx_ring->btf_id); + #if (PAGE_SIZE > 4096) /* At larger PAGE_SIZE, frame_sz depend on len size */ xdp.frame_sz = ice_rx_frame_truesize(rx_ring, size); diff --git a/drivers/net/ethernet/intel/ice/ice_txrx.h b/drivers/net/ethernet/intel/ice/ice_txrx.h index b43923ddf883cf..9419d4780acc1b 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx.h @@ -302,6 +302,7 @@ struct ice_ring { /* CL3 - 3rd cacheline starts here */ struct xdp_rxq_info xdp_rxq; struct sk_buff *skb; + s32 btf_id; /* CLX - the below items are only accessed infrequently and should be diff --git a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h index d77bc7686b61bd..54c8acab1691b0 100644 --- a/drivers/net/ethernet/intel/ice/ice_txrx_lib.h +++ b/drivers/net/ethernet/intel/ice/ice_txrx_lib.h @@ -46,14 +46,24 @@ static inline void ice_xdp_ring_update_tail(struct ice_ring *xdp_ring) writel_relaxed(xdp_ring->next_to_use, xdp_ring->tail); } -static inline void ice_xdp_set_meta(struct xdp_buff *xdp, union ice_32b_rx_flex_desc *desc) +static inline void ice_xdp_set_meta(struct xdp_buff *xdp, union ice_32b_rx_flex_desc *desc, s32 btf_id) { struct ice_32b_rx_flex_desc_nic *flex = (struct ice_32b_rx_flex_desc_nic *)desc; struct xdp_meta_generic *md = xdp->data - sizeof(struct xdp_meta_generic); - xdp->data_meta = md; md->rxcvid = le16_to_cpu(flex->flex_ts.flex.vlan_id); md->hash = le32_to_cpu(flex->rss_hash); + + md->flags = 0; + md->free_slot = 0; + md->csum_off = 0; + md->txcvid = 0; + md->csum = 0; + md->tstamp = 0; + + md->btf_id = btf_id; + + xdp->data_meta = md; } void ice_finalize_xdp_rx(struct ice_ring *rx_ring, unsigned int xdp_res); diff --git a/include/linux/btf.h b/include/linux/btf.h index 214fde93214b97..cd26d037a2dda5 100644 --- a/include/linux/btf.h +++ b/include/linux/btf.h @@ -94,6 +94,7 @@ u32 btf_obj_id(const struct btf *btf); bool btf_is_kernel(const struct btf *btf); bool btf_is_module(const struct btf *btf); struct module *btf_try_get_module(const struct btf *btf); +s32 btf_get_type_id(const struct module *mod, char *name, u32 kind); u32 btf_nr_types(const struct btf *btf); bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s, const struct btf_member *m, diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index dfe61df4f974d1..10fd0405fec9da 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -6152,6 +6152,43 @@ struct module *btf_try_get_module(const struct btf *btf) return res; } +struct btf *btf_get_from_module(const struct module *module) +{ + struct btf *res = NULL; +#ifdef CONFIG_DEBUG_INFO_BTF_MODULES + struct btf_module *btf_mod, *tmp; + + mutex_lock(&btf_module_mutex); + list_for_each_entry_safe(btf_mod, tmp, &btf_modules, list) { + if (btf_mod->module != module) + continue; + + res = btf_mod->btf; + + break; + } + mutex_unlock(&btf_module_mutex); +#endif + + return res; +} + +s32 btf_get_type_id(const struct module *mod, char *name, u32 kind) +{ + struct btf *btf; + + if (mod) + btf = btf_get_from_module(mod); + else + btf = bpf_get_btf_vmlinux(); + + if (!btf) + return 0; + + return btf_find_by_name_kind(btf, name, kind); +} +EXPORT_SYMBOL_GPL(btf_get_type_id); + BPF_CALL_4(bpf_btf_find_by_name_kind, char *, name, int, name_sz, u32, kind, int, flags) { struct btf *btf; From b0634948e345e3b3e5ca2d057874462894687bba Mon Sep 17 00:00:00 2001 From: Larysa Zaremba Date: Mon, 4 Oct 2021 18:27:13 +0200 Subject: [PATCH 5/8] samples: bpf: add simple sample with CORE Example prints out BTF ID returned by a libbpf helper and received in data_meta. It's assumed, pointer to BTF ID is data - sizeof(u32). Possible improvements: - print out RSS and VLAN ID, use CO-RE functions for this (this way user can avoid defining full hints structure) - improve user application (currently it does not ) Signed-off-by: Michal Swiatkowski Signed-off-by: Larysa Zaremba --- samples/bpf/Makefile | 8 +++-- samples/bpf/xdp_meta.bpf.c | 55 ++++++++++++++++++++++++++++ samples/bpf/xdp_meta_user.c | 72 +++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 samples/bpf/xdp_meta.bpf.c create mode 100644 samples/bpf/xdp_meta_user.c diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile index 4dc20be5fb96a6..9b5fc9f5e6c8d3 100644 --- a/samples/bpf/Makefile +++ b/samples/bpf/Makefile @@ -57,6 +57,7 @@ tprogs-y += xdp_redirect_map_multi tprogs-y += xdp_redirect_map tprogs-y += xdp_redirect tprogs-y += xdp_monitor +tprogs-y += xdp_meta # Libbpf dependencies LIBBPF = $(TOOLS_PATH)/lib/bpf/libbpf.a @@ -118,6 +119,7 @@ xdp_redirect_cpu-objs := xdp_redirect_cpu_user.o $(XDP_SAMPLE) xdp_redirect_map-objs := xdp_redirect_map_user.o $(XDP_SAMPLE) xdp_redirect-objs := xdp_redirect_user.o $(XDP_SAMPLE) xdp_monitor-objs := xdp_monitor_user.o $(XDP_SAMPLE) +xdp_meta-objs := xdp_meta_user.o # Tell kbuild to always build the programs always-y := $(tprogs-y) @@ -314,6 +316,7 @@ $(obj)/xdp_redirect_map_multi_user.o: $(obj)/xdp_redirect_map_multi.skel.h $(obj)/xdp_redirect_map_user.o: $(obj)/xdp_redirect_map.skel.h $(obj)/xdp_redirect_user.o: $(obj)/xdp_redirect.skel.h $(obj)/xdp_monitor_user.o: $(obj)/xdp_monitor.skel.h +$(obj)/xdp_meta_user.o: $(obj)/xdp_meta.skel.h $(obj)/tracex5_kern.o: $(obj)/syscall_nrs.h $(obj)/hbm_out_kern.o: $(src)/hbm.h $(src)/hbm_kern.h @@ -371,7 +374,8 @@ $(obj)/%.bpf.o: $(src)/%.bpf.c $(obj)/vmlinux.h $(src)/xdp_sample.bpf.h $(src)/x -c $(filter %.bpf.c,$^) -o $@ LINKED_SKELS := xdp_redirect_cpu.skel.h xdp_redirect_map_multi.skel.h \ - xdp_redirect_map.skel.h xdp_redirect.skel.h xdp_monitor.skel.h + xdp_redirect_map.skel.h xdp_redirect.skel.h xdp_monitor.skel.h \ + xdp_meta.skel.h clean-files += $(LINKED_SKELS) xdp_redirect_cpu.skel.h-deps := xdp_redirect_cpu.bpf.o xdp_sample.bpf.o @@ -379,9 +383,9 @@ xdp_redirect_map_multi.skel.h-deps := xdp_redirect_map_multi.bpf.o xdp_sample.bp xdp_redirect_map.skel.h-deps := xdp_redirect_map.bpf.o xdp_sample.bpf.o xdp_redirect.skel.h-deps := xdp_redirect.bpf.o xdp_sample.bpf.o xdp_monitor.skel.h-deps := xdp_monitor.bpf.o xdp_sample.bpf.o +xdp_meta.skel.h-deps := xdp_meta.bpf.o LINKED_BPF_SRCS := $(patsubst %.bpf.o,%.bpf.c,$(foreach skel,$(LINKED_SKELS),$($(skel)-deps))) - BPF_SRCS_LINKED := $(notdir $(wildcard $(src)/*.bpf.c)) BPF_OBJS_LINKED := $(patsubst %.bpf.c,$(obj)/%.bpf.o, $(BPF_SRCS_LINKED)) BPF_SKELS_LINKED := $(addprefix $(obj)/,$(LINKED_SKELS)) diff --git a/samples/bpf/xdp_meta.bpf.c b/samples/bpf/xdp_meta.bpf.c new file mode 100644 index 00000000000000..9f3bc5f7999f38 --- /dev/null +++ b/samples/bpf/xdp_meta.bpf.c @@ -0,0 +1,55 @@ +/* This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + */ +#include "vmlinux.h" + +#include +#include +#include + +struct xdp_meta_generic___minimal { + u32 btf_id; + u16 rxcvid; + u32 hash; +}; + +SEC("xdp") +int xdp_meta_prog(struct xdp_md *ctx) +{ + struct xdp_meta_generic___minimal *data_meta = + (void *)(long)ctx->data_meta; + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + struct ethhdr *eth = data; + u64 nh_off; + u32 btf_id_libbpf; + u32 btf_id_meta; + s32 err; + long *value; + + nh_off = sizeof(*eth); + if (data + nh_off > data_end) + return XDP_DROP; + + + if (data_meta + 1 > data) + return XDP_DROP; + + btf_id_libbpf = bpf_core_type_id_kernel(struct xdp_meta_generic___minimal); + err = bpf_probe_read_kernel(&btf_id_meta, sizeof(btf_id_meta), (void*)data - 4); + + /* Probably should not be in the final version */ + if (err){ + bpf_printk("id from libbpf %d, could not obtain id from hints metadata, error is %d\n", + btf_id_libbpf, err); + return XDP_DROP; + } + + bpf_printk("id from libbpf %d, id from hints metadata %d\n", + btf_id_libbpf, btf_id_meta); + + return XDP_PASS; +} + +char LICENSE[] SEC("license") = "GPL"; diff --git a/samples/bpf/xdp_meta_user.c b/samples/bpf/xdp_meta_user.c new file mode 100644 index 00000000000000..9422a180240d37 --- /dev/null +++ b/samples/bpf/xdp_meta_user.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xdp_meta.skel.h" + +int main(int argc, char **argv) +{ + __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_USE_METADATA; + __u32 prog_id, prog_fd; + struct xdp_meta *skel; + int ifindex, ret = 1; + + if (argc == optind) { + return ret; + } + + ifindex = if_nametoindex(argv[optind]); + if (!ifindex) + ifindex = strtoul(argv[optind], NULL, 0); + if (!ifindex) { + fprintf(stderr, "Bad interface index or name\n"); + goto end; + } + + skel = xdp_meta__open(); + if (!skel) { + fprintf(stderr, "Failed to xdp_meta__open: %s\n", + strerror(errno)); + ret = 1; + goto end; + } + + ret = xdp_meta__load(skel); + if (ret < 0) { + fprintf(stderr, "Failed to xdp_meta__load: %s\n", strerror(errno)); + ret = 1; + goto end_destroy; + } + + ret = 1; + prog_fd = bpf_program__fd(skel->progs.xdp_meta_prog); + if (bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags) < 0) { + fprintf(stderr, "Failed to set xdp link"); + goto end_destroy; + } + + if (bpf_get_link_xdp_id(ifindex, &prog_id, xdp_flags)) { + fprintf(stderr, "Failed to get XDP program id for ifindex"); + goto end_destroy; + } + + while (1) { + sleep(2); + } + + ret = 0; +end_destroy: + xdp_meta__destroy(skel); +end: + return ret; +} From 20f3208878e31f7b7601a68d26987bee10411c51 Mon Sep 17 00:00:00 2001 From: Larysa Zaremba Date: Thu, 7 Oct 2021 13:13:29 +0200 Subject: [PATCH 6/8] [TEMP] bpf: use xdp_meta_generic in kernel Type needs to be used in the kernel in order to be present in vmlinux BTF. Future Alex's changes to cpumap will ensure this, but for now we just declare a variable of the required type in a random place for testing purposes. --- kernel/bpf/cpumap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/bpf/cpumap.c b/kernel/bpf/cpumap.c index 585b2b77ccc4f1..7fe44cd178d498 100644 --- a/kernel/bpf/cpumap.c +++ b/kernel/bpf/cpumap.c @@ -215,6 +215,7 @@ static int cpu_map_bpf_prog_run_xdp(struct bpf_cpu_map_entry *rcpu, { struct xdp_rxq_info rxq; struct xdp_buff xdp; + volatile struct xdp_meta_generic xdp_meta_generic; int i, nframes = 0; xdp_set_return_frame_no_direct(); From 5520689adb804f817588add9df2a1bedd633f792 Mon Sep 17 00:00:00 2001 From: Larysa Zaremba Date: Thu, 7 Oct 2021 13:24:10 +0200 Subject: [PATCH 7/8] samples: bpf: Improve user experience in xdp_meta sample Ensure that xdp program is detached before user program termination. Print out trace_pipe. This allows to run example multiple times without additional commands. --- samples/bpf/xdp_meta_user.c | 58 +++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/samples/bpf/xdp_meta_user.c b/samples/bpf/xdp_meta_user.c index 9422a180240d37..78fc31304bbc44 100644 --- a/samples/bpf/xdp_meta_user.c +++ b/samples/bpf/xdp_meta_user.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -14,12 +15,45 @@ #include #include "xdp_meta.skel.h" +#define DEBUGFS "/sys/kernel/debug/tracing/" + +static volatile bool xdp_meta_sample_running = true; + +static void xdp_meta_sample_stop(int signo) +{ + xdp_meta_sample_running = false; +} + +/* Had to change the standard read_trace_pipe from trace_helpers.h */ +static void xdp_meta_read_trace_pipe(void) +{ + int trace_fd; + + trace_fd = open(DEBUGFS "trace_pipe", O_RDONLY, 0); + if (trace_fd < 0){ + fprintf(stderr, "Could not open the trace_pipe\n"); + return; + } + + while (xdp_meta_sample_running) { + static char buf[4096]; + ssize_t sz; + + sz = read(trace_fd, buf, sizeof(buf) - 1); + if (sz > 0) { + buf[sz] = 0; + puts(buf); + } + } +} + int main(int argc, char **argv) { __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST | XDP_FLAGS_USE_METADATA; - __u32 prog_id, prog_fd; + __u32 prog_id, prog_fd, running_prog_id; struct xdp_meta *skel; int ifindex, ret = 1; + struct sigaction handle_ctrl_c; if (argc == optind) { return ret; @@ -51,20 +85,32 @@ int main(int argc, char **argv) ret = 1; prog_fd = bpf_program__fd(skel->progs.xdp_meta_prog); if (bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags) < 0) { - fprintf(stderr, "Failed to set xdp link"); + fprintf(stderr, "Failed to set xdp link\n"); goto end_destroy; } if (bpf_get_link_xdp_id(ifindex, &prog_id, xdp_flags)) { - fprintf(stderr, "Failed to get XDP program id for ifindex"); + fprintf(stderr, "Failed to get XDP program id for ifindex\n"); goto end_destroy; } - while (1) { - sleep(2); - } + memset(&handle_ctrl_c, 0, sizeof(handle_ctrl_c)); + handle_ctrl_c.sa_handler = &xdp_meta_sample_stop; + sigaction(SIGINT, &handle_ctrl_c, NULL); + + xdp_meta_read_trace_pipe(); ret = 0; + + if(bpf_get_link_xdp_id(ifindex, &running_prog_id, xdp_flags) || running_prog_id != prog_id){ + fprintf(stderr, + "Failed to get the running XDP program id or another program is running. Exit without detaching.\n"); + goto end_destroy; + } + + fprintf(stderr, "Detaching the program...\n"); + bpf_set_link_xdp_fd(ifindex, -1, 0); + end_destroy: xdp_meta__destroy(skel); end: From 8c1d5da6991c76286b44592f740904a77b0275bf Mon Sep 17 00:00:00 2001 From: Larysa Zaremba Date: Thu, 7 Oct 2021 13:28:30 +0200 Subject: [PATCH 8/8] bpf: samples: Print out hash and RX VID It was tested on an untagged VLAN, so VID seem to be garbage. Hash looks fine, as well as hardcoded values. --- samples/bpf/xdp_meta.bpf.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/samples/bpf/xdp_meta.bpf.c b/samples/bpf/xdp_meta.bpf.c index 9f3bc5f7999f38..ff2f103efdc8b9 100644 --- a/samples/bpf/xdp_meta.bpf.c +++ b/samples/bpf/xdp_meta.bpf.c @@ -8,16 +8,10 @@ #include #include -struct xdp_meta_generic___minimal { - u32 btf_id; - u16 rxcvid; - u32 hash; -}; - SEC("xdp") int xdp_meta_prog(struct xdp_md *ctx) { - struct xdp_meta_generic___minimal *data_meta = + struct xdp_meta_generic *data_meta = (void *)(long)ctx->data_meta; void *data_end = (void *)(long)ctx->data_end; void *data = (void *)(long)ctx->data; @@ -25,7 +19,8 @@ int xdp_meta_prog(struct xdp_md *ctx) u64 nh_off; u32 btf_id_libbpf; u32 btf_id_meta; - s32 err; + u16 rxcvid; + u32 hash; long *value; nh_off = sizeof(*eth); @@ -36,19 +31,22 @@ int xdp_meta_prog(struct xdp_md *ctx) if (data_meta + 1 > data) return XDP_DROP; - btf_id_libbpf = bpf_core_type_id_kernel(struct xdp_meta_generic___minimal); - err = bpf_probe_read_kernel(&btf_id_meta, sizeof(btf_id_meta), (void*)data - 4); - - /* Probably should not be in the final version */ - if (err){ - bpf_printk("id from libbpf %d, could not obtain id from hints metadata, error is %d\n", - btf_id_libbpf, err); - return XDP_DROP; - } + btf_id_libbpf = bpf_core_type_id_kernel(struct xdp_meta_generic); + bpf_probe_read_kernel(&btf_id_meta, sizeof(btf_id_meta), (void*)data - 4); bpf_printk("id from libbpf %d, id from hints metadata %d\n", btf_id_libbpf, btf_id_meta); + if (btf_id_libbpf == btf_id_meta) + bpf_printk("Received meta is generic\n"); + else + bpf_printk("Received meta type is unknown\n"); + + + hash = BPF_CORE_READ(data_meta, hash); + rxcvid = BPF_CORE_READ(data_meta, rxcvid); + bpf_printk("Metadata. Hash: 0x%x, VID: %d\n", hash, rxcvid); + return XDP_PASS; }