There is no exact way how to figure out whether BPF devices support is
compiled into kernel. One way is to check kernel configure options but
this is not reliable as it may not be available. Let's try to do
syscall to which will list BPF cgroup device programs.
Signed-off-by: Pavel Hrdina <phrdina(a)redhat.com>
---
configure.ac | 3 +-
src/Makefile.am | 2 +
src/libvirt_private.syms | 3 ++
src/util/Makefile.inc.am | 2 +
src/util/vircgroupv2.c | 7 +++-
src/util/vircgroupv2devices.c | 73 +++++++++++++++++++++++++++++++++++
src/util/vircgroupv2devices.h | 27 +++++++++++++
7 files changed, 115 insertions(+), 2 deletions(-)
create mode 100644 src/util/vircgroupv2devices.c
create mode 100644 src/util/vircgroupv2devices.h
diff --git a/configure.ac b/configure.ac
index 0b7afece25..acc0e888ea 100644
--- a/configure.ac
+++ b/configure.ac
@@ -887,7 +887,8 @@ AC_CHECK_DECLS([clock_serv_t, host_get_clock_service,
clock_get_time],
# Check if we have new enough kernel to support BPF devices for cgroups v2
if test "$with_linux" = "yes"; then
- AC_CHECK_DECLS([BPF_PROG_QUERY], [], [], [#include <linux/bpf.h>])
+ AC_CHECK_DECLS([BPF_PROG_QUERY, BPF_CGROUP_DEVICE],
+ [], [], [#include <linux/bpf.h>])
fi
# Check if we need to look for ifconfig
diff --git a/src/Makefile.am b/src/Makefile.am
index cd386297ed..9d9e50d527 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -672,11 +672,13 @@ libvirt_setuid_rpc_client_la_SOURCES = \
util/viratomic.c \
util/viratomic.h \
util/virbitmap.c \
+ util/virbpf.c \
util/virbuffer.c \
util/vircgroup.c \
util/vircgroupbackend.c \
util/vircgroupv1.c \
util/vircgroupv2.c \
+ util/vircgroupv2devices.c \
util/vircommand.c \
util/virconf.c \
util/virdbus.c \
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 0cff580de2..6a822f7d90 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1611,6 +1611,9 @@ virCgroupV1Register;
# util/vircgroupv2.h
virCgroupV2Register;
+# util/vircgroupv2devices.h
+virCgroupV2DevicesAvailable;
+
# util/virclosecallbacks.h
virCloseCallbacksGet;
virCloseCallbacksGetConn;
diff --git a/src/util/Makefile.inc.am b/src/util/Makefile.inc.am
index 1fd7ad2d43..6eb9e1b889 100644
--- a/src/util/Makefile.inc.am
+++ b/src/util/Makefile.inc.am
@@ -31,6 +31,8 @@ UTIL_SOURCES = \
util/vircgroupv1.h \
util/vircgroupv2.c \
util/vircgroupv2.h \
+ util/vircgroupv2devices.c \
+ util/vircgroupv2devices.h \
util/virclosecallbacks.c \
util/virclosecallbacks.h \
util/vircommand.c \
diff --git a/src/util/vircgroupv2.c b/src/util/vircgroupv2.c
index cd58491da1..a56f3443e3 100644
--- a/src/util/vircgroupv2.c
+++ b/src/util/vircgroupv2.c
@@ -32,6 +32,7 @@
#include "vircgroup.h"
#include "vircgroupbackend.h"
#include "vircgroupv2.h"
+#include "vircgroupv2devices.h"
#include "virerror.h"
#include "virfile.h"
#include "virlog.h"
@@ -292,6 +293,8 @@ virCgroupV2DetectControllers(virCgroupPtr group,
/* In cgroup v2 there is no cpuacct controller, the cpu.stat file always
* exists with usage stats. */
group->unified.controllers |= 1 << VIR_CGROUP_CONTROLLER_CPUACCT;
+ if (virCgroupV2DevicesAvailable(group))
+ group->unified.controllers |= 1 << VIR_CGROUP_CONTROLLER_DEVICES;
for (i = 0; i < VIR_CGROUP_CONTROLLER_LAST; i++)
VIR_DEBUG("Controller '%s' present=%s",
@@ -406,8 +409,10 @@ virCgroupV2MakeGroup(virCgroupPtr parent ATTRIBUTE_UNUSED,
continue;
/* Controllers that are implicitly enabled if available. */
- if (i == VIR_CGROUP_CONTROLLER_CPUACCT)
+ if (i == VIR_CGROUP_CONTROLLER_CPUACCT ||
+ i == VIR_CGROUP_CONTROLLER_DEVICES) {
continue;
+ }
if (virCgroupV2EnableController(parent, i) < 0)
return -1;
diff --git a/src/util/vircgroupv2devices.c b/src/util/vircgroupv2devices.c
new file mode 100644
index 0000000000..10080d4fff
--- /dev/null
+++ b/src/util/vircgroupv2devices.c
@@ -0,0 +1,73 @@
+/*
+ * vircgroupv2devices.c: methods for cgroups v2 BPF devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ */
+#include <config.h>
+
+#if HAVE_DECL_BPF_CGROUP_DEVICE
+# include <fcntl.h>
+# include <linux/bpf.h>
+# include <sys/stat.h>
+# include <sys/syscall.h>
+# include <sys/types.h>
+#endif /* !HAVE_DECL_BPF_CGROUP_DEVICE */
+
+#include "internal.h"
+
+#define LIBVIRT_VIRCGROUPPRIV_H_ALLOW
+#include "vircgrouppriv.h"
+
+#include "virbpf.h"
+#include "vircgroup.h"
+#include "vircgroupv2devices.h"
+#include "virfile.h"
+#include "virlog.h"
+
+VIR_LOG_INIT("util.cgroup");
+
+#define VIR_FROM_THIS VIR_FROM_CGROUP
+
+#if HAVE_DECL_BPF_CGROUP_DEVICE
+bool
+virCgroupV2DevicesAvailable(virCgroupPtr group)
+{
+ bool ret = false;
+ int cgroupfd = -1;
+ unsigned int progCnt = 0;
+
+ cgroupfd = open(group->unified.mountPoint, O_RDONLY);
+ if (cgroupfd < 0) {
+ VIR_DEBUG("failed to open cgroup '%s'",
group->unified.mountPoint);
+ goto cleanup;
+ }
+
+ if (virBPFQueryProg(cgroupfd, 0, BPF_CGROUP_DEVICE, &progCnt, NULL) < 0) {
+ VIR_DEBUG("failed to query cgroup progs");
+ goto cleanup;
+ }
+
+ ret = true;
+ cleanup:
+ VIR_FORCE_CLOSE(cgroupfd);
+ return ret;
+}
+#else /* !HAVE_DECL_BPF_CGROUP_DEVICE */
+bool
+virCgroupV2DevicesAvailable(virCgroupPtr group ATTRIBUTE_UNUSED)
+{
+ return false;
+}
+#endif /* !HAVE_DECL_BPF_CGROUP_DEVICE */
diff --git a/src/util/vircgroupv2devices.h b/src/util/vircgroupv2devices.h
new file mode 100644
index 0000000000..2ab35681db
--- /dev/null
+++ b/src/util/vircgroupv2devices.h
@@ -0,0 +1,27 @@
+/*
+ * vircgroupv2devices.h: methods for cgroups v2 BPF devices
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <
http://www.gnu.org/licenses/>.
+ */
+
+#ifndef LIBVIRT_VIRCGROUPV2DEVICES_H
+# define LIBVIRT_VIRCGROUPV2DEVICES_H
+
+# include "vircgroup.h"
+
+bool
+virCgroupV2DevicesAvailable(virCgroupPtr group);
+
+#endif /* LIBVIRT_VIRCGROUPV2DEVICES_H */
--
2.20.1