aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/lib/bpf/bpf.c122
-rw-r--r--tools/lib/bpf/libbpf.c2
-rw-r--r--tools/lib/bpf/libbpf.h4
3 files changed, 128 insertions, 0 deletions
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index 5128677e4117..bf2772566240 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -25,6 +25,12 @@
25#include <asm/unistd.h> 25#include <asm/unistd.h>
26#include <linux/bpf.h> 26#include <linux/bpf.h>
27#include "bpf.h" 27#include "bpf.h"
28#include "libbpf.h"
29#include "nlattr.h"
30#include <linux/rtnetlink.h>
31#include <linux/if_link.h>
32#include <sys/socket.h>
33#include <errno.h>
28 34
29/* 35/*
30 * When building perf, unistd.h is overridden. __NR_bpf is 36 * When building perf, unistd.h is overridden. __NR_bpf is
@@ -46,7 +52,9 @@
46# endif 52# endif
47#endif 53#endif
48 54
55#ifndef min
49#define min(x, y) ((x) < (y) ? (x) : (y)) 56#define min(x, y) ((x) < (y) ? (x) : (y))
57#endif
50 58
51static inline __u64 ptr_to_u64(const void *ptr) 59static inline __u64 ptr_to_u64(const void *ptr)
52{ 60{
@@ -413,3 +421,117 @@ int bpf_obj_get_info_by_fd(int prog_fd, void *info, __u32 *info_len)
413 421
414 return err; 422 return err;
415} 423}
424
425int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags)
426{
427 struct sockaddr_nl sa;
428 int sock, seq = 0, len, ret = -1;
429 char buf[4096];
430 struct nlattr *nla, *nla_xdp;
431 struct {
432 struct nlmsghdr nh;
433 struct ifinfomsg ifinfo;
434 char attrbuf[64];
435 } req;
436 struct nlmsghdr *nh;
437 struct nlmsgerr *err;
438 socklen_t addrlen;
439
440 memset(&sa, 0, sizeof(sa));
441 sa.nl_family = AF_NETLINK;
442
443 sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
444 if (sock < 0) {
445 return -errno;
446 }
447
448 if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) < 0) {
449 ret = -errno;
450 goto cleanup;
451 }
452
453 addrlen = sizeof(sa);
454 if (getsockname(sock, (struct sockaddr *)&sa, &addrlen) < 0) {
455 ret = -errno;
456 goto cleanup;
457 }
458
459 if (addrlen != sizeof(sa)) {
460 ret = -LIBBPF_ERRNO__INTERNAL;
461 goto cleanup;
462 }
463
464 memset(&req, 0, sizeof(req));
465 req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
466 req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
467 req.nh.nlmsg_type = RTM_SETLINK;
468 req.nh.nlmsg_pid = 0;
469 req.nh.nlmsg_seq = ++seq;
470 req.ifinfo.ifi_family = AF_UNSPEC;
471 req.ifinfo.ifi_index = ifindex;
472
473 /* started nested attribute for XDP */
474 nla = (struct nlattr *)(((char *)&req)
475 + NLMSG_ALIGN(req.nh.nlmsg_len));
476 nla->nla_type = NLA_F_NESTED | IFLA_XDP;
477 nla->nla_len = NLA_HDRLEN;
478
479 /* add XDP fd */
480 nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
481 nla_xdp->nla_type = IFLA_XDP_FD;
482 nla_xdp->nla_len = NLA_HDRLEN + sizeof(int);
483 memcpy((char *)nla_xdp + NLA_HDRLEN, &fd, sizeof(fd));
484 nla->nla_len += nla_xdp->nla_len;
485
486 /* if user passed in any flags, add those too */
487 if (flags) {
488 nla_xdp = (struct nlattr *)((char *)nla + nla->nla_len);
489 nla_xdp->nla_type = IFLA_XDP_FLAGS;
490 nla_xdp->nla_len = NLA_HDRLEN + sizeof(flags);
491 memcpy((char *)nla_xdp + NLA_HDRLEN, &flags, sizeof(flags));
492 nla->nla_len += nla_xdp->nla_len;
493 }
494
495 req.nh.nlmsg_len += NLA_ALIGN(nla->nla_len);
496
497 if (send(sock, &req, req.nh.nlmsg_len, 0) < 0) {
498 ret = -errno;
499 goto cleanup;
500 }
501
502 len = recv(sock, buf, sizeof(buf), 0);
503 if (len < 0) {
504 ret = -errno;
505 goto cleanup;
506 }
507
508 for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len);
509 nh = NLMSG_NEXT(nh, len)) {
510 if (nh->nlmsg_pid != sa.nl_pid) {
511 ret = -LIBBPF_ERRNO__WRNGPID;
512 goto cleanup;
513 }
514 if (nh->nlmsg_seq != seq) {
515 ret = -LIBBPF_ERRNO__INVSEQ;
516 goto cleanup;
517 }
518 switch (nh->nlmsg_type) {
519 case NLMSG_ERROR:
520 err = (struct nlmsgerr *)NLMSG_DATA(nh);
521 if (!err->error)
522 continue;
523 ret = err->error;
524 goto cleanup;
525 case NLMSG_DONE:
526 break;
527 default:
528 break;
529 }
530 }
531
532 ret = 0;
533
534cleanup:
535 close(sock);
536 return ret;
537}
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 30c776375118..c60122d3ea85 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -106,6 +106,8 @@ static const char *libbpf_strerror_table[NR_ERRNO] = {
106 [ERRCODE_OFFSET(PROG2BIG)] = "Program too big", 106 [ERRCODE_OFFSET(PROG2BIG)] = "Program too big",
107 [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version", 107 [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version",
108 [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type", 108 [ERRCODE_OFFSET(PROGTYPE)] = "Kernel doesn't support this program type",
109 [ERRCODE_OFFSET(WRNGPID)] = "Wrong pid in netlink message",
110 [ERRCODE_OFFSET(INVSEQ)] = "Invalid netlink sequence",
109}; 111};
110 112
111int libbpf_strerror(int err, char *buf, size_t size) 113int libbpf_strerror(int err, char *buf, size_t size)
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 6e20003109e0..e42f96900318 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -42,6 +42,8 @@ enum libbpf_errno {
42 LIBBPF_ERRNO__PROG2BIG, /* Program too big */ 42 LIBBPF_ERRNO__PROG2BIG, /* Program too big */
43 LIBBPF_ERRNO__KVER, /* Incorrect kernel version */ 43 LIBBPF_ERRNO__KVER, /* Incorrect kernel version */
44 LIBBPF_ERRNO__PROGTYPE, /* Kernel doesn't support this program type */ 44 LIBBPF_ERRNO__PROGTYPE, /* Kernel doesn't support this program type */
45 LIBBPF_ERRNO__WRNGPID, /* Wrong pid in netlink message */
46 LIBBPF_ERRNO__INVSEQ, /* Invalid netlink sequence */
45 __LIBBPF_ERRNO__END, 47 __LIBBPF_ERRNO__END,
46}; 48};
47 49
@@ -246,4 +248,6 @@ long libbpf_get_error(const void *ptr);
246 248
247int bpf_prog_load(const char *file, enum bpf_prog_type type, 249int bpf_prog_load(const char *file, enum bpf_prog_type type,
248 struct bpf_object **pobj, int *prog_fd); 250 struct bpf_object **pobj, int *prog_fd);
251
252int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);
249#endif 253#endif