networkd: add a basic network daemon
This daemon listens for and configures network devices tagged with 'systemd-networkd'. By default, no devices are tagged so this daemon can safely run in parallel with existing network daemons/scripts. Networks are configured in /etc/systemd/network/*.network. The first .network file that matches a given link is applied. The matching logic is similar to the one for .link files, but additionally supports matching on interface name. The mid-term aim is to provide an alternative to ad-hoc scripts currently used in initrd's and for wired setups that don't change much (e.g., as seen on servers/and some embedded systems). Currently, static addresses and a gateway can be configured. Example .network file: [Match] Name=wlp2s0 [Network] Description=My Network Gateway=192.168.1.1 Address=192.168.1.23/24 Address=fe80::9aee:94ff:fe3f:c618/64
This commit is contained in:
parent
f52841825a
commit
f579559b3a
|
@ -58,6 +58,7 @@
|
||||||
/systemd-machined
|
/systemd-machined
|
||||||
/systemd-modules-load
|
/systemd-modules-load
|
||||||
/systemd-multi-seat-x
|
/systemd-multi-seat-x
|
||||||
|
/systemd-networkd
|
||||||
/systemd-notify
|
/systemd-notify
|
||||||
/systemd-nspawn
|
/systemd-nspawn
|
||||||
/systemd-quotacheck
|
/systemd-quotacheck
|
||||||
|
@ -133,6 +134,7 @@
|
||||||
/test-loopback
|
/test-loopback
|
||||||
/test-mmap-cache
|
/test-mmap-cache
|
||||||
/test-namespace
|
/test-namespace
|
||||||
|
/test-network
|
||||||
/test-ns
|
/test-ns
|
||||||
/test-path-util
|
/test-path-util
|
||||||
/test-prioq
|
/test-prioq
|
||||||
|
|
54
Makefile.am
54
Makefile.am
|
@ -177,6 +177,7 @@ AM_CPPFLAGS = \
|
||||||
-DKEXEC=\"$(KEXEC)\" \
|
-DKEXEC=\"$(KEXEC)\" \
|
||||||
-I $(top_srcdir)/src \
|
-I $(top_srcdir)/src \
|
||||||
-I $(top_srcdir)/src/shared \
|
-I $(top_srcdir)/src/shared \
|
||||||
|
-I $(top_srcdir)/src/network \
|
||||||
-I $(top_srcdir)/src/login \
|
-I $(top_srcdir)/src/login \
|
||||||
-I $(top_srcdir)/src/journal \
|
-I $(top_srcdir)/src/journal \
|
||||||
-I $(top_srcdir)/src/systemd \
|
-I $(top_srcdir)/src/systemd \
|
||||||
|
@ -3770,6 +3771,59 @@ EXTRA_DIST += \
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
rootlibexec_PROGRAMS += \
|
||||||
|
systemd-networkd
|
||||||
|
|
||||||
|
systemd_networkd_SOURCES = \
|
||||||
|
src/network/networkd.h \
|
||||||
|
src/network/networkd.c \
|
||||||
|
src/network/networkd-link.c \
|
||||||
|
src/network/networkd-network.c \
|
||||||
|
src/network/networkd-address.c \
|
||||||
|
src/network/networkd-route.c \
|
||||||
|
src/network/networkd-manager.c
|
||||||
|
|
||||||
|
nodist_systemd_networkd_SOURCES = \
|
||||||
|
src/network/networkd-gperf.c
|
||||||
|
|
||||||
|
systemd_networkd_LDADD = \
|
||||||
|
libudev-internal.la \
|
||||||
|
libsystemd-bus.la \
|
||||||
|
libsystemd-rtnl.la \
|
||||||
|
libsystemd-shared.la
|
||||||
|
|
||||||
|
nodist_systemunit_DATA += \
|
||||||
|
units/systemd-networkd.service
|
||||||
|
|
||||||
|
MULTI_USER_TARGET_WANTS += \
|
||||||
|
systemd-networkd.service
|
||||||
|
|
||||||
|
test_network_SOURCES = \
|
||||||
|
src/network/test-network.c \
|
||||||
|
src/network/networkd.h \
|
||||||
|
src/network/networkd-link.c \
|
||||||
|
src/network/networkd-network.c \
|
||||||
|
src/network/networkd-address.c \
|
||||||
|
src/network/networkd-route.c \
|
||||||
|
src/network/networkd-manager.c \
|
||||||
|
src/network/networkd-gperf.c
|
||||||
|
|
||||||
|
test_network_LDADD = \
|
||||||
|
libudev-internal.la \
|
||||||
|
libsystemd-bus.la \
|
||||||
|
libsystemd-rtnl.la \
|
||||||
|
libsystemd-shared.la
|
||||||
|
|
||||||
|
tests += test-network
|
||||||
|
|
||||||
|
EXTRA_DIST += \
|
||||||
|
src/network/networkd-gperf.gperf \
|
||||||
|
units/systemd-networkd.service.in
|
||||||
|
|
||||||
|
CLEANFILES += \
|
||||||
|
src/network/networkd-gperf.c
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
if ENABLE_LOGIND
|
if ENABLE_LOGIND
|
||||||
systemd_logind_SOURCES = \
|
systemd_logind_SOURCES = \
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
/networkd-gperf.c
|
|
@ -0,0 +1 @@
|
||||||
|
../Makefile
|
|
@ -0,0 +1,169 @@
|
||||||
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
Copyright 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 <net/if.h>
|
||||||
|
|
||||||
|
#include "networkd.h"
|
||||||
|
|
||||||
|
#include "utf8.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "conf-parser.h"
|
||||||
|
#include "net-util.h"
|
||||||
|
|
||||||
|
int address_new(Network *network, Address **ret) {
|
||||||
|
_cleanup_address_free_ Address *address = NULL;
|
||||||
|
|
||||||
|
address = new0(Address, 1);
|
||||||
|
if (!address)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
address->network = network;
|
||||||
|
|
||||||
|
LIST_PREPEND(addresses, network->addresses, address);
|
||||||
|
|
||||||
|
*ret = address;
|
||||||
|
address = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void address_free(Address *address) {
|
||||||
|
if (!address)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LIST_REMOVE(addresses, address->network->addresses, address);
|
||||||
|
|
||||||
|
free(address->label);
|
||||||
|
free(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
int address_configure(Manager *manager, Address *address, Link *link) {
|
||||||
|
_cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = sd_rtnl_message_addr_new(RTM_NEWADDR, link->ifindex,
|
||||||
|
address->family, address->prefixlen,
|
||||||
|
IFA_F_PERMANENT, RT_SCOPE_UNIVERSE, &req);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not allocate RTM_NEWADDR message: %s",
|
||||||
|
strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_rtnl_message_append(req, IFA_LOCAL, &address->in_addr);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not append IFA_LOCAL attribute: %s",
|
||||||
|
strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address->family == AF_INET) {
|
||||||
|
struct in_addr broadcast;
|
||||||
|
|
||||||
|
broadcast.s_addr = address->in_addr.in.s_addr |
|
||||||
|
htonl(0xfffffffflu >> address->prefixlen);
|
||||||
|
|
||||||
|
r = sd_rtnl_message_append(req, IFA_BROADCAST, &broadcast);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not append IFA_BROADCAST attribute: %s",
|
||||||
|
strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address->label) {
|
||||||
|
r = sd_rtnl_message_append(req, IFA_LABEL, address->label);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not append IFA_LABEL attribute: %s",
|
||||||
|
strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_rtnl_send_with_reply_and_block(manager->rtnl, req, 0, NULL);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not configure address: %s", strerror(-r));
|
||||||
|
return r != -EEXIST ? r : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("Configured interface address");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_parse_address(const char *unit,
|
||||||
|
const char *filename,
|
||||||
|
unsigned line,
|
||||||
|
const char *section,
|
||||||
|
const char *lvalue,
|
||||||
|
int ltype,
|
||||||
|
const char *rvalue,
|
||||||
|
void *data,
|
||||||
|
void *userdata) {
|
||||||
|
_cleanup_address_free_ Address *n = NULL;
|
||||||
|
_cleanup_free_ char *address = NULL;
|
||||||
|
const char *e;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(filename);
|
||||||
|
assert(lvalue);
|
||||||
|
assert(rvalue);
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
r = address_new(userdata, &n);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* Address=address/prefixlen */
|
||||||
|
|
||||||
|
/* prefixlen */
|
||||||
|
e = strchr(rvalue, '/');
|
||||||
|
if (e) {
|
||||||
|
unsigned i;
|
||||||
|
r = safe_atou(e + 1, &i);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||||
|
"Interface prefix length is invalid, "
|
||||||
|
"ignoring assignment: %s", e + 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
n->prefixlen = (unsigned char) i;
|
||||||
|
address = strndup(rvalue, e - rvalue);
|
||||||
|
if (!address)
|
||||||
|
return log_oom();
|
||||||
|
} else {
|
||||||
|
address = strdup(rvalue);
|
||||||
|
if (!address)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
|
r = net_parse_inaddr(address, &n->family, &n->in_addr);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||||
|
"Address is invalid, ignoring assignment: %s", address);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
%{
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "conf-parser.h"
|
||||||
|
#include "networkd.h"
|
||||||
|
#include "net-util.h"
|
||||||
|
%}
|
||||||
|
struct ConfigPerfItem;
|
||||||
|
%null_strings
|
||||||
|
%language=ANSI-C
|
||||||
|
%define slot-name section_and_lvalue
|
||||||
|
%define hash-function-name network_gperf_hash
|
||||||
|
%define lookup-function-name network_gperf_lookup
|
||||||
|
%readonly-tables
|
||||||
|
%omit-struct-type
|
||||||
|
%struct-type
|
||||||
|
%includes
|
||||||
|
%%
|
||||||
|
Match.MACAddress, config_parse_hwaddr, 0, offsetof(Network, match_mac)
|
||||||
|
Match.Path, config_parse_string, 0, offsetof(Network, match_path)
|
||||||
|
Match.Driver, config_parse_string, 0, offsetof(Network, match_driver)
|
||||||
|
Match.Type, config_parse_string, 0, offsetof(Network, match_type)
|
||||||
|
Match.Name, config_parse_ifname, 0, offsetof(Network, match_name)
|
||||||
|
Network.Description, config_parse_string, 0, offsetof(Network, description)
|
||||||
|
Network.Address, config_parse_address, 0, 0
|
||||||
|
Network.Gateway, config_parse_gateway, 0, 0
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
Copyright 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 <netinet/ether.h>
|
||||||
|
#include <linux/if.h>
|
||||||
|
|
||||||
|
#include "networkd.h"
|
||||||
|
#include "libudev-private.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
int link_new(Manager *manager, struct udev_device *device, Link **ret) {
|
||||||
|
_cleanup_link_free_ Link *link = NULL;
|
||||||
|
uint64_t ifindex;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(device);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
link = new0(Link, 1);
|
||||||
|
if (!link)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ifindex = udev_device_get_ifindex(device);
|
||||||
|
if (ifindex <= 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
link->ifindex = ifindex;
|
||||||
|
link->manager = manager;
|
||||||
|
|
||||||
|
r = hashmap_put(manager->links, &ifindex, link);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
*ret = link;
|
||||||
|
link = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void link_free(Link *link) {
|
||||||
|
if (!link)
|
||||||
|
return;
|
||||||
|
|
||||||
|
network_free(link->network);
|
||||||
|
|
||||||
|
hashmap_remove(link->manager->links, link);
|
||||||
|
|
||||||
|
free(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
int link_add(Manager *m, struct udev_device *device) {
|
||||||
|
Link *link;
|
||||||
|
Network *network;
|
||||||
|
int r;
|
||||||
|
uint64_t ifindex;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
assert(device);
|
||||||
|
|
||||||
|
ifindex = udev_device_get_ifindex(device);
|
||||||
|
link = hashmap_get(m->links, &ifindex);
|
||||||
|
if (link)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = link_new(m, device, &link);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("could not create link: %s", strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = network_get(m, device, &network);
|
||||||
|
if (r < 0)
|
||||||
|
return r == -ENOENT ? 0 : r;
|
||||||
|
|
||||||
|
r = network_apply(m, network, link);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int link_up(Manager *manager, Link *link) {
|
||||||
|
_cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = sd_rtnl_message_link_new(RTM_NEWLINK, link->ifindex, 0, IFF_UP, &req);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not allocate RTM_NEWLINK message");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_rtnl_send_with_reply_and_block(manager->rtnl, req, 0, NULL);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not UP link: %s", strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("Link is UP");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,210 @@
|
||||||
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
Copyright 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 "path-util.h"
|
||||||
|
#include "networkd.h"
|
||||||
|
#include "libudev-private.h"
|
||||||
|
|
||||||
|
int manager_new(Manager **ret) {
|
||||||
|
_cleanup_manager_free_ Manager *m = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
m = new0(Manager, 1);
|
||||||
|
if (!m)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
r = sd_event_new(&m->event);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_rtnl_open(0, &m->rtnl);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
m->udev = udev_new();
|
||||||
|
if (!m->udev)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
|
||||||
|
if (!m->udev_monitor)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
m->links = hashmap_new(uint64_hash_func, uint64_compare_func);
|
||||||
|
if (!m->links)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
LIST_HEAD_INIT(m->networks);
|
||||||
|
|
||||||
|
m->network_dirs = strv_new("/etc/systemd/network/",
|
||||||
|
"/run/systemd/network/",
|
||||||
|
"/usr/lib/systemd/network",
|
||||||
|
#ifdef HAVE_SPLIT_USER
|
||||||
|
"/lib/systemd/network",
|
||||||
|
#endif
|
||||||
|
NULL);
|
||||||
|
if (!m->network_dirs)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (!path_strv_canonicalize_uniq(m->network_dirs))
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*ret = m;
|
||||||
|
m = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void manager_free(Manager *m) {
|
||||||
|
udev_monitor_unref(m->udev_monitor);
|
||||||
|
udev_unref(m->udev);
|
||||||
|
sd_event_source_unref(m->udev_event_source);
|
||||||
|
sd_event_unref(m->event);
|
||||||
|
hashmap_free(m->links);
|
||||||
|
strv_free(m->network_dirs);
|
||||||
|
sd_rtnl_unref(m->rtnl);
|
||||||
|
|
||||||
|
free(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int manager_process_link(Manager *m, struct udev_device *device) {
|
||||||
|
Link *link;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (streq_ptr(udev_device_get_action(device), "remove")) {
|
||||||
|
uint64_t ifindex;
|
||||||
|
|
||||||
|
ifindex = udev_device_get_ifindex(device);
|
||||||
|
link = hashmap_get(m->links, &ifindex);
|
||||||
|
if (!link)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
link_free(link);
|
||||||
|
} else {
|
||||||
|
r = link_add(m, device);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not handle link %s: %s",
|
||||||
|
udev_device_get_sysname(device),
|
||||||
|
strerror(-r));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int manager_udev_enumerate_links(Manager *m) {
|
||||||
|
struct udev_list_entry *item = NULL, *first = NULL;
|
||||||
|
struct udev_enumerate *e;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
|
||||||
|
e = udev_enumerate_new(m->udev);
|
||||||
|
if (!e) {
|
||||||
|
r = -ENOMEM;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = udev_enumerate_add_match_subsystem(e, "net");
|
||||||
|
if (r < 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
r = udev_enumerate_add_match_tag(e, "systemd-networkd");
|
||||||
|
if (r < 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
r = udev_enumerate_scan_devices(e);
|
||||||
|
if (r < 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
first = udev_enumerate_get_list_entry(e);
|
||||||
|
udev_list_entry_foreach(item, first) {
|
||||||
|
struct udev_device *d;
|
||||||
|
int k;
|
||||||
|
|
||||||
|
d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
|
||||||
|
if (!d) {
|
||||||
|
r = -ENOMEM;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
k = manager_process_link(m, d);
|
||||||
|
udev_device_unref(d);
|
||||||
|
|
||||||
|
if (k < 0)
|
||||||
|
r = k;
|
||||||
|
}
|
||||||
|
|
||||||
|
finish:
|
||||||
|
if (e)
|
||||||
|
udev_enumerate_unref(e);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
|
||||||
|
Manager *m = userdata;
|
||||||
|
struct udev_monitor *monitor = m->udev_monitor;
|
||||||
|
struct udev_device *device;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
device = udev_monitor_receive_device(monitor);
|
||||||
|
if (!device)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
r = manager_process_link(m, device);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
udev_device_unref(device);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int manager_udev_listen(Manager *m) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not add udev monitor filter: %s", strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd-networkd");
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not add udev monitor filter: %s", strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = udev_monitor_enable_receiving(m->udev_monitor);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not enable udev monitor");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_event_add_io(m->event,
|
||||||
|
udev_monitor_get_fd(m->udev_monitor),
|
||||||
|
EPOLLIN, manager_dispatch_link_udev,
|
||||||
|
m, &m->udev_event_source);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,186 @@
|
||||||
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
Copyright 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 "networkd.h"
|
||||||
|
#include "net-util.h"
|
||||||
|
#include "path-util.h"
|
||||||
|
#include "conf-files.h"
|
||||||
|
#include "conf-parser.h"
|
||||||
|
|
||||||
|
static int network_load_one(Manager *manager, const char *filename) {
|
||||||
|
_cleanup_network_free_ Network *network = NULL;
|
||||||
|
_cleanup_fclose_ FILE *file = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
file = fopen(filename, "re");
|
||||||
|
if (!file) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
network = new0(Network, 1);
|
||||||
|
if (!network)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
LIST_HEAD_INIT(network->addresses);
|
||||||
|
|
||||||
|
r = config_parse(NULL, filename, file, "Match\0Network\0", config_item_perf_lookup,
|
||||||
|
(void*) network_gperf_lookup, false, false, network);
|
||||||
|
if (r < 0) {
|
||||||
|
log_warning("Could not parse config file %s: %s", filename, strerror(-r));
|
||||||
|
return r;
|
||||||
|
} else
|
||||||
|
log_debug("Parsed configuration file %s", filename);
|
||||||
|
|
||||||
|
network->filename = strdup(filename);
|
||||||
|
if (!network->filename)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
LIST_PREPEND(networks, manager->networks, network);
|
||||||
|
network = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int network_load(Manager *manager) {
|
||||||
|
Network *network;
|
||||||
|
char **files, **f;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(manager);
|
||||||
|
|
||||||
|
while ((network = manager->networks))
|
||||||
|
network_free(network);
|
||||||
|
|
||||||
|
/* update timestamp */
|
||||||
|
paths_check_timestamp(manager->network_dirs, &manager->network_dirs_ts_usec, true);
|
||||||
|
|
||||||
|
r = conf_files_list_strv(&files, ".network", NULL, (const char **)manager->network_dirs);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("failed to enumerate network files: %s", strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
STRV_FOREACH_BACKWARDS(f, files) {
|
||||||
|
r = network_load_one(manager, *f);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
strv_free(files);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool network_should_reload(Manager *manager) {
|
||||||
|
return paths_check_timestamp(manager->network_dirs, &manager->network_dirs_ts_usec, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void network_free(Network *network) {
|
||||||
|
Route *route;
|
||||||
|
Address *address;
|
||||||
|
|
||||||
|
if (!network)
|
||||||
|
return;
|
||||||
|
|
||||||
|
free(network->filename);
|
||||||
|
|
||||||
|
free(network->match_mac);
|
||||||
|
free(network->match_path);
|
||||||
|
free(network->match_driver);
|
||||||
|
free(network->match_type);
|
||||||
|
free(network->match_name);
|
||||||
|
|
||||||
|
free(network->description);
|
||||||
|
|
||||||
|
while ((route = network->routes))
|
||||||
|
route_free(route);
|
||||||
|
|
||||||
|
while ((address = network->addresses))
|
||||||
|
address_free(address);
|
||||||
|
|
||||||
|
LIST_REMOVE(networks, network->manager->networks, network);
|
||||||
|
|
||||||
|
free(network);
|
||||||
|
}
|
||||||
|
|
||||||
|
int network_get(Manager *manager, struct udev_device *device, Network **ret) {
|
||||||
|
Network *network;
|
||||||
|
|
||||||
|
assert(manager);
|
||||||
|
assert(device);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
if (network_should_reload(manager))
|
||||||
|
network_load(manager);
|
||||||
|
|
||||||
|
LIST_FOREACH(networks, network, manager->networks) {
|
||||||
|
if (net_match_config(network->match_mac, network->match_path,
|
||||||
|
network->match_driver, network->match_type,
|
||||||
|
network->match_name,
|
||||||
|
udev_device_get_sysattr_value(device, "address"),
|
||||||
|
udev_device_get_property_value(device, "ID_PATH"),
|
||||||
|
udev_device_get_driver(device),
|
||||||
|
udev_device_get_devtype(device),
|
||||||
|
udev_device_get_sysname(device))) {
|
||||||
|
log_debug("Network file %s applies to link %s",
|
||||||
|
network->filename,
|
||||||
|
udev_device_get_sysname(device));
|
||||||
|
*ret = network;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret = NULL;
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int network_apply(Manager *manager, Network *network, Link *link) {
|
||||||
|
Address *address;
|
||||||
|
Route *route;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
log_info("Network '%s' being applied to link '%u'",
|
||||||
|
network->description, (unsigned) link->ifindex);
|
||||||
|
|
||||||
|
link->network = network;
|
||||||
|
|
||||||
|
LIST_FOREACH(addresses, address, network->addresses) {
|
||||||
|
r = address_configure(manager, address, link);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = link_up(manager, link);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
LIST_FOREACH(routes, route, network->routes) {
|
||||||
|
r = route_configure(manager, route, link);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,129 @@
|
||||||
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
Copyright 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 <net/if.h>
|
||||||
|
|
||||||
|
#include "networkd.h"
|
||||||
|
|
||||||
|
#include "utf8.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "conf-parser.h"
|
||||||
|
#include "net-util.h"
|
||||||
|
|
||||||
|
int route_new(Network *network, Route **ret) {
|
||||||
|
_cleanup_route_free_ Route *route = NULL;
|
||||||
|
|
||||||
|
route = new0(Route, 1);
|
||||||
|
if (!route)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
route->network = network;
|
||||||
|
|
||||||
|
LIST_PREPEND(routes, network->routes, route);
|
||||||
|
|
||||||
|
*ret = route;
|
||||||
|
route = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void route_free(Route *route) {
|
||||||
|
if (!route)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LIST_REMOVE(routes, route->network->routes, route);
|
||||||
|
|
||||||
|
free(route);
|
||||||
|
}
|
||||||
|
|
||||||
|
int route_configure(Manager *manager, Route *route, Link *link) {
|
||||||
|
_cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(manager);
|
||||||
|
assert(link);
|
||||||
|
assert(link->ifindex > 0);
|
||||||
|
assert(route->family == AF_INET || route->family == AF_INET6);
|
||||||
|
|
||||||
|
r = sd_rtnl_message_route_new(RTM_NEWROUTE, route->family, 0, 0, 0,
|
||||||
|
RT_TABLE_MAIN, RT_SCOPE_UNIVERSE, RTPROT_BOOT,
|
||||||
|
RTN_UNICAST, 0, &req);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not create RTM_NEWROUTE message: %s", strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_rtnl_message_append(req, RTA_GATEWAY, &route->in_addr);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not append RTA_GATEWAY attribute: %s", strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_rtnl_message_append(req, RTA_OIF, &link->ifindex);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not append RTA_OIF attribute: %s", strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_rtnl_send_with_reply_and_block(manager->rtnl, req, 0, NULL);
|
||||||
|
if (r < 0) {
|
||||||
|
log_error("Could not configure route: %s", strerror(-r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("Configured route");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_parse_gateway(const char *unit,
|
||||||
|
const char *filename,
|
||||||
|
unsigned line,
|
||||||
|
const char *section,
|
||||||
|
const char *lvalue,
|
||||||
|
int ltype,
|
||||||
|
const char *rvalue,
|
||||||
|
void *data,
|
||||||
|
void *userdata) {
|
||||||
|
_cleanup_route_free_ Route *n = NULL;
|
||||||
|
_cleanup_free_ char *route = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(filename);
|
||||||
|
assert(lvalue);
|
||||||
|
assert(rvalue);
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
r = route_new(userdata, &n);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = net_parse_inaddr(rvalue, &n->family, &n->in_addr);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||||
|
"Route is invalid, ignoring assignment: %s", route);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
Copyright 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 "sd-event.h"
|
||||||
|
|
||||||
|
#include "networkd.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
_cleanup_manager_free_ Manager *m;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
log_set_target(LOG_TARGET_AUTO);
|
||||||
|
log_parse_environment();
|
||||||
|
log_open();
|
||||||
|
|
||||||
|
umask(0022);
|
||||||
|
|
||||||
|
if (argc != 1) {
|
||||||
|
log_error("This program takes no arguments.");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = manager_new(&m);
|
||||||
|
if (r < 0)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
r = manager_udev_listen(m);
|
||||||
|
if (r < 0)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
r = manager_udev_enumerate_links(m);
|
||||||
|
if (r < 0)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
r = sd_event_loop(m->event);
|
||||||
|
if (r < 0)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,170 @@
|
||||||
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
Copyright 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 <arpa/inet.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
|
||||||
|
#include "sd-event.h"
|
||||||
|
#include "sd-rtnl.h"
|
||||||
|
#include "udev.h"
|
||||||
|
|
||||||
|
#include "rtnl-util.h"
|
||||||
|
#include "hashmap.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
typedef struct Network Network;
|
||||||
|
typedef struct Link Link;
|
||||||
|
typedef struct Address Address;
|
||||||
|
typedef struct Route Route;
|
||||||
|
typedef struct Manager Manager;
|
||||||
|
|
||||||
|
struct Network {
|
||||||
|
Manager *manager;
|
||||||
|
|
||||||
|
char *filename;
|
||||||
|
|
||||||
|
struct ether_addr *match_mac;
|
||||||
|
char *match_path;
|
||||||
|
char *match_driver;
|
||||||
|
char *match_type;
|
||||||
|
char *match_name;
|
||||||
|
|
||||||
|
char *description;
|
||||||
|
|
||||||
|
LIST_HEAD(Address, addresses);
|
||||||
|
LIST_HEAD(Route, routes);
|
||||||
|
|
||||||
|
LIST_FIELDS(Network, networks);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Address {
|
||||||
|
Network *network;
|
||||||
|
|
||||||
|
unsigned char family;
|
||||||
|
unsigned char prefixlen;
|
||||||
|
char *label;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct in_addr in;
|
||||||
|
struct in6_addr in6;
|
||||||
|
} in_addr;
|
||||||
|
|
||||||
|
LIST_FIELDS(Address, addresses);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Route {
|
||||||
|
Network *network;
|
||||||
|
|
||||||
|
unsigned char family;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct in_addr in;
|
||||||
|
struct in6_addr in6;
|
||||||
|
} in_addr;
|
||||||
|
|
||||||
|
LIST_FIELDS(Route, routes);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Link {
|
||||||
|
Manager *manager;
|
||||||
|
|
||||||
|
int ifindex;
|
||||||
|
|
||||||
|
unsigned flags;
|
||||||
|
|
||||||
|
Network *network;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Manager {
|
||||||
|
sd_rtnl *rtnl;
|
||||||
|
sd_event *event;
|
||||||
|
struct udev *udev;
|
||||||
|
struct udev_monitor *udev_monitor;
|
||||||
|
sd_event_source *udev_event_source;
|
||||||
|
|
||||||
|
Hashmap *links;
|
||||||
|
LIST_HEAD(Network, networks);
|
||||||
|
|
||||||
|
char **network_dirs;
|
||||||
|
usec_t network_dirs_ts_usec;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Manager */
|
||||||
|
|
||||||
|
int manager_new(Manager **ret);
|
||||||
|
void manager_free(Manager *m);
|
||||||
|
|
||||||
|
int manager_udev_enumerate_links(Manager *m);
|
||||||
|
int manager_udev_listen(Manager *m);
|
||||||
|
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
|
||||||
|
#define _cleanup_manager_free_ _cleanup_(manager_freep)
|
||||||
|
|
||||||
|
/* Network */
|
||||||
|
|
||||||
|
int network_load(Manager *manager);
|
||||||
|
bool network_should_reload(Manager *manager);
|
||||||
|
|
||||||
|
void network_free(Network *network);
|
||||||
|
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_free);
|
||||||
|
#define _cleanup_network_free_ _cleanup_(network_freep)
|
||||||
|
|
||||||
|
int network_get(Manager *manager, struct udev_device *device, Network **ret);
|
||||||
|
int network_apply(Manager *manager, Network *network, Link *link);
|
||||||
|
|
||||||
|
const struct ConfigPerfItem* network_gperf_lookup(const char *key, unsigned length);
|
||||||
|
|
||||||
|
/* Route */
|
||||||
|
int route_new(Network *network, Route **ret);
|
||||||
|
void route_free(Route *route);
|
||||||
|
int route_configure(Manager *manager, Route *route, Link *link);
|
||||||
|
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free);
|
||||||
|
#define _cleanup_route_free_ _cleanup_(route_freep)
|
||||||
|
|
||||||
|
int config_parse_gateway(const char *unit, const char *filename, unsigned line,
|
||||||
|
const char *section, const char *lvalue, int ltype,
|
||||||
|
const char *rvalue, void *data, void *userdata);
|
||||||
|
|
||||||
|
/* Address */
|
||||||
|
int address_new(Network *network, Address **ret);
|
||||||
|
void address_free(Address *address);
|
||||||
|
int address_configure(Manager *manager, Address *address, Link *link);
|
||||||
|
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
|
||||||
|
#define _cleanup_address_free_ _cleanup_(address_freep)
|
||||||
|
|
||||||
|
int config_parse_address(const char *unit, const char *filename, unsigned line,
|
||||||
|
const char *section, const char *lvalue, int ltype,
|
||||||
|
const char *rvalue, void *data, void *userdata);
|
||||||
|
|
||||||
|
/* Link */
|
||||||
|
|
||||||
|
int link_new(Manager *manager, struct udev_device *device, Link **ret);
|
||||||
|
void link_free(Link *link);
|
||||||
|
int link_add(Manager *manager, struct udev_device *device);
|
||||||
|
int link_up(Manager *manager, Link *link);
|
||||||
|
|
||||||
|
DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_free);
|
||||||
|
#define _cleanup_link_free_ _cleanup_(link_freep)
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
||||||
|
|
||||||
|
/***
|
||||||
|
This file is part of systemd.
|
||||||
|
|
||||||
|
Copyright 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 "networkd.h"
|
||||||
|
|
||||||
|
static void test_link(struct udev_device *loopback) {
|
||||||
|
_cleanup_manager_free_ Manager *manager = NULL;
|
||||||
|
_cleanup_link_free_ Link *link = NULL;
|
||||||
|
|
||||||
|
manager_new(&manager);
|
||||||
|
|
||||||
|
assert(link_new(manager, loopback, &link) >= 0);
|
||||||
|
assert(link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_network_load(Manager *manager) {
|
||||||
|
assert(network_should_reload(manager) == true);
|
||||||
|
assert(network_load(manager) >= 0);
|
||||||
|
assert(network_should_reload(manager) == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_network_get(Manager *manager, struct udev_device *loopback) {
|
||||||
|
Network *network;
|
||||||
|
|
||||||
|
/* let's assume that the test machine does not have a .network file
|
||||||
|
that applies to the loopback device... */
|
||||||
|
assert(network_get(manager, loopback, &network) == -ENOENT);
|
||||||
|
assert(!network);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
_cleanup_manager_free_ Manager *manager = NULL;
|
||||||
|
struct udev *udev;
|
||||||
|
struct udev_device *loopback;
|
||||||
|
|
||||||
|
assert(manager_new(&manager) >= 0);
|
||||||
|
|
||||||
|
test_network_load(manager);
|
||||||
|
|
||||||
|
udev = udev_new();
|
||||||
|
assert(udev);
|
||||||
|
|
||||||
|
loopback = udev_device_new_from_syspath(udev, "/sys/class/net/lo");
|
||||||
|
assert(loopback);
|
||||||
|
assert(udev_device_get_ifindex(loopback) == 1);
|
||||||
|
|
||||||
|
test_network_get(manager, loopback);
|
||||||
|
|
||||||
|
test_link(loopback);
|
||||||
|
|
||||||
|
assert(manager_udev_enumerate_links(manager) >= 0);
|
||||||
|
assert(manager_udev_listen(manager) >= 0);
|
||||||
|
|
||||||
|
udev_device_unref(loopback);
|
||||||
|
udev_unref(udev);
|
||||||
|
}
|
|
@ -60,6 +60,7 @@
|
||||||
/initrd-parse-etc.service
|
/initrd-parse-etc.service
|
||||||
/initrd-switch-root.service
|
/initrd-switch-root.service
|
||||||
/initrd-udevadm-cleanup-db.service
|
/initrd-udevadm-cleanup-db.service
|
||||||
|
/systemd-networkd.service
|
||||||
/systemd-nspawn@.service
|
/systemd-nspawn@.service
|
||||||
/systemd-machined.service
|
/systemd-machined.service
|
||||||
/kmod-static-nodes.service
|
/kmod-static-nodes.service
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
# This file is part of systemd.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Network Service
|
||||||
|
Documentation=man:systemd-networkd.service(8)
|
||||||
|
DefaultDependencies=no
|
||||||
|
After=sysinit.target
|
||||||
|
Before=network.target
|
||||||
|
Wants=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Restart=always
|
||||||
|
RestartSec=0
|
||||||
|
ExecStart=@rootlibexecdir@/systemd-networkd
|
Loading…
Reference in New Issue