^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* Copyright (c) 2018 Facebook */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <memory.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/bpf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/rtnetlink.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <sys/socket.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "bpf.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "libbpf.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "libbpf_internal.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "nlattr.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #ifndef SOL_NETLINK
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define SOL_NETLINK 270
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) typedef int (*libbpf_dump_nlmsg_t)(void *cookie, void *msg, struct nlattr **tb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, libbpf_dump_nlmsg_t,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) void *cookie);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct xdp_id_md {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) int ifindex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) __u32 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct xdp_link_info info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static int libbpf_netlink_open(__u32 *nl_pid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct sockaddr_nl sa;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) socklen_t addrlen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) int one = 1, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) int sock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) memset(&sa, 0, sizeof(sa));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) sa.nl_family = AF_NETLINK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) sock = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (sock < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return -errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) &one, sizeof(one)) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) pr_warn("Netlink error reporting not supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) ret = -errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) addrlen = sizeof(sa);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) ret = -errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (addrlen != sizeof(sa)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) ret = -LIBBPF_ERRNO__INTERNAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) *nl_pid = sa.nl_pid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return sock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) close(sock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) __dump_nlmsg_t _fn, libbpf_dump_nlmsg_t fn,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) void *cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) bool multipart = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct nlmsgerr *err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct nlmsghdr *nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) char buf[4096];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) int len, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) while (multipart) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) multipart = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) len = recv(sock, buf, sizeof(buf), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (len < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) ret = -errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (len == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) nh = NLMSG_NEXT(nh, len)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (nh->nlmsg_pid != nl_pid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) ret = -LIBBPF_ERRNO__WRNGPID;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (nh->nlmsg_seq != seq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) ret = -LIBBPF_ERRNO__INVSEQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) if (nh->nlmsg_flags & NLM_F_MULTI)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) multipart = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) switch (nh->nlmsg_type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) case NLMSG_ERROR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) err = (struct nlmsgerr *)NLMSG_DATA(nh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (!err->error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) ret = err->error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) libbpf_nla_dump_errormsg(nh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) case NLMSG_DONE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) if (_fn) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) ret = _fn(nh, fn, cookie);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) __u32 flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) int sock, seq = 0, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) struct nlattr *nla, *nla_xdp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) struct nlmsghdr nh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct ifinfomsg ifinfo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) char attrbuf[64];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) } req;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) __u32 nl_pid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) sock = libbpf_netlink_open(&nl_pid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (sock < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return sock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) memset(&req, 0, sizeof(req));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) req.nh.nlmsg_type = RTM_SETLINK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) req.nh.nlmsg_pid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) req.nh.nlmsg_seq = ++seq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) req.ifinfo.ifi_family = AF_UNSPEC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) req.ifinfo.ifi_index = ifindex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /* started nested attribute for XDP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) nla = (struct nlattr *)(((char *)&req)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) + NLMSG_ALIGN(req.nh.nlmsg_len));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) nla->nla_type = NLA_F_NESTED | IFLA_XDP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) nla->nla_len = NLA_HDRLEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /* add XDP fd */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) nla_xdp->nla_type = IFLA_XDP_FD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) nla->nla_len += nla_xdp->nla_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) /* if user passed in any flags, add those too */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (flags) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) nla_xdp->nla_type = IFLA_XDP_FLAGS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) nla->nla_len += nla_xdp->nla_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (flags & XDP_FLAGS_REPLACE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) nla_xdp->nla_type = IFLA_XDP_EXPECTED_FD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) nla_xdp->nla_len = NLA_HDRLEN + sizeof(old_fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) memcpy((char *)nla_xdp + NLA_HDRLEN, &old_fd, sizeof(old_fd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) nla->nla_len += nla_xdp->nla_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) ret = -errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) goto cleanup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) ret = bpf_netlink_recv(sock, nl_pid, seq, NULL, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) cleanup:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) close(sock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) int bpf_set_link_xdp_fd_opts(int ifindex, int fd, __u32 flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) const struct bpf_xdp_set_link_opts *opts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) int old_fd = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (!OPTS_VALID(opts, bpf_xdp_set_link_opts))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (OPTS_HAS(opts, old_fd)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) old_fd = OPTS_GET(opts, old_fd, -1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) flags |= XDP_FLAGS_REPLACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) return __bpf_set_link_xdp_fd_replace(ifindex, fd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) old_fd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return __bpf_set_link_xdp_fd_replace(ifindex, fd, 0, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) static int __dump_link_nlmsg(struct nlmsghdr *nlh,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) struct nlattr *tb[IFLA_MAX + 1], *attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) struct ifinfomsg *ifi = NLMSG_DATA(nlh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) len = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) attr = (struct nlattr *) ((void *) ifi + NLMSG_ALIGN(sizeof(*ifi)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (libbpf_nla_parse(tb, IFLA_MAX, attr, len, NULL) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return -LIBBPF_ERRNO__NLPARSE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return dump_link_nlmsg(cookie, ifi, tb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static int get_xdp_info(void *cookie, void *msg, struct nlattr **tb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) struct nlattr *xdp_tb[IFLA_XDP_MAX + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) struct xdp_id_md *xdp_id = cookie;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) struct ifinfomsg *ifinfo = msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (xdp_id->ifindex && xdp_id->ifindex != ifinfo->ifi_index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (!tb[IFLA_XDP])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) ret = libbpf_nla_parse_nested(xdp_tb, IFLA_XDP_MAX, tb[IFLA_XDP], NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (!xdp_tb[IFLA_XDP_ATTACHED])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) xdp_id->info.attach_mode = libbpf_nla_getattr_u8(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) xdp_tb[IFLA_XDP_ATTACHED]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (xdp_id->info.attach_mode == XDP_ATTACHED_NONE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (xdp_tb[IFLA_XDP_PROG_ID])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) xdp_id->info.prog_id = libbpf_nla_getattr_u32(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) xdp_tb[IFLA_XDP_PROG_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (xdp_tb[IFLA_XDP_SKB_PROG_ID])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) xdp_id->info.skb_prog_id = libbpf_nla_getattr_u32(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) xdp_tb[IFLA_XDP_SKB_PROG_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (xdp_tb[IFLA_XDP_DRV_PROG_ID])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) xdp_id->info.drv_prog_id = libbpf_nla_getattr_u32(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) xdp_tb[IFLA_XDP_DRV_PROG_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (xdp_tb[IFLA_XDP_HW_PROG_ID])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) xdp_id->info.hw_prog_id = libbpf_nla_getattr_u32(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) xdp_tb[IFLA_XDP_HW_PROG_ID]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) static int libbpf_nl_get_link(int sock, unsigned int nl_pid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) int bpf_get_link_xdp_info(int ifindex, struct xdp_link_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) size_t info_size, __u32 flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) struct xdp_id_md xdp_id = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) int sock, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) __u32 nl_pid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) __u32 mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (flags & ~XDP_FLAGS_MASK || !info_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) /* Check whether the single {HW,DRV,SKB} mode is set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) flags &= (XDP_FLAGS_SKB_MODE | XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) mask = flags - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (flags && flags & mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) sock = libbpf_netlink_open(&nl_pid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (sock < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) return sock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) xdp_id.ifindex = ifindex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) xdp_id.flags = flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) ret = libbpf_nl_get_link(sock, nl_pid, get_xdp_info, &xdp_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) size_t sz = min(info_size, sizeof(xdp_id.info));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) memcpy(info, &xdp_id.info, sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) memset((void *) info + sz, 0, info_size - sz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) close(sock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) static __u32 get_xdp_id(struct xdp_link_info *info, __u32 flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) flags &= XDP_FLAGS_MODES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (info->attach_mode != XDP_ATTACHED_MULTI && !flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) return info->prog_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (flags & XDP_FLAGS_DRV_MODE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) return info->drv_prog_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) if (flags & XDP_FLAGS_HW_MODE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) return info->hw_prog_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if (flags & XDP_FLAGS_SKB_MODE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) return info->skb_prog_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) struct xdp_link_info info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) ret = bpf_get_link_xdp_info(ifindex, &info, sizeof(info), flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) *prog_id = get_xdp_id(&info, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) int libbpf_nl_get_link(int sock, unsigned int nl_pid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) struct nlmsghdr nlh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) struct ifinfomsg ifm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) } req = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) .nlh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) .nlh.nlmsg_type = RTM_GETLINK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) .nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) .ifm.ifi_family = AF_PACKET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) int seq = time(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) req.nlh.nlmsg_seq = seq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) if (send(sock, &req, req.nlh.nlmsg_len, 0) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) return -errno;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) return bpf_netlink_recv(sock, nl_pid, seq, __dump_link_nlmsg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) dump_link_nlmsg, cookie);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) }