diff mbox series

[bpf-next,v5,7/8] libbpf: Add a support for getting xdp prog id on ifindex

Message ID 20190201001954.4130-8-maciej.fijalkowski@intel.com
State Changes Requested
Delegated to: BPF Maintainers
Headers show
Series xdp: Avoid unloading xdp prog not attached by sample | expand

Commit Message

Maciej Fijalkowski Feb. 1, 2019, 12:19 a.m. UTC
Since we have a dedicated netlink attributes for xdp setup on a
particular interface, it is now possible to retrieve the program id that
is currently attached to the interface. The use case is targeted for
sample xdp programs, which will store the program id just after loading
bpf program onto iface. On shutdown, the sample will make sure that it
can unload the program by querying again the iface and verifying that
both program id's matches.

Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
---
 tools/lib/bpf/libbpf.h   |  1 +
 tools/lib/bpf/libbpf.map |  1 +
 tools/lib/bpf/netlink.c  | 85 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 87 insertions(+)

Comments

Daniel Borkmann Feb. 1, 2019, 9:43 p.m. UTC | #1
On 02/01/2019 01:19 AM, Maciej Fijalkowski wrote:
> Since we have a dedicated netlink attributes for xdp setup on a
> particular interface, it is now possible to retrieve the program id that
> is currently attached to the interface. The use case is targeted for
> sample xdp programs, which will store the program id just after loading
> bpf program onto iface. On shutdown, the sample will make sure that it
> can unload the program by querying again the iface and verifying that
> both program id's matches.
> 
> Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>
[...]
> +int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
> +{
> +	struct xdp_id_md xdp_id = {};
> +	int sock, ret;
> +	__u32 nl_pid;
> +	__u32 mask;
> +
> +	if (flags & ~XDP_FLAGS_MASK)
> +		return -EINVAL;
> +
> +	/* Check whether the single {HW,DRV,SKB} mode is set */
> +	flags &= (XDP_FLAGS_SKB_MODE | XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE);
> +	mask = flags - 1;
> +	if (flags && flags & mask)
> +		return -EINVAL;
> +
> +	sock = libbpf_netlink_open(&nl_pid);
> +	if (sock < 0)
> +		return sock;
> +
> +	xdp_id.ifindex = ifindex;
> +	xdp_id.flags = flags;
> +
> +	ret = libbpf_nl_get_link(sock, nl_pid, get_xdp_id, &xdp_id);
> +	if (!ret)
> +		*prog_id = xdp_id.id;
> +
> +	close(sock);
> +	return ret;
> +}

Btw, is anyone going to follow-up on XDP_ATTACHED_MULTI support as well
later on?

Thanks,
Daniel
Jakub Kicinski Feb. 1, 2019, 9:47 p.m. UTC | #2
On Fri, 1 Feb 2019 22:43:39 +0100, Daniel Borkmann wrote:
> On 02/01/2019 01:19 AM, Maciej Fijalkowski wrote:
> > Since we have a dedicated netlink attributes for xdp setup on a
> > particular interface, it is now possible to retrieve the program id that
> > is currently attached to the interface. The use case is targeted for
> > sample xdp programs, which will store the program id just after loading
> > bpf program onto iface. On shutdown, the sample will make sure that it
> > can unload the program by querying again the iface and verifying that
> > both program id's matches.
> > 
> > Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
> > Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>  
> [...]
> > +int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
> > +{
> > +	struct xdp_id_md xdp_id = {};
> > +	int sock, ret;
> > +	__u32 nl_pid;
> > +	__u32 mask;
> > +
> > +	if (flags & ~XDP_FLAGS_MASK)
> > +		return -EINVAL;
> > +
> > +	/* Check whether the single {HW,DRV,SKB} mode is set */
> > +	flags &= (XDP_FLAGS_SKB_MODE | XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE);
> > +	mask = flags - 1;
> > +	if (flags && flags & mask)
> > +		return -EINVAL;
> > +
> > +	sock = libbpf_netlink_open(&nl_pid);
> > +	if (sock < 0)
> > +		return sock;
> > +
> > +	xdp_id.ifindex = ifindex;
> > +	xdp_id.flags = flags;
> > +
> > +	ret = libbpf_nl_get_link(sock, nl_pid, get_xdp_id, &xdp_id);
> > +	if (!ret)
> > +		*prog_id = xdp_id.id;
> > +
> > +	close(sock);
> > +	return ret;
> > +}  
> 
> Btw, is anyone going to follow-up on XDP_ATTACHED_MULTI support as well
> later on?

