aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/bpf/bpf.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lib/bpf/bpf.c')
-rw-r--r--tools/lib/bpf/bpf.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 5128677e4117..592a58a2b681 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -1,3 +1,5 @@
1// SPDX-License-Identifier: LGPL-2.1
2
1/* 3/*
2 * common eBPF ELF operations. 4 * common eBPF ELF operations.
3 * 5 *
@@ -25,6 +27,16 @@
25#include <asm/unistd.h> 27#include <asm/unistd.h>
26#include <linux/bpf.h> 28#include <linux/bpf.h>
27#include "bpf.h" 29#include "bpf.h"
30#include "libbpf.h"
31#include "nlattr.h"
32#include <linux/rtnetlink.h>
33#include <linux/if_link.h>
34#include <sys/socket.h>
35#include <errno.h>
36
37#ifndef SOL_NETLINK
38#define SOL_NETLINK 270
39#endif
28 40
29/* 41/*
30 * When building perf, unistd.h is overridden. __NR_bpf is 42 * When building perf, unistd.h is overridden. __NR_bpf is
@@ -46,7 +58,9 @@
46# endif 58# endif
47#endif 59#endif
48 60
61#ifndef min
49#define min(x, y) ((x) < (y) ? (x) : (y)) 62#define min(x, y) ((x) < (y) ? (x) : (y))
63#endif
50 64
51static inline __u64 ptr_to_u64(const void *ptr) 65static inline __u64 ptr_to_u64(const void *ptr)
52{ 66{
@@ -413,3 +427,124 @@ int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len)
413 427
414 return err; 428 return err;
415} 429}
430
431int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
432{
433 struct sockaddr_nl sa;
434 int sock, seq = 0, len, ret = -1;
435 char buf[4096];
436 struct nlattr *nla, *nla_xdp;
437 struct {
438 struct nlmsghdr nh;
439 struct ifinfomsg ifinfo;
440 char attrbuf[64];
441 } req;
442 struct nlmsghdr *nh;
443 struct nlmsgerr *err;
444 socklen_t addrlen;
445 int one = 1;
446
447 memset(&sa, 0, sizeof(sa));
448 sa.nl_family = AF_NETLINK;
449
450 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
451 if (sock < 0) {
452 return -errno;
453 }
454
455 if (setsockopt(sock, SOL_NETLINK, NETLINK_EXT_ACK,
456 &one, sizeof(one)) < 0) {
457 fprintf(stderr, "Netlink error reporting not supported\n");
458 }
459
460 if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
461 ret = -errno;
462 goto cleanup;
463 }
464
465 addrlen = sizeof(sa);
466 if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) {
467 ret = -errno;
468 goto cleanup;
469 }
470
471 if (addrlen != sizeof(sa)) {
472 ret = -LIBBPF_ERRNO__INTERNAL;
473 goto cleanup;
474 }
475
476 memset(&req, 0, sizeof(req));
477 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
478 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
479 req.nh.nlmsg_type = RTM_SETLINK;
480 req.nh.nlmsg_pid = 0;
481 req.nh.nlmsg_seq = ++seq;
482 req.ifinfo.ifi_family = AF_UNSPEC;
483 req.ifinfo.ifi_index = ifindex;
484
485 /* started nested attribute for XDP */
486 nla = (struct nlattr *)(((char *)&req)
487 + NLMSG_ALIGN(req.nh.nlmsg_len));
488 nla->nla_type = NLA_F_NESTED | IFLA_XDP;
489 nla->nla_len = NLA_HDRLEN;
490
491 /* add XDP fd */
492 nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
493 nla_xdp->nla_type = IFLA_XDP_FD;
494 nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
495 memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
496 nla->nla_len += nla_xdp->nla_len;
497
498 /* if user passed in any flags, add those too */
499 if (flags) {
500 nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
501 nla_xdp->nla_type = IFLA_XDP_FLAGS;
502 nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
503 memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
504 nla->nla_len += nla_xdp->nla_len;
505 }
506
507 req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
508
509 if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
510 ret = -errno;
511 goto cleanup;
512 }
513
514 len = recv(sock, buf, sizeof(buf), 0);
515 if (len < 0) {
516 ret = -errno;
517 goto cleanup;
518 }
519
520 for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
521 nh = NLMSG_NEXT(nh, len)) {
522 if (nh->nlmsg_pid != sa.nl_pid) {
523 ret = -LIBBPF_ERRNO__WRNGPID;
524 goto cleanup;
525 }
526 if (nh->nlmsg_seq != seq) {
527 ret = -LIBBPF_ERRNO__INVSEQ;
528 goto cleanup;
529 }
530 switch (nh->nlmsg_type) {
531 case NLMSG_ERROR:
532 err = (struct nlmsgerr *)NLMSG_DATA(nh);
533 if (!err->error)
534 continue;
535 ret = err->error;
536 nla_dump_errormsg(nh);
537 goto cleanup;
538 case NLMSG_DONE:
539 break;
540 default:
541 break;
542 }
543 }
544
545 ret = 0;
546
547cleanup:
548 close(sock);
549 return ret;
550}