diff options
-rw-r--r-- | tools/lib/bpf/bpf.c | 122 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.c | 2 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.h | 4 |
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 | ||
51 | static inline __u64 ptr_to_u64(const void *ptr) | 59 | static 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 | |||
425 | int 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 | |||
534 | cleanup: | ||
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 | ||
111 | int libbpf_strerror(int err, char *buf, size_t size) | 113 | int 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 | ||
247 | int bpf_prog_load(const char *file, enum bpf_prog_type type, | 249 | int 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 | |||
252 | int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags); | ||
249 | #endif | 253 | #endif |