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