I haven't tested to be honest, but I think Maciek got that right -
get_xdp_id_attr() should return IFLA_XDP_PROG_ID or a mode-specific
attr based on flags.  And there is a check that only flag is set.

Or do you mean retrieving all program ids with one dump?
Daniel Borkmann Feb. 1, 2019, 11 p.m. UTC | #3
On 02/01/2019 10:47 PM, Jakub Kicinski wrote:
> On Fri, 1 Feb 2019 22:43:39 +0100, Daniel Borkmann wrote:
>> On 02/01/2019 01:19 AM, Maciej Fijalkowski wrote:
>>> Since we have a dedicated netlink attributes for xdp setup on a
>>> particular interface, it is now possible to retrieve the program id that
>>> is currently attached to the interface. The use case is targeted for
>>> sample xdp programs, which will store the program id just after loading
>>> bpf program onto iface. On shutdown, the sample will make sure that it
>>> can unload the program by querying again the iface and verifying that
>>> both program id's matches.
>>>
>>> Signed-off-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com>
>>> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com>  
>> [...]
>>> +int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
>>> +{
>>> +	struct xdp_id_md xdp_id = {};
>>> +	int sock, ret;
>>> +	__u32 nl_pid;
>>> +	__u32 mask;
>>> +
>>> +	if (flags & ~XDP_FLAGS_MASK)
>>> +		return -EINVAL;
>>> +
>>> +	/* Check whether the single {HW,DRV,SKB} mode is set */
>>> +	flags &= (XDP_FLAGS_SKB_MODE | XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE);
>>> +	mask = flags - 1;
>>> +	if (flags && flags & mask)
>>> +		return -EINVAL;
>>> +
>>> +	sock = libbpf_netlink_open(&nl_pid);
>>> +	if (sock < 0)
>>> +		return sock;
>>> +
>>> +	xdp_id.ifindex = ifindex;
>>> +	xdp_id.flags = flags;
>>> +
>>> +	ret = libbpf_nl_get_link(sock, nl_pid, get_xdp_id, &xdp_id);
>>> +	if (!ret)
>>> +		*prog_id = xdp_id.id;
>>> +
>>> +	close(sock);
>>> +	return ret;
>>> +}  
>>
>> Btw, is anyone going to follow-up on XDP_ATTACHED_MULTI support as well
>> later on?
> 
> I haven't tested to be honest, but I think Maciek got that right -
> get_xdp_id_attr() should return IFLA_XDP_PROG_ID or a mode-specific
> attr based on flags.  And there is a check that only flag is set.
> 
> Or do you mean retrieving all program ids with one dump?

Yeah was thinking about the latter, but agree it's fine and probably
cleaner this way here.
diff mbox series

Patch

diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 931be6f3408c..43c77e98df6f 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -317,6 +317,7 @@  LIBBPF_API int bpf_prog_load(const char *file, enum bpf_prog_type type,
 			     struct bpf_object **pobj, int *prog_fd);
 
 LIBBPF_API int bpf_set_link_xdp_fd(int ifindex, int fd, __u32 flags);
