| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735 |
- // SPDX-License-Identifier: GPL-2.0
- /* Reference program for verifying XDP metadata on real HW. Functional test
- * only, doesn't test the performance.
- *
- * RX:
- * - UDP 9091 packets are diverted into AF_XDP
- * - Metadata verified:
- * - rx_timestamp
- * - rx_hash
- *
- * TX:
- * - UDP 9091 packets trigger TX reply
- * - TX HW timestamp is requested and reported back upon completion
- * - TX checksum is requested
- */
- #include <test_progs.h>
- #include <network_helpers.h>
- #include "xdp_hw_metadata.skel.h"
- #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>
- #include <linux/udp.h>
- #include <linux/sockios.h>
- #include <linux/if_xdp.h>
- #include <sys/mman.h>
- #include <net/if.h>
- #include <ctype.h>
- #include <poll.h>
- #include <time.h>
- #include <unistd.h>
- #include <libgen.h>
- #include "xdp_metadata.h"
- #define UMEM_NUM 256
- #define UMEM_FRAME_SIZE XSK_UMEM__DEFAULT_FRAME_SIZE
- #define UMEM_SIZE (UMEM_FRAME_SIZE * UMEM_NUM)
- #define XDP_FLAGS (XDP_FLAGS_DRV_MODE | XDP_FLAGS_REPLACE)
- struct xsk {
- void *umem_area;
- struct xsk_umem *umem;
- struct xsk_ring_prod fill;
- struct xsk_ring_cons comp;
- struct xsk_ring_prod tx;
- struct xsk_ring_cons rx;
- struct xsk_socket *socket;
- };
- struct xdp_hw_metadata *bpf_obj;
- __u16 bind_flags = XDP_USE_NEED_WAKEUP | XDP_ZEROCOPY;
- struct xsk *rx_xsk;
- const char *ifname;
- int ifindex;
- int rxq;
- bool skip_tx;
- __u64 last_hw_rx_timestamp;
- __u64 last_xdp_rx_timestamp;
- void test__fail(void) { /* for network_helpers.c */ }
- static int open_xsk(int ifindex, struct xsk *xsk, __u32 queue_id)
- {
- int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
- const struct xsk_socket_config socket_config = {
- .rx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
- .tx_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
- .bind_flags = bind_flags,
- };
- const struct xsk_umem_config umem_config = {
- .fill_size = XSK_RING_PROD__DEFAULT_NUM_DESCS,
- .comp_size = XSK_RING_CONS__DEFAULT_NUM_DESCS,
- .frame_size = XSK_UMEM__DEFAULT_FRAME_SIZE,
- .flags = XDP_UMEM_TX_METADATA_LEN,
- .tx_metadata_len = sizeof(struct xsk_tx_metadata),
- };
- __u32 idx = 0;
- u64 addr;
- int ret;
- int i;
- xsk->umem_area = mmap(NULL, UMEM_SIZE, PROT_READ | PROT_WRITE, mmap_flags, -1, 0);
- if (xsk->umem_area == MAP_FAILED)
- return -ENOMEM;
- ret = xsk_umem__create(&xsk->umem,
- xsk->umem_area, UMEM_SIZE,
- &xsk->fill,
- &xsk->comp,
- &umem_config);
- if (ret)
- return ret;
- ret = xsk_socket__create(&xsk->socket, ifindex, queue_id,
- xsk->umem,
- &xsk->rx,
- &xsk->tx,
- &socket_config);
- if (ret)
- return ret;
- /* First half of umem is for TX. This way address matches 1-to-1
- * to the completion queue index.
- */
- for (i = 0; i < UMEM_NUM / 2; i++) {
- addr = i * UMEM_FRAME_SIZE;
- printf("%p: tx_desc[%d] -> %lx\n", xsk, i, addr);
- }
- /* Second half of umem is for RX. */
- ret = xsk_ring_prod__reserve(&xsk->fill, UMEM_NUM / 2, &idx);
- for (i = 0; i < UMEM_NUM / 2; i++) {
- addr = (UMEM_NUM / 2 + i) * UMEM_FRAME_SIZE;
- printf("%p: rx_desc[%d] -> %lx\n", xsk, i, addr);
- *xsk_ring_prod__fill_addr(&xsk->fill, idx + i) = addr;
- }
- xsk_ring_prod__submit(&xsk->fill, ret);
- return 0;
- }
- static void close_xsk(struct xsk *xsk)
- {
- if (xsk->umem)
- xsk_umem__delete(xsk->umem);
- if (xsk->socket)
- xsk_socket__delete(xsk->socket);
- munmap(xsk->umem_area, UMEM_SIZE);
- }
- static void refill_rx(struct xsk *xsk, __u64 addr)
- {
- __u32 idx;
- if (xsk_ring_prod__reserve(&xsk->fill, 1, &idx) == 1) {
- printf("%p: complete rx idx=%u addr=%llx\n", xsk, idx, addr);
- *xsk_ring_prod__fill_addr(&xsk->fill, idx) = addr;
- xsk_ring_prod__submit(&xsk->fill, 1);
- }
- }
- static int kick_tx(struct xsk *xsk)
- {
- return sendto(xsk_socket__fd(xsk->socket), NULL, 0, MSG_DONTWAIT, NULL, 0);
- }
- static int kick_rx(struct xsk *xsk)
- {
- return recvfrom(xsk_socket__fd(xsk->socket), NULL, 0, MSG_DONTWAIT, NULL, NULL);
- }
- #define NANOSEC_PER_SEC 1000000000 /* 10^9 */
- static __u64 gettime(clockid_t clock_id)
- {
- struct timespec t;
- int res;
- /* See man clock_gettime(2) for type of clock_id's */
- res = clock_gettime(clock_id, &t);
- if (res < 0)
- error(res, errno, "Error with clock_gettime()");
- return (__u64) t.tv_sec * NANOSEC_PER_SEC + t.tv_nsec;
- }
- static void print_tstamp_delta(const char *name, const char *refname,
- __u64 tstamp, __u64 reference)
- {
- __s64 delta = (__s64)reference - (__s64)tstamp;
- printf("%s: %llu (sec:%0.4f) delta to %s sec:%0.4f (%0.3f usec)\n",
- name, tstamp, (double)tstamp / NANOSEC_PER_SEC, refname,
- (double)delta / NANOSEC_PER_SEC,
- (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->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->hint_valid & XDP_META_FIELD_TS) {
- __u64 ref_tstamp = gettime(clock_id);
- /* store received timestamps to calculate a delta at tx */
- last_hw_rx_timestamp = meta->rx_timestamp;
- last_xdp_rx_timestamp = meta->xdp_timestamp;
- print_tstamp_delta("HW RX-time", "User RX-time",
- meta->rx_timestamp, ref_tstamp);
- print_tstamp_delta("XDP RX-time", "User RX-time",
- meta->xdp_timestamp, ref_tstamp);
- } else {
- 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);
- }
- }
- static void verify_skb_metadata(int fd)
- {
- char cmsg_buf[1024];
- char packet_buf[128];
- struct scm_timestamping *ts;
- struct iovec packet_iov;
- struct cmsghdr *cmsg;
- struct msghdr hdr;
- memset(&hdr, 0, sizeof(hdr));
- hdr.msg_iov = &packet_iov;
- hdr.msg_iovlen = 1;
- packet_iov.iov_base = packet_buf;
- packet_iov.iov_len = sizeof(packet_buf);
- hdr.msg_control = cmsg_buf;
- hdr.msg_controllen = sizeof(cmsg_buf);
- if (recvmsg(fd, &hdr, 0) < 0)
- error(1, errno, "recvmsg");
- for (cmsg = CMSG_FIRSTHDR(&hdr); cmsg != NULL;
- cmsg = CMSG_NXTHDR(&hdr, cmsg)) {
- if (cmsg->cmsg_level != SOL_SOCKET)
- continue;
- switch (cmsg->cmsg_type) {
- case SCM_TIMESTAMPING:
- ts = (struct scm_timestamping *)CMSG_DATA(cmsg);
- if (ts->ts[2].tv_sec || ts->ts[2].tv_nsec) {
- printf("found skb hwtstamp = %lu.%lu\n",
- ts->ts[2].tv_sec, ts->ts[2].tv_nsec);
- return;
- }
- break;
- default:
- break;
- }
- }
- printf("skb hwtstamp is not found!\n");
- }
- static bool complete_tx(struct xsk *xsk, clockid_t clock_id)
- {
- struct xsk_tx_metadata *meta;
- __u64 addr;
- void *data;
- __u32 idx;
- if (!xsk_ring_cons__peek(&xsk->comp, 1, &idx))
- return false;
- addr = *xsk_ring_cons__comp_addr(&xsk->comp, idx);
- data = xsk_umem__get_data(xsk->umem_area, addr);
- meta = data - sizeof(struct xsk_tx_metadata);
- printf("%p: complete tx idx=%u addr=%llx\n", xsk, idx, addr);
- if (meta->completion.tx_timestamp) {
- __u64 ref_tstamp = gettime(clock_id);
- print_tstamp_delta("HW TX-complete-time", "User TX-complete-time",
- meta->completion.tx_timestamp, ref_tstamp);
- print_tstamp_delta("XDP RX-time", "User TX-complete-time",
- last_xdp_rx_timestamp, ref_tstamp);
- print_tstamp_delta("HW RX-time", "HW TX-complete-time",
- last_hw_rx_timestamp, meta->completion.tx_timestamp);
- } else {
- printf("No tx_timestamp\n");
- }
- xsk_ring_cons__release(&xsk->comp, 1);
- return true;
- }
- #define swap(a, b, len) do { \
- for (int i = 0; i < len; i++) { \
- __u8 tmp = ((__u8 *)a)[i]; \
- ((__u8 *)a)[i] = ((__u8 *)b)[i]; \
- ((__u8 *)b)[i] = tmp; \
- } \
- } while (0)
- static void ping_pong(struct xsk *xsk, void *rx_packet, clockid_t clock_id)
- {
- struct xsk_tx_metadata *meta;
- struct ipv6hdr *ip6h = NULL;
- struct iphdr *iph = NULL;
- struct xdp_desc *tx_desc;
- struct udphdr *udph;
- struct ethhdr *eth;
- __sum16 want_csum;
- void *data;
- __u32 idx;
- int ret;
- int len;
- ret = xsk_ring_prod__reserve(&xsk->tx, 1, &idx);
- if (ret != 1) {
- printf("%p: failed to reserve tx slot\n", xsk);
- return;
- }
- tx_desc = xsk_ring_prod__tx_desc(&xsk->tx, idx);
- tx_desc->addr = idx % (UMEM_NUM / 2) * UMEM_FRAME_SIZE + sizeof(struct xsk_tx_metadata);
- data = xsk_umem__get_data(xsk->umem_area, tx_desc->addr);
- meta = data - sizeof(struct xsk_tx_metadata);
- memset(meta, 0, sizeof(*meta));
- meta->flags = XDP_TXMD_FLAGS_TIMESTAMP;
- eth = rx_packet;
- if (eth->h_proto == htons(ETH_P_IP)) {
- iph = (void *)(eth + 1);
- udph = (void *)(iph + 1);
- } else if (eth->h_proto == htons(ETH_P_IPV6)) {
- ip6h = (void *)(eth + 1);
- udph = (void *)(ip6h + 1);
- } else {
- printf("%p: failed to detect IP version for ping pong %04x\n", xsk, eth->h_proto);
- xsk_ring_prod__cancel(&xsk->tx, 1);
- return;
- }
- len = ETH_HLEN;
- if (ip6h)
- len += sizeof(*ip6h) + ntohs(ip6h->payload_len);
- if (iph)
- len += ntohs(iph->tot_len);
- swap(eth->h_dest, eth->h_source, ETH_ALEN);
- if (iph)
- swap(&iph->saddr, &iph->daddr, 4);
- else
- swap(&ip6h->saddr, &ip6h->daddr, 16);
- swap(&udph->source, &udph->dest, 2);
- want_csum = udph->check;
- if (ip6h)
- udph->check = ~csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr,
- ntohs(udph->len), IPPROTO_UDP, 0);
- else
- udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
- ntohs(udph->len), IPPROTO_UDP, 0);
- meta->flags |= XDP_TXMD_FLAGS_CHECKSUM;
- if (iph)
- meta->request.csum_start = sizeof(*eth) + sizeof(*iph);
- else
- meta->request.csum_start = sizeof(*eth) + sizeof(*ip6h);
- meta->request.csum_offset = offsetof(struct udphdr, check);
- printf("%p: ping-pong with csum=%04x (want %04x) csum_start=%d csum_offset=%d\n",
- xsk, ntohs(udph->check), ntohs(want_csum),
- meta->request.csum_start, meta->request.csum_offset);
- memcpy(data, rx_packet, len); /* don't share umem chunk for simplicity */
- tx_desc->options |= XDP_TX_METADATA;
- tx_desc->len = len;
- xsk_ring_prod__submit(&xsk->tx, 1);
- }
- static int verify_metadata(struct xsk *rx_xsk, int rxq, int server_fd, clockid_t clock_id)
- {
- const struct xdp_desc *rx_desc;
- struct pollfd fds[rxq + 1];
- __u64 comp_addr;
- __u64 addr;
- __u32 idx = 0;
- int ret;
- int i;
- for (i = 0; i < rxq; i++) {
- fds[i].fd = xsk_socket__fd(rx_xsk[i].socket);
- fds[i].events = POLLIN;
- fds[i].revents = 0;
- }
- fds[rxq].fd = server_fd;
- fds[rxq].events = POLLIN;
- fds[rxq].revents = 0;
- while (true) {
- errno = 0;
- for (i = 0; i < rxq; i++) {
- ret = kick_rx(&rx_xsk[i]);
- if (ret)
- printf("kick_rx ret=%d\n", ret);
- }
- ret = poll(fds, rxq + 1, 1000);
- printf("poll: %d (%d) skip=%llu fail=%llu redir=%llu\n",
- ret, errno, bpf_obj->bss->pkts_skip,
- bpf_obj->bss->pkts_fail, bpf_obj->bss->pkts_redir);
- if (ret < 0)
- break;
- if (ret == 0)
- continue;
- if (fds[rxq].revents)
- verify_skb_metadata(server_fd);
- for (i = 0; i < rxq; i++) {
- bool first_seg = true;
- bool is_eop = true;
- if (fds[i].revents == 0)
- continue;
- struct xsk *xsk = &rx_xsk[i];
- peek:
- ret = xsk_ring_cons__peek(&xsk->rx, 1, &idx);
- printf("xsk_ring_cons__peek: %d\n", ret);
- if (ret != 1)
- continue;
- rx_desc = xsk_ring_cons__rx_desc(&xsk->rx, idx);
- comp_addr = xsk_umem__extract_addr(rx_desc->addr);
- addr = xsk_umem__add_offset_to_addr(rx_desc->addr);
- is_eop = !(rx_desc->options & XDP_PKT_CONTD);
- printf("%p: rx_desc[%u]->addr=%llx addr=%llx comp_addr=%llx%s\n",
- xsk, idx, rx_desc->addr, addr, comp_addr, is_eop ? " EoP" : "");
- if (first_seg) {
- verify_xdp_metadata(xsk_umem__get_data(xsk->umem_area, addr),
- clock_id);
- first_seg = false;
- if (!skip_tx) {
- /* mirror first chunk back */
- ping_pong(xsk, xsk_umem__get_data(xsk->umem_area, addr),
- clock_id);
- ret = kick_tx(xsk);
- if (ret)
- printf("kick_tx ret=%d\n", ret);
- for (int j = 0; j < 500; j++) {
- if (complete_tx(xsk, clock_id))
- break;
- usleep(10);
- }
- }
- }
- xsk_ring_cons__release(&xsk->rx, 1);
- refill_rx(xsk, comp_addr);
- if (!is_eop)
- goto peek;
- }
- }
- return 0;
- }
- static int rxq_num(const char *ifname)
- {
- struct ethtool_channels ch = {
- .cmd = ETHTOOL_GCHANNELS,
- };
- struct ifreq ifr = {
- .ifr_data = (void *)&ch,
- };
- strncpy(ifr.ifr_name, ifname, IF_NAMESIZE - 1);
- int fd, ret;
- fd = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (fd < 0)
- error(1, errno, "socket");
- ret = ioctl(fd, SIOCETHTOOL, &ifr);
- if (ret < 0)
- error(1, errno, "ioctl(SIOCETHTOOL)");
- close(fd);
- return ch.rx_count + ch.combined_count;
- }
- static void hwtstamp_ioctl(int op, const char *ifname, struct hwtstamp_config *cfg)
- {
- struct ifreq ifr = {
- .ifr_data = (void *)cfg,
- };
- strncpy(ifr.ifr_name, ifname, IF_NAMESIZE - 1);
- int fd, ret;
- fd = socket(AF_UNIX, SOCK_DGRAM, 0);
- if (fd < 0)
- error(1, errno, "socket");
- ret = ioctl(fd, op, &ifr);
- if (ret < 0)
- error(1, errno, "ioctl(%d)", op);
- close(fd);
- }
- static struct hwtstamp_config saved_hwtstamp_cfg;
- static const char *saved_hwtstamp_ifname;
- static void hwtstamp_restore(void)
- {
- hwtstamp_ioctl(SIOCSHWTSTAMP, saved_hwtstamp_ifname, &saved_hwtstamp_cfg);
- }
- static void hwtstamp_enable(const char *ifname)
- {
- struct hwtstamp_config cfg = {
- .rx_filter = HWTSTAMP_FILTER_ALL,
- };
- hwtstamp_ioctl(SIOCGHWTSTAMP, ifname, &saved_hwtstamp_cfg);
- saved_hwtstamp_ifname = strdup(ifname);
- atexit(hwtstamp_restore);
- hwtstamp_ioctl(SIOCSHWTSTAMP, ifname, &cfg);
- }
- static void cleanup(void)
- {
- LIBBPF_OPTS(bpf_xdp_attach_opts, opts);
- int ret;
- int i;
- if (bpf_obj) {
- opts.old_prog_fd = bpf_program__fd(bpf_obj->progs.rx);
- if (opts.old_prog_fd >= 0) {
- printf("detaching bpf program....\n");
- ret = bpf_xdp_detach(ifindex, XDP_FLAGS, &opts);
- if (ret)
- printf("failed to detach XDP program: %d\n", ret);
- }
- }
- for (i = 0; i < rxq; i++)
- close_xsk(&rx_xsk[i]);
- if (bpf_obj)
- xdp_hw_metadata__destroy(bpf_obj);
- free((void *)saved_hwtstamp_ifname);
- }
- static void handle_signal(int sig)
- {
- /* interrupting poll() is all we need */
- }
- static void timestamping_enable(int fd, int val)
- {
- int ret;
- ret = setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING, &val, sizeof(val));
- if (ret < 0)
- error(1, errno, "setsockopt(SO_TIMESTAMPING)");
- }
- static void print_usage(void)
- {
- const char *usage =
- "Usage: xdp_hw_metadata [OPTIONS] [IFNAME]\n"
- " -c Run in copy mode (zerocopy is default)\n"
- " -h Display this help and exit\n\n"
- " -m Enable multi-buffer XDP for larger MTU\n"
- " -r Don't generate AF_XDP reply (rx metadata only)\n"
- "Generate test packets on the other machine with:\n"
- " echo -n xdp | nc -u -q1 <dst_ip> 9091\n";
- printf("%s", usage);
- }
- static void read_args(int argc, char *argv[])
- {
- int opt;
- while ((opt = getopt(argc, argv, "chmr")) != -1) {
- switch (opt) {
- case 'c':
- bind_flags &= ~XDP_USE_NEED_WAKEUP;
- bind_flags &= ~XDP_ZEROCOPY;
- bind_flags |= XDP_COPY;
- break;
- case 'h':
- print_usage();
- exit(0);
- case 'm':
- bind_flags |= XDP_USE_SG;
- break;
- case 'r':
- skip_tx = true;
- break;
- case '?':
- if (isprint(optopt))
- fprintf(stderr, "Unknown option: -%c\n", optopt);
- fallthrough;
- default:
- print_usage();
- error(-1, opterr, "Command line options error");
- }
- }
- if (optind >= argc) {
- fprintf(stderr, "No device name provided\n");
- print_usage();
- exit(-1);
- }
- ifname = argv[optind];
- ifindex = if_nametoindex(ifname);
- if (!ifname)
- error(-1, errno, "Invalid interface name");
- }
- int main(int argc, char *argv[])
- {
- clockid_t clock_id = CLOCK_TAI;
- int server_fd = -1;
- int ret;
- int i;
- struct bpf_program *prog;
- read_args(argc, argv);
- rxq = rxq_num(ifname);
- printf("rxq: %d\n", rxq);
- hwtstamp_enable(ifname);
- rx_xsk = malloc(sizeof(struct xsk) * rxq);
- if (!rx_xsk)
- error(1, ENOMEM, "malloc");
- for (i = 0; i < rxq; i++) {
- printf("open_xsk(%s, %p, %d)\n", ifname, &rx_xsk[i], i);
- ret = open_xsk(ifindex, &rx_xsk[i], i);
- if (ret)
- error(1, -ret, "open_xsk");
- printf("xsk_socket__fd() -> %d\n", xsk_socket__fd(rx_xsk[i].socket));
- }
- printf("open bpf program...\n");
- bpf_obj = xdp_hw_metadata__open();
- if (libbpf_get_error(bpf_obj))
- error(1, libbpf_get_error(bpf_obj), "xdp_hw_metadata__open");
- prog = bpf_object__find_program_by_name(bpf_obj->obj, "rx");
- bpf_program__set_ifindex(prog, ifindex);
- bpf_program__set_flags(prog, BPF_F_XDP_DEV_BOUND_ONLY);
- printf("load bpf program...\n");
- ret = xdp_hw_metadata__load(bpf_obj);
- if (ret)
- error(1, -ret, "xdp_hw_metadata__load");
- printf("prepare skb endpoint...\n");
- server_fd = start_server(AF_INET6, SOCK_DGRAM, NULL, 9092, 1000);
- if (server_fd < 0)
- error(1, errno, "start_server");
- timestamping_enable(server_fd,
- SOF_TIMESTAMPING_SOFTWARE |
- SOF_TIMESTAMPING_RAW_HARDWARE);
- printf("prepare xsk map...\n");
- for (i = 0; i < rxq; i++) {
- int sock_fd = xsk_socket__fd(rx_xsk[i].socket);
- __u32 queue_id = i;
- printf("map[%d] = %d\n", queue_id, sock_fd);
- ret = bpf_map_update_elem(bpf_map__fd(bpf_obj->maps.xsk), &queue_id, &sock_fd, 0);
- if (ret)
- error(1, -ret, "bpf_map_update_elem");
- }
- printf("attach bpf program...\n");
- ret = bpf_xdp_attach(ifindex,
- bpf_program__fd(bpf_obj->progs.rx),
- XDP_FLAGS, NULL);
- if (ret)
- error(1, -ret, "bpf_xdp_attach");
- signal(SIGINT, handle_signal);
- ret = verify_metadata(rx_xsk, rxq, server_fd, clock_id);
- close(server_fd);
- cleanup();
- if (ret)
- error(1, -ret, "verify_metadata");
- }
|