diff --git a/man/systemd.link.xml b/man/systemd.link.xml
index 162674f769..fb091b883c 100644
--- a/man/systemd.link.xml
+++ b/man/systemd.link.xml
@@ -172,6 +172,17 @@
for details.
+
+ KernelVersion=
+
+ Checks whether the kernel version (as reported by uname -r) matches a certain
+ expression (or if prefixed with the exclamation mark does not match it). See
+ ConditionKernelVersion= in
+ systemd.unit5 for
+ details.
+
+
+
Architecture=
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index 4e5d47f585..b9647a2f7a 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -232,6 +232,16 @@
+
+ KernelVersion=
+
+ Checks whether the kernel version (as reported by uname -r) matches a certain
+ expression (or if prefixed with the exclamation mark does not match it). See
+ ConditionKernelVersion= in
+ systemd.unit5 for details.
+
+
+
Architecture=
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 3466f3a3cf..f78beaa7dc 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -193,6 +193,17 @@
+
+ KernelVersion=
+
+ Checks whether the kernel version (as reported by uname -r) matches a certain
+ expression (or if prefixed with the exclamation mark does not match it). See
+ ConditionKernelVersion= in
+ systemd.unit5 for
+ details.
+
+
+
Architecture=
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index 005fdea73c..0d35d619e0 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -923,6 +923,7 @@
ConditionVirtualization=
ConditionHost=
ConditionKernelCommandLine=
+ ConditionKernelVersion=
ConditionSecurity=
ConditionCapability=
ConditionACPower=
@@ -1050,6 +1051,10 @@
the exact assignment is looked for with right and left hand
side matching.
+ ConditionKernelVersion= may be used to check whether the kernel version (as reported
+ by uname -r) matches a certain expression (or if prefixed with the exclamation mark does not
+ match it). The argument must be a single string, optionally containing shell-style globs.
+
ConditionSecurity= may be used to
check whether the given security module is enabled on the
system. Currently, the recognized values are
@@ -1201,6 +1206,7 @@
AssertVirtualization=
AssertHost=
AssertKernelCommandLine=
+ AssertKernelVersion=
AssertSecurity=
AssertCapability=
AssertACPower=
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 5604312bc5..549c7eb4d6 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -241,6 +241,7 @@ Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_F
Unit.ConditionNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, offsetof(Unit, conditions)
Unit.ConditionFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, offsetof(Unit, conditions)
Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, conditions)
+Unit.ConditionKernelVersion, config_parse_unit_condition_string, CONDITION_KERNEL_VERSION, offsetof(Unit, conditions)
Unit.ConditionArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, conditions)
Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, conditions)
Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, conditions)
@@ -263,6 +264,7 @@ Unit.AssertFileIsExecutable, config_parse_unit_condition_path, CONDITION_F
Unit.AssertNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, offsetof(Unit, asserts)
Unit.AssertFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, offsetof(Unit, asserts)
Unit.AssertKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, asserts)
+Unit.AssertKernelVersion, config_parse_unit_condition_string, CONDITION_KERNEL_VERSION, offsetof(Unit, asserts)
Unit.AssertArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, asserts)
Unit.AssertVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, asserts)
Unit.AssertSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, asserts)
diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index e48b7d22dd..c20e9fca35 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -116,7 +116,8 @@ bool net_match_config(const struct ether_addr *match_mac,
char * const *match_names,
Condition *match_host,
Condition *match_virt,
- Condition *match_kernel,
+ Condition *match_kernel_cmdline,
+ Condition *match_kernel_version,
Condition *match_arch,
const struct ether_addr *dev_mac,
const char *dev_path,
@@ -131,7 +132,10 @@ bool net_match_config(const struct ether_addr *match_mac,
if (match_virt && condition_test(match_virt) <= 0)
return false;
- if (match_kernel && condition_test(match_kernel) <= 0)
+ if (match_kernel_cmdline && condition_test(match_kernel_cmdline) <= 0)
+ return false;
+
+ if (match_kernel_version && condition_test(match_kernel_version) <= 0)
return false;
if (match_arch && condition_test(match_arch) <= 0)
diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h
index a54adac602..4e69f1a598 100644
--- a/src/libsystemd-network/network-internal.h
+++ b/src/libsystemd-network/network-internal.h
@@ -37,7 +37,8 @@ bool net_match_config(const struct ether_addr *match_mac,
char * const *match_name,
Condition *match_host,
Condition *match_virt,
- Condition *match_kernel,
+ Condition *match_kernel_cmdline,
+ Condition *match_kernel_version,
Condition *match_arch,
const struct ether_addr *dev_mac,
const char *dev_path,
diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf
index 3aeba06ee0..03b8661957 100644
--- a/src/network/netdev/netdev-gperf.gperf
+++ b/src/network/netdev/netdev-gperf.gperf
@@ -33,7 +33,8 @@ struct ConfigPerfItem;
%%
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(NetDev, match_host)
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(NetDev, match_virt)
-Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, match_kernel)
+Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, match_kernel_cmdline)
+Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(NetDev, match_kernel_version)
Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(NetDev, match_arch)
NetDev.Description, config_parse_string, 0, offsetof(NetDev, description)
NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, ifname)
diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c
index 7afe30f7fb..7cf110672f 100644
--- a/src/network/netdev/netdev.c
+++ b/src/network/netdev/netdev.c
@@ -149,7 +149,8 @@ static void netdev_free(NetDev *netdev) {
condition_free_list(netdev->match_host);
condition_free_list(netdev->match_virt);
- condition_free_list(netdev->match_kernel);
+ condition_free_list(netdev->match_kernel_cmdline);
+ condition_free_list(netdev->match_kernel_version);
condition_free_list(netdev->match_arch);
if (NETDEV_VTABLE(netdev) &&
@@ -642,7 +643,8 @@ static int netdev_load_one(Manager *manager, const char *filename) {
/* skip out early if configuration does not match the environment */
if (net_match_config(NULL, NULL, NULL, NULL, NULL,
netdev_raw->match_host, netdev_raw->match_virt,
- netdev_raw->match_kernel, netdev_raw->match_arch,
+ netdev_raw->match_kernel_cmdline, netdev_raw->match_kernel_version,
+ netdev_raw->match_arch,
NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
return 0;
diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h
index 24915b2b04..507b86a078 100644
--- a/src/network/netdev/netdev.h
+++ b/src/network/netdev/netdev.h
@@ -93,7 +93,8 @@ typedef struct NetDev {
Condition *match_host;
Condition *match_virt;
- Condition *match_kernel;
+ Condition *match_kernel_cmdline;
+ Condition *match_kernel_version;
Condition *match_arch;
NetDevState state;
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 57a96aff94..cb0c01fbe7 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -27,7 +27,8 @@ Match.Type, config_parse_strv,
Match.Name, config_parse_ifnames, 0, offsetof(Network, match_name)
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, match_host)
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, match_virt)
-Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel)
+Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel_cmdline)
+Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(Network, match_kernel_version)
Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch)
Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac)
Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 8e37a0a229..b037fc67e3 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -431,7 +431,8 @@ void network_free(Network *network) {
condition_free_list(network->match_host);
condition_free_list(network->match_virt);
- condition_free_list(network->match_kernel);
+ condition_free_list(network->match_kernel_cmdline);
+ condition_free_list(network->match_kernel_version);
condition_free_list(network->match_arch);
free(network->dhcp_server_timezone);
@@ -485,8 +486,8 @@ int network_get(Manager *manager, struct udev_device *device,
if (net_match_config(network->match_mac, network->match_path,
network->match_driver, network->match_type,
network->match_name, network->match_host,
- network->match_virt, network->match_kernel,
- network->match_arch,
+ network->match_virt, network->match_kernel_cmdline,
+ network->match_kernel_version, network->match_arch,
address, path, parent_driver, driver,
devtype, ifname)) {
if (network->match_name && device) {
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 49c62654b6..702aa7692a 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -112,7 +112,8 @@ struct Network {
Condition *match_host;
Condition *match_virt;
- Condition *match_kernel;
+ Condition *match_kernel_cmdline;
+ Condition *match_kernel_version;
Condition *match_arch;
char *description;
diff --git a/src/shared/condition.c b/src/shared/condition.c
index d4bbaf3c65..887c9a7588 100644
--- a/src/shared/condition.c
+++ b/src/shared/condition.c
@@ -26,6 +26,7 @@
#include
#include
#include
+#include
#include
#include
@@ -143,6 +144,18 @@ static int condition_test_kernel_command_line(Condition *c) {
return false;
}
+static int condition_test_kernel_version(Condition *c) {
+ struct utsname u;
+
+ assert(c);
+ assert(c->parameter);
+ assert(c->type == CONDITION_KERNEL_VERSION);
+
+ assert_se(uname(&u) >= 0);
+
+ return fnmatch(c->parameter, u.release, 0) == 0;
+}
+
static int condition_test_user(Condition *c) {
uid_t id;
int r;
@@ -552,6 +565,7 @@ int condition_test(Condition *c) {
[CONDITION_FILE_NOT_EMPTY] = condition_test_file_not_empty,
[CONDITION_FILE_IS_EXECUTABLE] = condition_test_file_is_executable,
[CONDITION_KERNEL_COMMAND_LINE] = condition_test_kernel_command_line,
+ [CONDITION_KERNEL_VERSION] = condition_test_kernel_version,
[CONDITION_VIRTUALIZATION] = condition_test_virtualization,
[CONDITION_SECURITY] = condition_test_security,
[CONDITION_CAPABILITY] = condition_test_capability,
@@ -612,6 +626,7 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
[CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
[CONDITION_HOST] = "ConditionHost",
[CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
+ [CONDITION_KERNEL_VERSION] = "ConditionKernelVersion",
[CONDITION_SECURITY] = "ConditionSecurity",
[CONDITION_CAPABILITY] = "ConditionCapability",
[CONDITION_AC_POWER] = "ConditionACPower",
@@ -639,6 +654,7 @@ static const char* const assert_type_table[_CONDITION_TYPE_MAX] = {
[CONDITION_VIRTUALIZATION] = "AssertVirtualization",
[CONDITION_HOST] = "AssertHost",
[CONDITION_KERNEL_COMMAND_LINE] = "AssertKernelCommandLine",
+ [CONDITION_KERNEL_VERSION] = "AssertKernelVersion",
[CONDITION_SECURITY] = "AssertSecurity",
[CONDITION_CAPABILITY] = "AssertCapability",
[CONDITION_AC_POWER] = "AssertACPower",
diff --git a/src/shared/condition.h b/src/shared/condition.h
index 715866be70..98af2daaee 100644
--- a/src/shared/condition.h
+++ b/src/shared/condition.h
@@ -31,6 +31,7 @@ typedef enum ConditionType {
CONDITION_VIRTUALIZATION,
CONDITION_HOST,
CONDITION_KERNEL_COMMAND_LINE,
+ CONDITION_KERNEL_VERSION,
CONDITION_SECURITY,
CONDITION_CAPABILITY,
CONDITION_AC_POWER,
diff --git a/src/test/test-condition.c b/src/test/test-condition.c
index bf455aac89..8fb2ad5d18 100644
--- a/src/test/test-condition.c
+++ b/src/test/test-condition.c
@@ -20,6 +20,7 @@
#include
#include
+#include
#include
#include "sd-id128.h"
@@ -38,10 +39,11 @@
#include "selinux-util.h"
#include "set.h"
#include "smack-util.h"
+#include "string-util.h"
#include "strv.h"
-#include "virt.h"
-#include "util.h"
#include "user-util.h"
+#include "util.h"
+#include "virt.h"
static void test_condition_test_path(void) {
Condition *condition;
@@ -298,6 +300,41 @@ static void test_condition_test_kernel_command_line(void) {
condition_free(condition);
}
+static void test_condition_test_kernel_version(void) {
+ Condition *condition;
+ struct utsname u;
+
+ condition = condition_new(CONDITION_KERNEL_VERSION, "*thisreallyshouldntbeinthekernelversion*", false, false);
+ assert_se(condition);
+ assert_se(!condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_KERNEL_VERSION, "*", false, false);
+ assert_se(condition);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ condition = condition_new(CONDITION_KERNEL_VERSION, "", false, false);
+ assert_se(condition);
+ assert_se(!condition_test(condition));
+ condition_free(condition);
+
+ assert_se(uname(&u) >= 0);
+
+ condition = condition_new(CONDITION_KERNEL_VERSION, u.release, false, false);
+ assert_se(condition);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+
+ strshorten(u.release, 4);
+ strcpy(strchr(u.release, 0), "*");
+
+ condition = condition_new(CONDITION_KERNEL_VERSION, u.release, false, false);
+ assert_se(condition);
+ assert_se(condition_test(condition));
+ condition_free(condition);
+}
+
static void test_condition_test_null(void) {
Condition *condition;
@@ -556,6 +593,7 @@ int main(int argc, char *argv[]) {
test_condition_test_host();
test_condition_test_architecture();
test_condition_test_kernel_command_line();
+ test_condition_test_kernel_version();
test_condition_test_null();
test_condition_test_security();
test_condition_test_virtualization();
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
index 85f0a0625b..5cb126d870 100644
--- a/src/udev/net/link-config-gperf.gperf
+++ b/src/udev/net/link-config-gperf.gperf
@@ -26,7 +26,8 @@ Match.Driver, config_parse_strv, 0,
Match.Type, config_parse_strv, 0, offsetof(link_config, match_type)
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(link_config, match_host)
Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(link_config, match_virt)
-Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, match_kernel)
+Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, match_kernel_cmdline)
+Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(link_config, match_kernel_version)
Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(link_config, match_arch)
Link.Description, config_parse_string, 0, offsetof(link_config, description)
Link.MACAddressPolicy, config_parse_mac_policy, 0, offsetof(link_config, mac_policy)
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index 92d41a6e95..a4368f088d 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -77,7 +77,8 @@ static void link_config_free(link_config *link) {
free(link->match_name);
free(link->match_host);
free(link->match_virt);
- free(link->match_kernel);
+ free(link->match_kernel_cmdline);
+ free(link->match_kernel_version);
free(link->match_arch);
free(link->description);
@@ -248,7 +249,8 @@ int link_config_get(link_config_ctx *ctx, struct udev_device *device,
if (net_match_config(link->match_mac, link->match_path, link->match_driver,
link->match_type, link->match_name, link->match_host,
- link->match_virt, link->match_kernel, link->match_arch,
+ link->match_virt, link->match_kernel_cmdline,
+ link->match_kernel_version, link->match_arch,
attr_value ? ether_aton(attr_value) : NULL,
udev_device_get_property_value(device, "ID_PATH"),
udev_device_get_driver(udev_device_get_parent(device)),
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index a413251bd0..dabc3eff8f 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -58,7 +58,8 @@ struct link_config {
char **match_name;
Condition *match_host;
Condition *match_virt;
- Condition *match_kernel;
+ Condition *match_kernel_cmdline;
+ Condition *match_kernel_version;
Condition *match_arch;
char *description;