Merge: CNB95: xdp: Add VLAN tag hint
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/4222 JIRA: https://issues.redhat.com/browse/RHEL-31890 Depends: !4111 Signed-off-by: Petr Oros <poros@redhat.com> Approved-by: Ivan Vecera <ivecera@redhat.com> Approved-by: Toke Høiland-Jørgensen <toke@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Lucas Zampieri <lzampier@redhat.com>
This commit is contained in:
commit
2a3757c7c9
|
@ -54,6 +54,10 @@ definitions:
|
|||
name: hash
|
||||
doc:
|
||||
Device is capable of exposing receive packet hash via bpf_xdp_metadata_rx_hash().
|
||||
-
|
||||
name: vlan-tag
|
||||
doc:
|
||||
Device is capable of exposing receive packet VLAN tag via bpf_xdp_metadata_rx_vlan_tag().
|
||||
-
|
||||
type: flags
|
||||
name: xsk-flags
|
||||
|
|
|
@ -20,7 +20,13 @@ Currently, the following kfuncs are supported. In the future, as more
|
|||
metadata is supported, this set will grow:
|
||||
|
||||
.. kernel-doc:: net/core/xdp.c
|
||||
:identifiers: bpf_xdp_metadata_rx_timestamp bpf_xdp_metadata_rx_hash
|
||||
:identifiers: bpf_xdp_metadata_rx_timestamp
|
||||
|
||||
.. kernel-doc:: net/core/xdp.c
|
||||
:identifiers: bpf_xdp_metadata_rx_hash
|
||||
|
||||
.. kernel-doc:: net/core/xdp.c
|
||||
:identifiers: bpf_xdp_metadata_rx_vlan_tag
|
||||
|
||||
An XDP program can use these kfuncs to read the metadata into stack
|
||||
variables for its own consumption. Or, to pass the metadata on to other
|
||||
|
|
|
@ -1666,6 +1666,24 @@ static int veth_xdp_rx_hash(const struct xdp_md *ctx, u32 *hash,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int veth_xdp_rx_vlan_tag(const struct xdp_md *ctx, __be16 *vlan_proto,
|
||||
u16 *vlan_tci)
|
||||
{
|
||||
const struct veth_xdp_buff *_ctx = (void *)ctx;
|
||||
const struct sk_buff *skb = _ctx->skb;
|
||||
int err;
|
||||
|
||||
if (!skb)
|
||||
return -ENODATA;
|
||||
|
||||
err = __vlan_hwaccel_get_tag(skb, vlan_tci);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*vlan_proto = skb->vlan_proto;
|
||||
return err;
|
||||
}
|
||||
|
||||
static const struct net_device_ops veth_netdev_ops = {
|
||||
.ndo_init = veth_dev_init,
|
||||
.ndo_open = veth_open,
|
||||
|
@ -1690,6 +1708,7 @@ static const struct net_device_ops veth_netdev_ops = {
|
|||
static const struct xdp_metadata_ops veth_xdp_metadata_ops = {
|
||||
.xmo_rx_timestamp = veth_xdp_rx_timestamp,
|
||||
.xmo_rx_hash = veth_xdp_rx_hash,
|
||||
.xmo_rx_vlan_tag = veth_xdp_rx_vlan_tag,
|
||||
};
|
||||
|
||||
#define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HW_CSUM | \
|
||||
|
|
|
@ -543,7 +543,7 @@ static inline int __vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci)
|
|||
struct vlan_ethhdr *veth = skb_vlan_eth_hdr(skb);
|
||||
|
||||
if (!eth_type_vlan(veth->h_vlan_proto))
|
||||
return -EINVAL;
|
||||
return -ENODATA;
|
||||
|
||||
*vlan_tci = ntohs(veth->h_vlan_TCI);
|
||||
return 0;
|
||||
|
@ -564,7 +564,7 @@ static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb,
|
|||
return 0;
|
||||
} else {
|
||||
*vlan_tci = 0;
|
||||
return -EINVAL;
|
||||
return -ENODATA;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1608,6 +1608,8 @@ struct xdp_metadata_ops {
|
|||
int (*xmo_rx_timestamp)(const struct xdp_md *ctx, u64 *timestamp);
|
||||
int (*xmo_rx_hash)(const struct xdp_md *ctx, u32 *hash,
|
||||
enum xdp_rss_hash_type *rss_type);
|
||||
int (*xmo_rx_vlan_tag)(const struct xdp_md *ctx, __be16 *vlan_proto,
|
||||
u16 *vlan_tci);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -406,6 +406,10 @@ void xdp_attachment_setup(struct xdp_attachment_info *info,
|
|||
NETDEV_XDP_RX_METADATA_HASH, \
|
||||
bpf_xdp_metadata_rx_hash, \
|
||||
xmo_rx_hash) \
|
||||
XDP_METADATA_KFUNC(XDP_METADATA_KFUNC_RX_VLAN_TAG, \
|
||||
NETDEV_XDP_RX_METADATA_VLAN_TAG, \
|
||||
bpf_xdp_metadata_rx_vlan_tag, \
|
||||
xmo_rx_vlan_tag) \
|
||||
|
||||
enum xdp_rx_metadata {
|
||||
#define XDP_METADATA_KFUNC(name, _, __, ___) name,
|
||||
|
|
|
@ -14,6 +14,12 @@
|
|||
|
||||
#ifdef CONFIG_XDP_SOCKETS
|
||||
|
||||
struct xsk_cb_desc {
|
||||
void *src;
|
||||
u8 off;
|
||||
u8 bytes;
|
||||
};
|
||||
|
||||
void xsk_tx_completed(struct xsk_buff_pool *pool, u32 nb_entries);
|
||||
bool xsk_tx_peek_desc(struct xsk_buff_pool *pool, struct xdp_desc *desc);
|
||||
u32 xsk_tx_peek_release_desc_batch(struct xsk_buff_pool *pool, u32 max);
|
||||
|
@ -47,6 +53,12 @@ static inline void xsk_pool_set_rxq_info(struct xsk_buff_pool *pool,
|
|||
xp_set_rxq_info(pool, rxq);
|
||||
}
|
||||
|
||||
static inline void xsk_pool_fill_cb(struct xsk_buff_pool *pool,
|
||||
struct xsk_cb_desc *desc)
|
||||
{
|
||||
xp_fill_cb(pool, desc);
|
||||
}
|
||||
|
||||
static inline unsigned int xsk_pool_get_napi_id(struct xsk_buff_pool *pool)
|
||||
{
|
||||
#ifdef CONFIG_NET_RX_BUSY_POLL
|
||||
|
@ -292,6 +304,11 @@ static inline void xsk_pool_set_rxq_info(struct xsk_buff_pool *pool,
|
|||
{
|
||||
}
|
||||
|
||||
static inline void xsk_pool_fill_cb(struct xsk_buff_pool *pool,
|
||||
struct xsk_cb_desc *desc)
|
||||
{
|
||||
}
|
||||
|
||||
static inline unsigned int xsk_pool_get_napi_id(struct xsk_buff_pool *pool)
|
||||
{
|
||||
return 0;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
struct xsk_buff_pool;
|
||||
struct xdp_rxq_info;
|
||||
struct xsk_cb_desc;
|
||||
struct xsk_queue;
|
||||
struct xdp_desc;
|
||||
struct xdp_umem;
|
||||
|
@ -135,6 +136,7 @@ static inline void xp_init_xskb_dma(struct xdp_buff_xsk *xskb, struct xsk_buff_p
|
|||
|
||||
/* AF_XDP ZC drivers, via xdp_sock_buff.h */
|
||||
void xp_set_rxq_info(struct xsk_buff_pool *pool, struct xdp_rxq_info *rxq);
|
||||
void xp_fill_cb(struct xsk_buff_pool *pool, struct xsk_cb_desc *desc);
|
||||
int xp_dma_map(struct xsk_buff_pool *pool, struct device *dev,
|
||||
unsigned long attrs, struct page **pages, u32 nr_pages);
|
||||
void xp_dma_unmap(struct xsk_buff_pool *pool, unsigned long attrs);
|
||||
|
|
|
@ -44,13 +44,13 @@ enum netdev_xdp_act {
|
|||
* timestamp via bpf_xdp_metadata_rx_timestamp().
|
||||
* @NETDEV_XDP_RX_METADATA_HASH: Device is capable of exposing receive packet
|
||||
* hash via bpf_xdp_metadata_rx_hash().
|
||||
* @NETDEV_XDP_RX_METADATA_VLAN_TAG: Device is capable of exposing receive
|
||||
* packet VLAN tag via bpf_xdp_metadata_rx_vlan_tag().
|
||||
*/
|
||||
enum netdev_xdp_rx_metadata {
|
||||
NETDEV_XDP_RX_METADATA_TIMESTAMP = 1,
|
||||
NETDEV_XDP_RX_METADATA_HASH = 2,
|
||||
|
||||
/* private: */
|
||||
NETDEV_XDP_RX_METADATA_MASK = 3,
|
||||
NETDEV_XDP_RX_METADATA_VLAN_TAG = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -63,9 +63,6 @@ enum netdev_xdp_rx_metadata {
|
|||
enum netdev_xsk_flags {
|
||||
NETDEV_XSK_FLAGS_TX_TIMESTAMP = 1,
|
||||
NETDEV_XSK_FLAGS_TX_CHECKSUM = 2,
|
||||
|
||||
/* private: */
|
||||
NETDEV_XSK_FLAGS_MASK = 3,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
|
@ -737,6 +737,39 @@ __bpf_kfunc int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, u32 *hash,
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/**
|
||||
* bpf_xdp_metadata_rx_vlan_tag - Get XDP packet outermost VLAN tag
|
||||
* @ctx: XDP context pointer.
|
||||
* @vlan_proto: Destination pointer for VLAN Tag protocol identifier (TPID).
|
||||
* @vlan_tci: Destination pointer for VLAN TCI (VID + DEI + PCP)
|
||||
*
|
||||
* In case of success, ``vlan_proto`` contains *Tag protocol identifier (TPID)*,
|
||||
* usually ``ETH_P_8021Q`` or ``ETH_P_8021AD``, but some networks can use
|
||||
* custom TPIDs. ``vlan_proto`` is stored in **network byte order (BE)**
|
||||
* and should be used as follows:
|
||||
* ``if (vlan_proto == bpf_htons(ETH_P_8021Q)) do_something();``
|
||||
*
|
||||
* ``vlan_tci`` contains the remaining 16 bits of a VLAN tag.
|
||||
* Driver is expected to provide those in **host byte order (usually LE)**,
|
||||
* so the bpf program should not perform byte conversion.
|
||||
* According to 802.1Q standard, *VLAN TCI (Tag control information)*
|
||||
* is a bit field that contains:
|
||||
* *VLAN identifier (VID)* that can be read with ``vlan_tci & 0xfff``,
|
||||
* *Drop eligible indicator (DEI)* - 1 bit,
|
||||
* *Priority code point (PCP)* - 3 bits.
|
||||
* For detailed meaning of DEI and PCP, please refer to other sources.
|
||||
*
|
||||
* Return:
|
||||
* * Returns 0 on success or ``-errno`` on error.
|
||||
* * ``-EOPNOTSUPP`` : device driver doesn't implement kfunc
|
||||
* * ``-ENODATA`` : VLAN tag was not stripped or is not available
|
||||
*/
|
||||
__bpf_kfunc int bpf_xdp_metadata_rx_vlan_tag(const struct xdp_md *ctx,
|
||||
__be16 *vlan_proto, u16 *vlan_tci)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
__bpf_kfunc_end_defs();
|
||||
|
||||
BTF_SET8_START(xdp_metadata_kfunc_ids)
|
||||
|
|
|
@ -125,6 +125,18 @@ void xp_set_rxq_info(struct xsk_buff_pool *pool, struct xdp_rxq_info *rxq)
|
|||
}
|
||||
EXPORT_SYMBOL(xp_set_rxq_info);
|
||||
|
||||
void xp_fill_cb(struct xsk_buff_pool *pool, struct xsk_cb_desc *desc)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < pool->heads_cnt; i++) {
|
||||
struct xdp_buff_xsk *xskb = &pool->heads[i];
|
||||
|
||||
memcpy(xskb->cb + desc->off, desc->src, desc->bytes);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(xp_fill_cb);
|
||||
|
||||
static void xp_disable_drv_zc(struct xsk_buff_pool *pool)
|
||||
{
|
||||
struct netdev_bpf bpf;
|
||||
|
|
|
@ -44,13 +44,13 @@ enum netdev_xdp_act {
|
|||
* timestamp via bpf_xdp_metadata_rx_timestamp().
|
||||
* @NETDEV_XDP_RX_METADATA_HASH: Device is capable of exposing receive packet
|
||||
* hash via bpf_xdp_metadata_rx_hash().
|
||||
* @NETDEV_XDP_RX_METADATA_VLAN_TAG: Device is capable of exposing receive
|
||||
* packet VLAN tag via bpf_xdp_metadata_rx_vlan_tag().
|
||||
*/
|
||||
enum netdev_xdp_rx_metadata {
|
||||
NETDEV_XDP_RX_METADATA_TIMESTAMP = 1,
|
||||
NETDEV_XDP_RX_METADATA_HASH = 2,
|
||||
|
||||
/* private: */
|
||||
NETDEV_XDP_RX_METADATA_MASK = 3,
|
||||
NETDEV_XDP_RX_METADATA_VLAN_TAG = 4,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -53,6 +53,7 @@ const char *netdev_xdp_act_str(enum netdev_xdp_act value)
|
|||
static const char * const netdev_xdp_rx_metadata_strmap[] = {
|
||||
[0] = "timestamp",
|
||||
[1] = "hash",
|
||||
[2] = "vlan-tag",
|
||||
};
|
||||
|
||||
const char *netdev_xdp_rx_metadata_str(enum netdev_xdp_rx_metadata value)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#define UDP_PAYLOAD_BYTES 4
|
||||
|
||||
#define AF_XDP_SOURCE_PORT 1234
|
||||
#define UDP_SOURCE_PORT 1234
|
||||
#define AF_XDP_CONSUMER_PORT 8080
|
||||
|
||||
#define UMEM_NUM 16
|
||||
|
@ -33,6 +33,18 @@
|
|||
#define RX_ADDR "10.0.0.2"
|
||||
#define PREFIX_LEN "8"
|
||||
#define FAMILY AF_INET
|
||||
#define TX_NETNS_NAME "xdp_metadata_tx"
|
||||
#define RX_NETNS_NAME "xdp_metadata_rx"
|
||||
#define TX_MAC "00:00:00:00:00:01"
|
||||
#define RX_MAC "00:00:00:00:00:02"
|
||||
|
||||
#define VLAN_ID 59
|
||||
#define VLAN_PROTO "802.1Q"
|
||||
#define VLAN_PID htons(ETH_P_8021Q)
|
||||
#define TX_NAME_VLAN TX_NAME "." TO_STR(VLAN_ID)
|
||||
|
||||
#define XDP_RSS_TYPE_L4 BIT(3)
|
||||
#define VLAN_VID_MASK 0xfff
|
||||
|
||||
struct xsk {
|
||||
void *umem_area;
|
||||
|
@ -181,7 +193,7 @@ static int generate_packet(struct xsk *xsk, __u16 dst_port)
|
|||
ASSERT_EQ(inet_pton(FAMILY, RX_ADDR, &iph->daddr), 1, "inet_pton(RX_ADDR)");
|
||||
ip_csum(iph);
|
||||
|
||||
udph->source = htons(AF_XDP_SOURCE_PORT);
|
||||
udph->source = htons(UDP_SOURCE_PORT);
|
||||
udph->dest = htons(dst_port);
|
||||
udph->len = htons(sizeof(*udph) + UDP_PAYLOAD_BYTES);
|
||||
udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
|
||||
|
@ -204,6 +216,30 @@ static int generate_packet(struct xsk *xsk, __u16 dst_port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int generate_packet_inet(void)
|
||||
{
|
||||
char udp_payload[UDP_PAYLOAD_BYTES];
|
||||
struct sockaddr_in rx_addr;
|
||||
int sock_fd, err = 0;
|
||||
|
||||
/* Build a packet */
|
||||
memset(udp_payload, 0xAA, UDP_PAYLOAD_BYTES);
|
||||
rx_addr.sin_addr.s_addr = inet_addr(RX_ADDR);
|
||||
rx_addr.sin_family = AF_INET;
|
||||
rx_addr.sin_port = htons(AF_XDP_CONSUMER_PORT);
|
||||
|
||||
sock_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (!ASSERT_GE(sock_fd, 0, "socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)"))
|
||||
return sock_fd;
|
||||
|
||||
err = sendto(sock_fd, udp_payload, UDP_PAYLOAD_BYTES, MSG_DONTWAIT,
|
||||
(void *)&rx_addr, sizeof(rx_addr));
|
||||
ASSERT_GE(err, 0, "sendto");
|
||||
|
||||
close(sock_fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void complete_tx(struct xsk *xsk)
|
||||
{
|
||||
struct xsk_tx_metadata *meta;
|
||||
|
@ -236,7 +272,7 @@ static void refill_rx(struct xsk *xsk, __u64 addr)
|
|||
}
|
||||
}
|
||||
|
||||
static int verify_xsk_metadata(struct xsk *xsk)
|
||||
static int verify_xsk_metadata(struct xsk *xsk, bool sent_from_af_xdp)
|
||||
{
|
||||
const struct xdp_desc *rx_desc;
|
||||
struct pollfd fds = {};
|
||||
|
@ -290,17 +326,42 @@ static int verify_xsk_metadata(struct xsk *xsk)
|
|||
if (!ASSERT_NEQ(meta->rx_hash, 0, "rx_hash"))
|
||||
return -1;
|
||||
|
||||
if (!sent_from_af_xdp) {
|
||||
if (!ASSERT_NEQ(meta->rx_hash_type & XDP_RSS_TYPE_L4, 0, "rx_hash_type"))
|
||||
return -1;
|
||||
|
||||
if (!ASSERT_EQ(meta->rx_vlan_tci & VLAN_VID_MASK, VLAN_ID, "rx_vlan_tci"))
|
||||
return -1;
|
||||
|
||||
if (!ASSERT_EQ(meta->rx_vlan_proto, VLAN_PID, "rx_vlan_proto"))
|
||||
return -1;
|
||||
goto done;
|
||||
}
|
||||
|
||||
ASSERT_EQ(meta->rx_hash_type, 0, "rx_hash_type");
|
||||
|
||||
/* checksum offload */
|
||||
ASSERT_EQ(udph->check, htons(0x721c), "csum");
|
||||
|
||||
done:
|
||||
xsk_ring_cons__release(&xsk->rx, 1);
|
||||
refill_rx(xsk, comp_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void switch_ns_to_rx(struct nstoken **tok)
|
||||
{
|
||||
close_netns(*tok);
|
||||
*tok = open_netns(RX_NETNS_NAME);
|
||||
}
|
||||
|
||||
static void switch_ns_to_tx(struct nstoken **tok)
|
||||
{
|
||||
close_netns(*tok);
|
||||
*tok = open_netns(TX_NETNS_NAME);
|
||||
}
|
||||
|
||||
void test_xdp_metadata(void)
|
||||
{
|
||||
struct xdp_metadata2 *bpf_obj2 = NULL;
|
||||
|
@ -318,27 +379,35 @@ void test_xdp_metadata(void)
|
|||
int sock_fd;
|
||||
int ret;
|
||||
|
||||
/* Setup new networking namespace, with a veth pair. */
|
||||
/* Setup new networking namespaces, with a veth pair. */
|
||||
SYS(out, "ip netns add " TX_NETNS_NAME);
|
||||
SYS(out, "ip netns add " RX_NETNS_NAME);
|
||||
|
||||
SYS(out, "ip netns add xdp_metadata");
|
||||
tok = open_netns("xdp_metadata");
|
||||
tok = open_netns(TX_NETNS_NAME);
|
||||
SYS(out, "ip link add numtxqueues 1 numrxqueues 1 " TX_NAME
|
||||
" type veth peer " RX_NAME " numtxqueues 1 numrxqueues 1");
|
||||
SYS(out, "ip link set dev " TX_NAME " address 00:00:00:00:00:01");
|
||||
SYS(out, "ip link set dev " RX_NAME " address 00:00:00:00:00:02");
|
||||
SYS(out, "ip link set " RX_NAME " netns " RX_NETNS_NAME);
|
||||
|
||||
SYS(out, "ip link set dev " TX_NAME " address " TX_MAC);
|
||||
SYS(out, "ip link set dev " TX_NAME " up");
|
||||
|
||||
SYS(out, "ip link add link " TX_NAME " " TX_NAME_VLAN
|
||||
" type vlan proto " VLAN_PROTO " id " TO_STR(VLAN_ID));
|
||||
SYS(out, "ip link set dev " TX_NAME_VLAN " up");
|
||||
SYS(out, "ip addr add " TX_ADDR "/" PREFIX_LEN " dev " TX_NAME_VLAN);
|
||||
|
||||
/* Avoid ARP calls */
|
||||
SYS(out, "ip -4 neigh add " RX_ADDR " lladdr " RX_MAC " dev " TX_NAME_VLAN);
|
||||
|
||||
switch_ns_to_rx(&tok);
|
||||
|
||||
SYS(out, "ip link set dev " RX_NAME " address " RX_MAC);
|
||||
SYS(out, "ip link set dev " RX_NAME " up");
|
||||
SYS(out, "ip addr add " TX_ADDR "/" PREFIX_LEN " dev " TX_NAME);
|
||||
SYS(out, "ip addr add " RX_ADDR "/" PREFIX_LEN " dev " RX_NAME);
|
||||
|
||||
rx_ifindex = if_nametoindex(RX_NAME);
|
||||
tx_ifindex = if_nametoindex(TX_NAME);
|
||||
|
||||
/* Setup separate AF_XDP for TX and RX interfaces. */
|
||||
|
||||
ret = open_xsk(tx_ifindex, &tx_xsk);
|
||||
if (!ASSERT_OK(ret, "open_xsk(TX_NAME)"))
|
||||
goto out;
|
||||
/* Setup separate AF_XDP for RX interface. */
|
||||
|
||||
ret = open_xsk(rx_ifindex, &rx_xsk);
|
||||
if (!ASSERT_OK(ret, "open_xsk(RX_NAME)"))
|
||||
|
@ -379,18 +448,38 @@ void test_xdp_metadata(void)
|
|||
if (!ASSERT_GE(ret, 0, "bpf_map_update_elem"))
|
||||
goto out;
|
||||
|
||||
/* Send packet destined to RX AF_XDP socket. */
|
||||
switch_ns_to_tx(&tok);
|
||||
|
||||
/* Setup separate AF_XDP for TX interface nad send packet to the RX socket. */
|
||||
tx_ifindex = if_nametoindex(TX_NAME);
|
||||
ret = open_xsk(tx_ifindex, &tx_xsk);
|
||||
if (!ASSERT_OK(ret, "open_xsk(TX_NAME)"))
|
||||
goto out;
|
||||
|
||||
if (!ASSERT_GE(generate_packet(&tx_xsk, AF_XDP_CONSUMER_PORT), 0,
|
||||
"generate AF_XDP_CONSUMER_PORT"))
|
||||
goto out;
|
||||
|
||||
/* Verify AF_XDP RX packet has proper metadata. */
|
||||
if (!ASSERT_GE(verify_xsk_metadata(&rx_xsk), 0,
|
||||
switch_ns_to_rx(&tok);
|
||||
|
||||
/* Verify packet sent from AF_XDP has proper metadata. */
|
||||
if (!ASSERT_GE(verify_xsk_metadata(&rx_xsk, true), 0,
|
||||
"verify_xsk_metadata"))
|
||||
goto out;
|
||||
|
||||
switch_ns_to_tx(&tok);
|
||||
complete_tx(&tx_xsk);
|
||||
|
||||
/* Now check metadata of packet, generated with network stack */
|
||||
if (!ASSERT_GE(generate_packet_inet(), 0, "generate UDP packet"))
|
||||
goto out;
|
||||
|
||||
switch_ns_to_rx(&tok);
|
||||
|
||||
if (!ASSERT_GE(verify_xsk_metadata(&rx_xsk, false), 0,
|
||||
"verify_xsk_metadata"))
|
||||
goto out;
|
||||
|
||||
/* Make sure freplace correctly picks up original bound device
|
||||
* and doesn't crash.
|
||||
*/
|
||||
|
@ -408,11 +497,15 @@ void test_xdp_metadata(void)
|
|||
if (!ASSERT_OK(xdp_metadata2__attach(bpf_obj2), "attach freplace"))
|
||||
goto out;
|
||||
|
||||
switch_ns_to_tx(&tok);
|
||||
|
||||
/* Send packet to trigger . */
|
||||
if (!ASSERT_GE(generate_packet(&tx_xsk, AF_XDP_CONSUMER_PORT), 0,
|
||||
"generate freplace packet"))
|
||||
goto out;
|
||||
|
||||
switch_ns_to_rx(&tok);
|
||||
|
||||
while (!retries--) {
|
||||
if (bpf_obj2->bss->called)
|
||||
break;
|
||||
|
@ -427,5 +520,6 @@ out:
|
|||
xdp_metadata__destroy(bpf_obj);
|
||||
if (tok)
|
||||
close_netns(tok);
|
||||
SYS_NOFAIL("ip netns del xdp_metadata");
|
||||
SYS_NOFAIL("ip netns del " RX_NETNS_NAME);
|
||||
SYS_NOFAIL("ip netns del " TX_NETNS_NAME);
|
||||
}
|
||||
|
|
|
@ -20,21 +20,32 @@ extern int bpf_xdp_metadata_rx_timestamp(const struct xdp_md *ctx,
|
|||
__u64 *timestamp) __ksym;
|
||||
extern int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, __u32 *hash,
|
||||
enum xdp_rss_hash_type *rss_type) __ksym;
|
||||
extern int bpf_xdp_metadata_rx_vlan_tag(const struct xdp_md *ctx,
|
||||
__be16 *vlan_proto,
|
||||
__u16 *vlan_tci) __ksym;
|
||||
|
||||
SEC("xdp.frags")
|
||||
int rx(struct xdp_md *ctx)
|
||||
{
|
||||
void *data, *data_meta, *data_end;
|
||||
struct ipv6hdr *ip6h = NULL;
|
||||
struct ethhdr *eth = NULL;
|
||||
struct udphdr *udp = NULL;
|
||||
struct iphdr *iph = NULL;
|
||||
struct xdp_meta *meta;
|
||||
struct ethhdr *eth;
|
||||
int err;
|
||||
|
||||
data = (void *)(long)ctx->data;
|
||||
data_end = (void *)(long)ctx->data_end;
|
||||
eth = data;
|
||||
|
||||
if (eth + 1 < data_end && (eth->h_proto == bpf_htons(ETH_P_8021AD) ||
|
||||
eth->h_proto == bpf_htons(ETH_P_8021Q)))
|
||||
eth = (void *)eth + sizeof(struct vlan_hdr);
|
||||
|
||||
if (eth + 1 < data_end && eth->h_proto == bpf_htons(ETH_P_8021Q))
|
||||
eth = (void *)eth + sizeof(struct vlan_hdr);
|
||||
|
||||
if (eth + 1 < data_end) {
|
||||
if (eth->h_proto == bpf_htons(ETH_P_IP)) {
|
||||
iph = (void *)(eth + 1);
|
||||
|
@ -76,15 +87,28 @@ int rx(struct xdp_md *ctx)
|
|||
return XDP_PASS;
|
||||
}
|
||||
|
||||
err = bpf_xdp_metadata_rx_timestamp(ctx, &meta->rx_timestamp);
|
||||
if (!err)
|
||||
meta->xdp_timestamp = bpf_ktime_get_tai_ns();
|
||||
else
|
||||
meta->rx_timestamp = 0; /* Used by AF_XDP as not avail signal */
|
||||
meta->hint_valid = 0;
|
||||
|
||||
err = bpf_xdp_metadata_rx_hash(ctx, &meta->rx_hash, &meta->rx_hash_type);
|
||||
if (err < 0)
|
||||
meta->rx_hash_err = err; /* Used by AF_XDP as no hash signal */
|
||||
meta->xdp_timestamp = bpf_ktime_get_tai_ns();
|
||||
err = bpf_xdp_metadata_rx_timestamp(ctx, &meta->rx_timestamp);
|
||||
if (err)
|
||||
meta->rx_timestamp_err = err;
|
||||
else
|
||||
meta->hint_valid |= XDP_META_FIELD_TS;
|
||||
|
||||
err = bpf_xdp_metadata_rx_hash(ctx, &meta->rx_hash,
|
||||
&meta->rx_hash_type);
|
||||
if (err)
|
||||
meta->rx_hash_err = err;
|
||||
else
|
||||
meta->hint_valid |= XDP_META_FIELD_RSS;
|
||||
|
||||
err = bpf_xdp_metadata_rx_vlan_tag(ctx, &meta->rx_vlan_proto,
|
||||
&meta->rx_vlan_tci);
|
||||
if (err)
|
||||
meta->rx_vlan_tag_err = err;
|
||||
else
|
||||
meta->hint_valid |= XDP_META_FIELD_VLAN_TAG;
|
||||
|
||||
__sync_add_and_fetch(&pkts_redir, 1);
|
||||
return bpf_redirect_map(&xsk, ctx->rx_queue_index, XDP_PASS);
|
||||
|
|
|
@ -23,6 +23,9 @@ extern int bpf_xdp_metadata_rx_timestamp(const struct xdp_md *ctx,
|
|||
__u64 *timestamp) __ksym;
|
||||
extern int bpf_xdp_metadata_rx_hash(const struct xdp_md *ctx, __u32 *hash,
|
||||
enum xdp_rss_hash_type *rss_type) __ksym;
|
||||
extern int bpf_xdp_metadata_rx_vlan_tag(const struct xdp_md *ctx,
|
||||
__be16 *vlan_proto,
|
||||
__u16 *vlan_tci) __ksym;
|
||||
|
||||
SEC("xdp")
|
||||
int rx(struct xdp_md *ctx)
|
||||
|
@ -57,6 +60,8 @@ int rx(struct xdp_md *ctx)
|
|||
meta->rx_timestamp = 1;
|
||||
|
||||
bpf_xdp_metadata_rx_hash(ctx, &meta->rx_hash, &meta->rx_hash_type);
|
||||
bpf_xdp_metadata_rx_vlan_tag(ctx, &meta->rx_vlan_proto,
|
||||
&meta->rx_vlan_tci);
|
||||
|
||||
return bpf_redirect_map(&xsk, ctx->rx_queue_index, XDP_PASS);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
#include <bpf/libbpf.h>
|
||||
#include <time.h>
|
||||
|
||||
#define __TO_STR(x) #x
|
||||
#define TO_STR(x) __TO_STR(x)
|
||||
|
||||
int parse_num_list(const char *s, bool **set, int *set_len);
|
||||
__u32 link_info_prog_id(const struct bpf_link *link, struct bpf_link_info *info);
|
||||
int bpf_prog_test_load(const char *file, enum bpf_prog_type type,
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include "xsk.h"
|
||||
|
||||
#include <error.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bits.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/errqueue.h>
|
||||
#include <linux/if_link.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
|
@ -182,19 +185,31 @@ static void print_tstamp_delta(const char *name, const char *refname,
|
|||
(double)delta / 1000);
|
||||
}
|
||||
|
||||
#define VLAN_PRIO_MASK GENMASK(15, 13) /* Priority Code Point */
|
||||
#define VLAN_DEI_MASK GENMASK(12, 12) /* Drop Eligible Indicator */
|
||||
#define VLAN_VID_MASK GENMASK(11, 0) /* VLAN Identifier */
|
||||
static void print_vlan_tci(__u16 tag)
|
||||
{
|
||||
__u16 vlan_id = FIELD_GET(VLAN_VID_MASK, tag);
|
||||
__u8 pcp = FIELD_GET(VLAN_PRIO_MASK, tag);
|
||||
bool dei = FIELD_GET(VLAN_DEI_MASK, tag);
|
||||
|
||||
printf("PCP=%u, DEI=%d, VID=0x%X\n", pcp, dei, vlan_id);
|
||||
}
|
||||
|
||||
static void verify_xdp_metadata(void *data, clockid_t clock_id)
|
||||
{
|
||||
struct xdp_meta *meta;
|
||||
|
||||
meta = data - sizeof(*meta);
|
||||
|
||||
if (meta->rx_hash_err < 0)
|
||||
printf("No rx_hash err=%d\n", meta->rx_hash_err);
|
||||
else
|
||||
if (meta->hint_valid & XDP_META_FIELD_RSS)
|
||||
printf("rx_hash: 0x%X with RSS type:0x%X\n",
|
||||
meta->rx_hash, meta->rx_hash_type);
|
||||
else
|
||||
printf("No rx_hash, err=%d\n", meta->rx_hash_err);
|
||||
|
||||
if (meta->rx_timestamp) {
|
||||
if (meta->hint_valid & XDP_META_FIELD_TS) {
|
||||
__u64 ref_tstamp = gettime(clock_id);
|
||||
|
||||
/* store received timestamps to calculate a delta at tx */
|
||||
|
@ -206,7 +221,16 @@ static void verify_xdp_metadata(void *data, clockid_t clock_id)
|
|||
print_tstamp_delta("XDP RX-time", "User RX-time",
|
||||
meta->xdp_timestamp, ref_tstamp);
|
||||
} else {
|
||||
printf("No rx_timestamp\n");
|
||||
printf("No rx_timestamp, err=%d\n", meta->rx_timestamp_err);
|
||||
}
|
||||
|
||||
if (meta->hint_valid & XDP_META_FIELD_VLAN_TAG) {
|
||||
printf("rx_vlan_proto: 0x%X\n", ntohs(meta->rx_vlan_proto));
|
||||
printf("rx_vlan_tci: ");
|
||||
print_vlan_tci(meta->rx_vlan_tci);
|
||||
} else {
|
||||
printf("No rx_vlan_tci or rx_vlan_proto, err=%d\n",
|
||||
meta->rx_vlan_tag_err);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,44 @@
|
|||
#define ETH_P_IPV6 0x86DD
|
||||
#endif
|
||||
|
||||
#ifndef ETH_P_8021Q
|
||||
#define ETH_P_8021Q 0x8100
|
||||
#endif
|
||||
|
||||
#ifndef ETH_P_8021AD
|
||||
#define ETH_P_8021AD 0x88A8
|
||||
#endif
|
||||
|
||||
#ifndef BIT
|
||||
#define BIT(nr) (1 << (nr))
|
||||
#endif
|
||||
|
||||
/* Non-existent checksum status */
|
||||
#define XDP_CHECKSUM_MAGIC BIT(2)
|
||||
|
||||
enum xdp_meta_field {
|
||||
XDP_META_FIELD_TS = BIT(0),
|
||||
XDP_META_FIELD_RSS = BIT(1),
|
||||
XDP_META_FIELD_VLAN_TAG = BIT(2),
|
||||
};
|
||||
|
||||
struct xdp_meta {
|
||||
__u64 rx_timestamp;
|
||||
union {
|
||||
__u64 rx_timestamp;
|
||||
__s32 rx_timestamp_err;
|
||||
};
|
||||
__u64 xdp_timestamp;
|
||||
__u32 rx_hash;
|
||||
union {
|
||||
__u32 rx_hash_type;
|
||||
__s32 rx_hash_err;
|
||||
};
|
||||
union {
|
||||
struct {
|
||||
__be16 rx_vlan_proto;
|
||||
__u16 rx_vlan_tci;
|
||||
};
|
||||
__s32 rx_vlan_tag_err;
|
||||
};
|
||||
enum xdp_meta_field hint_valid;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue