Message ID | a72609ef4f0de7fee5376c40dbf54ad7f13bfb8d.1675245258.git.lorenzo@kernel.org (mailing list archive) |
---|---|
State | Accepted |
Commit | 04d58f1b26a436c429581d286528ea3c01624462 |
Delegated to: | BPF |
Headers | show |
Series | xdp: introduce xdp-feature support | expand |
On Wed, Feb 1, 2023 at 2:25 AM Lorenzo Bianconi <lorenzo@kernel.org> wrote: > > 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> > --- > tools/lib/bpf/libbpf.h | 3 +- > tools/lib/bpf/netlink.c | 96 +++++++++++++++++++++++++++++++++++++++++ > tools/lib/bpf/nlattr.h | 12 ++++++ > 3 files changed, 110 insertions(+), 1 deletion(-) > [...] > @@ -366,6 +433,10 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) > .ifinfo.ifi_family = AF_PACKET, > }; > struct xdp_id_md xdp_id = {}; > + struct xdp_features_md md = { > + .ifindex = ifindex, > + }; > + __u16 id; > int err; > > if (!OPTS_VALID(opts, bpf_xdp_query_opts)) > @@ -393,6 +464,31 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) > OPTS_SET(opts, skb_prog_id, xdp_id.info.skb_prog_id); > OPTS_SET(opts, attach_mode, xdp_id.info.attach_mode); > > + if (!OPTS_HAS(opts, feature_flags)) > + return 0; > + > + err = libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id); > + if (err < 0) > + return libbpf_err(err); > + > + memset(&req, 0, sizeof(req)); > + req.nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); > + req.nh.nlmsg_flags = NLM_F_REQUEST; > + req.nh.nlmsg_type = id; > + req.gnl.cmd = NETDEV_CMD_DEV_GET; > + req.gnl.version = 2; > + > + err = nlattr_add(&req, NETDEV_A_DEV_IFINDEX, &ifindex, sizeof(ifindex)); > + if (err < 0) > + return err; just noticed this, we need to use libbpf_err(err) here like in other error cases to set errno properly. Can you please send a follow up? > + > + err = libbpf_netlink_send_recv(&req, NETLINK_GENERIC, > + parse_xdp_features, NULL, &md); > + if (err) > + return libbpf_err(err); > + > + opts->feature_flags = md.flags; > + > return 0; > } > [...]
> On Wed, Feb 1, 2023 at 2:25 AM Lorenzo Bianconi <lorenzo@kernel.org> wrote: > > > > 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> > > --- > > tools/lib/bpf/libbpf.h | 3 +- > > tools/lib/bpf/netlink.c | 96 +++++++++++++++++++++++++++++++++++++++++ > > tools/lib/bpf/nlattr.h | 12 ++++++ > > 3 files changed, 110 insertions(+), 1 deletion(-) > > > > [...] > > > @@ -366,6 +433,10 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) > > .ifinfo.ifi_family = AF_PACKET, > > }; > > struct xdp_id_md xdp_id = {}; > > + struct xdp_features_md md = { > > + .ifindex = ifindex, > > + }; > > + __u16 id; > > int err; > > > > if (!OPTS_VALID(opts, bpf_xdp_query_opts)) > > @@ -393,6 +464,31 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) > > OPTS_SET(opts, skb_prog_id, xdp_id.info.skb_prog_id); > > OPTS_SET(opts, attach_mode, xdp_id.info.attach_mode); > > > > + if (!OPTS_HAS(opts, feature_flags)) > > + return 0; > > + > > + err = libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id); > > + if (err < 0) > > + return libbpf_err(err); > > + > > + memset(&req, 0, sizeof(req)); > > + req.nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); > > + req.nh.nlmsg_flags = NLM_F_REQUEST; > > + req.nh.nlmsg_type = id; > > + req.gnl.cmd = NETDEV_CMD_DEV_GET; > > + req.gnl.version = 2; > > + > > + err = nlattr_add(&req, NETDEV_A_DEV_IFINDEX, &ifindex, sizeof(ifindex)); > > + if (err < 0) > > + return err; > > just noticed this, we need to use libbpf_err(err) here like in other > error cases to set errno properly. Can you please send a follow up? sure, I will post a fix. Regards, Lorenzo > > > + > > + err = libbpf_netlink_send_recv(&req, NETLINK_GENERIC, > > + parse_xdp_features, NULL, &md); > > + if (err) > > + return libbpf_err(err); > > + > > + opts->feature_flags = md.flags; > > + > > return 0; > > } > > > > [...] >
On 2/1/23 2:24 AM, Lorenzo Bianconi wrote: > 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> > --- > tools/lib/bpf/libbpf.h | 3 +- > tools/lib/bpf/netlink.c | 96 +++++++++++++++++++++++++++++++++++++++++ > tools/lib/bpf/nlattr.h | 12 ++++++ > 3 files changed, 110 insertions(+), 1 deletion(-) > [...] > + > int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) > { > struct libbpf_nla_req req = { > @@ -366,6 +433,10 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) > .ifinfo.ifi_family = AF_PACKET, > }; > struct xdp_id_md xdp_id = {}; > + struct xdp_features_md md = { > + .ifindex = ifindex, > + }; > + __u16 id; > int err; > > if (!OPTS_VALID(opts, bpf_xdp_query_opts)) > @@ -393,6 +464,31 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) > OPTS_SET(opts, skb_prog_id, xdp_id.info.skb_prog_id); > OPTS_SET(opts, attach_mode, xdp_id.info.attach_mode); > > + if (!OPTS_HAS(opts, feature_flags)) > + return 0; > + > + err = libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id); > + if (err < 0) > + return libbpf_err(err); Hi, Lorenzo, Using latest libbpf repo (https://github.com/libbpf/libbpf, sync'ed from source), looks like the above change won't work if the program is running on an old kernel, e.g., 5.12 kernel. In this particular combination, in user space, bpf_xdp_query_opts does have 'feature_flags' member, so the control can reach libbpf_netlink_resolve_genl_family_id(). However, the family 'netdev' is only available in latest kernel (after this patch set). So the error will return in the above. This breaks backward compatibility since old working application won't work any more with a refresh of libbpf. I could not come up with an easy solution for this. One thing we could do is to treat 'libbpf_netlink_resolve_genl_family_id()' as a probe, so return 0 if probe fails. err = libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id); if (err < 0) return 0; Please let me know whether my suggestion makes sense or there could be a better solution. > + > + memset(&req, 0, sizeof(req)); > + req.nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); > + req.nh.nlmsg_flags = NLM_F_REQUEST; > + req.nh.nlmsg_type = id; > + req.gnl.cmd = NETDEV_CMD_DEV_GET; > + req.gnl.version = 2; > + > + err = nlattr_add(&req, NETDEV_A_DEV_IFINDEX, &ifindex, sizeof(ifindex)); > + if (err < 0) > + return err; > + > + err = libbpf_netlink_send_recv(&req, NETLINK_GENERIC, > + parse_xdp_features, NULL, &md); > + if (err) > + return libbpf_err(err); > + > + opts->feature_flags = md.flags; > + > return 0; > } > [...]
On Mon, Feb 27, 2023 at 12:39 PM Yonghong Song <yhs@meta.com> wrote: > > > > On 2/1/23 2:24 AM, Lorenzo Bianconi wrote: > > 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> > > --- > > tools/lib/bpf/libbpf.h | 3 +- > > tools/lib/bpf/netlink.c | 96 +++++++++++++++++++++++++++++++++++++++++ > > tools/lib/bpf/nlattr.h | 12 ++++++ > > 3 files changed, 110 insertions(+), 1 deletion(-) > > > [...] > > + > > int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) > > { > > struct libbpf_nla_req req = { > > @@ -366,6 +433,10 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) > > .ifinfo.ifi_family = AF_PACKET, > > }; > > struct xdp_id_md xdp_id = {}; > > + struct xdp_features_md md = { > > + .ifindex = ifindex, > > + }; > > + __u16 id; > > int err; > > > > if (!OPTS_VALID(opts, bpf_xdp_query_opts)) > > @@ -393,6 +464,31 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) > > OPTS_SET(opts, skb_prog_id, xdp_id.info.skb_prog_id); > > OPTS_SET(opts, attach_mode, xdp_id.info.attach_mode); > > > > + if (!OPTS_HAS(opts, feature_flags)) > > + return 0; > > + > > + err = libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id); > > + if (err < 0) > > + return libbpf_err(err); > > Hi, Lorenzo, > > Using latest libbpf repo (https://github.com/libbpf/libbpf, sync'ed from > source), looks like the above change won't work if the program is > running on an old kernel, e.g., 5.12 kernel. > > In this particular combination, in user space, bpf_xdp_query_opts does > have 'feature_flags' member, so the control can reach > libbpf_netlink_resolve_genl_family_id(). However, the family 'netdev' > is only available in latest kernel (after this patch set). So > the error will return in the above. > > This breaks backward compatibility since old working application won't > work any more with a refresh of libbpf. > > I could not come up with an easy solution for this. One thing we could > do is to treat 'libbpf_netlink_resolve_genl_family_id()' as a probe, so > return 0 if probe fails. > > err = libbpf_netlink_resolve_genl_family_id("netdev", > sizeof("netdev"), &id); > if (err < 0) > return 0; > > Please let me know whether my suggestion makes sense or there could be a > better solution. > feature_flags is an output parameter and if the "netdev" family doesn't exist then there are no feature flags to return, right? Is there a specific error code that's returned when such a family doesn't exist? If yes, we should check for it and return 0 for feature_flags. If not, we'll have to do a generic < 0 check as Yonghong proposes. > > > + > > + memset(&req, 0, sizeof(req)); > > + req.nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); > > + req.nh.nlmsg_flags = NLM_F_REQUEST; > > + req.nh.nlmsg_type = id; > > + req.gnl.cmd = NETDEV_CMD_DEV_GET; > > + req.gnl.version = 2; > > + > > + err = nlattr_add(&req, NETDEV_A_DEV_IFINDEX, &ifindex, sizeof(ifindex)); > > + if (err < 0) > > + return err; > > + > > + err = libbpf_netlink_send_recv(&req, NETLINK_GENERIC, > > + parse_xdp_features, NULL, &md); > > + if (err) > > + return libbpf_err(err); > > + > > + opts->feature_flags = md.flags; > > + > > return 0; > > } > > > [...]
On 2/27/23 1:01 PM, Andrii Nakryiko wrote: > On Mon, Feb 27, 2023 at 12:39 PM Yonghong Song <yhs@meta.com> wrote: >> >> >> >> On 2/1/23 2:24 AM, Lorenzo Bianconi wrote: >>> 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> >>> --- >>> tools/lib/bpf/libbpf.h | 3 +- >>> tools/lib/bpf/netlink.c | 96 +++++++++++++++++++++++++++++++++++++++++ >>> tools/lib/bpf/nlattr.h | 12 ++++++ >>> 3 files changed, 110 insertions(+), 1 deletion(-) >>> >> [...] >>> + >>> int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) >>> { >>> struct libbpf_nla_req req = { >>> @@ -366,6 +433,10 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) >>> .ifinfo.ifi_family = AF_PACKET, >>> }; >>> struct xdp_id_md xdp_id = {}; >>> + struct xdp_features_md md = { >>> + .ifindex = ifindex, >>> + }; >>> + __u16 id; >>> int err; >>> >>> if (!OPTS_VALID(opts, bpf_xdp_query_opts)) >>> @@ -393,6 +464,31 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) >>> OPTS_SET(opts, skb_prog_id, xdp_id.info.skb_prog_id); >>> OPTS_SET(opts, attach_mode, xdp_id.info.attach_mode); >>> >>> + if (!OPTS_HAS(opts, feature_flags)) >>> + return 0; >>> + >>> + err = libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id); >>> + if (err < 0) >>> + return libbpf_err(err); >> >> Hi, Lorenzo, >> >> Using latest libbpf repo (https://github.com/libbpf/libbpf, sync'ed from >> source), looks like the above change won't work if the program is >> running on an old kernel, e.g., 5.12 kernel. >> >> In this particular combination, in user space, bpf_xdp_query_opts does >> have 'feature_flags' member, so the control can reach >> libbpf_netlink_resolve_genl_family_id(). However, the family 'netdev' >> is only available in latest kernel (after this patch set). So >> the error will return in the above. >> >> This breaks backward compatibility since old working application won't >> work any more with a refresh of libbpf. >> >> I could not come up with an easy solution for this. One thing we could >> do is to treat 'libbpf_netlink_resolve_genl_family_id()' as a probe, so >> return 0 if probe fails. >> >> err = libbpf_netlink_resolve_genl_family_id("netdev", >> sizeof("netdev"), &id); >> if (err < 0) >> return 0; >> >> Please let me know whether my suggestion makes sense or there could be a >> better solution. >> > > feature_flags is an output parameter and if the "netdev" family > doesn't exist then there are no feature flags to return, right? > > Is there a specific error code that's returned when such a family > doesn't exist? If yes, we should check for it and return 0 for > feature_flags. If not, we'll have to do a generic < 0 check as > Yonghong proposes. We can check -ENOENT. err = libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id); - if (err < 0) + if (err < 0) { + if (err == -ENOENT) + return 0; return libbpf_err(err); + } Let me propose a patch for this. > > >> >>> + >>> + memset(&req, 0, sizeof(req)); >>> + req.nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); >>> + req.nh.nlmsg_flags = NLM_F_REQUEST; >>> + req.nh.nlmsg_type = id; >>> + req.gnl.cmd = NETDEV_CMD_DEV_GET; >>> + req.gnl.version = 2; >>> + >>> + err = nlattr_add(&req, NETDEV_A_DEV_IFINDEX, &ifindex, sizeof(ifindex)); >>> + if (err < 0) >>> + return err; >>> + >>> + err = libbpf_netlink_send_recv(&req, NETLINK_GENERIC, >>> + parse_xdp_features, NULL, &md); >>> + if (err) >>> + return libbpf_err(err); >>> + >>> + opts->feature_flags = md.flags; >>> + >>> return 0; >>> } >>> >> [...]
On Mon, Feb 27, 2023 at 2:05 PM Yonghong Song <yhs@meta.com> wrote: > > > > On 2/27/23 1:01 PM, Andrii Nakryiko wrote: > > On Mon, Feb 27, 2023 at 12:39 PM Yonghong Song <yhs@meta.com> wrote: > >> > >> > >> > >> On 2/1/23 2:24 AM, Lorenzo Bianconi wrote: > >>> 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> > >>> --- > >>> tools/lib/bpf/libbpf.h | 3 +- > >>> tools/lib/bpf/netlink.c | 96 +++++++++++++++++++++++++++++++++++++++++ > >>> tools/lib/bpf/nlattr.h | 12 ++++++ > >>> 3 files changed, 110 insertions(+), 1 deletion(-) > >>> > >> [...] > >>> + > >>> int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) > >>> { > >>> struct libbpf_nla_req req = { > >>> @@ -366,6 +433,10 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) > >>> .ifinfo.ifi_family = AF_PACKET, > >>> }; > >>> struct xdp_id_md xdp_id = {}; > >>> + struct xdp_features_md md = { > >>> + .ifindex = ifindex, > >>> + }; > >>> + __u16 id; > >>> int err; > >>> > >>> if (!OPTS_VALID(opts, bpf_xdp_query_opts)) > >>> @@ -393,6 +464,31 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) > >>> OPTS_SET(opts, skb_prog_id, xdp_id.info.skb_prog_id); > >>> OPTS_SET(opts, attach_mode, xdp_id.info.attach_mode); > >>> > >>> + if (!OPTS_HAS(opts, feature_flags)) > >>> + return 0; > >>> + > >>> + err = libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id); > >>> + if (err < 0) > >>> + return libbpf_err(err); > >> > >> Hi, Lorenzo, > >> > >> Using latest libbpf repo (https://github.com/libbpf/libbpf, sync'ed from > >> source), looks like the above change won't work if the program is > >> running on an old kernel, e.g., 5.12 kernel. > >> > >> In this particular combination, in user space, bpf_xdp_query_opts does > >> have 'feature_flags' member, so the control can reach > >> libbpf_netlink_resolve_genl_family_id(). However, the family 'netdev' > >> is only available in latest kernel (after this patch set). So > >> the error will return in the above. > >> > >> This breaks backward compatibility since old working application won't > >> work any more with a refresh of libbpf. > >> > >> I could not come up with an easy solution for this. One thing we could > >> do is to treat 'libbpf_netlink_resolve_genl_family_id()' as a probe, so > >> return 0 if probe fails. > >> > >> err = libbpf_netlink_resolve_genl_family_id("netdev", > >> sizeof("netdev"), &id); > >> if (err < 0) > >> return 0; > >> > >> Please let me know whether my suggestion makes sense or there could be a > >> better solution. > >> > > > > feature_flags is an output parameter and if the "netdev" family > > doesn't exist then there are no feature flags to return, right? > > > > Is there a specific error code that's returned when such a family > > doesn't exist? If yes, we should check for it and return 0 for > > feature_flags. If not, we'll have to do a generic < 0 check as > > Yonghong proposes. > > We can check -ENOENT. > > err = libbpf_netlink_resolve_genl_family_id("netdev", > sizeof("netdev"), &id); > - if (err < 0) > + if (err < 0) { > + if (err == -ENOENT) > + return 0; > return libbpf_err(err); > + } > > Let me propose a patch for this. we might add more options beyond feature_flags, so these early returns are a bit error-prone, let's convert this code to if () { } else? > > > > > > >> > >>> + > >>> + memset(&req, 0, sizeof(req)); > >>> + req.nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); > >>> + req.nh.nlmsg_flags = NLM_F_REQUEST; > >>> + req.nh.nlmsg_type = id; > >>> + req.gnl.cmd = NETDEV_CMD_DEV_GET; > >>> + req.gnl.version = 2; > >>> + > >>> + err = nlattr_add(&req, NETDEV_A_DEV_IFINDEX, &ifindex, sizeof(ifindex)); > >>> + if (err < 0) > >>> + return err; > >>> + > >>> + err = libbpf_netlink_send_recv(&req, NETLINK_GENERIC, > >>> + parse_xdp_features, NULL, &md); > >>> + if (err) > >>> + return libbpf_err(err); > >>> + > >>> + opts->feature_flags = md.flags; > >>> + > >>> return 0; > >>> } > >>> > >> [...]
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 8777ff21ea1d..b18581277eb2 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -1048,9 +1048,10 @@ struct bpf_xdp_query_opts { __u32 hw_prog_id; /* output */ __u32 skb_prog_id; /* output */ __u8 attach_mode; /* output */ + __u64 feature_flags; /* output */ size_t :0; }; -#define bpf_xdp_query_opts__last_field attach_mode +#define bpf_xdp_query_opts__last_field feature_flags LIBBPF_API int bpf_xdp_attach(int ifindex, int prog_fd, __u32 flags, const struct bpf_xdp_attach_opts *opts); diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c index d2468a04a6c3..32b13b7a11b0 100644 --- a/tools/lib/bpf/netlink.c +++ b/tools/lib/bpf/netlink.c @@ -9,6 +9,7 @@ #include <linux/if_ether.h> #include <linux/pkt_cls.h> #include <linux/rtnetlink.h> +#include <linux/netdev.h> #include <sys/socket.h> #include <errno.h> #include <time.h> @@ -39,6 +40,12 @@ struct xdp_id_md { int ifindex; __u32 flags; struct xdp_link_info info; + __u64 feature_flags; +}; + +struct xdp_features_md { + int ifindex; + __u64 flags; }; static int libbpf_netlink_open(__u32 *nl_pid, int proto) @@ -238,6 +245,43 @@ static int libbpf_netlink_send_recv(struct libbpf_nla_req *req, return ret; } +static int parse_genl_family_id(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn, + void *cookie) +{ + struct genlmsghdr *gnl = NLMSG_DATA(nh); + struct nlattr *na = (struct nlattr *)((void *)gnl + GENL_HDRLEN); + struct nlattr *tb[CTRL_ATTR_FAMILY_ID + 1]; + __u16 *id = cookie; + + libbpf_nla_parse(tb, CTRL_ATTR_FAMILY_ID, na, + NLMSG_PAYLOAD(nh, sizeof(*gnl)), NULL); + if (!tb[CTRL_ATTR_FAMILY_ID]) + return NL_CONT; + + *id = libbpf_nla_getattr_u16(tb[CTRL_ATTR_FAMILY_ID]); + return NL_DONE; +} + +static int libbpf_netlink_resolve_genl_family_id(const char *name, + __u16 len, __u16 *id) +{ + struct libbpf_nla_req req = { + .nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN), + .nh.nlmsg_type = GENL_ID_CTRL, + .nh.nlmsg_flags = NLM_F_REQUEST, + .gnl.cmd = CTRL_CMD_GETFAMILY, + .gnl.version = 2, + }; + int err; + + err = nlattr_add(&req, CTRL_ATTR_FAMILY_NAME, name, len); + if (err < 0) + return err; + + return libbpf_netlink_send_recv(&req, NETLINK_GENERIC, + parse_genl_family_id, NULL, id); +} + static int __bpf_set_link_xdp_fd_replace(int ifindex, int fd, int old_fd, __u32 flags) { @@ -357,6 +401,29 @@ static int get_xdp_info(void *cookie, void *msg, struct nlattr **tb) return 0; } +static int parse_xdp_features(struct nlmsghdr *nh, libbpf_dump_nlmsg_t fn, + void *cookie) +{ + struct genlmsghdr *gnl = NLMSG_DATA(nh); + struct nlattr *na = (struct nlattr *)((void *)gnl + GENL_HDRLEN); + struct nlattr *tb[NETDEV_CMD_MAX + 1]; + struct xdp_features_md *md = cookie; + __u32 ifindex; + + libbpf_nla_parse(tb, NETDEV_CMD_MAX, na, + NLMSG_PAYLOAD(nh, sizeof(*gnl)), NULL); + + if (!tb[NETDEV_A_DEV_IFINDEX] || !tb[NETDEV_A_DEV_XDP_FEATURES]) + return NL_CONT; + + ifindex = libbpf_nla_getattr_u32(tb[NETDEV_A_DEV_IFINDEX]); + if (ifindex != md->ifindex) + return NL_CONT; + + md->flags = libbpf_nla_getattr_u64(tb[NETDEV_A_DEV_XDP_FEATURES]); + return NL_DONE; +} + int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) { struct libbpf_nla_req req = { @@ -366,6 +433,10 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) .ifinfo.ifi_family = AF_PACKET, }; struct xdp_id_md xdp_id = {}; + struct xdp_features_md md = { + .ifindex = ifindex, + }; + __u16 id; int err; if (!OPTS_VALID(opts, bpf_xdp_query_opts)) @@ -393,6 +464,31 @@ int bpf_xdp_query(int ifindex, int xdp_flags, struct bpf_xdp_query_opts *opts) OPTS_SET(opts, skb_prog_id, xdp_id.info.skb_prog_id); OPTS_SET(opts, attach_mode, xdp_id.info.attach_mode); + if (!OPTS_HAS(opts, feature_flags)) + return 0; + + err = libbpf_netlink_resolve_genl_family_id("netdev", sizeof("netdev"), &id); + if (err < 0) + return libbpf_err(err); + + memset(&req, 0, sizeof(req)); + req.nh.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); + req.nh.nlmsg_flags = NLM_F_REQUEST; + req.nh.nlmsg_type = id; + req.gnl.cmd = NETDEV_CMD_DEV_GET; + req.gnl.version = 2; + + err = nlattr_add(&req, NETDEV_A_DEV_IFINDEX, &ifindex, sizeof(ifindex)); + if (err < 0) + return err; + + err = libbpf_netlink_send_recv(&req, NETLINK_GENERIC, + parse_xdp_features, NULL, &md); + if (err) + return libbpf_err(err); + + opts->feature_flags = md.flags; + return 0; } diff --git a/tools/lib/bpf/nlattr.h b/tools/lib/bpf/nlattr.h index 4d15ae2ff812..d92d1c1de700 100644 --- a/tools/lib/bpf/nlattr.h +++ b/tools/lib/bpf/nlattr.h @@ -14,6 +14,7 @@ #include <errno.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> +#include <linux/genetlink.h> /* avoid multiple definition of netlink features */ #define __LINUX_NETLINK_H @@ -58,6 +59,7 @@ struct libbpf_nla_req { union { struct ifinfomsg ifinfo; struct tcmsg tc; + struct genlmsghdr gnl; }; char buf[128]; }; @@ -89,11 +91,21 @@ static inline uint8_t libbpf_nla_getattr_u8(const struct nlattr *nla) return *(uint8_t *)libbpf_nla_data(nla); } +static inline uint16_t libbpf_nla_getattr_u16(const struct nlattr *nla) +{ + return *(uint16_t *)libbpf_nla_data(nla); +} + static inline uint32_t libbpf_nla_getattr_u32(const struct nlattr *nla) { return *(uint32_t *)libbpf_nla_data(nla); } +static inline uint64_t libbpf_nla_getattr_u64(const struct nlattr *nla) +{ + return *(uint64_t *)libbpf_nla_data(nla); +} + static inline const char *libbpf_nla_getattr_str(const struct nlattr *nla) { return (const char *)libbpf_nla_data(nla);