1f7010770SYonghong Song // SPDX-License-Identifier: LGPL-2.1 2f7010770SYonghong Song /* Copyright (c) 2018 Facebook */ 3f7010770SYonghong Song 4f7010770SYonghong Song #include <stdlib.h> 5f7010770SYonghong Song #include <memory.h> 6f7010770SYonghong Song #include <unistd.h> 7f7010770SYonghong Song #include <linux/bpf.h> 8f7010770SYonghong Song #include <linux/rtnetlink.h> 9f7010770SYonghong Song #include <sys/socket.h> 10f7010770SYonghong Song #include <errno.h> 11f7010770SYonghong Song #include <time.h> 12f7010770SYonghong Song 13f7010770SYonghong Song #include "bpf.h" 14f7010770SYonghong Song #include "libbpf.h" 15f7010770SYonghong Song #include "nlattr.h" 16f7010770SYonghong Song 17f7010770SYonghong Song #ifndef SOL_NETLINK 18f7010770SYonghong Song #define SOL_NETLINK 270 19f7010770SYonghong Song #endif 20f7010770SYonghong Song 21f7010770SYonghong Song static int bpf_netlink_open(__u32 *nl_pid) 22f7010770SYonghong Song { 23f7010770SYonghong Song struct sockaddr_nl sa; 24f7010770SYonghong Song socklen_t addrlen; 25f7010770SYonghong Song int one = 1, ret; 26f7010770SYonghong Song int sock; 27f7010770SYonghong Song 28f7010770SYonghong Song memset(&sa, 0, sizeof(sa)); 29f7010770SYonghong Song sa.nl_family = AF_NETLINK; 30f7010770SYonghong Song 31f7010770SYonghong Song sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 32f7010770SYonghong Song if (sock < 0) 33f7010770SYonghong Song return -errno; 34f7010770SYonghong Song 35f7010770SYonghong Song if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK, 36f7010770SYonghong Song &one, sizeof(one)) < 0) { 37f7010770SYonghong Song fprintf(stderr, "Netlink error reporting not supported\n"); 38f7010770SYonghong Song } 39f7010770SYonghong Song 40f7010770SYonghong Song if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) { 41f7010770SYonghong Song ret = -errno; 42f7010770SYonghong Song goto cleanup; 43f7010770SYonghong Song } 44f7010770SYonghong Song 45f7010770SYonghong Song addrlen = sizeof(sa); 46f7010770SYonghong Song if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) { 47f7010770SYonghong Song ret = -errno; 48f7010770SYonghong Song goto cleanup; 49f7010770SYonghong Song } 50f7010770SYonghong Song 51f7010770SYonghong Song if (addrlen != sizeof(sa)) { 52f7010770SYonghong Song ret = -LIBBPF_ERRNO__INTERNAL; 53f7010770SYonghong Song goto cleanup; 54f7010770SYonghong Song } 55f7010770SYonghong Song 56f7010770SYonghong Song *nl_pid = sa.nl_pid; 57f7010770SYonghong Song return sock; 58f7010770SYonghong Song 59f7010770SYonghong Song cleanup: 60f7010770SYonghong Song close(sock); 61f7010770SYonghong Song return ret; 62f7010770SYonghong Song } 63f7010770SYonghong Song 64f7010770SYonghong Song static int bpf_netlink_recv(int sock, __u32 nl_pid, int seq) 65f7010770SYonghong Song { 66f7010770SYonghong Song struct nlmsgerr *err; 67f7010770SYonghong Song struct nlmsghdr *nh; 68f7010770SYonghong Song char buf[4096]; 69f7010770SYonghong Song int len, ret; 70f7010770SYonghong Song 71f7010770SYonghong Song while (1) { 72f7010770SYonghong Song len = recv(sock, buf, sizeof(buf), 0); 73f7010770SYonghong Song if (len < 0) { 74f7010770SYonghong Song ret = -errno; 75f7010770SYonghong Song goto done; 76f7010770SYonghong Song } 77f7010770SYonghong Song 78f7010770SYonghong Song for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); 79f7010770SYonghong Song nh = NLMSG_NEXT(nh, len)) { 80f7010770SYonghong Song if (nh->nlmsg_pid != nl_pid) { 81f7010770SYonghong Song ret = -LIBBPF_ERRNO__WRNGPID; 82f7010770SYonghong Song goto done; 83f7010770SYonghong Song } 84f7010770SYonghong Song if (nh->nlmsg_seq != seq) { 85f7010770SYonghong Song ret = -LIBBPF_ERRNO__INVSEQ; 86f7010770SYonghong Song goto done; 87f7010770SYonghong Song } 88f7010770SYonghong Song switch (nh->nlmsg_type) { 89f7010770SYonghong Song case NLMSG_ERROR: 90f7010770SYonghong Song err = (struct nlmsgerr *)NLMSG_DATA(nh); 91f7010770SYonghong Song if (!err->error) 92f7010770SYonghong Song continue; 93f7010770SYonghong Song ret = err->error; 94f7010770SYonghong Song nla_dump_errormsg(nh); 95f7010770SYonghong Song goto done; 96f7010770SYonghong Song case NLMSG_DONE: 97f7010770SYonghong Song return 0; 98f7010770SYonghong Song default: 99f7010770SYonghong Song break; 100f7010770SYonghong Song } 101f7010770SYonghong Song } 102f7010770SYonghong Song } 103f7010770SYonghong Song ret = 0; 104f7010770SYonghong Song done: 105f7010770SYonghong Song return ret; 106f7010770SYonghong Song } 107f7010770SYonghong Song 108f7010770SYonghong Song int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags) 109f7010770SYonghong Song { 110f7010770SYonghong Song int sock, seq = 0, ret; 111f7010770SYonghong Song struct nlattr *nla, *nla_xdp; 112f7010770SYonghong Song struct { 113f7010770SYonghong Song struct nlmsghdr nh; 114f7010770SYonghong Song struct ifinfomsg ifinfo; 115f7010770SYonghong Song char attrbuf[64]; 116f7010770SYonghong Song } req; 117f7010770SYonghong Song __u32 nl_pid; 118f7010770SYonghong Song 119f7010770SYonghong Song sock = bpf_netlink_open(&nl_pid); 120f7010770SYonghong Song if (sock < 0) 121f7010770SYonghong Song return sock; 122f7010770SYonghong Song 123f7010770SYonghong Song memset(&req, 0, sizeof(req)); 124f7010770SYonghong Song req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 125f7010770SYonghong Song req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 126f7010770SYonghong Song req.nh.nlmsg_type = RTM_SETLINK; 127f7010770SYonghong Song req.nh.nlmsg_pid = 0; 128f7010770SYonghong Song req.nh.nlmsg_seq = ++seq; 129f7010770SYonghong Song req.ifinfo.ifi_family = AF_UNSPEC; 130f7010770SYonghong Song req.ifinfo.ifi_index = ifindex; 131f7010770SYonghong Song 132f7010770SYonghong Song /* started nested attribute for XDP */ 133f7010770SYonghong Song nla = (struct nlattr *)(((char *)&req) 134f7010770SYonghong Song + NLMSG_ALIGN(req.nh.nlmsg_len)); 135f7010770SYonghong Song nla->nla_type = NLA_F_NESTED | IFLA_XDP; 136f7010770SYonghong Song nla->nla_len = NLA_HDRLEN; 137f7010770SYonghong Song 138f7010770SYonghong Song /* add XDP fd */ 139f7010770SYonghong Song nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); 140f7010770SYonghong Song nla_xdp->nla_type = IFLA_XDP_FD; 141f7010770SYonghong Song nla_xdp->nla_len = NLA_HDRLEN + sizeof(int); 142f7010770SYonghong Song memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd)); 143f7010770SYonghong Song nla->nla_len += nla_xdp->nla_len; 144f7010770SYonghong Song 145f7010770SYonghong Song /* if user passed in any flags, add those too */ 146f7010770SYonghong Song if (flags) { 147f7010770SYonghong Song nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len); 148f7010770SYonghong Song nla_xdp->nla_type = IFLA_XDP_FLAGS; 149f7010770SYonghong Song nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags); 150f7010770SYonghong Song memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags)); 151f7010770SYonghong Song nla->nla_len += nla_xdp->nla_len; 152f7010770SYonghong Song } 153f7010770SYonghong Song 154f7010770SYonghong Song req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len); 155f7010770SYonghong Song 156f7010770SYonghong Song if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) { 157f7010770SYonghong Song ret = -errno; 158f7010770SYonghong Song goto cleanup; 159f7010770SYonghong Song } 160f7010770SYonghong Song ret = bpf_netlink_recv(sock, nl_pid, seq); 161f7010770SYonghong Song 162f7010770SYonghong Song cleanup: 163f7010770SYonghong Song close(sock); 164f7010770SYonghong Song return ret; 165f7010770SYonghong Song } 166