18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 28c2ecf20Sopenharmony_ci/* Copyright (c) 2018 Facebook */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <stdlib.h> 58c2ecf20Sopenharmony_ci#include <memory.h> 68c2ecf20Sopenharmony_ci#include <unistd.h> 78c2ecf20Sopenharmony_ci#include <linux/bpf.h> 88c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h> 98c2ecf20Sopenharmony_ci#include <sys/socket.h> 108c2ecf20Sopenharmony_ci#include <errno.h> 118c2ecf20Sopenharmony_ci#include <time.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "bpf.h" 148c2ecf20Sopenharmony_ci#include "libbpf.h" 158c2ecf20Sopenharmony_ci#include "libbpf_internal.h" 168c2ecf20Sopenharmony_ci#include "nlattr.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#ifndef SOL_NETLINK 198c2ecf20Sopenharmony_ci#define SOL_NETLINK 270 208c2ecf20Sopenharmony_ci#endif 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_citypedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_citypedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, libbpf_dump_nlmsg_t, 258c2ecf20Sopenharmony_ci void *cookie); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct xdp_id_md { 288c2ecf20Sopenharmony_ci int ifindex; 298c2ecf20Sopenharmony_ci __u32 flags; 308c2ecf20Sopenharmony_ci struct xdp_link_info info; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int libbpf_netlink_open(__u32 *nl_pid) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci struct sockaddr_nl sa; 368c2ecf20Sopenharmony_ci socklen_t addrlen; 378c2ecf20Sopenharmony_ci int one = 1, ret; 388c2ecf20Sopenharmony_ci int sock; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci memset(&sa, 0, sizeof(sa)); 418c2ecf20Sopenharmony_ci sa.nl_family = AF_NETLINK; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); 448c2ecf20Sopenharmony_ci if (sock < 0) 458c2ecf20Sopenharmony_ci return -errno; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK, 488c2ecf20Sopenharmony_ci &one, sizeof(one)) < 0) { 498c2ecf20Sopenharmony_ci pr_warn("Netlink error reporting not supported\n"); 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { 538c2ecf20Sopenharmony_ci ret = -errno; 548c2ecf20Sopenharmony_ci goto cleanup; 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci addrlen = sizeof(sa); 588c2ecf20Sopenharmony_ci if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) { 598c2ecf20Sopenharmony_ci ret = -errno; 608c2ecf20Sopenharmony_ci goto cleanup; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (addrlen != sizeof(sa)) { 648c2ecf20Sopenharmony_ci ret = -LIBBPF_ERRNO__INTERNAL; 658c2ecf20Sopenharmony_ci goto cleanup; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci *nl_pid = sa.nl_pid; 698c2ecf20Sopenharmony_ci return sock; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cicleanup: 728c2ecf20Sopenharmony_ci close(sock); 738c2ecf20Sopenharmony_ci return ret; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int bpf_netlink_recv(int sock, __u32 nl_pid, int seq, 778c2ecf20Sopenharmony_ci __dump_nlmsg_t _fn, libbpf_dump_nlmsg_t fn, 788c2ecf20Sopenharmony_ci void *cookie) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci bool multipart = true; 818c2ecf20Sopenharmony_ci struct nlmsgerr *err; 828c2ecf20Sopenharmony_ci struct nlmsghdr *nh; 838c2ecf20Sopenharmony_ci char buf[4096]; 848c2ecf20Sopenharmony_ci int len, ret; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci while (multipart) { 878c2ecf20Sopenharmony_ci multipart = false; 888c2ecf20Sopenharmony_ci len = recv(sock, buf, sizeof(buf), 0); 898c2ecf20Sopenharmony_ci if (len < 0) { 908c2ecf20Sopenharmony_ci ret = -errno; 918c2ecf20Sopenharmony_ci goto done; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (len == 0) 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); 988c2ecf20Sopenharmony_ci nh = NLMSG_NEXT(nh, len)) { 998c2ecf20Sopenharmony_ci if (nh->nlmsg_pid != nl_pid) { 1008c2ecf20Sopenharmony_ci ret = -LIBBPF_ERRNO__WRNGPID; 1018c2ecf20Sopenharmony_ci goto done; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci if (nh->nlmsg_seq != seq) { 1048c2ecf20Sopenharmony_ci ret = -LIBBPF_ERRNO__INVSEQ; 1058c2ecf20Sopenharmony_ci goto done; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci if (nh->nlmsg_flags & NLM_F_MULTI) 1088c2ecf20Sopenharmony_ci multipart = true; 1098c2ecf20Sopenharmony_ci switch (nh->nlmsg_type) { 1108c2ecf20Sopenharmony_ci case NLMSG_ERROR: 1118c2ecf20Sopenharmony_ci err = (struct nlmsgerr *)NLMSG_DATA(nh); 1128c2ecf20Sopenharmony_ci if (!err->error) 1138c2ecf20Sopenharmony_ci continue; 1148c2ecf20Sopenharmony_ci ret = err->error; 1158c2ecf20Sopenharmony_ci libbpf_nla_dump_errormsg(nh); 1168c2ecf20Sopenharmony_ci goto done; 1178c2ecf20Sopenharmony_ci case NLMSG_DONE: 1188c2ecf20Sopenharmony_ci return 0; 1198c2ecf20Sopenharmony_ci default: 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci if (_fn) { 1238c2ecf20Sopenharmony_ci ret = _fn(nh, fn, cookie); 1248c2ecf20Sopenharmony_ci if (ret) 1258c2ecf20Sopenharmony_ci return ret; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci ret = 0; 1308c2ecf20Sopenharmony_cidone: 1318c2ecf20Sopenharmony_ci return ret; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd, 1358c2ecf20Sopenharmony_ci __u32 flags) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci int sock, seq = 0, ret; 1388c2ecf20Sopenharmony_ci struct nlattr *nla, *nla_xdp; 1398c2ecf20Sopenharmony_ci struct { 1408c2ecf20Sopenharmony_ci struct nlmsghdr nh; 1418c2ecf20Sopenharmony_ci struct ifinfomsg ifinfo; 1428c2ecf20Sopenharmony_ci char attrbuf[64]; 1438c2ecf20Sopenharmony_ci } req; 1448c2ecf20Sopenharmony_ci __u32 nl_pid = 0; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci sock = libbpf_netlink_open(&nl_pid); 1478c2ecf20Sopenharmony_ci if (sock < 0) 1488c2ecf20Sopenharmony_ci return sock; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci memset(&req, 0, sizeof(req)); 1518c2ecf20Sopenharmony_ci req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 1528c2ecf20Sopenharmony_ci req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 1538c2ecf20Sopenharmony_ci req.nh.nlmsg_type = RTM_SETLINK; 1548c2ecf20Sopenharmony_ci req.nh.nlmsg_pid = 0; 1558c2ecf20Sopenharmony_ci req.nh.nlmsg_seq = ++seq; 1568c2ecf20Sopenharmony_ci req.ifinfo.ifi_family = AF_UNSPEC; 1578c2ecf20Sopenharmony_ci req.ifinfo.ifi_index = ifindex; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* started nested attribute for XDP */ 1608c2ecf20Sopenharmony_ci nla = (struct nlattr *)(((char *)&req) 1618c2ecf20Sopenharmony_ci + NLMSG_ALIGN(req.nh.nlmsg_len)); 1628c2ecf20Sopenharmony_ci nla->nla_type = NLA_F_NESTED | IFLA_XDP; 1638c2ecf20Sopenharmony_ci nla->nla_len = NLA_HDRLEN; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* add XDP fd */ 1668c2ecf20Sopenharmony_ci nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); 1678c2ecf20Sopenharmony_ci nla_xdp->nla_type = IFLA_XDP_FD; 1688c2ecf20Sopenharmony_ci nla_xdp->nla_len = NLA_HDRLEN + sizeof(int); 1698c2ecf20Sopenharmony_ci memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd)); 1708c2ecf20Sopenharmony_ci nla->nla_len += nla_xdp->nla_len; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci /* if user passed in any flags, add those too */ 1738c2ecf20Sopenharmony_ci if (flags) { 1748c2ecf20Sopenharmony_ci nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); 1758c2ecf20Sopenharmony_ci nla_xdp->nla_type = IFLA_XDP_FLAGS; 1768c2ecf20Sopenharmony_ci nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags); 1778c2ecf20Sopenharmony_ci memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags)); 1788c2ecf20Sopenharmony_ci nla->nla_len += nla_xdp->nla_len; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (flags & XDP_FLAGS_REPLACE) { 1828c2ecf20Sopenharmony_ci nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); 1838c2ecf20Sopenharmony_ci nla_xdp->nla_type = IFLA_XDP_EXPECTED_FD; 1848c2ecf20Sopenharmony_ci nla_xdp->nla_len = NLA_HDRLEN + sizeof(old_fd); 1858c2ecf20Sopenharmony_ci memcpy((char *)nla_xdp + NLA_HDRLEN, &old_fd, sizeof(old_fd)); 1868c2ecf20Sopenharmony_ci nla->nla_len += nla_xdp->nla_len; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) { 1928c2ecf20Sopenharmony_ci ret = -errno; 1938c2ecf20Sopenharmony_ci goto cleanup; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci ret = bpf_netlink_recv(sock, nl_pid, seq, NULL, NULL, NULL); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cicleanup: 1988c2ecf20Sopenharmony_ci close(sock); 1998c2ecf20Sopenharmony_ci return ret; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ciint bpf_set_link_xdp_fd_opts(int ifindex, int fd, __u32 flags, 2038c2ecf20Sopenharmony_ci const struct bpf_xdp_set_link_opts *opts) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci int old_fd = -1; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (!OPTS_VALID(opts, bpf_xdp_set_link_opts)) 2088c2ecf20Sopenharmony_ci return -EINVAL; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci if (OPTS_HAS(opts, old_fd)) { 2118c2ecf20Sopenharmony_ci old_fd = OPTS_GET(opts, old_fd, -1); 2128c2ecf20Sopenharmony_ci flags |= XDP_FLAGS_REPLACE; 2138c2ecf20Sopenharmony_ci } 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci return __bpf_set_link_xdp_fd_replace(ifindex, fd, 2168c2ecf20Sopenharmony_ci old_fd, 2178c2ecf20Sopenharmony_ci flags); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ciint bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci return __bpf_set_link_xdp_fd_replace(ifindex, fd, 0, flags); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int __dump_link_nlmsg(struct nlmsghdr *nlh, 2268c2ecf20Sopenharmony_ci libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct nlattr *tb[IFLA_MAX + 1], *attr; 2298c2ecf20Sopenharmony_ci struct ifinfomsg *ifi = NLMSG_DATA(nlh); 2308c2ecf20Sopenharmony_ci int len; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi)); 2338c2ecf20Sopenharmony_ci attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi))); 2348c2ecf20Sopenharmony_ci if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0) 2358c2ecf20Sopenharmony_ci return -LIBBPF_ERRNO__NLPARSE; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return dump_link_nlmsg(cookie, ifi, tb); 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int get_xdp_info(void *cookie, void *msg, struct nlattr **tb) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct nlattr *xdp_tb[IFLA_XDP_MAX + 1]; 2438c2ecf20Sopenharmony_ci struct xdp_id_md *xdp_id = cookie; 2448c2ecf20Sopenharmony_ci struct ifinfomsg *ifinfo = msg; 2458c2ecf20Sopenharmony_ci int ret; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (xdp_id->ifindex && xdp_id->ifindex != ifinfo->ifi_index) 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (!tb[IFLA_XDP]) 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci ret = libbpf_nla_parse_nested(xdp_tb, IFLA_XDP_MAX, tb[IFLA_XDP], NULL); 2548c2ecf20Sopenharmony_ci if (ret) 2558c2ecf20Sopenharmony_ci return ret; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (!xdp_tb[IFLA_XDP_ATTACHED]) 2588c2ecf20Sopenharmony_ci return 0; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci xdp_id->info.attach_mode = libbpf_nla_getattr_u8( 2618c2ecf20Sopenharmony_ci xdp_tb[IFLA_XDP_ATTACHED]); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (xdp_id->info.attach_mode == XDP_ATTACHED_NONE) 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (xdp_tb[IFLA_XDP_PROG_ID]) 2678c2ecf20Sopenharmony_ci xdp_id->info.prog_id = libbpf_nla_getattr_u32( 2688c2ecf20Sopenharmony_ci xdp_tb[IFLA_XDP_PROG_ID]); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (xdp_tb[IFLA_XDP_SKB_PROG_ID]) 2718c2ecf20Sopenharmony_ci xdp_id->info.skb_prog_id = libbpf_nla_getattr_u32( 2728c2ecf20Sopenharmony_ci xdp_tb[IFLA_XDP_SKB_PROG_ID]); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (xdp_tb[IFLA_XDP_DRV_PROG_ID]) 2758c2ecf20Sopenharmony_ci xdp_id->info.drv_prog_id = libbpf_nla_getattr_u32( 2768c2ecf20Sopenharmony_ci xdp_tb[IFLA_XDP_DRV_PROG_ID]); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (xdp_tb[IFLA_XDP_HW_PROG_ID]) 2798c2ecf20Sopenharmony_ci xdp_id->info.hw_prog_id = libbpf_nla_getattr_u32( 2808c2ecf20Sopenharmony_ci xdp_tb[IFLA_XDP_HW_PROG_ID]); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int libbpf_nl_get_link(int sock, unsigned int nl_pid, 2868c2ecf20Sopenharmony_ci libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ciint bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info, 2898c2ecf20Sopenharmony_ci size_t info_size, __u32 flags) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct xdp_id_md xdp_id = {}; 2928c2ecf20Sopenharmony_ci int sock, ret; 2938c2ecf20Sopenharmony_ci __u32 nl_pid = 0; 2948c2ecf20Sopenharmony_ci __u32 mask; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (flags & ~XDP_FLAGS_MASK || !info_size) 2978c2ecf20Sopenharmony_ci return -EINVAL; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* Check whether the single {HW,DRV,SKB} mode is set */ 3008c2ecf20Sopenharmony_ci flags &= (XDP_FLAGS_SKB_MODE | XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE); 3018c2ecf20Sopenharmony_ci mask = flags - 1; 3028c2ecf20Sopenharmony_ci if (flags && flags & mask) 3038c2ecf20Sopenharmony_ci return -EINVAL; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci sock = libbpf_netlink_open(&nl_pid); 3068c2ecf20Sopenharmony_ci if (sock < 0) 3078c2ecf20Sopenharmony_ci return sock; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci xdp_id.ifindex = ifindex; 3108c2ecf20Sopenharmony_ci xdp_id.flags = flags; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci ret = libbpf_nl_get_link(sock, nl_pid, get_xdp_info, &xdp_id); 3138c2ecf20Sopenharmony_ci if (!ret) { 3148c2ecf20Sopenharmony_ci size_t sz = min(info_size, sizeof(xdp_id.info)); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci memcpy(info, &xdp_id.info, sz); 3178c2ecf20Sopenharmony_ci memset((void *) info + sz, 0, info_size - sz); 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci close(sock); 3218c2ecf20Sopenharmony_ci return ret; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic __u32 get_xdp_id(struct xdp_link_info *info, __u32 flags) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci flags &= XDP_FLAGS_MODES; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (info->attach_mode != XDP_ATTACHED_MULTI && !flags) 3298c2ecf20Sopenharmony_ci return info->prog_id; 3308c2ecf20Sopenharmony_ci if (flags & XDP_FLAGS_DRV_MODE) 3318c2ecf20Sopenharmony_ci return info->drv_prog_id; 3328c2ecf20Sopenharmony_ci if (flags & XDP_FLAGS_HW_MODE) 3338c2ecf20Sopenharmony_ci return info->hw_prog_id; 3348c2ecf20Sopenharmony_ci if (flags & XDP_FLAGS_SKB_MODE) 3358c2ecf20Sopenharmony_ci return info->skb_prog_id; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ciint bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct xdp_link_info info; 3438c2ecf20Sopenharmony_ci int ret; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci ret = bpf_get_link_xdp_info(ifindex, &info, sizeof(info), flags); 3468c2ecf20Sopenharmony_ci if (!ret) 3478c2ecf20Sopenharmony_ci *prog_id = get_xdp_id(&info, flags); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return ret; 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ciint libbpf_nl_get_link(int sock, unsigned int nl_pid, 3538c2ecf20Sopenharmony_ci libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie) 3548c2ecf20Sopenharmony_ci{ 3558c2ecf20Sopenharmony_ci struct { 3568c2ecf20Sopenharmony_ci struct nlmsghdr nlh; 3578c2ecf20Sopenharmony_ci struct ifinfomsg ifm; 3588c2ecf20Sopenharmony_ci } req = { 3598c2ecf20Sopenharmony_ci .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), 3608c2ecf20Sopenharmony_ci .nlh.nlmsg_type = RTM_GETLINK, 3618c2ecf20Sopenharmony_ci .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, 3628c2ecf20Sopenharmony_ci .ifm.ifi_family = AF_PACKET, 3638c2ecf20Sopenharmony_ci }; 3648c2ecf20Sopenharmony_ci int seq = time(NULL); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci req.nlh.nlmsg_seq = seq; 3678c2ecf20Sopenharmony_ci if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0) 3688c2ecf20Sopenharmony_ci return -errno; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return bpf_netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg, 3718c2ecf20Sopenharmony_ci dump_link_nlmsg, cookie); 3728c2ecf20Sopenharmony_ci} 373