summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am19
-rw-r--r--TODO8
-rw-r--r--rules/85-net-configure-link.rules11
-rw-r--r--src/udev/net/.gitignore1
l---------src/udev/net/Makefile1
-rw-r--r--src/udev/net/link-config-gperf.gperf21
-rw-r--r--src/udev/net/link-config.c244
-rw-r--r--src/udev/net/link-config.h55
-rw-r--r--src/udev/udev-builtin-net_link.c96
-rw-r--r--src/udev/udev-builtin.c1
-rw-r--r--src/udev/udev.h2
11 files changed, 456 insertions, 3 deletions
diff --git a/Makefile.am b/Makefile.am
index c41fdd7fe3..22389a6b90 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -83,6 +83,7 @@ userunitdir=$(prefix)/lib/systemd/user
userpresetdir=$(prefix)/lib/systemd/user-preset
tmpfilesdir=$(prefix)/lib/tmpfiles.d
sysctldir=$(prefix)/lib/sysctl.d
+linkdir=$(prefix)/lib/net/links
pkgincludedir=$(includedir)/systemd
systemgeneratordir=$(rootlibexecdir)/system-generators
usergeneratordir=$(prefix)/lib/systemd/user-generators
@@ -179,6 +180,7 @@ AM_CPPFLAGS = \
-I $(top_srcdir)/src/core \
-I $(top_srcdir)/src/libudev \
-I $(top_srcdir)/src/udev \
+ -I $(top_srcdir)/src/udev/net \
-I $(top_builddir)/src/udev \
-I $(top_srcdir)/src/libsystemd-bus \
$(OUR_CPPFLAGS)
@@ -2208,6 +2210,7 @@ dist_udevrules_DATA += \
rules/75-tty-description.rules \
rules/78-sound-card.rules \
rules/80-net-name-slot.rules \
+ rules/85-net-configure-link.rules \
rules/95-udev-late.rules
dist_udevhwdb_DATA = \
@@ -2288,19 +2291,27 @@ libudev_core_la_SOURCES = \
src/udev/udev-builtin-input_id.c \
src/udev/udev-builtin-keyboard.c \
src/udev/udev-builtin-net_id.c \
+ src/udev/udev-builtin-net_link.c \
src/udev/udev-builtin-path_id.c \
- src/udev/udev-builtin-usb_id.c
+ src/udev/udev-builtin-usb_id.c \
+ src/udev/net/link-config.h \
+ src/udev/net/link-config.c
nodist_libudev_core_la_SOURCES = \
src/udev/keyboard-keys-from-name.h \
- src/udev/keyboard-keys-to-name.h
+ src/udev/keyboard-keys-to-name.h \
+ src/udev/net/link-config-gperf.c
BUILT_SOURCES += \
$(nodist_libudev_core_la_SOURCES)
CLEANFILES += \
src/udev/keyboard-keys-from-name.gperf \
- src/udev/keyboard-keys.txt
+ src/udev/keyboard-keys.txt \
+ src/udev/net/link-config-gperf.c
+
+EXTRA_DIST += \
+ src/udev/net/link-config-gperf.gperf
libudev_core_la_CFLAGS = \
$(AM_CFLAGS) \
@@ -4456,6 +4467,8 @@ endif
INSTALL_DIRS += \
$(prefix)/lib/modules-load.d \
$(sysconfdir)/modules-load.d \
+ $(prefix)/lib/net/links \
+ $(sysconfdir)/net/links \
$(prefix)/lib/sysctl.d \
$(sysconfdir)/sysctl.d \
$(prefix)/lib/kernel/install.d \
diff --git a/TODO b/TODO
index cbb2cbe9bf..a3ea2f3fe8 100644
--- a/TODO
+++ b/TODO
@@ -714,6 +714,14 @@ Features:
* systemd-run is missing zsh completion scripts
+* udev-link-config:
+ - Make sure ID_PATH is always exported and complete for
+ network devices where possible, so we can safely rely
+ on Path= matching
+ - NamePolicy= replace the current naming rules
+ - MACPolicy= support 'firmware', 'synthetic' and 'random'
+ - Check if Driver= is broken, or just my driver (bcma)
+
External:
* dbus:
diff --git a/rules/85-net-configure-link.rules b/rules/85-net-configure-link.rules
new file mode 100644
index 0000000000..29d689325d
--- /dev/null
+++ b/rules/85-net-configure-link.rules
@@ -0,0 +1,11 @@
+# do not edit this file, it will be overwritten on update
+
+SUBSYSTEM!="net", GOTO="net_link_end"
+
+IMPORT{builtin}="path_id"
+
+ACTION!="add", GOTO="net_link_end"
+
+RUN{builtin}="net_link"
+
+LABEL="net_link_end"
diff --git a/src/udev/net/.gitignore b/src/udev/net/.gitignore
new file mode 100644
index 0000000000..9ca85bacc9
--- /dev/null
+++ b/src/udev/net/.gitignore
@@ -0,0 +1 @@
+/link-config-gperf.c
diff --git a/src/udev/net/Makefile b/src/udev/net/Makefile
new file mode 120000
index 0000000000..94aaae2c4d
--- /dev/null
+++ b/src/udev/net/Makefile
@@ -0,0 +1 @@
+../../Makefile \ No newline at end of file
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
new file mode 100644
index 0000000000..c567e6dfaa
--- /dev/null
+++ b/src/udev/net/link-config-gperf.gperf
@@ -0,0 +1,21 @@
+%{
+#include <stddef.h>
+#include "conf-parser.h"
+#include "link-config.h"
+%}
+struct ConfigPerfItem;
+%null_strings
+%language=ANSI-C
+%define slot-name section_and_lvalue
+%define hash-function-name link_config_gperf_hash
+%define lookup-function-name link_config_gperf_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+Match.MACAddress, config_parse_string, 0, offsetof(link_config, match_mac)
+Match.Path, config_parse_string, 0, offsetof(link_config, match_path)
+Match.Driver, config_parse_string, 0, offsetof(link_config, match_driver)
+Match.Type, config_parse_string, 0, offsetof(link_config, match_type)
+Link.Description, config_parse_string, 0, offsetof(link_config, description)
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
new file mode 100644
index 0000000000..7686d87f80
--- /dev/null
+++ b/src/udev/net/link-config.c
@@ -0,0 +1,244 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
+
+ systemd 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.
+
+ systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "link-config.h"
+
+#include "util.h"
+#include "log.h"
+#include "strv.h"
+#include "path-util.h"
+#include "conf-parser.h"
+#include "conf-files.h"
+
+struct link_config_ctx {
+ LIST_HEAD(link_config, links);
+
+ char **link_dirs;
+ usec_t *link_dirs_ts_usec;
+};
+
+int link_config_ctx_new(link_config_ctx **ret) {
+ link_config_ctx *ctx;
+
+ if (!ret)
+ return -EINVAL;
+
+ ctx = new0(link_config_ctx, 1);
+ if (!ctx)
+ return -ENOMEM;
+
+ LIST_HEAD_INIT(ctx->links);
+
+ ctx->link_dirs = strv_new("/etc/net/links",
+ "/run/net/links",
+ "/usr/lib/net/links",
+ NULL);
+ if (!ctx->link_dirs) {
+ log_error("failed to build link config directory array");
+ link_config_ctx_free(ctx);
+ return -ENOMEM;
+ }
+ if (!path_strv_canonicalize_uniq(ctx->link_dirs)) {
+ log_error("failed to canonicalize link config directories\n");
+ link_config_ctx_free(ctx);
+ return -ENOMEM;
+ }
+
+ ctx->link_dirs_ts_usec = calloc(strv_length(ctx->link_dirs), sizeof(usec_t));
+ if(!ctx->link_dirs_ts_usec) {
+ link_config_ctx_free(ctx);
+ return -ENOMEM;
+ }
+
+ *ret = ctx;
+ return 0;
+}
+
+static void link_configs_free(link_config_ctx *ctx) {
+ link_config *link, *link_next;
+
+ if (!ctx)
+ return;
+
+ LIST_FOREACH_SAFE(links, link, link_next, ctx->links) {
+ free(link->filename);
+ free(link->match_path);
+ free(link->match_driver);
+ free(link->match_type);
+ free(link->description);
+
+ free(link);
+ }
+}
+
+void link_config_ctx_free(link_config_ctx *ctx) {
+ if (!ctx)
+ return;
+
+ strv_free(ctx->link_dirs);
+ free(ctx->link_dirs_ts_usec);
+ link_configs_free(ctx);
+
+ free(ctx);
+
+ return;
+}
+
+static int load_link(link_config_ctx *ctx, const char *filename) {
+ link_config *link;
+ FILE *file;
+ int r;
+
+ file = fopen(filename, "re");
+ if (!file) {
+ if (errno == ENOENT)
+ return 0;
+ else
+ return errno;
+ }
+
+ link = new0(link_config, 1);
+ if (!link) {
+ r = log_oom();
+ goto failure;
+ }
+
+ r = config_parse(NULL, filename, file, "Match\0Link\0Ethernet\0", config_item_perf_lookup,
+ (void*) link_config_gperf_lookup, false, false, link);
+ if (r < 0) {
+ log_warning("Colud not parse config file %s: %s", filename, strerror(-r));
+ goto failure;
+ } else
+ log_info("Parsed configuration file %s", filename);
+
+ link->filename = strdup(filename);
+
+ LIST_PREPEND(links, ctx->links, link);
+
+ return 0;
+
+failure:
+ free(link);
+ return r;
+}
+
+int link_config_load(link_config_ctx *ctx) {
+ int r;
+ char **files, **f;
+
+ link_configs_free(ctx);
+
+ /* update timestamps */
+ paths_check_timestamp(ctx->link_dirs, ctx->link_dirs_ts_usec, true);
+
+ r = conf_files_list_strv(&files, ".link", NULL, (const char **)ctx->link_dirs);
+ if (r < 0) {
+ log_error("failed to enumerate link files: %s", strerror(-r));
+ return r;
+ }
+
+ STRV_FOREACH_BACKWARDS(f, files) {
+ r = load_link(ctx, *f);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+bool link_config_should_reload(link_config_ctx *ctx) {
+ return paths_check_timestamp(ctx->link_dirs, ctx->link_dirs_ts_usec, false);
+}
+
+static bool match_config(link_config *match, struct udev_device *device) {
+ const char *property;
+
+ if (match->match_mac) {
+ property = udev_device_get_sysattr_value(device, "address");
+ if (!property || !streq(match->match_mac, property)) {
+ log_debug("Device MAC address (%s) did not match MACAddress=%s", property, match->match_mac);
+ return 0;
+ }
+ }
+
+ if (match->match_path) {
+ property = udev_device_get_property_value(device, "ID_PATH");
+ if (!property || !streq(match->match_path, property)) {
+ log_debug("Device's persistent path (%s) did not match Path=%s", property, match->match_path);
+ return 0;
+ }
+ }
+
+ if (match->match_driver) {
+ property = udev_device_get_driver(device);
+ if (!property || !streq(match->match_driver, property)) {
+ log_debug("Device driver (%s) did not match Driver=%s", property, match->match_driver);
+ return 0;
+ }
+ }
+
+ if (match->match_type) {
+ property = udev_device_get_devtype(device);
+ if (!property || !streq(match->match_type, property)) {
+ log_debug("Device type (%s) did not match Type=%s", property, match->match_type);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int link_config_get(link_config_ctx *ctx, struct udev_device *device, link_config **ret) {
+ link_config *link;
+
+ LIST_FOREACH(links, link, ctx->links) {
+ if (!match_config(link, device)) {
+ log_info("Config file %s does not apply to device %s", link->filename, udev_device_get_sysname(device));
+ } else {
+ log_info("Config file %s applies to device %s", link->filename, udev_device_get_sysname(device));
+ *ret = link;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int link_config_apply(link_config_ctx *ctx, link_config *config, struct udev_device *device) {
+ const char *name;
+ int r;
+
+ name = udev_device_get_sysname(device);
+ if (!name)
+ return -EINVAL;
+
+ log_info("Configuring %s", name);
+
+ if (config->description) {
+ r = udev_device_set_sysattr_value(device, "ifalias", config->description);
+ if (r < 0)
+ log_warning("Could not set description of %s to '%s': %s", name, config->description, strerror(-r));
+ else
+ log_info("Set link description of %s to '%s'", name, config->description);
+ }
+
+ return 0;
+}
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
new file mode 100644
index 0000000000..da5608ce4c
--- /dev/null
+++ b/src/udev/net/link-config.h
@@ -0,0 +1,55 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
+
+ systemd 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.
+
+ systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#pragma once
+
+#include "libudev.h"
+#include "util.h"
+#include "list.h"
+
+
+typedef struct link_config_ctx link_config_ctx;
+typedef struct link_config link_config;
+
+struct link_config {
+ char *filename;
+
+ char *match_mac;
+ char *match_path;
+ char *match_driver;
+ char *match_type;
+
+ char *description;
+
+ LIST_FIELDS(link_config, links);
+};
+
+int link_config_ctx_new(link_config_ctx **ret);
+void link_config_ctx_free(link_config_ctx *ctx);
+
+int link_config_load(link_config_ctx *ctx);
+bool link_config_should_reload(link_config_ctx *ctx);
+
+int link_config_get(link_config_ctx *ctx, struct udev_device *device, struct link_config **ret);
+int link_config_apply(link_config_ctx *ctx, struct link_config *config, struct udev_device *device);
+
+/* gperf lookup function */
+const struct ConfigPerfItem* link_config_gperf_lookup(const char *key, unsigned length);
diff --git a/src/udev/udev-builtin-net_link.c b/src/udev/udev-builtin-net_link.c
new file mode 100644
index 0000000000..d7cbe6a016
--- /dev/null
+++ b/src/udev/udev-builtin-net_link.c
@@ -0,0 +1,96 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Tom Gundersen
+
+ systemd 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.
+
+ systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "link-config.h"
+#include "udev.h"
+#include "log.h"
+
+link_config_ctx *ctx;
+
+static int builtin_net_link(struct udev_device *dev, int argc, char **argv, bool test) {
+ link_config *link;
+ int r;
+
+ if (argc > 1) {
+ log_error("This program takes no arguments.");
+ return EXIT_FAILURE;
+ }
+
+ r = link_config_get(ctx, dev, &link);
+ if (r < 0) {
+ if (r == -ENOENT) {
+ log_info("No matching link configuration found");
+ return EXIT_SUCCESS;
+ } else {
+ log_error("Could not get link config");
+ return EXIT_FAILURE;
+ }
+ }
+
+ r = link_config_apply(ctx, link, dev);
+ if (r < 0) {
+ log_error("Could not apply link config");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int builtin_net_link_init(struct udev *udev) {
+ int r;
+
+ if (ctx)
+ return 0;
+
+ r = link_config_ctx_new(&ctx);
+ if (r < 0)
+ return r;
+
+ r = link_config_load(ctx);
+ if (r < 0)
+ return r;
+
+ log_debug("Created link configuration context");
+ return 0;
+}
+
+static void builtin_net_link_exit(struct udev *udev) {
+ link_config_ctx_free(ctx);
+ log_debug("Unloaded link configuration context");
+}
+
+static bool builtin_net_link_validate(struct udev *udev) {
+ log_debug("Check if link configuration needs reloading");
+ if (!ctx)
+ return false;
+
+ return link_config_should_reload(ctx);
+}
+
+const struct udev_builtin udev_builtin_net_link = {
+ .name = "net_link",
+ .cmd = builtin_net_link,
+ .init = builtin_net_link_init,
+ .exit = builtin_net_link_exit,
+ .validate = builtin_net_link_validate,
+ .help = "configure network link",
+ .run_once = false,
+};
diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c
index 6b3a518c2e..85901e8ee3 100644
--- a/src/udev/udev-builtin.c
+++ b/src/udev/udev-builtin.c
@@ -44,6 +44,7 @@ static const struct udev_builtin *builtins[] = {
[UDEV_BUILTIN_KMOD] = &udev_builtin_kmod,
#endif
[UDEV_BUILTIN_NET_ID] = &udev_builtin_net_id,
+ [UDEV_BUILTIN_NET_LINK] = &udev_builtin_net_link,
[UDEV_BUILTIN_PATH_ID] = &udev_builtin_path_id,
[UDEV_BUILTIN_USB_ID] = &udev_builtin_usb_id,
#ifdef HAVE_ACL
diff --git a/src/udev/udev.h b/src/udev/udev.h
index 29e96d637e..7cca8b8c83 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -153,6 +153,7 @@ enum udev_builtin_cmd {
UDEV_BUILTIN_KMOD,
#endif
UDEV_BUILTIN_NET_ID,
+ UDEV_BUILTIN_NET_LINK,
UDEV_BUILTIN_PATH_ID,
UDEV_BUILTIN_USB_ID,
#ifdef HAVE_ACL
@@ -183,6 +184,7 @@ extern const struct udev_builtin udev_builtin_keyboard;
extern const struct udev_builtin udev_builtin_kmod;
#endif
extern const struct udev_builtin udev_builtin_net_id;
+extern const struct udev_builtin udev_builtin_net_link;
extern const struct udev_builtin udev_builtin_path_id;
extern const struct udev_builtin udev_builtin_usb_id;
extern const struct udev_builtin udev_builtin_uaccess;