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 int bpf_set_link_xdp_fd(int ifindex
, int fd
, __u32 flags
)
137 int sock
, seq
= 0, ret
;
138 struct nlattr
*nla
, *nla_xdp
;
141 struct ifinfomsg ifinfo
;
146 sock
= libbpf_netlink_open(&nl_pid
);
150 memset(&req
, 0, sizeof(req
));
151 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
152 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
153 req
.nh
.nlmsg_type
= RTM_SETLINK
;
154 req
.nh
.nlmsg_pid
= 0;
155 req
.nh
.nlmsg_seq
= ++seq
;
156 req
.ifinfo
.ifi_family
= AF_UNSPEC
;
157 req
.ifinfo
.ifi_index
= ifindex
;
159 /* started nested attribute for XDP */
160 nla
= (struct nlattr
*)(((char *)&req
)
161 + NLMSG_ALIGN(req
.nh
.nlmsg_len
));
162 nla
->nla_type
= NLA_F_NESTED
| IFLA_XDP
;
163 nla
->nla_len
= NLA_HDRLEN
;
166 nla_xdp
= (struct nlattr
*)((char *)nla
+ nla
->nla_len
);
167 nla_xdp
->nla_type
= IFLA_XDP_FD
;
168 nla_xdp
->nla_len
= NLA_HDRLEN
+ sizeof(int);
169 memcpy((char *)nla_xdp
+ NLA_HDRLEN
, &fd
, sizeof(fd
));
170 nla
->nla_len
+= nla_xdp
->nla_len
;
172 /* if user passed in any flags, add those too */
174 nla_xdp
= (struct nlattr
*)((char *)nla
+ nla
->nla_len
);
175 nla_xdp
->nla_type
= IFLA_XDP_FLAGS
;
176 nla_xdp
->nla_len
= NLA_HDRLEN
+ sizeof(flags
);
177 memcpy((char *)nla_xdp
+ NLA_HDRLEN
, &flags
, sizeof(flags
));
178 nla
->nla_len
+= nla_xdp
->nla_len
;
181 req
.nh
.nlmsg_len
+= NLA_ALIGN(nla
->nla_len
);
183 if (send(sock
, &req
, req
.nh
.nlmsg_len
, 0) < 0) {
187 ret
= bpf_netlink_recv(sock
, nl_pid
, seq
, NULL
, NULL
, NULL
);
194 static int __dump_link_nlmsg(struct nlmsghdr
*nlh
,
195 libbpf_dump_nlmsg_t dump_link_nlmsg
, void *cookie
)
197 struct nlattr
*tb
[IFLA_MAX
+ 1], *attr
;
198 struct ifinfomsg
*ifi
= NLMSG_DATA(nlh
);
201 len
= nlh
->nlmsg_len
- NLMSG_LENGTH(sizeof(*ifi
));
202 attr
= (struct nlattr
*) ((void *) ifi
+ NLMSG_ALIGN(sizeof(*ifi
)));
203 if (libbpf_nla_parse(tb
, IFLA_MAX
, attr
, len
, NULL
) != 0)
204 return -LIBBPF_ERRNO__NLPARSE
;
206 return dump_link_nlmsg(cookie
, ifi
, tb
);
209 static int get_xdp_info(void *cookie
, void *msg
, struct nlattr
**tb
)
211 struct nlattr
*xdp_tb
[IFLA_XDP_MAX
+ 1];
212 struct xdp_id_md
*xdp_id
= cookie
;
213 struct ifinfomsg
*ifinfo
= msg
;
216 if (xdp_id
->ifindex
&& xdp_id
->ifindex
!= ifinfo
->ifi_index
)
222 ret
= libbpf_nla_parse_nested(xdp_tb
, IFLA_XDP_MAX
, tb
[IFLA_XDP
], NULL
);
226 if (!xdp_tb
[IFLA_XDP_ATTACHED
])
229 xdp_id
->info
.attach_mode
= libbpf_nla_getattr_u8(
230 xdp_tb
[IFLA_XDP_ATTACHED
]);
232 if (xdp_id
->info
.attach_mode
== XDP_ATTACHED_NONE
)
235 if (xdp_tb
[IFLA_XDP_PROG_ID
])
236 xdp_id
->info
.prog_id
= libbpf_nla_getattr_u32(
237 xdp_tb
[IFLA_XDP_PROG_ID
]);
239 if (xdp_tb
[IFLA_XDP_SKB_PROG_ID
])
240 xdp_id
->info
.skb_prog_id
= libbpf_nla_getattr_u32(
241 xdp_tb
[IFLA_XDP_SKB_PROG_ID
]);
243 if (xdp_tb
[IFLA_XDP_DRV_PROG_ID
])
244 xdp_id
->info
.drv_prog_id
= libbpf_nla_getattr_u32(
245 xdp_tb
[IFLA_XDP_DRV_PROG_ID
]);
247 if (xdp_tb
[IFLA_XDP_HW_PROG_ID
])
248 xdp_id
->info
.hw_prog_id
= libbpf_nla_getattr_u32(
249 xdp_tb
[IFLA_XDP_HW_PROG_ID
]);
254 int bpf_get_link_xdp_info(int ifindex
, struct xdp_link_info
*info
,
255 size_t info_size
, __u32 flags
)
257 struct xdp_id_md xdp_id
= {};
262 if (flags
& ~XDP_FLAGS_MASK
|| !info_size
)
265 /* Check whether the single {HW,DRV,SKB} mode is set */
266 flags
&= (XDP_FLAGS_SKB_MODE
| XDP_FLAGS_DRV_MODE
| XDP_FLAGS_HW_MODE
);
268 if (flags
&& flags
& mask
)
271 sock
= libbpf_netlink_open(&nl_pid
);
275 xdp_id
.ifindex
= ifindex
;
276 xdp_id
.flags
= flags
;
278 ret
= libbpf_nl_get_link(sock
, nl_pid
, get_xdp_info
, &xdp_id
);
280 size_t sz
= min(info_size
, sizeof(xdp_id
.info
));
282 memcpy(info
, &xdp_id
.info
, sz
);
283 memset((void *) info
+ sz
, 0, info_size
- sz
);
290 static __u32
get_xdp_id(struct xdp_link_info
*info
, __u32 flags
)
292 if (info
->attach_mode
!= XDP_ATTACHED_MULTI
)
293 return info
->prog_id
;
294 if (flags
& XDP_FLAGS_DRV_MODE
)
295 return info
->drv_prog_id
;
296 if (flags
& XDP_FLAGS_HW_MODE
)
297 return info
->hw_prog_id
;
298 if (flags
& XDP_FLAGS_SKB_MODE
)
299 return info
->skb_prog_id
;
304 int bpf_get_link_xdp_id(int ifindex
, __u32
*prog_id
, __u32 flags
)
306 struct xdp_link_info info
;
309 ret
= bpf_get_link_xdp_info(ifindex
, &info
, sizeof(info
), flags
);
311 *prog_id
= get_xdp_id(&info
, flags
);
316 int libbpf_nl_get_link(int sock
, unsigned int nl_pid
,
317 libbpf_dump_nlmsg_t dump_link_nlmsg
, void *cookie
)
321 struct ifinfomsg ifm
;
323 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
324 .nlh
.nlmsg_type
= RTM_GETLINK
,
325 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
326 .ifm
.ifi_family
= AF_PACKET
,
328 int seq
= time(NULL
);
330 req
.nlh
.nlmsg_seq
= seq
;
331 if (send(sock
, &req
, req
.nlh
.nlmsg_len
, 0) < 0)
334 return bpf_netlink_recv(sock
, nl_pid
, seq
, __dump_link_nlmsg
,
335 dump_link_nlmsg
, cookie
);
338 static int __dump_class_nlmsg(struct nlmsghdr
*nlh
,
339 libbpf_dump_nlmsg_t dump_class_nlmsg
,
342 struct nlattr
*tb
[TCA_MAX
+ 1], *attr
;
343 struct tcmsg
*t
= NLMSG_DATA(nlh
);
346 len
= nlh
->nlmsg_len
- NLMSG_LENGTH(sizeof(*t
));
347 attr
= (struct nlattr
*) ((void *) t
+ NLMSG_ALIGN(sizeof(*t
)));
348 if (libbpf_nla_parse(tb
, TCA_MAX
, attr
, len
, NULL
) != 0)
349 return -LIBBPF_ERRNO__NLPARSE
;
351 return dump_class_nlmsg(cookie
, t
, tb
);
354 int libbpf_nl_get_class(int sock
, unsigned int nl_pid
, int ifindex
,
355 libbpf_dump_nlmsg_t dump_class_nlmsg
, void *cookie
)
361 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct tcmsg
)),
362 .nlh
.nlmsg_type
= RTM_GETTCLASS
,
363 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
364 .t
.tcm_family
= AF_UNSPEC
,
365 .t
.tcm_ifindex
= ifindex
,
367 int seq
= time(NULL
);
369 req
.nlh
.nlmsg_seq
= seq
;
370 if (send(sock
, &req
, req
.nlh
.nlmsg_len
, 0) < 0)
373 return bpf_netlink_recv(sock
, nl_pid
, seq
, __dump_class_nlmsg
,
374 dump_class_nlmsg
, cookie
);
377 static int __dump_qdisc_nlmsg(struct nlmsghdr
*nlh
,
378 libbpf_dump_nlmsg_t dump_qdisc_nlmsg
,
381 struct nlattr
*tb
[TCA_MAX
+ 1], *attr
;
382 struct tcmsg
*t
= NLMSG_DATA(nlh
);
385 len
= nlh
->nlmsg_len
- NLMSG_LENGTH(sizeof(*t
));
386 attr
= (struct nlattr
*) ((void *) t
+ NLMSG_ALIGN(sizeof(*t
)));
387 if (libbpf_nla_parse(tb
, TCA_MAX
, attr
, len
, NULL
) != 0)
388 return -LIBBPF_ERRNO__NLPARSE
;
390 return dump_qdisc_nlmsg(cookie
, t
, tb
);
393 int libbpf_nl_get_qdisc(int sock
, unsigned int nl_pid
, int ifindex
,
394 libbpf_dump_nlmsg_t dump_qdisc_nlmsg
, void *cookie
)
400 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct tcmsg
)),
401 .nlh
.nlmsg_type
= RTM_GETQDISC
,
402 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
403 .t
.tcm_family
= AF_UNSPEC
,
404 .t
.tcm_ifindex
= ifindex
,
406 int seq
= time(NULL
);
408 req
.nlh
.nlmsg_seq
= seq
;
409 if (send(sock
, &req
, req
.nlh
.nlmsg_len
, 0) < 0)
412 return bpf_netlink_recv(sock
, nl_pid
, seq
, __dump_qdisc_nlmsg
,
413 dump_qdisc_nlmsg
, cookie
);
416 static int __dump_filter_nlmsg(struct nlmsghdr
*nlh
,
417 libbpf_dump_nlmsg_t dump_filter_nlmsg
,
420 struct nlattr
*tb
[TCA_MAX
+ 1], *attr
;
421 struct tcmsg
*t
= NLMSG_DATA(nlh
);
424 len
= nlh
->nlmsg_len
- NLMSG_LENGTH(sizeof(*t
));
425 attr
= (struct nlattr
*) ((void *) t
+ NLMSG_ALIGN(sizeof(*t
)));
426 if (libbpf_nla_parse(tb
, TCA_MAX
, attr
, len
, NULL
) != 0)
427 return -LIBBPF_ERRNO__NLPARSE
;
429 return dump_filter_nlmsg(cookie
, t
, tb
);
432 int libbpf_nl_get_filter(int sock
, unsigned int nl_pid
, int ifindex
, int handle
,
433 libbpf_dump_nlmsg_t dump_filter_nlmsg
, void *cookie
)
439 .nlh
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct tcmsg
)),
440 .nlh
.nlmsg_type
= RTM_GETTFILTER
,
441 .nlh
.nlmsg_flags
= NLM_F_DUMP
| NLM_F_REQUEST
,
442 .t
.tcm_family
= AF_UNSPEC
,
443 .t
.tcm_ifindex
= ifindex
,
444 .t
.tcm_parent
= handle
,
446 int seq
= time(NULL
);
448 req
.nlh
.nlmsg_seq
= seq
;
449 if (send(sock
, &req
, req
.nlh
.nlmsg_len
, 0) < 0)
452 return bpf_netlink_recv(sock
, nl_pid
, seq
, __dump_filter_nlmsg
,
453 dump_filter_nlmsg
, cookie
);