1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 /* Copyright (c) 2018 Facebook */
9 #include <linux/if_ether.h>
10 #include <linux/pkt_cls.h>
11 #include <linux/rtnetlink.h>
12 #include <linux/netdev.h>
13 #include <sys/socket.h>
19 #include "libbpf_internal.h"
23 #define SOL_NETLINK 270
26 typedef int (*libbpf_dump_nlmsg_t
)(void *cookie
, void *msg
, struct nlattr
**tb
);
28 typedef int (*__dump_nlmsg_t
)(struct nlmsghdr
*nlmsg
, libbpf_dump_nlmsg_t
,
31 struct xdp_link_info
{
42 struct xdp_link_info info
;
46 struct xdp_features_md
{
48 __u32 xdp_zc_max_segs
;
52 static int libbpf_netlink_open(__u32
*nl_pid
, int proto
)
54 struct sockaddr_nl sa
;
59 memset(&sa
, 0, sizeof(sa
));
60 sa
.nl_family
= AF_NETLINK
;
62 sock
= socket(AF_NETLINK
, SOCK_RAW
| SOCK_CLOEXEC
, proto
);
66 if (setsockopt(sock
, SOL_NETLINK
, NETLINK_EXT_ACK
,
67 &one
, sizeof(one
)) < 0) {
68 pr_warn("Netlink error reporting not supported\n");
71 if (bind(sock
, (struct sockaddr
*)&sa
, sizeof(sa
)) < 0) {
77 if (getsockname(sock
, (struct sockaddr
*)&sa
, &addrlen
) < 0) {
82 if (addrlen
!= sizeof(sa
)) {
83 ret
= -LIBBPF_ERRNO__INTERNAL
;
95 static void libbpf_netlink_close(int sock
)
106 static int netlink_recvmsg(int sock
, struct msghdr
*mhdr
, int flags
)
111 len
= recvmsg(sock
, mhdr
, flags
);
112 } while (len
< 0 && (errno
== EINTR
|| errno
== EAGAIN
));
119 static int alloc_iov(struct iovec
*iov
, int len
)
123 nbuf
= realloc(iov
->iov_base
, len
);
127 iov
->iov_base
= nbuf
;
132 static int libbpf_netlink_recv(int sock
, __u32 nl_pid
, int seq
,
133 __dump_nlmsg_t _fn
, libbpf_dump_nlmsg_t fn
,
136 struct iovec iov
= {};
137 struct msghdr mhdr
= {
141 bool multipart
= true;
142 struct nlmsgerr
*err
;
146 ret
= alloc_iov(&iov
, 4096);
153 len
= netlink_recvmsg(sock
, &mhdr
, MSG_PEEK
| MSG_TRUNC
);
159 if (len
> iov
.iov_len
) {
160 ret
= alloc_iov(&iov
, len
);
165 len
= netlink_recvmsg(sock
, &mhdr
, 0);
174 for (nh
= (struct nlmsghdr
*)iov
.iov_base
; NLMSG_OK(nh
, len
);
175 nh
= NLMSG_NEXT(nh
, len
)) {
176 if (nh
->nlmsg_pid
!= nl_pid
) {
177 ret
= -LIBBPF_ERRNO__WRNGPID
;
180 if (nh
->nlmsg_seq
!= seq
) {
181 ret
= -LIBBPF_ERRNO__INVSEQ
;
184 if (nh
->nlmsg_flags
& NLM_F_MULTI
)
186 switch (nh
->nlmsg_type
) {
188 err
= (struct nlmsgerr
*)NLMSG_DATA(nh
);
192 libbpf_nla_dump_errormsg(nh
);
201 ret
= _fn(nh
, fn
, cookie
);
222 static int libbpf_netlink_send_recv(struct libbpf_nla_req
*req
,
223 int proto
, __dump_nlmsg_t parse_msg
,
224 libbpf_dump_nlmsg_t parse_attr
,
230 sock
= libbpf_netlink_open(&nl_pid
, proto
);
234 req
->nh
.nlmsg_pid
= 0;
235 req
->nh
.nlmsg_seq
= time(NULL
);
237 if (send(sock
, req
, req
->nh
.nlmsg_len
, 0) < 0) {
242 ret
= libbpf_netlink_recv(sock
, nl_pid
, req
->nh
.nlmsg_seq
,
243 parse_msg
, parse_attr
, cookie
);
245 libbpf_netlink_close(sock
);
249 static int parse_genl_family_id(struct nlmsghdr
*nh
, libbpf_dump_nlmsg_t fn
,
252 struct genlmsghdr
*gnl
= NLMSG_DATA(nh
);
253 struct nlattr
*na
= (struct nlattr
*)((void *)gnl
+ GENL_HDRLEN
);
254 struct nlattr
*tb
[CTRL_ATTR_FAMILY_ID
+ 1];
257 libbpf_nla_parse(tb
, CTRL_ATTR_FAMILY_ID
, na
,
258 NLMSG_PAYLOAD(nh
, sizeof(*gnl
)), NULL
);
259 if (!tb
[CTRL_ATTR_FAMILY_ID
])
262 *id
= libbpf_nla_getattr_u16(tb
[CTRL_ATTR_FAMILY_ID
]);
266 static int libbpf_netlink_resolve_genl_family_id(const char *name
,
267 __u16 len
, __u16
*id
)
269 struct libbpf_nla_req req
= {
270 .nh
.nlmsg_len
= NLMSG_LENGTH(GENL_HDRLEN
),
271 .nh
.nlmsg_type
= GENL_ID_CTRL
,
272 .nh
.nlmsg_flags
= NLM_F_REQUEST
,
273 .gnl
.cmd
= CTRL_CMD_GETFAMILY
,
278 err
= nlattr_add(&req
, CTRL_ATTR_FAMILY_NAME
, name
, len
);
282 return libbpf_netlink_send_recv(&req
, NETLINK_GENERIC
,
283 parse_genl_family_id
, NULL
, id
);
286 static int __bpf_set_link_xdp_fd_replace(int ifindex
, int fd
, int old_fd
,
291 struct libbpf_nla_req req
;
293 memset(&req
, 0, sizeof(req
));
294 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
295 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
296 req
.nh
.nlmsg_type
= RTM_SETLINK
;
297 req
.ifinfo
.ifi_family
= AF_UNSPEC
;
298 req
.ifinfo
.ifi_index
= ifindex
;
300 nla
= nlattr_begin_nested(&req
, IFLA_XDP
);
303 ret
= nlattr_add(&req
, IFLA_XDP_FD
, &fd
, sizeof(fd
));
307 ret
= nlattr_add(&req
, IFLA_XDP_FLAGS
, &flags
, sizeof(flags
));
311 if (flags
& XDP_FLAGS_REPLACE
) {
312 ret
= nlattr_add(&req
, IFLA_XDP_EXPECTED_FD
, &old_fd
,
317 nlattr_end_nested(&req
, nla
);
319 return libbpf_netlink_send_recv(&req
, NETLINK_ROUTE
, NULL
, NULL
, NULL
);
322 int bpf_xdp_attach(int ifindex
, int prog_fd
, __u32 flags
, const struct bpf_xdp_attach_opts
*opts
)
324 int old_prog_fd
, err
;
326 if (!OPTS_VALID(opts
, bpf_xdp_attach_opts
))
327 return libbpf_err(-EINVAL
);
329 old_prog_fd
= OPTS_GET(opts
, old_prog_fd
, 0);
331 flags
|= XDP_FLAGS_REPLACE
;
335 err
= __bpf_set_link_xdp_fd_replace(ifindex
, prog_fd
, old_prog_fd
, flags
);
336 return libbpf_err(err
);
339 int bpf_xdp_detach(int ifindex
, __u32 flags
, const struct bpf_xdp_attach_opts
*opts
)
341 return bpf_xdp_attach(ifindex
, -1, flags
, opts
);
344 static int __dump_link_nlmsg(struct nlmsghdr
*nlh
,
345 libbpf_dump_nlmsg_t dump_link_nlmsg
, void *cookie
)
347 struct nlattr
*tb
[IFLA_MAX
+ 1], *attr
;
348 struct ifinfomsg
*ifi
= NLMSG_DATA(nlh
);
351 len
= nlh
->nlmsg_len
- NLMSG_LENGTH(sizeof(*ifi
));
352 attr
= (struct nlattr
*) ((void *) ifi
+ NLMSG_ALIGN(sizeof(*ifi
)));
354 if (libbpf_nla_parse(tb
, IFLA_MAX
, attr
, len
, NULL
) != 0)
355 return -LIBBPF_ERRNO__NLPARSE
;
357 return dump_link_nlmsg(cookie
, ifi
, tb
);
360 static int get_xdp_info(void *cookie
, void *msg
, struct nlattr
**tb
)
362 struct nlattr
*xdp_tb
[IFLA_XDP_MAX
+ 1];
363 struct xdp_id_md
*xdp_id
= cookie
;
364 struct ifinfomsg
*ifinfo
= msg
;
367 if (xdp_id
->ifindex
&& xdp_id
->ifindex
!= ifinfo
->ifi_index
)
373 ret
= libbpf_nla_parse_nested(xdp_tb
, IFLA_XDP_MAX
, tb
[IFLA_XDP
], NULL
);
377 if (!xdp_tb
[IFLA_XDP_ATTACHED
])
380 xdp_id
->info
.attach_mode
= libbpf_nla_getattr_u8(
381 xdp_tb
[IFLA_XDP_ATTACHED
]);
383 if (xdp_id
->info
.attach_mode
== XDP_ATTACHED_NONE
)
386 if (xdp_tb
[IFLA_XDP_PROG_ID
])
387 xdp_id
->info
.prog_id
= libbpf_nla_getattr_u32(
388 xdp_tb
[IFLA_XDP_PROG_ID
]);
390 if (xdp_tb
[IFLA_XDP_SKB_PROG_ID
])
391 xdp_id
->info
.skb_prog_id
= libbpf_nla_getattr_u32(
392 xdp_tb
[IFLA_XDP_SKB_PROG_ID
]);
394 if (xdp_tb
[IFLA_XDP_DRV_PROG_ID
])
395 xdp_id
->info
.drv_prog_id
= libbpf_nla_getattr_u32(
396 xdp_tb
[IFLA_XDP_DRV_PROG_ID
]);
398 if (xdp_tb
[IFLA_XDP_HW_PROG_ID
])
399 xdp_id
->info
.hw_prog_id
= libbpf_nla_getattr_u32(
400 xdp_tb
[IFLA_XDP_HW_PROG_ID
]);
405 static int parse_xdp_features(struct nlmsghdr
*nh
, libbpf_dump_nlmsg_t fn
,
408 struct genlmsghdr
*gnl
= NLMSG_DATA(nh
);
409 struct nlattr
*na
= (struct nlattr
*)((void *)gnl
+ GENL_HDRLEN
);
410 struct nlattr
*tb
[NETDEV_CMD_MAX
+ 1];
411 struct xdp_features_md
*md
= cookie
;
414 libbpf_nla_parse(tb
, NETDEV_CMD_MAX
, na
,
415 NLMSG_PAYLOAD(nh
, sizeof(*gnl
)), NULL
);
417 if (!tb
[NETDEV_A_DEV_IFINDEX
] || !tb
[NETDEV_A_DEV_XDP_FEATURES
])
420 ifindex
= libbpf_nla_getattr_u32(tb
[NETDEV_A_DEV_IFINDEX
]);
421 if (ifindex
!= md
->ifindex
)
424 md
->flags
= libbpf_nla_getattr_u64(tb
[NETDEV_A_DEV_XDP_FEATURES
]);
425 if (tb
[NETDEV_A_DEV_XDP_ZC_MAX_SEGS
])
426 md
->xdp_zc_max_segs
=
427 libbpf_nla_getattr_u32(tb
[NETDEV_A_DEV_XDP_ZC_MAX_SEGS
]);
431 int bpf_xdp_query(int ifindex
, int xdp_flags
, struct bpf_xdp_query_opts
*opts
)
433 struct libbpf_nla_req req
= {
434 .nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
435 .nh
.nlmsg_type
= RTM_GETLINK
,
436 .nh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
437 .ifinfo
.ifi_family
= AF_PACKET
,
439 struct xdp_id_md xdp_id
= {};
440 struct xdp_features_md md
= {
446 if (!OPTS_VALID(opts
, bpf_xdp_query_opts
))
447 return libbpf_err(-EINVAL
);
449 if (xdp_flags
& ~XDP_FLAGS_MASK
)
450 return libbpf_err(-EINVAL
);
452 /* Check whether the single {HW,DRV,SKB} mode is set */
453 xdp_flags
&= XDP_FLAGS_SKB_MODE
| XDP_FLAGS_DRV_MODE
| XDP_FLAGS_HW_MODE
;
454 if (xdp_flags
& (xdp_flags
- 1))
455 return libbpf_err(-EINVAL
);
457 xdp_id
.ifindex
= ifindex
;
458 xdp_id
.flags
= xdp_flags
;
460 err
= libbpf_netlink_send_recv(&req
, NETLINK_ROUTE
, __dump_link_nlmsg
,
461 get_xdp_info
, &xdp_id
);
463 return libbpf_err(err
);
465 OPTS_SET(opts
, prog_id
, xdp_id
.info
.prog_id
);
466 OPTS_SET(opts
, drv_prog_id
, xdp_id
.info
.drv_prog_id
);
467 OPTS_SET(opts
, hw_prog_id
, xdp_id
.info
.hw_prog_id
);
468 OPTS_SET(opts
, skb_prog_id
, xdp_id
.info
.skb_prog_id
);
469 OPTS_SET(opts
, attach_mode
, xdp_id
.info
.attach_mode
);
471 if (!OPTS_HAS(opts
, feature_flags
))
474 err
= libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id
);
476 if (err
== -ENOENT
) {
477 opts
->feature_flags
= 0;
478 goto skip_feature_flags
;
480 return libbpf_err(err
);
483 memset(&req
, 0, sizeof(req
));
484 req
.nh
.nlmsg_len
= NLMSG_LENGTH(GENL_HDRLEN
);
485 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
;
486 req
.nh
.nlmsg_type
= id
;
487 req
.gnl
.cmd
= NETDEV_CMD_DEV_GET
;
490 err
= nlattr_add(&req
, NETDEV_A_DEV_IFINDEX
, &ifindex
, sizeof(ifindex
));
492 return libbpf_err(err
);
494 err
= libbpf_netlink_send_recv(&req
, NETLINK_GENERIC
,
495 parse_xdp_features
, NULL
, &md
);
497 return libbpf_err(err
);
499 OPTS_SET(opts
, feature_flags
, md
.flags
);
500 OPTS_SET(opts
, xdp_zc_max_segs
, md
.xdp_zc_max_segs
);
506 int bpf_xdp_query_id(int ifindex
, int flags
, __u32
*prog_id
)
508 LIBBPF_OPTS(bpf_xdp_query_opts
, opts
);
511 ret
= bpf_xdp_query(ifindex
, flags
, &opts
);
513 return libbpf_err(ret
);
515 flags
&= XDP_FLAGS_MODES
;
517 if (opts
.attach_mode
!= XDP_ATTACHED_MULTI
&& !flags
)
518 *prog_id
= opts
.prog_id
;
519 else if (flags
& XDP_FLAGS_DRV_MODE
)
520 *prog_id
= opts
.drv_prog_id
;
521 else if (flags
& XDP_FLAGS_HW_MODE
)
522 *prog_id
= opts
.hw_prog_id
;
523 else if (flags
& XDP_FLAGS_SKB_MODE
)
524 *prog_id
= opts
.skb_prog_id
;
532 typedef int (*qdisc_config_t
)(struct libbpf_nla_req
*req
);
534 static int clsact_config(struct libbpf_nla_req
*req
)
536 req
->tc
.tcm_parent
= TC_H_CLSACT
;
537 req
->tc
.tcm_handle
= TC_H_MAKE(TC_H_CLSACT
, 0);
539 return nlattr_add(req
, TCA_KIND
, "clsact", sizeof("clsact"));
542 static int attach_point_to_config(struct bpf_tc_hook
*hook
,
543 qdisc_config_t
*config
)
545 switch (OPTS_GET(hook
, attach_point
, 0)) {
548 case BPF_TC_INGRESS
| BPF_TC_EGRESS
:
549 if (OPTS_GET(hook
, parent
, 0))
551 *config
= &clsact_config
;
560 static int tc_get_tcm_parent(enum bpf_tc_attach_point attach_point
,
563 switch (attach_point
) {
568 *parent
= TC_H_MAKE(TC_H_CLSACT
,
569 attach_point
== BPF_TC_INGRESS
?
570 TC_H_MIN_INGRESS
: TC_H_MIN_EGRESS
);
582 static int tc_qdisc_modify(struct bpf_tc_hook
*hook
, int cmd
, int flags
)
584 qdisc_config_t config
;
586 struct libbpf_nla_req req
;
588 ret
= attach_point_to_config(hook
, &config
);
592 memset(&req
, 0, sizeof(req
));
593 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct tcmsg
));
594 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
| flags
;
595 req
.nh
.nlmsg_type
= cmd
;
596 req
.tc
.tcm_family
= AF_UNSPEC
;
597 req
.tc
.tcm_ifindex
= OPTS_GET(hook
, ifindex
, 0);
603 return libbpf_netlink_send_recv(&req
, NETLINK_ROUTE
, NULL
, NULL
, NULL
);
606 static int tc_qdisc_create_excl(struct bpf_tc_hook
*hook
)
608 return tc_qdisc_modify(hook
, RTM_NEWQDISC
, NLM_F_CREATE
| NLM_F_EXCL
);
611 static int tc_qdisc_delete(struct bpf_tc_hook
*hook
)
613 return tc_qdisc_modify(hook
, RTM_DELQDISC
, 0);
616 int bpf_tc_hook_create(struct bpf_tc_hook
*hook
)
620 if (!hook
|| !OPTS_VALID(hook
, bpf_tc_hook
) ||
621 OPTS_GET(hook
, ifindex
, 0) <= 0)
622 return libbpf_err(-EINVAL
);
624 ret
= tc_qdisc_create_excl(hook
);
625 return libbpf_err(ret
);
628 static int __bpf_tc_detach(const struct bpf_tc_hook
*hook
,
629 const struct bpf_tc_opts
*opts
,
632 int bpf_tc_hook_destroy(struct bpf_tc_hook
*hook
)
634 if (!hook
|| !OPTS_VALID(hook
, bpf_tc_hook
) ||
635 OPTS_GET(hook
, ifindex
, 0) <= 0)
636 return libbpf_err(-EINVAL
);
638 switch (OPTS_GET(hook
, attach_point
, 0)) {
641 return libbpf_err(__bpf_tc_detach(hook
, NULL
, true));
642 case BPF_TC_INGRESS
| BPF_TC_EGRESS
:
643 return libbpf_err(tc_qdisc_delete(hook
));
645 return libbpf_err(-EOPNOTSUPP
);
647 return libbpf_err(-EINVAL
);
652 struct bpf_tc_opts
*opts
;
656 static int __get_tc_info(void *cookie
, struct tcmsg
*tc
, struct nlattr
**tb
,
659 struct nlattr
*tbb
[TCA_BPF_MAX
+ 1];
660 struct bpf_cb_ctx
*info
= cookie
;
662 if (!info
|| !info
->opts
)
664 if (unicast
&& info
->processed
)
666 if (!tb
[TCA_OPTIONS
])
669 libbpf_nla_parse_nested(tbb
, TCA_BPF_MAX
, tb
[TCA_OPTIONS
], NULL
);
670 if (!tbb
[TCA_BPF_ID
])
673 OPTS_SET(info
->opts
, prog_id
, libbpf_nla_getattr_u32(tbb
[TCA_BPF_ID
]));
674 OPTS_SET(info
->opts
, handle
, tc
->tcm_handle
);
675 OPTS_SET(info
->opts
, priority
, TC_H_MAJ(tc
->tcm_info
) >> 16);
677 info
->processed
= true;
678 return unicast
? NL_NEXT
: NL_DONE
;
681 static int get_tc_info(struct nlmsghdr
*nh
, libbpf_dump_nlmsg_t fn
,
684 struct tcmsg
*tc
= NLMSG_DATA(nh
);
685 struct nlattr
*tb
[TCA_MAX
+ 1];
687 libbpf_nla_parse(tb
, TCA_MAX
,
688 (struct nlattr
*)((void *)tc
+ NLMSG_ALIGN(sizeof(*tc
))),
689 NLMSG_PAYLOAD(nh
, sizeof(*tc
)), NULL
);
692 return __get_tc_info(cookie
, tc
, tb
, nh
->nlmsg_flags
& NLM_F_ECHO
);
695 static int tc_add_fd_and_name(struct libbpf_nla_req
*req
, int fd
)
697 struct bpf_prog_info info
;
698 __u32 info_len
= sizeof(info
);
702 memset(&info
, 0, info_len
);
703 ret
= bpf_prog_get_info_by_fd(fd
, &info
, &info_len
);
707 ret
= nlattr_add(req
, TCA_BPF_FD
, &fd
, sizeof(fd
));
710 len
= snprintf(name
, sizeof(name
), "%s:[%u]", info
.name
, info
.id
);
713 if (len
>= sizeof(name
))
714 return -ENAMETOOLONG
;
715 return nlattr_add(req
, TCA_BPF_NAME
, name
, len
+ 1);
718 int bpf_tc_attach(const struct bpf_tc_hook
*hook
, struct bpf_tc_opts
*opts
)
720 __u32 protocol
, bpf_flags
, handle
, priority
, parent
, prog_id
, flags
;
721 int ret
, ifindex
, attach_point
, prog_fd
;
722 struct bpf_cb_ctx info
= {};
723 struct libbpf_nla_req req
;
726 if (!hook
|| !opts
||
727 !OPTS_VALID(hook
, bpf_tc_hook
) ||
728 !OPTS_VALID(opts
, bpf_tc_opts
))
729 return libbpf_err(-EINVAL
);
731 ifindex
= OPTS_GET(hook
, ifindex
, 0);
732 parent
= OPTS_GET(hook
, parent
, 0);
733 attach_point
= OPTS_GET(hook
, attach_point
, 0);
735 handle
= OPTS_GET(opts
, handle
, 0);
736 priority
= OPTS_GET(opts
, priority
, 0);
737 prog_fd
= OPTS_GET(opts
, prog_fd
, 0);
738 prog_id
= OPTS_GET(opts
, prog_id
, 0);
739 flags
= OPTS_GET(opts
, flags
, 0);
741 if (ifindex
<= 0 || !prog_fd
|| prog_id
)
742 return libbpf_err(-EINVAL
);
743 if (priority
> UINT16_MAX
)
744 return libbpf_err(-EINVAL
);
745 if (flags
& ~BPF_TC_F_REPLACE
)
746 return libbpf_err(-EINVAL
);
748 flags
= (flags
& BPF_TC_F_REPLACE
) ? NLM_F_REPLACE
: NLM_F_EXCL
;
749 protocol
= ETH_P_ALL
;
751 memset(&req
, 0, sizeof(req
));
752 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct tcmsg
));
753 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_CREATE
|
755 req
.nh
.nlmsg_type
= RTM_NEWTFILTER
;
756 req
.tc
.tcm_family
= AF_UNSPEC
;
757 req
.tc
.tcm_ifindex
= ifindex
;
758 req
.tc
.tcm_handle
= handle
;
759 req
.tc
.tcm_info
= TC_H_MAKE(priority
<< 16, htons(protocol
));
761 ret
= tc_get_tcm_parent(attach_point
, &parent
);
763 return libbpf_err(ret
);
764 req
.tc
.tcm_parent
= parent
;
766 ret
= nlattr_add(&req
, TCA_KIND
, "bpf", sizeof("bpf"));
768 return libbpf_err(ret
);
769 nla
= nlattr_begin_nested(&req
, TCA_OPTIONS
);
771 return libbpf_err(-EMSGSIZE
);
772 ret
= tc_add_fd_and_name(&req
, prog_fd
);
774 return libbpf_err(ret
);
775 bpf_flags
= TCA_BPF_FLAG_ACT_DIRECT
;
776 ret
= nlattr_add(&req
, TCA_BPF_FLAGS
, &bpf_flags
, sizeof(bpf_flags
));
778 return libbpf_err(ret
);
779 nlattr_end_nested(&req
, nla
);
783 ret
= libbpf_netlink_send_recv(&req
, NETLINK_ROUTE
, get_tc_info
, NULL
,
786 return libbpf_err(ret
);
788 return libbpf_err(-ENOENT
);
792 static int __bpf_tc_detach(const struct bpf_tc_hook
*hook
,
793 const struct bpf_tc_opts
*opts
,
796 __u32 protocol
= 0, handle
, priority
, parent
, prog_id
, flags
;
797 int ret
, ifindex
, attach_point
, prog_fd
;
798 struct libbpf_nla_req req
;
801 !OPTS_VALID(hook
, bpf_tc_hook
) ||
802 !OPTS_VALID(opts
, bpf_tc_opts
))
805 ifindex
= OPTS_GET(hook
, ifindex
, 0);
806 parent
= OPTS_GET(hook
, parent
, 0);
807 attach_point
= OPTS_GET(hook
, attach_point
, 0);
809 handle
= OPTS_GET(opts
, handle
, 0);
810 priority
= OPTS_GET(opts
, priority
, 0);
811 prog_fd
= OPTS_GET(opts
, prog_fd
, 0);
812 prog_id
= OPTS_GET(opts
, prog_id
, 0);
813 flags
= OPTS_GET(opts
, flags
, 0);
815 if (ifindex
<= 0 || flags
|| prog_fd
|| prog_id
)
817 if (priority
> UINT16_MAX
)
820 if (!handle
|| !priority
)
822 protocol
= ETH_P_ALL
;
824 if (handle
|| priority
)
828 memset(&req
, 0, sizeof(req
));
829 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct tcmsg
));
830 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
831 req
.nh
.nlmsg_type
= RTM_DELTFILTER
;
832 req
.tc
.tcm_family
= AF_UNSPEC
;
833 req
.tc
.tcm_ifindex
= ifindex
;
835 req
.tc
.tcm_handle
= handle
;
836 req
.tc
.tcm_info
= TC_H_MAKE(priority
<< 16, htons(protocol
));
839 ret
= tc_get_tcm_parent(attach_point
, &parent
);
842 req
.tc
.tcm_parent
= parent
;
845 ret
= nlattr_add(&req
, TCA_KIND
, "bpf", sizeof("bpf"));
850 return libbpf_netlink_send_recv(&req
, NETLINK_ROUTE
, NULL
, NULL
, NULL
);
853 int bpf_tc_detach(const struct bpf_tc_hook
*hook
,
854 const struct bpf_tc_opts
*opts
)
859 return libbpf_err(-EINVAL
);
861 ret
= __bpf_tc_detach(hook
, opts
, false);
862 return libbpf_err(ret
);
865 int bpf_tc_query(const struct bpf_tc_hook
*hook
, struct bpf_tc_opts
*opts
)
867 __u32 protocol
, handle
, priority
, parent
, prog_id
, flags
;
868 int ret
, ifindex
, attach_point
, prog_fd
;
869 struct bpf_cb_ctx info
= {};
870 struct libbpf_nla_req req
;
872 if (!hook
|| !opts
||
873 !OPTS_VALID(hook
, bpf_tc_hook
) ||
874 !OPTS_VALID(opts
, bpf_tc_opts
))
875 return libbpf_err(-EINVAL
);
877 ifindex
= OPTS_GET(hook
, ifindex
, 0);
878 parent
= OPTS_GET(hook
, parent
, 0);
879 attach_point
= OPTS_GET(hook
, attach_point
, 0);
881 handle
= OPTS_GET(opts
, handle
, 0);
882 priority
= OPTS_GET(opts
, priority
, 0);
883 prog_fd
= OPTS_GET(opts
, prog_fd
, 0);
884 prog_id
= OPTS_GET(opts
, prog_id
, 0);
885 flags
= OPTS_GET(opts
, flags
, 0);
887 if (ifindex
<= 0 || flags
|| prog_fd
|| prog_id
||
888 !handle
|| !priority
)
889 return libbpf_err(-EINVAL
);
890 if (priority
> UINT16_MAX
)
891 return libbpf_err(-EINVAL
);
893 protocol
= ETH_P_ALL
;
895 memset(&req
, 0, sizeof(req
));
896 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct tcmsg
));
897 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
;
898 req
.nh
.nlmsg_type
= RTM_GETTFILTER
;
899 req
.tc
.tcm_family
= AF_UNSPEC
;
900 req
.tc
.tcm_ifindex
= ifindex
;
901 req
.tc
.tcm_handle
= handle
;
902 req
.tc
.tcm_info
= TC_H_MAKE(priority
<< 16, htons(protocol
));
904 ret
= tc_get_tcm_parent(attach_point
, &parent
);
906 return libbpf_err(ret
);
907 req
.tc
.tcm_parent
= parent
;
909 ret
= nlattr_add(&req
, TCA_KIND
, "bpf", sizeof("bpf"));
911 return libbpf_err(ret
);
915 ret
= libbpf_netlink_send_recv(&req
, NETLINK_ROUTE
, get_tc_info
, NULL
,
918 return libbpf_err(ret
);
920 return libbpf_err(-ENOENT
);