Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

libbpf: add API to get XDP/XSK supported features

Extend bpf_xdp_query routine in order to get XDP/XSK supported features
of netdev over route netlink interface.
Extend libbpf netlink implementation in order to support netlink_generic
protocol.

Co-developed-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Co-developed-by: Marek Majtyka <alardam@gmail.com>
Signed-off-by: Marek Majtyka <alardam@gmail.com>
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Link: https://lore.kernel.org/r/a72609ef4f0de7fee5376c40dbf54ad7f13bfb8d.1675245258.git.lorenzo@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Lorenzo Bianconi and committed by
Alexei Starovoitov
04d58f1b 8f166931

+110 -1
+2 -1
tools/lib/bpf/libbpf.h
··· 1048 1048 __u32 hw_prog_id; /* output */ 1049 1049 __u32 skb_prog_id; /* output */ 1050 1050 __u8 attach_mode; /* output */ 1051 + __u64 feature_flags; /* output */ 1051 1052 size_t :0; 1052 1053 }; 1053 - #define bpf_xdp_query_opts__last_field attach_mode 1054 + #define bpf_xdp_query_opts__last_field feature_flags 1054 1055 1055 1056 LIBBPF_API int bpf_xdp_attach(int ifindex, int prog_fd, __u32 flags, 1056 1057 const struct bpf_xdp_attach_opts *opts);
+96
tools/lib/bpf/netlink.c
··· 9 9 #include <linux/if_ether.h> 10 10 #include <linux/pkt_cls.h> 11 11 #include <linux/rtnetlink.h> 12 + #include <linux/netdev.h> 12 13 #include <sys/socket.h> 13 14 #include <errno.h> 14 15 #include <time.h> ··· 40 39 int ifindex; 41 40 __u32 flags; 42 41 struct xdp_link_info info; 42 + __u64 feature_flags; 43 + }; 44 + 45 + struct xdp_features_md { 46 + int ifindex; 47 + __u64 flags; 43 48 }; 44 49 45 50 static int libbpf_netlink_open(__u32 *nl_pid, int proto) ··· 245 238 return ret; 246 239 } 247 240 241 + static int parse_genl_family_id(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn, 242 + void *cookie) 243 + { 244 + struct genlmsghdr *gnl = NLMSG_DATA(nh); 245 + struct nlattr *na = (struct nlattr *)((void *)gnl + GENL_HDRLEN); 246 + struct nlattr *tb[CTRL_ATTR_FAMILY_ID + 1]; 247 + __u16 *id = cookie; 248 + 249 + libbpf_nla_parse(tb, CTRL_ATTR_FAMILY_ID, na, 250 + NLMSG_PAYLOAD(nh, sizeof(*gnl)), NULL); 251 + if (!tb[CTRL_ATTR_FAMILY_ID]) 252 + return NL_CONT; 253 + 254 + *id = libbpf_nla_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]); 255 + return NL_DONE; 256 + } 257 + 258 + static int libbpf_netlink_resolve_genl_family_id(const char *name, 259 + __u16 len, __u16 *id) 260 + { 261 + struct libbpf_nla_req req = { 262 + .nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN), 263 + .nh.nlmsg_type = GENL_ID_CTRL, 264 + .nh.nlmsg_flags = NLM_F_REQUEST, 265 + .gnl.cmd = CTRL_CMD_GETFAMILY, 266 + .gnl.version = 2, 267 + }; 268 + int err; 269 + 270 + err = nlattr_add(&req, CTRL_ATTR_FAMILY_NAME, name, len); 271 + if (err < 0) 272 + return err; 273 + 274 + return libbpf_netlink_send_recv(&req, NETLINK_GENERIC, 275 + parse_genl_family_id, NULL, id); 276 + } 277 + 248 278 static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd, 249 279 __u32 flags) 250 280 { ··· 401 357 return 0; 402 358 } 403 359 360 + static int parse_xdp_features(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn, 361 + void *cookie) 362 + { 363 + struct genlmsghdr *gnl = NLMSG_DATA(nh); 364 + struct nlattr *na = (struct nlattr *)((void *)gnl + GENL_HDRLEN); 365 + struct nlattr *tb[NETDEV_CMD_MAX + 1]; 366 + struct xdp_features_md *md = cookie; 367 + __u32 ifindex; 368 + 369 + libbpf_nla_parse(tb, NETDEV_CMD_MAX, na, 370 + NLMSG_PAYLOAD(nh, sizeof(*gnl)), NULL); 371 + 372 + if (!tb[NETDEV_A_DEV_IFINDEX] || !tb[NETDEV_A_DEV_XDP_FEATURES]) 373 + return NL_CONT; 374 + 375 + ifindex = libbpf_nla_getattr_u32(tb[NETDEV_A_DEV_IFINDEX]); 376 + if (ifindex != md->ifindex) 377 + return NL_CONT; 378 + 379 + md->flags = libbpf_nla_getattr_u64(tb[NETDEV_A_DEV_XDP_FEATURES]); 380 + return NL_DONE; 381 + } 382 + 404 383 int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) 405 384 { 406 385 struct libbpf_nla_req req = { ··· 433 366 .ifinfo.ifi_family = AF_PACKET, 434 367 }; 435 368 struct xdp_id_md xdp_id = {}; 369 + struct xdp_features_md md = { 370 + .ifindex = ifindex, 371 + }; 372 + __u16 id; 436 373 int err; 437 374 438 375 if (!OPTS_VALID(opts, bpf_xdp_query_opts)) ··· 463 392 OPTS_SET(opts, hw_prog_id, xdp_id.info.hw_prog_id); 464 393 OPTS_SET(opts, skb_prog_id, xdp_id.info.skb_prog_id); 465 394 OPTS_SET(opts, attach_mode, xdp_id.info.attach_mode); 395 + 396 + if (!OPTS_HAS(opts, feature_flags)) 397 + return 0; 398 + 399 + err = libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id); 400 + if (err < 0) 401 + return libbpf_err(err); 402 + 403 + memset(&req, 0, sizeof(req)); 404 + req.nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); 405 + req.nh.nlmsg_flags = NLM_F_REQUEST; 406 + req.nh.nlmsg_type = id; 407 + req.gnl.cmd = NETDEV_CMD_DEV_GET; 408 + req.gnl.version = 2; 409 + 410 + err = nlattr_add(&req, NETDEV_A_DEV_IFINDEX, &ifindex, sizeof(ifindex)); 411 + if (err < 0) 412 + return err; 413 + 414 + err = libbpf_netlink_send_recv(&req, NETLINK_GENERIC, 415 + parse_xdp_features, NULL, &md); 416 + if (err) 417 + return libbpf_err(err); 418 + 419 + opts->feature_flags = md.flags; 466 420 467 421 return 0; 468 422 }
+12
tools/lib/bpf/nlattr.h
··· 14 14 #include <errno.h> 15 15 #include <linux/netlink.h> 16 16 #include <linux/rtnetlink.h> 17 + #include <linux/genetlink.h> 17 18 18 19 /* avoid multiple definition of netlink features */ 19 20 #define __LINUX_NETLINK_H ··· 59 58 union { 60 59 struct ifinfomsg ifinfo; 61 60 struct tcmsg tc; 61 + struct genlmsghdr gnl; 62 62 }; 63 63 char buf[128]; 64 64 }; ··· 91 89 return *(uint8_t *)libbpf_nla_data(nla); 92 90 } 93 91 92 + static inline uint16_t libbpf_nla_getattr_u16(const struct nlattr *nla) 93 + { 94 + return *(uint16_t *)libbpf_nla_data(nla); 95 + } 96 + 94 97 static inline uint32_t libbpf_nla_getattr_u32(const struct nlattr *nla) 95 98 { 96 99 return *(uint32_t *)libbpf_nla_data(nla); 100 + } 101 + 102 + static inline uint64_t libbpf_nla_getattr_u64(const struct nlattr *nla) 103 + { 104 + return *(uint64_t *)libbpf_nla_data(nla); 97 105 } 98 106 99 107 static inline const char *libbpf_nla_getattr_str(const struct nlattr *nla)