1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 /* Copyright (c) 2018 Facebook */
8 #include <linux/rtnetlink.h>
9 #include <sys/socket.h>
15 #include "libbpf_internal.h"
18 /* make sure libbpf doesn't use kernel-only integer typedefs */
19 #pragma GCC poison u8 u16 u32 u64 s8 s16 s32 s64
22 #define SOL_NETLINK 270
25 typedef int (*__dump_nlmsg_t
)(struct nlmsghdr
*nlmsg
, libbpf_dump_nlmsg_t
,
31 struct xdp_link_info info
;
34 int libbpf_netlink_open(__u32
*nl_pid
)
36 struct sockaddr_nl sa
;
41 memset(&sa
, 0, sizeof(sa
));
42 sa
.nl_family
= AF_NETLINK
;
44 sock
= socket(AF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
48 if (setsockopt(sock
, SOL_NETLINK
, NETLINK_EXT_ACK
,
49 &one
, sizeof(one
)) < 0) {
50 pr_warn("Netlink error reporting not supported\n");
53 if (bind(sock
, (struct sockaddr
*)&sa
, sizeof(sa
)) < 0) {
59 if (getsockname(sock
, (struct sockaddr
*)&sa
, &addrlen
) < 0) {
64 if (addrlen
!= sizeof(sa
)) {
65 ret
= -LIBBPF_ERRNO__INTERNAL
;
77 static int bpf_netlink_recv(int sock
, __u32 nl_pid
, int seq
,
78 __dump_nlmsg_t _fn
, libbpf_dump_nlmsg_t fn
,
81 bool multipart
= true;
89 len
= recv(sock
, buf
, sizeof(buf
), 0);
98 for (nh
= (struct nlmsghdr
*)buf
; NLMSG_OK(nh
, len
);
99 nh
= NLMSG_NEXT(nh
, len
)) {
100 if (nh
->nlmsg_pid
!= nl_pid
) {
101 ret
= -LIBBPF_ERRNO__WRNGPID
;
104 if (nh
->nlmsg_seq
!= seq
) {
105 ret
= -LIBBPF_ERRNO__INVSEQ
;
108 if (nh
->nlmsg_flags
& NLM_F_MULTI
)
110 switch (nh
->nlmsg_type
) {
112 err
= (struct nlmsgerr
*)NLMSG_DATA(nh
);
116 libbpf_nla_dump_errormsg(nh
);
124 ret
= _fn(nh
, fn
, cookie
);
135 static int __bpf_set_link_xdp_fd_replace(int ifindex
, int fd
, int old_fd
,
138 int sock
, seq
= 0, ret
;
139 struct nlattr
*nla
, *nla_xdp
;
142 struct ifinfomsg ifinfo
;
147 sock
= libbpf_netlink_open(&nl_pid
);
151 memset(&req
, 0, sizeof(req
));
152 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
153 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
154 req
.nh
.nlmsg_type
= RTM_SETLINK
;
155 req
.nh
.nlmsg_pid
= 0;
156 req
.nh
.nlmsg_seq
= ++seq
;
157 req
.ifinfo
.ifi_family
= AF_UNSPEC
;
158 req
.ifinfo
.ifi_index
= ifindex
;
160 /* started nested attribute for XDP */
161 nla
= (struct nlattr
*)(((char *)&req
)
162 + NLMSG_ALIGN(req
.nh
.nlmsg_len
));
163 nla
->nla_type
= NLA_F_NESTED
| IFLA_XDP
;
164 nla
->nla_len
= NLA_HDRLEN
;
167 nla_xdp
= (struct nlattr
*)((char *)nla
+ nla
->nla_len
);
168 nla_xdp
->nla_type
= IFLA_XDP_FD
;
169 nla_xdp
->nla_len
= NLA_HDRLEN
+ sizeof(int);
170 memcpy((char *)nla_xdp
+ NLA_HDRLEN
, &fd
, sizeof(fd
));
171 nla
->nla_len
+= nla_xdp
->nla_len
;
173 /* if user passed in any flags, add those too */
175 nla_xdp
= (struct nlattr
*)((char *)nla
+ nla
->nla_len
);
176 nla_xdp
->nla_type
= IFLA_XDP_FLAGS
;
177 nla_xdp
->nla_len
= NLA_HDRLEN
+ sizeof(flags
);
178 memcpy((char *)nla_xdp
+ NLA_HDRLEN
, &flags
, sizeof(flags
));
179 nla
->nla_len
+= nla_xdp
->nla_len
;
182 if (flags
& XDP_FLAGS_REPLACE
) {
183 nla_xdp
= (struct nlattr
*)((char *)nla
+ nla
->nla_len
);
184 nla_xdp
->nla_type
= IFLA_XDP_EXPECTED_FD
;
185 nla_xdp
->nla_len
= NLA_HDRLEN
+ sizeof(old_fd
);
186 memcpy((char *)nla_xdp
+ NLA_HDRLEN
, &old_fd
, sizeof(old_fd
));
187 nla
->nla_len
+= nla_xdp
->nla_len
;
190 req
.nh
.nlmsg_len
+= NLA_ALIGN(nla
->nla_len
);
192 if (send(sock
, &req
, req
.nh
.nlmsg_len
, 0) < 0) {
196 ret
= bpf_netlink_recv(sock
, nl_pid
, seq
, NULL
, NULL
, NULL
);
203 int bpf_set_link_xdp_fd_opts(int ifindex
, int fd
, __u32 flags
,
204 const struct bpf_xdp_set_link_opts
*opts
)
208 if (!OPTS_VALID(opts
, bpf_xdp_set_link_opts
))
211 if (OPTS_HAS(opts
, old_fd
)) {
212 old_fd
= OPTS_GET(opts
, old_fd
, -1);
213 flags
|= XDP_FLAGS_REPLACE
;
216 return __bpf_set_link_xdp_fd_replace(ifindex
, fd
,
221 int bpf_set_link_xdp_fd(int ifindex
, int fd
, __u32 flags
)
223 return __bpf_set_link_xdp_fd_replace(ifindex
, fd
, 0, flags
);
226 static int __dump_link_nlmsg(struct nlmsghdr
*nlh
,
227 libbpf_dump_nlmsg_t dump_link_nlmsg
, void *cookie
)
229 struct nlattr
*tb
[IFLA_MAX
+ 1], *attr
;
230 struct ifinfomsg
*ifi
= NLMSG_DATA(nlh
);
233 len
= nlh
->nlmsg_len
- NLMSG_LENGTH(sizeof(*ifi
));
234 attr
= (struct nlattr
*) ((void *) ifi
+ NLMSG_ALIGN(sizeof(*ifi
)));
235 if (libbpf_nla_parse(tb
, IFLA_MAX
, attr
, len
, NULL
) != 0)
236 return -LIBBPF_ERRNO__NLPARSE
;
238 return dump_link_nlmsg(cookie
, ifi
, tb
);
241 static int get_xdp_info(void *cookie
, void *msg
, struct nlattr
**tb
)
243 struct nlattr
*xdp_tb
[IFLA_XDP_MAX
+ 1];
244 struct xdp_id_md
*xdp_id
= cookie
;
245 struct ifinfomsg
*ifinfo
= msg
;
248 if (xdp_id
->ifindex
&& xdp_id
->ifindex
!= ifinfo
->ifi_index
)
254 ret
= libbpf_nla_parse_nested(xdp_tb
, IFLA_XDP_MAX
, tb
[IFLA_XDP
], NULL
);
258 if (!xdp_tb
[IFLA_XDP_ATTACHED
])
261 xdp_id
->info
.attach_mode
= libbpf_nla_getattr_u8(
262 xdp_tb
[IFLA_XDP_ATTACHED
]);
264 if (xdp_id
->info
.attach_mode
== XDP_ATTACHED_NONE
)
267 if (xdp_tb
[IFLA_XDP_PROG_ID
])
268 xdp_id
->info
.prog_id
= libbpf_nla_getattr_u32(
269 xdp_tb
[IFLA_XDP_PROG_ID
]);
271 if (xdp_tb
[IFLA_XDP_SKB_PROG_ID
])
272 xdp_id
->info
.skb_prog_id
= libbpf_nla_getattr_u32(
273 xdp_tb
[IFLA_XDP_SKB_PROG_ID
]);
275 if (xdp_tb
[IFLA_XDP_DRV_PROG_ID
])
276 xdp_id
->info
.drv_prog_id
= libbpf_nla_getattr_u32(
277 xdp_tb
[IFLA_XDP_DRV_PROG_ID
]);
279 if (xdp_tb
[IFLA_XDP_HW_PROG_ID
])
280 xdp_id
->info
.hw_prog_id
= libbpf_nla_getattr_u32(
281 xdp_tb
[IFLA_XDP_HW_PROG_ID
]);
286 int bpf_get_link_xdp_info(int ifindex
, struct xdp_link_info
*info
,
287 size_t info_size
, __u32 flags
)
289 struct xdp_id_md xdp_id
= {};
294 if (flags
& ~XDP_FLAGS_MASK
|| !info_size
)
297 /* Check whether the single {HW,DRV,SKB} mode is set */
298 flags
&= (XDP_FLAGS_SKB_MODE
| XDP_FLAGS_DRV_MODE
| XDP_FLAGS_HW_MODE
);
300 if (flags
&& flags
& mask
)
303 sock
= libbpf_netlink_open(&nl_pid
);
307 xdp_id
.ifindex
= ifindex
;
308 xdp_id
.flags
= flags
;
310 ret
= libbpf_nl_get_link(sock
, nl_pid
, get_xdp_info
, &xdp_id
);
312 size_t sz
= min(info_size
, sizeof(xdp_id
.info
));
314 memcpy(info
, &xdp_id
.info
, sz
);
315 memset((void *) info
+ sz
, 0, info_size
- sz
);
322 static __u32
get_xdp_id(struct xdp_link_info
*info
, __u32 flags
)
324 if (info
->attach_mode
!= XDP_ATTACHED_MULTI
)
325 return info
->prog_id
;
326 if (flags
& XDP_FLAGS_DRV_MODE
)
327 return info
->drv_prog_id
;
328 if (flags
& XDP_FLAGS_HW_MODE
)
329 return info
->hw_prog_id
;
330 if (flags
& XDP_FLAGS_SKB_MODE
)
331 return info
->skb_prog_id
;
336 int bpf_get_link_xdp_id(int ifindex
, __u32
*prog_id
, __u32 flags
)
338 struct xdp_link_info info
;
341 ret
= bpf_get_link_xdp_info(ifindex
, &info
, sizeof(info
), flags
);
343 *prog_id
= get_xdp_id(&info
, flags
);
348 int libbpf_nl_get_link(int sock
, unsigned int nl_pid
,
349 libbpf_dump_nlmsg_t dump_link_nlmsg
, void *cookie
)
353 struct ifinfomsg ifm
;
355 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
356 .nlh
.nlmsg_type
= RTM_GETLINK
,
357 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
358 .ifm
.ifi_family
= AF_PACKET
,
360 int seq
= time(NULL
);
362 req
.nlh
.nlmsg_seq
= seq
;
363 if (send(sock
, &req
, req
.nlh
.nlmsg_len
, 0) < 0)
366 return bpf_netlink_recv(sock
, nl_pid
, seq
, __dump_link_nlmsg
,
367 dump_link_nlmsg
, cookie
);
370 static int __dump_class_nlmsg(struct nlmsghdr
*nlh
,
371 libbpf_dump_nlmsg_t dump_class_nlmsg
,
374 struct nlattr
*tb
[TCA_MAX
+ 1], *attr
;
375 struct tcmsg
*t
= NLMSG_DATA(nlh
);
378 len
= nlh
->nlmsg_len
- NLMSG_LENGTH(sizeof(*t
));
379 attr
= (struct nlattr
*) ((void *) t
+ NLMSG_ALIGN(sizeof(*t
)));
380 if (libbpf_nla_parse(tb
, TCA_MAX
, attr
, len
, NULL
) != 0)
381 return -LIBBPF_ERRNO__NLPARSE
;
383 return dump_class_nlmsg(cookie
, t
, tb
);
386 int libbpf_nl_get_class(int sock
, unsigned int nl_pid
, int ifindex
,
387 libbpf_dump_nlmsg_t dump_class_nlmsg
, void *cookie
)
393 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct tcmsg
)),
394 .nlh
.nlmsg_type
= RTM_GETTCLASS
,
395 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
396 .t
.tcm_family
= AF_UNSPEC
,
397 .t
.tcm_ifindex
= ifindex
,
399 int seq
= time(NULL
);
401 req
.nlh
.nlmsg_seq
= seq
;
402 if (send(sock
, &req
, req
.nlh
.nlmsg_len
, 0) < 0)
405 return bpf_netlink_recv(sock
, nl_pid
, seq
, __dump_class_nlmsg
,
406 dump_class_nlmsg
, cookie
);
409 static int __dump_qdisc_nlmsg(struct nlmsghdr
*nlh
,
410 libbpf_dump_nlmsg_t dump_qdisc_nlmsg
,
413 struct nlattr
*tb
[TCA_MAX
+ 1], *attr
;
414 struct tcmsg
*t
= NLMSG_DATA(nlh
);
417 len
= nlh
->nlmsg_len
- NLMSG_LENGTH(sizeof(*t
));
418 attr
= (struct nlattr
*) ((void *) t
+ NLMSG_ALIGN(sizeof(*t
)));
419 if (libbpf_nla_parse(tb
, TCA_MAX
, attr
, len
, NULL
) != 0)
420 return -LIBBPF_ERRNO__NLPARSE
;
422 return dump_qdisc_nlmsg(cookie
, t
, tb
);
425 int libbpf_nl_get_qdisc(int sock
, unsigned int nl_pid
, int ifindex
,
426 libbpf_dump_nlmsg_t dump_qdisc_nlmsg
, void *cookie
)
432 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct tcmsg
)),
433 .nlh
.nlmsg_type
= RTM_GETQDISC
,
434 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
435 .t
.tcm_family
= AF_UNSPEC
,
436 .t
.tcm_ifindex
= ifindex
,
438 int seq
= time(NULL
);
440 req
.nlh
.nlmsg_seq
= seq
;
441 if (send(sock
, &req
, req
.nlh
.nlmsg_len
, 0) < 0)
444 return bpf_netlink_recv(sock
, nl_pid
, seq
, __dump_qdisc_nlmsg
,
445 dump_qdisc_nlmsg
, cookie
);
448 static int __dump_filter_nlmsg(struct nlmsghdr
*nlh
,
449 libbpf_dump_nlmsg_t dump_filter_nlmsg
,
452 struct nlattr
*tb
[TCA_MAX
+ 1], *attr
;
453 struct tcmsg
*t
= NLMSG_DATA(nlh
);
456 len
= nlh
->nlmsg_len
- NLMSG_LENGTH(sizeof(*t
));
457 attr
= (struct nlattr
*) ((void *) t
+ NLMSG_ALIGN(sizeof(*t
)));
458 if (libbpf_nla_parse(tb
, TCA_MAX
, attr
, len
, NULL
) != 0)
459 return -LIBBPF_ERRNO__NLPARSE
;
461 return dump_filter_nlmsg(cookie
, t
, tb
);
464 int libbpf_nl_get_filter(int sock
, unsigned int nl_pid
, int ifindex
, int handle
,
465 libbpf_dump_nlmsg_t dump_filter_nlmsg
, void *cookie
)
471 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct tcmsg
)),
472 .nlh
.nlmsg_type
= RTM_GETTFILTER
,
473 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
474 .t
.tcm_family
= AF_UNSPEC
,
475 .t
.tcm_ifindex
= ifindex
,
476 .t
.tcm_parent
= handle
,
478 int seq
= time(NULL
);
480 req
.nlh
.nlmsg_seq
= seq
;
481 if (send(sock
, &req
, req
.nlh
.nlmsg_len
, 0) < 0)
484 return bpf_netlink_recv(sock
, nl_pid
, seq
, __dump_filter_nlmsg
,
485 dump_filter_nlmsg
, cookie
);