+LIBBPF_API int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags);
 
 enum bpf_perf_event_ret {
 	LIBBPF_PERF_EVENT_DONE	= 0,
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index b183c6c3b990..d0e023a75d72 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -131,4 +131,5 @@  LIBBPF_0.0.2 {
 		bpf_probe_map_type;
 		bpf_probe_prog_type;
 		bpf_object__find_map_fd_by_name;
+		bpf_get_link_xdp_id;
 } LIBBPF_0.0.1;
diff --git a/tools/lib/bpf/netlink.c b/tools/lib/bpf/netlink.c
index 0ce67aea8f3b..ce3ec81b71c0 100644
--- a/tools/lib/bpf/netlink.c
+++ b/tools/lib/bpf/netlink.c
@@ -21,6 +21,12 @@ 
 typedef int (*__dump_nlmsg_t)(struct nlmsghdr *nlmsg, libbpf_dump_nlmsg_t,
 			      void *cookie);
 
+struct xdp_id_md {
+	int ifindex;
+	__u32 flags;
+	__u32 id;
+};
+
 int libbpf_netlink_open(__u32 *nl_pid)
 {
 	struct sockaddr_nl sa;
@@ -196,6 +202,85 @@  static int __dump_link_nlmsg(struct nlmsghdr *nlh,
 	return dump_link_nlmsg(cookie, ifi, tb);
 }
 
+static unsigned char get_xdp_id_attr(unsigned char mode, __u32 flags)
+{
+	if (mode != XDP_ATTACHED_MULTI)
+		return IFLA_XDP_PROG_ID;
+	if (flags & XDP_FLAGS_DRV_MODE)
+		return IFLA_XDP_DRV_PROG_ID;
+	if (flags & XDP_FLAGS_HW_MODE)
+		return IFLA_XDP_HW_PROG_ID;
+	if (flags & XDP_FLAGS_SKB_MODE)
+		return IFLA_XDP_SKB_PROG_ID;
+
+	return IFLA_XDP_UNSPEC;
+}
+
+static int get_xdp_id(void *cookie, void *msg, struct nlattr **tb)
+{
+	struct nlattr *xdp_tb[IFLA_XDP_MAX + 1];
+	struct xdp_id_md *xdp_id = cookie;
+	struct ifinfomsg *ifinfo = msg;
+	unsigned char mode, xdp_attr;
+	int ret;
+
+	if (xdp_id->ifindex && xdp_id->ifindex != ifinfo->ifi_index)
+		return 0;
+
+	if (!tb[IFLA_XDP])
+		return 0;
+
+	ret = libbpf_nla_parse_nested(xdp_tb, IFLA_XDP_MAX, tb[IFLA_XDP], NULL);
+	if (ret)
+		return ret;
+
+	if (!xdp_tb[IFLA_XDP_ATTACHED])
+		return 0;
+
+	mode = libbpf_nla_getattr_u8(xdp_tb[IFLA_XDP_ATTACHED]);
+	if (mode == XDP_ATTACHED_NONE)
+		return 0;
+
+	xdp_attr = get_xdp_id_attr(mode, xdp_id->flags);
+	if (!xdp_attr || !xdp_tb[xdp_attr])
+		return 0;
+
+	xdp_id->id = libbpf_nla_getattr_u32(xdp_tb[xdp_attr]);
+
+	return 0;
+}
+
+int bpf_get_link_xdp_id(int ifindex, __u32 *prog_id, __u32 flags)
+{
+	struct xdp_id_md xdp_id = {};
+	int sock, ret;
+	__u32 nl_pid;
+	__u32 mask;
+
+	if (flags & ~XDP_FLAGS_MASK)
+		return -EINVAL;
+
+	/* Check whether the single {HW,DRV,SKB} mode is set */
+	flags &= (XDP_FLAGS_SKB_MODE | XDP_FLAGS_DRV_MODE | XDP_FLAGS_HW_MODE);
+	mask = flags - 1;
+	if (flags && flags & mask)
+		return -EINVAL;
+
+	sock = libbpf_netlink_open(&nl_pid);
+	if (sock < 0)
+		return sock;
+
+	xdp_id.ifindex = ifindex;
+	xdp_id.flags = flags;
+
+	ret = libbpf_nl_get_link(sock, nl_pid, get_xdp_id, &xdp_id);
+	if (!ret)
+		*prog_id = xdp_id.id;
+
+	close(sock);
+	return ret;
+}
+
 int libbpf_nl_get_link(int sock, unsigned int nl_pid,
 		       libbpf_dump_nlmsg_t dump_link_nlmsg, void *cookie)
 {