diff options
Diffstat (limited to 'src/network')
36 files changed, 1817 insertions, 959 deletions
diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 9d6c453dbc..c78b9444b6 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -19,29 +19,28 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> #include <getopt.h> #include <net/if.h> +#include <stdbool.h> -#include "sd-network.h" -#include "sd-netlink.h" -#include "sd-hwdb.h" #include "sd-device.h" +#include "sd-hwdb.h" +#include "sd-netlink.h" +#include "sd-network.h" -#include "strv.h" -#include "build.h" -#include "util.h" -#include "pager.h" -#include "lldp.h" -#include "netlink-util.h" +#include "arphrd-list.h" #include "device-util.h" +#include "ether-addr-util.h" #include "hwdb-util.h" -#include "arphrd-list.h" +#include "lldp.h" #include "local-addresses.h" +#include "netlink-util.h" +#include "pager.h" #include "socket-util.h" -#include "ether-addr-util.h" -#include "verbs.h" +#include "strv.h" #include "terminal-util.h" +#include "util.h" +#include "verbs.h" static bool arg_no_pager = false; static bool arg_legend = true; @@ -166,10 +165,10 @@ static void operational_state_to_color(const char *state, const char **on, const if (streq_ptr(state, "routable")) { *on = ansi_highlight_green(); - *off = ansi_highlight_off(); + *off = ansi_normal(); } else if (streq_ptr(state, "degraded")) { *on = ansi_highlight_yellow(); - *off = ansi_highlight_off(); + *off = ansi_normal(); } else *on = *off = ""; } @@ -180,13 +179,13 @@ static void setup_state_to_color(const char *state, const char **on, const char if (streq_ptr(state, "configured")) { *on = ansi_highlight_green(); - *off = ansi_highlight_off(); + *off = ansi_normal(); } else if (streq_ptr(state, "configuring")) { *on = ansi_highlight_yellow(); - *off = ansi_highlight_off(); + *off = ansi_normal(); } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) { *on = ansi_highlight_red(); - *off = ansi_highlight_off(); + *off = ansi_normal(); } else *on = *off = ""; } @@ -227,7 +226,7 @@ static int list_links(int argc, char *argv[], void *userdata) { _cleanup_device_unref_ sd_device *d = NULL; const char *on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup; - char devid[2 + DECIMAL_STR_MAX(int)]; + char devid[2 + DECIMAL_STR_MAX(int)]; _cleanup_free_ char *t = NULL; sd_network_link_get_operational_state(links[i].ifindex, &operational_state); @@ -497,7 +496,7 @@ static int link_status_one( sd_hwdb *hwdb, const char *name) { _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL; - _cleanup_free_ char *setup_state = NULL, *operational_state = NULL; + _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL; _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; _cleanup_device_unref_ sd_device *d = NULL; char devid[2 + DECIMAL_STR_MAX(int)]; @@ -570,7 +569,6 @@ static int link_status_one( setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); sd_network_link_get_dns(ifindex, &dns); - sd_network_link_get_ntp(ifindex, &ntp); sd_network_link_get_domains(ifindex, &domains); r = sd_network_link_get_wildcard_domain(ifindex); if (r > 0) { @@ -652,6 +650,8 @@ static int link_status_one( dump_list(" DNS: ", dns); if (!strv_isempty(domains)) dump_list(" Domain: ", domains); + + (void) sd_network_link_get_ntp(ifindex, &ntp); if (!strv_isempty(ntp)) dump_list(" NTP: ", ntp); @@ -661,6 +661,10 @@ static int link_status_one( if (!strv_isempty(carrier_bound_by)) dump_list("Carrier Bound By: ", carrier_bound_by); + (void) sd_network_link_get_timezone(ifindex, &tz); + if (tz) + printf(" Time Zone: %s", tz); + return 0; } @@ -976,7 +980,7 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { return log_warning_errno(r < 0 ? r : ERANGE, "Failed to parse TTL \"%s\": %m", b); - time = now(CLOCK_BOOTTIME); + time = now(clock_boottime_or_monotonic()); if (x < time) continue; @@ -1058,9 +1062,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_NO_PAGER: arg_no_pager = true; diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c index 584a956a7e..d609daafde 100644 --- a/src/network/networkd-address-pool.c +++ b/src/network/networkd-address-pool.c @@ -19,9 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - #include "networkd.h" -#include "networkd-link.h" +#include "networkd-address-pool.h" int address_pool_new( Manager *m, diff --git a/src/network/networkd-address-pool.h b/src/network/networkd-address-pool.h new file mode 100644 index 0000000000..e6207ccce6 --- /dev/null +++ b/src/network/networkd-address-pool.h @@ -0,0 +1,43 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + 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/>. +***/ + +typedef struct AddressPool AddressPool; + +#include "networkd.h" + +struct AddressPool { + Manager *manager; + + int family; + unsigned prefixlen; + + union in_addr_union in_addr; + + LIST_FIELDS(AddressPool, address_pools); +}; + +int address_pool_new(Manager *m, AddressPool **ret, int family, const union in_addr_union *u, unsigned prefixlen); +int address_pool_new_from_string(Manager *m, AddressPool **ret, int family, const char *p, unsigned prefixlen); +void address_pool_free(AddressPool *p); + +int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found); diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 172ca43a7d..388beb5d4c 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -25,8 +25,10 @@ #include "util.h" #include "conf-parser.h" #include "firewall-util.h" +#include "netlink-util.h" + #include "networkd.h" -#include "networkd-link.h" +#include "networkd-address.h" static void address_init(Address *address) { assert(address); @@ -428,15 +430,13 @@ int config_parse_broadcast( return r; if (n->family == AF_INET6) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue); return 0; } r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Broadcast is invalid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue); return 0; } @@ -485,10 +485,10 @@ int config_parse_address(const char *unit, e = strchr(rvalue, '/'); if (e) { unsigned i; + r = safe_atou(e + 1, &i); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Prefix length is invalid, ignoring assignment: %s", e + 1); + log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1); return 0; } @@ -500,23 +500,20 @@ int config_parse_address(const char *unit, r = in_addr_from_string_auto(address, &f, &buffer); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Address is invalid, ignoring assignment: %s", address); + log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address); return 0; } if (!e && f == AF_INET) { r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address); + log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address); return 0; } } if (n->family != AF_UNSPEC && f != n->family) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Address is incompatible, ignoring assignment: %s", address); + log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address); return 0; } @@ -565,9 +562,7 @@ int config_parse_label(const char *unit, return log_oom(); if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Interface label is not ASCII clean or is too" - " long, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is not ASCII clean or is too long, ignoring assignment: %s", rvalue); free(label); return 0; } diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h new file mode 100644 index 0000000000..39789a2382 --- /dev/null +++ b/src/network/networkd-address.h @@ -0,0 +1,73 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + 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 <inttypes.h> +#include <stdbool.h> + +#include "in-addr-util.h" + +typedef struct Address Address; + +#include "networkd.h" +#include "networkd-network.h" +#include "networkd-link.h" + +#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU + +struct Address { + Network *network; + unsigned section; + + int family; + unsigned char prefixlen; + unsigned char scope; + uint32_t flags; + char *label; + + struct in_addr broadcast; + struct ifa_cacheinfo cinfo; + + union in_addr_union in_addr; + union in_addr_union in_addr_peer; + + bool ip_masquerade_done; + + LIST_FIELDS(Address, addresses); +}; + +int address_new_static(Network *network, unsigned section, Address **ret); +int address_new_dynamic(Address **ret); +void address_free(Address *address); +int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback); +int address_update(Address *address, Link *link, sd_netlink_message_handler_t callback); +int address_drop(Address *address, Link *link, sd_netlink_message_handler_t callback); +int address_establish(Address *address, Link *link); +int address_release(Address *address, Link *link); +bool address_equal(Address *a1, Address *a2); + +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, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_broadcast(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_label(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index d446bfa8b3..04f04df117 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -39,8 +39,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_error(link, "could not set DHCPv4 route: %s", - strerror(-r)); + log_link_error_errno(link, r, "Could not set DHCPv4 route: %m"); link_enter_failed(link); } @@ -61,40 +60,25 @@ static int link_set_dhcp_routes(Link *link) { assert(link->dhcp_lease); r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); - if (r < 0 && r != -ENOENT) { - log_link_warning(link, - "DHCP error: could not get gateway: %s", - strerror(-r)); - return r; - } + if (r < 0 && r != -ENODATA) + return log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m"); + if (r >= 0) { struct in_addr address; _cleanup_route_free_ Route *route = NULL; _cleanup_route_free_ Route *route_gw = NULL; r = sd_dhcp_lease_get_address(link->dhcp_lease, &address); - if (r < 0) { - log_link_warning(link, - "DHCP error: could not get address: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_warning_errno(link, r, "DHCP error: could not get address: %m"); r = route_new_dynamic(&route, RTPROT_DHCP); - if (r < 0) { - log_link_error(link, - "Could not allocate route: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_error_errno(link, r, "Could not allocate route: %m"); r = route_new_dynamic(&route_gw, RTPROT_DHCP); - if (r < 0) { - log_link_error(link, - "Could not allocate route: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_error_errno(link, r, "Could not allocate route: %m"); /* The dhcp netmask may mask out the gateway. Add an explicit * route for the gw host so that we can route no matter the @@ -107,12 +91,8 @@ static int link_set_dhcp_routes(Link *link) { route_gw->metrics = link->network->dhcp_route_metric; r = route_configure(route_gw, link, &dhcp4_route_handler); - if (r < 0) { - log_link_warning(link, - "could not set host route: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_warning_errno(link, r, "Could not set host route: %m"); link->dhcp4_messages ++; @@ -123,9 +103,7 @@ static int link_set_dhcp_routes(Link *link) { r = route_configure(route, link, &dhcp4_route_handler); if (r < 0) { - log_link_warning(link, - "could not set routes: %s", - strerror(-r)); + log_link_warning_errno(link, r, "Could not set routes: %m"); link_enter_failed(link); return r; } @@ -134,25 +112,17 @@ static int link_set_dhcp_routes(Link *link) { } n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes); - if (n == -ENOENT) + if (n == -ENODATA) return 0; - if (n < 0) { - log_link_warning(link, - "DHCP error: could not get routes: %s", - strerror(-n)); - - return n; - } + if (n < 0) + return log_link_warning_errno(link, n, "DHCP error: could not get routes: %m"); for (i = 0; i < n; i++) { _cleanup_route_free_ Route *route = NULL; r = route_new_dynamic(&route, RTPROT_DHCP); - if (r < 0) { - log_link_error(link, "Could not allocate route: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_error_errno(link, r, "Could not allocate route: %m"); route->family = AF_INET; route->in_addr.in = static_routes[i].gw_addr; @@ -161,12 +131,8 @@ static int link_set_dhcp_routes(Link *link) { route->metrics = link->network->dhcp_route_metric; r = route_configure(route, link, &dhcp4_route_handler); - if (r < 0) { - log_link_warning(link, - "could not set host route: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_warning_errno(link, r, "Could not set host route: %m"); link->dhcp4_messages ++; } @@ -248,7 +214,7 @@ static int dhcp_lease_lost(Link *link) { address->in_addr.in = addr; address->prefixlen = prefixlen; - address_drop(address, link, &link_address_drop_handler); + address_drop(address, link, &link_address_drop_handler); } } @@ -270,12 +236,16 @@ static int dhcp_lease_lost(Link *link) { if (link->network->dhcp_hostname) { const char *hostname = NULL; - r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname); - if (r >= 0 && hostname) { - r = link_set_hostname(link, ""); + if (link->network->hostname) + hostname = link->network->hostname; + else + (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname); + + if (hostname) { + /* If a hostname was set due to the lease, then unset it now. */ + r = link_set_hostname(link, NULL); if (r < 0) - log_link_error(link, - "Failed to reset transient hostname"); + log_link_warning_errno(link, r, "Failed to reset transient hostname: %m"); } } @@ -294,8 +264,7 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_error(link, "could not set DHCPv4 address: %s", - strerror(-r)); + log_link_error_errno(link, r, "Could not set DHCPv4 address: %m"); link_enter_failed(link); } else if (r >= 0) link_rtnl_process_address(rtnl, m, link->manager); @@ -351,45 +320,30 @@ static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) { assert(link->network); r = sd_dhcp_client_get_lease(client, &lease); - if (r < 0) { - log_link_warning(link, "DHCP error: no lease %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_warning_errno(link, r, "DHCP error: no lease: %m"); sd_dhcp_lease_unref(link->dhcp_lease); link->dhcp4_configured = false; - link->dhcp_lease = lease; + link->dhcp_lease = sd_dhcp_lease_ref(lease); r = sd_dhcp_lease_get_address(lease, &address); - if (r < 0) { - log_link_warning(link, "DHCP error: no address: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_warning_errno(link, r, "DHCP error: no address: %m"); r = sd_dhcp_lease_get_netmask(lease, &netmask); - if (r < 0) { - log_link_warning(link, "DHCP error: no netmask: %s", - strerror(-r)); - return r; - } + if (r < 0) + return log_link_warning_errno(link, r, "DHCP error: no netmask: %m"); if (!link->network->dhcp_critical) { - r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, - &lifetime); - if (r < 0) { - log_link_warning(link, - "DHCP error: no lifetime: %s", - strerror(-r)); - return r; - } + r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime); + if (r < 0) + return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m"); } r = dhcp4_update_address(link, &address, &netmask, lifetime); if (r < 0) { - log_link_warning(link, "could not update IP address: %s", - strerror(-r)); + log_link_warning_errno(link, r, "Could not update IP address: %m"); link_enter_failed(link); return r; } @@ -411,21 +365,21 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { r = sd_dhcp_client_get_lease(client, &lease); if (r < 0) - return log_link_error_errno(link, r, "DHCP error: no lease: %m"); + return log_link_error_errno(link, r, "DHCP error: No lease: %m"); r = sd_dhcp_lease_get_address(lease, &address); if (r < 0) - return log_link_error_errno(link, r, "DHCP error: no address: %m"); + return log_link_error_errno(link, r, "DHCP error: No address: %m"); r = sd_dhcp_lease_get_netmask(lease, &netmask); if (r < 0) - return log_link_error_errno(link, r, "DHCP error: no netmask: %m"); + return log_link_error_errno(link, r, "DHCP error: No netmask: %m"); prefixlen = in_addr_netmask_to_prefixlen(&netmask); r = sd_dhcp_lease_get_router(lease, &gateway); - if (r < 0 && r != -ENOENT) - return log_link_error_errno(link, r, "DHCP error: could not get gateway: %m"); + if (r < 0 && r != -ENODATA) + return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m"); if (r >= 0) log_struct(LOG_INFO, @@ -448,7 +402,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { "PREFIXLEN=%u", prefixlen, NULL); - link->dhcp_lease = lease; + link->dhcp_lease = sd_dhcp_lease_ref(lease); if (link->network->dhcp_mtu) { uint16_t mtu; @@ -462,16 +416,32 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { } if (link->network->dhcp_hostname) { - const char *hostname; + const char *hostname = NULL; - r = sd_dhcp_lease_get_hostname(lease, &hostname); - if (r >= 0) { + if (link->network->hostname) + hostname = link->network->hostname; + else + (void) sd_dhcp_lease_get_hostname(lease, &hostname); + + if (hostname) { r = link_set_hostname(link, hostname); if (r < 0) log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname); } } + if (link->network->dhcp_timezone) { + const char *tz = NULL; + + (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz); + + if (tz) { + r = link_set_timezone(link, tz); + if (r < 0) + log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz); + } + } + if (!link->network->dhcp_critical) { r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime); if (r < 0) { @@ -501,12 +471,11 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { return; switch (event) { - case DHCP_EVENT_EXPIRED: - case DHCP_EVENT_STOP: - case DHCP_EVENT_IP_CHANGE: + case SD_DHCP_CLIENT_EVENT_EXPIRED: + case SD_DHCP_CLIENT_EVENT_STOP: + case SD_DHCP_CLIENT_EVENT_IP_CHANGE: if (link->network->dhcp_critical) { - log_link_error(link, - "DHCPv4 connection considered system critical, ignoring request to reconfigure it."); + log_link_error(link, "DHCPv4 connection considered system critical, ignoring request to reconfigure it."); return; } @@ -518,7 +487,7 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { } } - if (event == DHCP_EVENT_IP_CHANGE) { + if (event == SD_DHCP_CLIENT_EVENT_IP_CHANGE) { r = dhcp_lease_acquired(client, link); if (r < 0) { link_enter_failed(link); @@ -527,14 +496,14 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { } break; - case DHCP_EVENT_RENEW: + case SD_DHCP_CLIENT_EVENT_RENEW: r = dhcp_lease_renew(client, link); if (r < 0) { link_enter_failed(link); return; } break; - case DHCP_EVENT_IP_ACQUIRE: + case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE: r = dhcp_lease_acquired(client, link); if (r < 0) { link_enter_failed(link); @@ -543,13 +512,9 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { break; default: if (event < 0) - log_link_warning(link, - "DHCP error: client failed: %s", - strerror(-event)); + log_link_warning_errno(link, event, "DHCP error: Client failed: %m"); else - log_link_warning(link, - "DHCP unknown event: %d", - event); + log_link_warning(link, "DHCP unknown event: %i", event); break; } @@ -597,10 +562,10 @@ int dhcp4_configure(Link *link) { } if (link->network->dhcp_mtu) { - r = sd_dhcp_client_set_request_option(link->dhcp_client, - DHCP_OPTION_INTERFACE_MTU); - if (r < 0) - return r; + r = sd_dhcp_client_set_request_option(link->dhcp_client, + DHCP_OPTION_INTERFACE_MTU); + if (r < 0) + return r; } if (link->network->dhcp_routes) { @@ -610,20 +575,34 @@ int dhcp4_configure(Link *link) { return r; r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_CLASSLESS_STATIC_ROUTE); - if (r < 0) - return r; + if (r < 0) + return r; } + /* Always acquire the timezone and NTP*/ + r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_NTP_SERVER); + if (r < 0) + return r; + + r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_NEW_TZDB_TIMEZONE); + if (r < 0) + return r; + if (link->network->dhcp_sendhost) { _cleanup_free_ char *hostname = NULL; + const char *hn = NULL; + + if (!link->network->hostname) { + hostname = gethostname_malloc(); + if (!hostname) + return -ENOMEM; - hostname = gethostname_malloc(); - if (!hostname) - return -ENOMEM; + hn = hostname; + } else + hn = link->network->hostname; - if (!is_localhost(hostname)) { - r = sd_dhcp_client_set_hostname(link->dhcp_client, - hostname); + if (!is_localhost(hn)) { + r = sd_dhcp_client_set_hostname(link->dhcp_client, hn); if (r < 0) return r; } diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 3a5ac1c39b..3cb7b8d9ca 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -53,8 +53,7 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, return 1; } - log_link_error(link, "Could not set DHCPv6 address: %s", - strerror(-r)); + log_link_error_errno(link, r, "Could not set DHCPv6 address: %m"); link_enter_failed(link); @@ -84,8 +83,8 @@ static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr, addr->cinfo.ifa_valid = lifetime_valid; log_link_info(link, - "DHCPv6 address "SD_ICMP6_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d", - SD_ICMP6_ADDRESS_FORMAT_VAL(addr->in_addr.in6), + "DHCPv6 address "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d", + SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addr->in_addr.in6), addr->prefixlen, lifetime_preferred, lifetime_valid); r = address_update(addr, link, dhcp6_address_handler); @@ -115,8 +114,7 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) { r = sd_icmp6_ra_get_prefixlen(link->icmp6_router_discovery, &ip6_addr, &prefixlen); if (r < 0 && r != -EADDRNOTAVAIL) { - log_link_warning(link, "Could not get prefix information: %s", - strerror(-r)); + log_link_warning_errno(link, r, "Could not get prefix information: %m"); return r; } @@ -144,13 +142,15 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { return; switch(event) { - case DHCP6_EVENT_STOP: - case DHCP6_EVENT_RESEND_EXPIRE: - case DHCP6_EVENT_RETRANS_MAX: - log_link_debug(link, "DHCPv6 event %d", event); + case SD_DHCP6_CLIENT_EVENT_STOP: + case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE: + case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX: + log_link_warning(link, "DHCPv6 lease lost"); + + link->dhcp6_configured = false; break; - case DHCP6_EVENT_IP_ACQUIRE: + case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE: r = dhcp6_lease_address_acquired(client, link); if (r < 0) { link_enter_failed(link); @@ -158,24 +158,25 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { } /* fall through */ - case DHCP6_EVENT_INFORMATION_REQUEST: + case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST: r = dhcp6_lease_information_acquired(client, link); if (r < 0) { link_enter_failed(link); return; } + link->dhcp6_configured = true; break; default: if (event < 0) - log_link_warning(link, "DHCPv6 error: %s", - strerror(-event)); + log_link_warning_errno(link, event, "DHCPv6 error: %m"); else - log_link_warning(link, "DHCPv6 unknown event: %d", - event); + log_link_warning(link, "DHCPv6 unknown event: %d", event); return; } + + link_client_handler(link); } static int dhcp6_configure(Link *link, int event) { @@ -183,91 +184,86 @@ static int dhcp6_configure(Link *link, int event) { bool information_request; assert_return(link, -EINVAL); + assert_return(IN_SET(event, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT, + SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER, + SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED), -EINVAL); - if (link->dhcp6_client) { - if (event != ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED) - return 0; + link->dhcp6_configured = false; + if (link->dhcp6_client) { r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &information_request); if (r < 0) { - log_link_warning(link, "Could not get DHCPv6 Information request setting: %s", - strerror(-r)); - link->dhcp6_client = - sd_dhcp6_client_unref(link->dhcp6_client); - return r; + log_link_warning_errno(link, r, "Could not get DHCPv6 Information request setting: %m"); + goto error; } - if (!information_request) - return r; + if (information_request && event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) { + r = sd_dhcp6_client_stop(link->dhcp6_client); + if (r < 0) { + log_link_warning_errno(link, r, "Could not stop DHCPv6 while setting Managed mode: %m"); + goto error; + } + + r = sd_dhcp6_client_set_information_request(link->dhcp6_client, + false); + if (r < 0) { + log_link_warning_errno(link, r, "Could not unset DHCPv6 Information request: %m"); + goto error; + } - r = sd_dhcp6_client_set_information_request(link->dhcp6_client, - false); - if (r < 0) { - log_link_warning(link, "Could not unset DHCPv6 Information request: %s", - strerror(-r)); - link->dhcp6_client = - sd_dhcp6_client_unref(link->dhcp6_client); - return r; } r = sd_dhcp6_client_start(link->dhcp6_client); - if (r < 0) { - log_link_warning(link, "Could not restart DHCPv6 after enabling Information request: %s", - strerror(-r)); - link->dhcp6_client = - sd_dhcp6_client_unref(link->dhcp6_client); - return r; + if (r < 0 && r != -EALREADY) { + log_link_warning_errno(link, r, "Could not restart DHCPv6: %m"); + goto error; } + if (r == -EALREADY) + link->dhcp6_configured = true; + return r; } r = sd_dhcp6_client_new(&link->dhcp6_client); if (r < 0) - return r; + goto error; r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0); - if (r < 0) { - link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); - return r; - } + if (r < 0) + goto error; r = sd_dhcp6_client_set_mac(link->dhcp6_client, (const uint8_t *) &link->mac, sizeof (link->mac), ARPHRD_ETHER); - if (r < 0) { - link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); - return r; - } + if (r < 0) + goto error; r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex); - if (r < 0) { - link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); - return r; - } + if (r < 0) + goto error; r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler, link); - if (r < 0) { - link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); - return r; - } + if (r < 0) + goto error; - if (event == ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER) { + if (event == SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) { r = sd_dhcp6_client_set_information_request(link->dhcp6_client, true); - if (r < 0) { - link->dhcp6_client = - sd_dhcp6_client_unref(link->dhcp6_client); - return r; - } + if (r < 0) + goto error; } r = sd_dhcp6_client_start(link->dhcp6_client); if (r < 0) - link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); + goto error; + + return r; + error: + link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); return r; } @@ -287,8 +283,8 @@ static int dhcp6_prefix_expired(Link *link) { if (r < 0) return r; - log_link_info(link, "IPv6 prefix "SD_ICMP6_ADDRESS_FORMAT_STR"/%d expired", - SD_ICMP6_ADDRESS_FORMAT_VAL(*expired_prefix), + log_link_info(link, "IPv6 prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d expired", + SD_ICMP6_ND_ADDRESS_FORMAT_VAL(*expired_prefix), expired_prefixlen); sd_dhcp6_lease_reset_address_iter(lease); @@ -302,7 +298,7 @@ static int dhcp6_prefix_expired(Link *link) { if (r < 0) continue; - log_link_info(link, "IPv6 prefix length updated "SD_ICMP6_ADDRESS_FORMAT_STR"/%d", SD_ICMP6_ADDRESS_FORMAT_VAL(ip6_addr), 128); + log_link_info(link, "IPv6 prefix length updated "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d", SD_ICMP6_ND_ADDRESS_FORMAT_VAL(ip6_addr), 128); dhcp6_address_update(link, &ip6_addr, 128, lifetime_preferred, lifetime_valid); } @@ -321,17 +317,17 @@ static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) { return; switch(event) { - case ICMP6_EVENT_ROUTER_ADVERTISMENT_NONE: + case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE: return; - case ICMP6_EVENT_ROUTER_ADVERTISMENT_TIMEOUT: - case ICMP6_EVENT_ROUTER_ADVERTISMENT_OTHER: - case ICMP6_EVENT_ROUTER_ADVERTISMENT_MANAGED: + case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT: + case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER: + case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED: dhcp6_configure(link, event); break; - case ICMP6_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED: + case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED: if (!link->rtnl_extended_attrs) dhcp6_prefix_expired(link); @@ -339,11 +335,9 @@ static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) { default: if (event < 0) - log_link_warning(link, "ICMPv6 error: %s", - strerror(-event)); + log_link_warning_errno(link, event, "ICMPv6 error: %m"); else - log_link_warning(link, "ICMPv6 unknown event: %d", - event); + log_link_warning(link, "ICMPv6 unknown event: %d", event); break; } diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c index 0f2510e904..9cb63cb79f 100644 --- a/src/network/networkd-fdb.c +++ b/src/network/networkd-fdb.c @@ -22,10 +22,12 @@ #include <net/if.h> #include <net/ethernet.h> -#include "networkd.h" -#include "networkd-link.h" #include "conf-parser.h" #include "util.h" +#include "netlink-util.h" + +#include "networkd.h" +#include "networkd-fdb.h" /* create a new FDB entry or get an existing one. */ int fdb_entry_new_static(Network *const network, @@ -195,7 +197,7 @@ int config_parse_fdb_hwaddr( &fdb_entry->mac_addr->ether_addr_octet[5]); if (ETHER_ADDR_LEN != r) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not a valid MAC address, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue); return 0; } diff --git a/src/network/networkd-fdb.h b/src/network/networkd-fdb.h new file mode 100644 index 0000000000..f0efb902d0 --- /dev/null +++ b/src/network/networkd-fdb.h @@ -0,0 +1,47 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + 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/>. +***/ + +typedef struct FdbEntry FdbEntry; + +#include "networkd.h" +#include "networkd-network.h" + +struct FdbEntry { + Network *network; + unsigned section; + + struct ether_addr *mac_addr; + uint16_t vlan_id; + + LIST_FIELDS(FdbEntry, static_fdb_entries); +}; + +int fdb_entry_new_static(Network *const network, const unsigned section, FdbEntry **ret); +void fdb_entry_free(FdbEntry *fdb_entry); +int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry); + +DEFINE_TRIVIAL_CLEANUP_FUNC(FdbEntry*, fdb_entry_free); +#define _cleanup_fdbentry_free_ _cleanup_(fdb_entry_freep) + +int config_parse_fdb_hwaddr(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_fdb_vlan_id(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 0a27a30278..1902b3d23a 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -44,7 +44,7 @@ static int ipv4ll_address_lost(Link *link) { r = address_new_dynamic(&address); if (r < 0) { - log_link_error(link, "Could not allocate address: %s", strerror(-r)); + log_link_error_errno(link, r, "Could not allocate address: %m"); return r; } @@ -57,8 +57,7 @@ static int ipv4ll_address_lost(Link *link) { r = route_new_dynamic(&route, RTPROT_UNSPEC); if (r < 0) { - log_link_error(link, "Could not allocate route: %s", - strerror(-r)); + log_link_error_errno(link, r, "Could not allocate route: %m"); return r; } @@ -82,7 +81,7 @@ static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *u r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_error(link, "could not set ipv4ll route: %s", strerror(-r)); + log_link_error_errno(link, r, "could not set ipv4ll route: %m"); link_enter_failed(link); } @@ -103,7 +102,7 @@ static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_error(link, "could not set ipv4ll address: %s", strerror(-r)); + log_link_error_errno(link, r, "could not set ipv4ll address: %m"); link_enter_failed(link); } else if (r >= 0) link_rtnl_process_address(rtnl, m, link->manager); @@ -179,15 +178,15 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){ return; switch(event) { - case IPV4LL_EVENT_STOP: - case IPV4LL_EVENT_CONFLICT: + case SD_IPV4LL_EVENT_STOP: + case SD_IPV4LL_EVENT_CONFLICT: r = ipv4ll_address_lost(link); if (r < 0) { link_enter_failed(link); return; } break; - case IPV4LL_EVENT_BIND: + case SD_IPV4LL_EVENT_BIND: r = ipv4ll_address_claimed(ll, link); if (r < 0) { link_enter_failed(link); @@ -195,10 +194,7 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){ } break; default: - if (event < 0) - log_link_warning(link, "IPv4 link-local error: %s", strerror(-event)); - else - log_link_warning(link, "IPv4 link-local unknown event: %d", event); + log_link_warning(link, "IPv4 link-local unknown event: %d", event); break; } } @@ -218,7 +214,9 @@ int ipv4ll_configure(Link *link) { if (link->udev_device) { r = net_get_unique_predictable_data(link->udev_device, seed); if (r >= 0) { - r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed); + assert_cc(sizeof(unsigned) <= 8); + + r = sd_ipv4ll_set_address_seed(link->ipv4ll, *(unsigned *)seed); if (r < 0) return r; } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 9550e89a15..db3975f466 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -29,7 +29,10 @@ #include "socket-util.h" #include "bus-util.h" #include "udev-util.h" +#include "netlink-util.h" +#include "dhcp-lease-internal.h" #include "network-internal.h" + #include "networkd-link.h" #include "networkd-netdev.h" @@ -498,8 +501,13 @@ void link_client_handler(Link *link) { !link->ipv4ll_route) return; - if (link_dhcp4_enabled(link) && !link->dhcp4_configured) - return; + if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) && + !link->dhcp4_configured) || + (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) && + !link->dhcp6_configured) || + (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) && + !link->dhcp4_configured && !link->dhcp6_configured)) + return; if (link->state != LINK_STATE_CONFIGURED) link_enter_configured(link); @@ -613,6 +621,96 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda return 1; } +static int link_push_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) { + _cleanup_free_ struct in_addr *addresses = NULL; + size_t n_addresses = 0, n_allocated = 0; + char **a; + + log_debug("Copying DNS server information from %s", link->ifname); + + if (!link->network) + return 0; + + STRV_FOREACH(a, link->network->dns) { + struct in_addr ia; + + /* Only look for IPv4 addresses */ + if (inet_pton(AF_INET, *a, &ia) <= 0) + continue; + + if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1)) + return log_oom(); + + addresses[n_addresses++] = ia; + } + + if (link->network->dhcp_dns && + link->dhcp_lease) { + const struct in_addr *da = NULL; + int n; + + n = sd_dhcp_lease_get_dns(link->dhcp_lease, &da); + if (n > 0) { + + if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + n)) + return log_oom(); + + memcpy(addresses + n_addresses, da, n * sizeof(struct in_addr)); + n_addresses += n; + } + } + + if (n_addresses <= 0) + return 0; + + return sd_dhcp_server_set_dns(s, addresses, n_addresses); +} + +static int link_push_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) { + _cleanup_free_ struct in_addr *addresses = NULL; + size_t n_addresses = 0, n_allocated = 0; + char **a; + + if (!link->network) + return 0; + + log_debug("Copying NTP server information from %s", link->ifname); + + STRV_FOREACH(a, link->network->ntp) { + struct in_addr ia; + + /* Only look for IPv4 addresses */ + if (inet_pton(AF_INET, *a, &ia) <= 0) + continue; + + if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1)) + return log_oom(); + + addresses[n_addresses++] = ia; + } + + if (link->network->dhcp_ntp && + link->dhcp_lease) { + const struct in_addr *da = NULL; + int n; + + n = sd_dhcp_lease_get_ntp(link->dhcp_lease, &da); + if (n > 0) { + + if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + n)) + return log_oom(); + + memcpy(addresses + n_addresses, da, n * sizeof(struct in_addr)); + n_addresses += n; + } + } + + if (n_addresses <= 0) + return 0; + + return sd_dhcp_server_set_ntp(s, addresses, n_addresses); +} + static int link_enter_set_addresses(Link *link) { Address *ad; int r; @@ -637,8 +735,9 @@ static int link_enter_set_addresses(Link *link) { /* now that we can figure out a default address for the dhcp server, start it */ if (link_dhcp4_server_enabled(link)) { - struct in_addr pool_start; Address *address; + Link *uplink = NULL; + bool acquired_uplink = false; address = link_find_dhcp_server_address(link); if (!address) { @@ -647,16 +746,9 @@ static int link_enter_set_addresses(Link *link) { return 0; } - r = sd_dhcp_server_set_address(link->dhcp_server, - &address->in_addr.in, - address->prefixlen); - if (r < 0) - return r; - - /* offer 32 addresses starting from the address following the server address */ - pool_start.s_addr = htobe32(be32toh(address->in_addr.in.s_addr) + 1); - r = sd_dhcp_server_set_lease_pool(link->dhcp_server, - &pool_start, 32); + /* use the server address' subnet as the pool */ + r = sd_dhcp_server_configure_pool(link->dhcp_server, &address->in_addr.in, address->prefixlen, + link->network->dhcp_server_pool_offset, link->network->dhcp_server_pool_size); if (r < 0) return r; @@ -665,13 +757,83 @@ static int link_enter_set_addresses(Link *link) { &main_address->in_addr.in); if (r < 0) return r; - - r = sd_dhcp_server_set_prefixlen(link->dhcp_server, - main_address->prefixlen); - if (r < 0) - return r; */ + if (link->network->dhcp_server_max_lease_time_usec > 0) { + r = sd_dhcp_server_set_max_lease_time( + link->dhcp_server, + DIV_ROUND_UP(link->network->dhcp_server_max_lease_time_usec, USEC_PER_SEC)); + if (r < 0) + return r; + } + + if (link->network->dhcp_server_default_lease_time_usec > 0) { + r = sd_dhcp_server_set_default_lease_time( + link->dhcp_server, + DIV_ROUND_UP(link->network->dhcp_server_default_lease_time_usec, USEC_PER_SEC)); + if (r < 0) + return r; + } + + if (link->network->dhcp_server_emit_dns) { + + if (link->network->n_dhcp_server_dns > 0) + r = sd_dhcp_server_set_dns(link->dhcp_server, link->network->dhcp_server_dns, link->network->n_dhcp_server_dns); + else { + uplink = manager_find_uplink(link->manager, link); + acquired_uplink = true; + + if (!uplink) { + log_link_debug(link, "Not emitting DNS server information on link, couldn't find suitable uplink."); + r = 0; + } else + r = link_push_dns_to_dhcp_server(uplink, link->dhcp_server); + } + if (r < 0) + log_link_warning_errno(link, r, "Failed to set DNS server for DHCP server, ignoring: %m"); + } + + + if (link->network->dhcp_server_emit_ntp) { + + if (link->network->n_dhcp_server_ntp > 0) + r = sd_dhcp_server_set_ntp(link->dhcp_server, link->network->dhcp_server_ntp, link->network->n_dhcp_server_ntp); + else { + if (!acquired_uplink) + uplink = manager_find_uplink(link->manager, link); + + if (!uplink) { + log_link_debug(link, "Not emitting NTP server information on link, couldn't find suitable uplink."); + r = 0; + } else + r = link_push_ntp_to_dhcp_server(uplink, link->dhcp_server); + + } + if (r < 0) + log_link_warning_errno(link, r, "Failed to set NTP server for DHCP server, ignoring: %m"); + } + + if (link->network->dhcp_server_emit_timezone) { + _cleanup_free_ char *buffer = NULL; + const char *tz = NULL; + + if (link->network->dhcp_server_timezone) + tz = link->network->dhcp_server_timezone; + else { + r = get_timezone(&buffer); + if (r < 0) + log_warning_errno(r, "Failed to determine timezone: %m"); + else + tz = buffer; + } + + if (tz) { + r = sd_dhcp_server_set_timezone(link->dhcp_server, tz); + if (r < 0) + return r; + } + } + r = sd_dhcp_server_start(link->dhcp_server); if (r < 0) { log_link_warning_errno(link, r, "Could not start DHCPv4 server instance: %m"); @@ -743,7 +905,7 @@ static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userd static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { _cleanup_link_unref_ Link *link = userdata; - int r; + const sd_bus_error *e; assert(m); assert(link); @@ -751,21 +913,20 @@ static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) return 1; - r = sd_bus_message_get_errno(m); - if (r > 0) - log_link_warning_errno(link, r, "Could not set hostname: %m"); + e = sd_bus_message_get_error(m); + if (e) + log_link_warning_errno(link, sd_bus_error_get_errno(e), "Could not set hostname: %s", e->message); return 1; } int link_set_hostname(Link *link, const char *hostname) { - int r = 0; + int r; assert(link); assert(link->manager); - assert(hostname); - log_link_debug(link, "Setting transient hostname: '%s'", hostname); + log_link_debug(link, "Setting transient hostname: '%s'", strna(hostname)); if (!link->manager->bus) { /* TODO: replace by assert when we can rely on kdbus */ @@ -794,6 +955,57 @@ int link_set_hostname(Link *link, const char *hostname) { return 0; } +static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { + _cleanup_link_unref_ Link *link = userdata; + const sd_bus_error *e; + + assert(m); + assert(link); + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return 1; + + e = sd_bus_message_get_error(m); + if (e) + log_link_warning_errno(link, sd_bus_error_get_errno(e), "Could not set timezone: %s", e->message); + + return 1; +} + +int link_set_timezone(Link *link, const char *tz) { + int r; + + assert(link); + assert(link->manager); + assert(tz); + + log_link_debug(link, "Setting system timezone: '%s'", tz); + + if (!link->manager->bus) { + log_link_info(link, "Not connected to system bus, ignoring timezone."); + return 0; + } + + r = sd_bus_call_method_async( + link->manager->bus, + NULL, + "org.freedesktop.timedate1", + "/org/freedesktop/timedate1", + "org.freedesktop.timedate1", + "SetTimezone", + set_timezone_handler, + link, + "sb", + tz, + false); + if (r < 0) + return log_link_error_errno(link, r, "Could not set timezone: %m"); + + link_ref(link); + + return 0; +} + static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -846,9 +1058,6 @@ static int link_set_bridge(Link *link) { assert(link); assert(link->network); - if(link->network->cost == 0) - return 0; - r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex); if (r < 0) return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m"); @@ -861,6 +1070,26 @@ static int link_set_bridge(Link *link) { if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_PROTINFO attribute: %m"); + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_GUARD, !link->network->use_bpdu); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_GUARD attribute: %m"); + + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MODE, link->network->hairpin); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MODE attribute: %m"); + + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_FAST_LEAVE, link->network->fast_leave); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_FAST_LEAVE attribute: %m"); + + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_PROTECT, !link->network->allow_port_to_be_root); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_PROTECT attribute: %m"); + + r = sd_netlink_message_append_u8(req, IFLA_BRPORT_UNICAST_FLOOD, link->network->unicast_flood); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m"); + if(link->network->cost != 0) { r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost); if (r < 0) @@ -888,13 +1117,16 @@ static void lldp_handler(sd_lldp *lldp, int event, void *userdata) { assert(link->network); assert(link->manager); - if (event != UPDATE_INFO) - return; - - r = sd_lldp_save(link->lldp, link->lldp_file); - if (r < 0) - log_link_warning_errno(link, r, "Could not save LLDP: %m"); + switch (event) { + case SD_LLDP_EVENT_UPDATE_INFO: + r = sd_lldp_save(link->lldp, link->lldp_file); + if (r < 0) + log_link_warning_errno(link, r, "Could not save LLDP: %m"); + break; + default: + break; + } } static int link_acquire_conf(Link *link) { @@ -1565,6 +1797,45 @@ static int link_set_ipv6_privacy_extensions(Link *link) { return 0; } +static int link_set_ipv6_accept_ra(Link *link) { + const char *p = NULL, *v = NULL; + int r; + + /* Make this a NOP if IPv6 is not available */ + if (!socket_ipv6_is_supported()) + return 0; + + if (link->flags & IFF_LOOPBACK) + return 0; + + /* If unset use system default (enabled if local forwarding is disabled. + * disabled if local forwarding is enabled). + * If set, ignore or enforce RA independent of local forwarding state. + */ + if (link->network->ipv6_accept_ra < 0) { + /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */ + v = "1"; + } else if (link->network->ipv6_accept_ra > 0) { + /* "2" means accept RA even if ip_forward is enabled */ + v = "2"; + } else { + /* "0" means ignore RA */ + v = "0"; + } + p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra"); + + r = write_string_file(p, v, 0); + if (r < 0) { + /* If the right value is set anyway, don't complain */ + if (verify_one_line_file(p, v) > 0) + return 0; + + log_link_warning_errno(link, r, "Cannot configure IPv6 accept_ra for interface: %m"); + } + + return 0; +} + static int link_configure(Link *link) { int r; @@ -1588,6 +1859,10 @@ static int link_configure(Link *link) { if (r < 0) return r; + r = link_set_ipv6_accept_ra(link); + if (r < 0) + return r; + if (link_ipv4ll_enabled(link)) { r = ipv4ll_configure(link); if (r < 0) @@ -1928,7 +2203,7 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) { log_link_debug(link, "Link %d added", link->ifindex); - if (detect_container(NULL) <= 0) { + if (detect_container() <= 0) { /* not in a container, udev will be around */ sprintf(ifindex_str, "n%d", link->ifindex); device = udev_device_new_from_device_id(m->udev, ifindex_str); @@ -2042,10 +2317,9 @@ int link_update(Link *link, sd_netlink_message *m) { link_free_carrier_maps(link); - free(link->ifname); - link->ifname = strdup(ifname); - if (!link->ifname) - return -ENOMEM; + r = free_and_strdup(&link->ifname, ifname); + if (r < 0) + return r; r = link_new_carrier_maps(link); if (r < 0) @@ -2224,6 +2498,14 @@ int link_save(Link *link) { if (link->network) { char **address, **domain; bool space; + sd_dhcp6_lease *dhcp6_lease = NULL; + + if (link->dhcp6_client) { + r = sd_dhcp6_client_get_lease(link->dhcp6_client, + &dhcp6_lease); + if (r < 0) + log_link_debug(link, "No DHCPv6 lease"); + } fprintf(f, "NETWORK_FILE=%s\n", link->network->filename); @@ -2245,6 +2527,19 @@ int link_save(Link *link) { if (space) fputc(' ', f); serialize_in_addrs(f, addresses, r); + space = true; + } + } + + if (link->network->dhcp_dns && dhcp6_lease) { + struct in6_addr *in6_addrs; + + r = sd_dhcp6_lease_get_dns(dhcp6_lease, &in6_addrs); + if (r > 0) { + if (space) + fputc(' ', f); + serialize_in6_addrs(f, in6_addrs, r); + space = true; } } @@ -2268,6 +2563,32 @@ int link_save(Link *link) { if (space) fputc(' ', f); serialize_in_addrs(f, addresses, r); + space = true; + } + } + + if (link->network->dhcp_ntp && dhcp6_lease) { + struct in6_addr *in6_addrs; + char **hosts; + char **hostname; + + r = sd_dhcp6_lease_get_ntp_addrs(dhcp6_lease, + &in6_addrs); + if (r > 0) { + if (space) + fputc(' ', f); + serialize_in6_addrs(f, in6_addrs, r); + space = true; + } + + r = sd_dhcp6_lease_get_ntp_fqdn(dhcp6_lease, &hosts); + if (r > 0) { + STRV_FOREACH(hostname, hosts) { + if (space) + fputc(' ', f); + fputs(*hostname, f); + space = true; + } } } @@ -2291,6 +2612,21 @@ int link_save(Link *link) { if (space) fputc(' ', f); fputs(domainname, f); + space = true; + } + } + + if (link->network->dhcp_domains && dhcp6_lease) { + char **domains; + + r = sd_dhcp6_lease_get_domains(dhcp6_lease, &domains); + if (r >= 0) { + STRV_FOREACH(domain, domains) { + if (space) + fputc(' ', f); + fputs(*domain, f); + space = true; + } } } @@ -2300,7 +2636,7 @@ int link_save(Link *link) { yes_no(link->network->wildcard_domain)); fprintf(f, "LLMNR=%s\n", - llmnr_support_to_string(link->network->llmnr)); + resolve_support_to_string(link->network->llmnr)); } if (!hashmap_isempty(link->bound_to_links)) { @@ -2336,9 +2672,17 @@ int link_save(Link *link) { } if (link->dhcp_lease) { + const char *tz = NULL; + + r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz); + if (r >= 0) + fprintf(f, "TIMEZONE=%s\n", tz); + } + + if (link->dhcp_lease) { assert(link->network); - r = sd_dhcp_lease_save(link->dhcp_lease, link->lease_file); + r = dhcp_lease_save(link->dhcp_lease, link->lease_file); if (r < 0) goto fail; @@ -2371,14 +2715,13 @@ int link_save(Link *link) { } return 0; + fail: - log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file); (void) unlink(link->state_file); - if (temp_path) (void) unlink(temp_path); - return r; + return log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file); } static const char* const link_state_table[_LINK_STATE_MAX] = { diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 2dcbbda607..7b219c6854 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -1,5 +1,7 @@ /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +#pragma once + /*** This file is part of systemd. @@ -19,11 +21,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once - #include <endian.h> -#include "networkd.h" +#include "sd-dhcp-client.h" +#include "sd-dhcp-server.h" +#include "sd-ipv4ll.h" +#include "sd-icmp6-nd.h" +#include "sd-dhcp6-client.h" +#include "sd-lldp.h" + +typedef struct Link Link; typedef enum LinkState { LINK_STATE_PENDING, @@ -38,6 +45,21 @@ typedef enum LinkState { _LINK_STATE_INVALID = -1 } LinkState; +typedef enum LinkOperationalState { + LINK_OPERSTATE_OFF, + LINK_OPERSTATE_NO_CARRIER, + LINK_OPERSTATE_DORMANT, + LINK_OPERSTATE_CARRIER, + LINK_OPERSTATE_DEGRADED, + LINK_OPERSTATE_ROUTABLE, + _LINK_OPERSTATE_MAX, + _LINK_OPERSTATE_INVALID = -1 +} LinkOperationalState; + +#include "networkd.h" +#include "networkd-network.h" +#include "networkd-address.h" + struct Link { Manager *manager; @@ -69,6 +91,7 @@ struct Link { uint16_t original_mtu; unsigned dhcp4_messages; bool dhcp4_configured; + bool dhcp6_configured; sd_ipv4ll *ipv4ll; bool ipv4ll_address; @@ -115,6 +138,7 @@ bool link_has_carrier(Link *link); int link_set_mtu(Link *link, uint32_t mtu); int link_set_hostname(Link *link, const char *hostname); +int link_set_timezone(Link *link, const char *timezone); int ipv4ll_configure(Link *link); int dhcp4_configure(Link *link); @@ -130,6 +154,9 @@ bool link_dhcp6_enabled(Link *link); const char* link_state_to_string(LinkState s) _const_; LinkState link_state_from_string(const char *s) _pure_; +const char* link_operstate_to_string(LinkOperationalState s) _const_; +LinkOperationalState link_operstate_from_string(const char *s) _pure_; + extern const sd_bus_vtable link_vtable[]; int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index a5c2351cf9..b4259cafef 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -22,20 +22,21 @@ #include <sys/socket.h> #include <linux/if.h> +#include "sd-netlink.h" +#include "sd-daemon.h" + #include "conf-parser.h" #include "path-util.h" -#include "networkd.h" -#include "networkd-netdev.h" -#include "networkd-link.h" #include "libudev-private.h" #include "udev-util.h" #include "netlink-util.h" #include "bus-util.h" #include "def.h" #include "virt.h" +#include "set.h" +#include "local-addresses.h" -#include "sd-netlink.h" -#include "sd-daemon.h" +#include "networkd.h" /* use 8 MB for receive socket kernel queue. */ #define RCVBUF_SIZE (8*1024*1024) @@ -99,7 +100,7 @@ static int manager_reset_all(Manager *m) { HASHMAP_FOREACH(link, m->links, i) { r = link_carrier_reset(link); if (r < 0) - log_link_warning_errno(link, r, "could not reset carrier: %m"); + log_link_warning_errno(link, r, "Could not reset carrier: %m"); } return 0; @@ -145,7 +146,9 @@ int manager_connect_bus(Manager *m) { return log_error_errno(r, "Failed to install bus reconnect time event: %m"); return 0; - } if (r < 0) + } + + if (r < 0) return r; r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot, @@ -202,7 +205,7 @@ static int manager_udev_process_link(Manager *m, struct udev_device *device) { ifindex = udev_device_get_ifindex(device); if (ifindex <= 0) { - log_debug("ignoring udev ADD event for device with invalid ifindex"); + log_debug("Ignoring udev ADD event for device with invalid ifindex"); return 0; } @@ -238,7 +241,7 @@ static int manager_connect_udev(Manager *m) { /* udev does not initialize devices inside containers, * so we rely on them being already initialized before * entering the container */ - if (detect_container(NULL) > 0) + if (detect_container() > 0) return 0; m->udev = udev_new(); @@ -289,23 +292,23 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa if (sd_netlink_message_is_error(message)) { r = sd_netlink_message_get_errno(message); if (r < 0) - log_warning_errno(r, "rtnl: could not receive link: %m"); + log_warning_errno(r, "rtnl: Could not receive link: %m"); return 0; } r = sd_netlink_message_get_type(message, &type); if (r < 0) { - log_warning_errno(r, "rtnl: could not get message type: %m"); + log_warning_errno(r, "rtnl: Could not get message type: %m"); return 0; } else if (type != RTM_NEWLINK && type != RTM_DELLINK) { - log_warning("rtnl: received unexpected message type when processing link"); + log_warning("rtnl: Received unexpected message type when processing link"); return 0; } r = sd_rtnl_message_link_get_ifindex(message, &ifindex); if (r < 0) { - log_warning_errno(r, "rtnl: could not get ifindex from link: %m"); + log_warning_errno(r, "rtnl: Could not get ifindex from link: %m"); return 0; } else if (ifindex <= 0) { log_warning("rtnl: received link message with invalid ifindex: %d", ifindex); @@ -315,7 +318,7 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name); if (r < 0) { - log_warning_errno(r, "rtnl: received link message without ifname: %m"); + log_warning_errno(r, "rtnl: Received link message without ifname: %m"); return 0; } else netdev_get(m, name, &netdev); @@ -326,7 +329,7 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa /* link is new, so add it */ r = link_add(m, message, &link); if (r < 0) { - log_warning_errno(r, "could not add new link: %m"); + log_warning_errno(r, "Could not add new link: %m"); return 0; } } @@ -335,7 +338,7 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa /* netdev exists, so make sure the ifindex matches */ r = netdev_set_ifindex(netdev, message); if (r < 0) { - log_warning_errno(r, "could not set ifindex on netdev: %m"); + log_warning_errno(r, "Could not set ifindex on netdev: %m"); return 0; } } @@ -474,13 +477,13 @@ void manager_free(Manager *m) { free(m->state_file); + sd_event_source_unref(m->udev_event_source); udev_monitor_unref(m->udev_monitor); udev_unref(m->udev); + sd_bus_unref(m->bus); sd_bus_slot_unref(m->prepare_for_sleep_slot); - sd_event_source_unref(m->udev_event_source); sd_event_source_unref(m->bus_retry_event_source); - sd_event_unref(m->event); while ((link = hashmap_first(m->links))) link_unref(link); @@ -499,6 +502,7 @@ void manager_free(Manager *m) { address_pool_free(pool); sd_netlink_unref(m->rtnl); + sd_event_unref(m->event); free(m); } @@ -753,7 +757,7 @@ int manager_save(Manager *m) { r = set_put_in_addrv(dns, addresses, r); if (r < 0) return r; - } else if (r < 0 && r != -ENOENT) + } else if (r < 0 && r != -ENODATA) return r; } @@ -765,7 +769,7 @@ int manager_save(Manager *m) { r = set_put_in_addrv(ntp, addresses, r); if (r < 0) return r; - } else if (r < 0 && r != -ENOENT) + } else if (r < 0 && r != -ENODATA) return r; } @@ -777,7 +781,7 @@ int manager_save(Manager *m) { r = set_put_strdup(domains, domainname); if (r < 0) return r; - } else if (r != -ENOENT) + } else if (r != -ENODATA) return r; } } @@ -818,10 +822,10 @@ int manager_save(Manager *m) { return 0; fail: - log_error_errno(r, "Failed to save network state to %s: %m", m->state_file); - unlink(m->state_file); - unlink(temp_path); - return r; + (void) unlink(m->state_file); + (void) unlink(temp_path); + + return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file); } int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) { @@ -844,36 +848,39 @@ int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, uni return 0; } -const char *address_family_boolean_to_string(AddressFamilyBoolean b) { - if (b == ADDRESS_FAMILY_YES || - b == ADDRESS_FAMILY_NO) - return yes_no(b == ADDRESS_FAMILY_YES); +Link* manager_find_uplink(Manager *m, Link *exclude) { + _cleanup_free_ struct local_address *gateways = NULL; + int n, i; - if (b == ADDRESS_FAMILY_IPV4) - return "ipv4"; - if (b == ADDRESS_FAMILY_IPV6) - return "ipv6"; + assert(m); - return NULL; -} + /* Looks for a suitable "uplink", via black magic: an + * interface that is up and where the default route with the + * highest priority points to. */ -AddressFamilyBoolean address_family_boolean_from_string(const char *s) { - int r; + n = local_gateways(m->rtnl, 0, AF_UNSPEC, &gateways); + if (n < 0) { + log_warning_errno(n, "Failed to determine list of default gateways: %m"); + return NULL; + } + + for (i = 0; i < n; i++) { + Link *link; + + link = hashmap_get(m->links, INT_TO_PTR(gateways[i].ifindex)); + if (!link) { + log_debug("Weird, found a gateway for a link we don't know. Ignoring."); + continue; + } - /* Make this a true superset of a boolean */ + if (link == exclude) + continue; - r = parse_boolean(s); - if (r > 0) - return ADDRESS_FAMILY_YES; - if (r == 0) - return ADDRESS_FAMILY_NO; + if (link->operstate < LINK_OPERSTATE_ROUTABLE) + continue; - if (streq(s, "ipv4")) - return ADDRESS_FAMILY_IPV4; - if (streq(s, "ipv6")) - return ADDRESS_FAMILY_IPV6; + return link; + } - return _ADDRESS_FAMILY_BOOLEAN_INVALID; + return NULL; } - -DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option"); diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c index a60034dbe6..bcaba57937 100644 --- a/src/network/networkd-netdev-bond.c +++ b/src/network/networkd-netdev-bond.c @@ -204,9 +204,8 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin if (b->lacp_rate != _NETDEV_BOND_LACP_RATE_INVALID && b->mode == NETDEV_BOND_MODE_802_3AD) { r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate ); - if (r < 0) { + if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_LACP_RATE attribute: %m"); - } } if (b->miimon != 0) { @@ -358,12 +357,12 @@ int config_parse_arp_ip_target_address(const char *unit, r = in_addr_from_string_auto(n, &f, &buffer->ip); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n); + log_syntax(unit, LOG_ERR, filename, line, r, "Bond ARP ip target address is invalid, ignoring assignment: %s", n); return 0; } if (f != AF_INET) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n); + log_syntax(unit, LOG_ERR, filename, line, 0, "Bond ARP ip target address is invalid, ignoring assignment: %s", n); return 0; } @@ -374,7 +373,7 @@ int config_parse_arp_ip_target_address(const char *unit, } if (b->n_arp_ip_targets > NETDEV_BOND_ARP_TARGETS_MAX) - log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX); + log_syntax(unit, LOG_WARNING, filename, line, 0, "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX); return 0; } diff --git a/src/network/networkd-netdev-bond.h b/src/network/networkd-netdev-bond.h index 9991fa731f..0cdce1605e 100644 --- a/src/network/networkd-netdev-bond.h +++ b/src/network/networkd-netdev-bond.h @@ -1,5 +1,7 @@ /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +#pragma once + /*** This file is part of systemd. @@ -19,7 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once +#include "in-addr-util.h" typedef struct Bond Bond; diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index 010c106610..e0bd0e024a 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -29,6 +29,7 @@ NetDev.MTUBytes, config_parse_iec_size, 0, NetDev.MACAddress, config_parse_hwaddr, 0, offsetof(NetDev, mac) VLAN.Id, config_parse_uint64, 0, offsetof(VLan, id) MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode) +MACVTAP.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode) IPVLAN.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode) Tunnel.Local, config_parse_tunnel_address, 0, offsetof(Tunnel, local) Tunnel.Remote, config_parse_tunnel_address, 0, offsetof(Tunnel, remote) @@ -36,6 +37,9 @@ Tunnel.TOS, config_parse_unsigned, 0, Tunnel.TTL, config_parse_unsigned, 0, offsetof(Tunnel, ttl) Tunnel.DiscoverPathMTU, config_parse_bool, 0, offsetof(Tunnel, pmtudisc) Tunnel.Mode, config_parse_ip6tnl_mode, 0, offsetof(Tunnel, ip6tnl_mode) +Tunnel.IPv6FlowLabel, config_parse_ipv6_flowlabel, 0, offsetof(Tunnel, ipv6_flowlabel) +Tunnel.CopyDSCP, config_parse_bool, 0, offsetof(Tunnel, copy_dscp) +Tunnel.EncapsulationLimit, config_parse_encap_limit, 0, offsetof(Tunnel, encap_limit) Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer) Peer.MACAddress, config_parse_hwaddr, 0, offsetof(Veth, mac_peer) VXLAN.Id, config_parse_uint64, 0, offsetof(VxLan, id) @@ -51,6 +55,7 @@ VXLAN.UDPCheckSum, config_parse_bool, 0, VXLAN.UDP6ZeroCheckSumRx, config_parse_bool, 0, offsetof(VxLan, udp6zerocsumrx) VXLAN.UDP6ZeroCheckSumTx, config_parse_bool, 0, offsetof(VxLan, udp6zerocsumtx) VXLAN.FDBAgeingSec, config_parse_sec, 0, offsetof(VxLan, fdb_ageing) +VXLAN.GroupPolicyExtension, config_parse_bool, 0, offsetof(VxLan, group_policy) Tun.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue) Tun.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue) Tun.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info) @@ -59,7 +64,7 @@ Tun.Group, config_parse_string, 0, Tap.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue) Tap.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue) Tap.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info) -Tap.VnetHeader, config_parse_bool, 0, offsetof(TunTap, vnet_hdr) +Tap.VNetHeader, config_parse_bool, 0, offsetof(TunTap, vnet_hdr) Tap.User, config_parse_string, 0, offsetof(TunTap, user_name) Tap.Group, config_parse_string, 0, offsetof(TunTap, group_name) Bond.Mode, config_parse_bond_mode, 0, offsetof(Bond, mode) diff --git a/src/network/networkd-netdev-macvlan.c b/src/network/networkd-netdev-macvlan.c index c2c564935c..e17de793ce 100644 --- a/src/network/networkd-netdev-macvlan.c +++ b/src/network/networkd-netdev-macvlan.c @@ -35,14 +35,20 @@ DEFINE_STRING_TABLE_LOOKUP(macvlan_mode, MacVlanMode); DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode"); static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) { - MacVlan *m = MACVLAN(netdev); + MacVlan *m; int r; assert(netdev); - assert(m); assert(link); assert(netdev->ifname); + if (netdev->kind == NETDEV_KIND_MACVLAN) + m = MACVLAN(netdev); + else + m = MACVTAP(netdev); + + assert(m); + if (m->mode != _NETDEV_MACVLAN_MODE_INVALID) { r = sd_netlink_message_append_u32(req, IFLA_MACVLAN_MODE, m->mode); if (r < 0) @@ -53,14 +59,28 @@ static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_net } static void macvlan_init(NetDev *n) { - MacVlan *m = MACVLAN(n); + MacVlan *m; assert(n); + + if (n->kind == NETDEV_KIND_MACVLAN) + m = MACVLAN(n); + else + m = MACVTAP(n); + assert(m); m->mode = _NETDEV_MACVLAN_MODE_INVALID; } +const NetDevVTable macvtap_vtable = { + .object_size = sizeof(MacVlan), + .init = macvlan_init, + .sections = "Match\0NetDev\0MACVTAP\0", + .fill_message_create = netdev_macvlan_fill_message_create, + .create_type = NETDEV_CREATE_STACKED, +}; + const NetDevVTable macvlan_vtable = { .object_size = sizeof(MacVlan), .init = macvlan_init, diff --git a/src/network/networkd-netdev-macvlan.h b/src/network/networkd-netdev-macvlan.h index d61efc16d4..c491bfa312 100644 --- a/src/network/networkd-netdev-macvlan.h +++ b/src/network/networkd-netdev-macvlan.h @@ -41,6 +41,7 @@ struct MacVlan { }; extern const NetDevVTable macvlan_vtable; +extern const NetDevVTable macvtap_vtable; const char *macvlan_mode_to_string(MacVlanMode d) _const_; MacVlanMode macvlan_mode_from_string(const char *d) _pure_; diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c index 5533fb5c7b..c9b7fa96e2 100644 --- a/src/network/networkd-netdev-tunnel.c +++ b/src/network/networkd-netdev-tunnel.c @@ -33,6 +33,7 @@ #include "conf-parser.h" #define DEFAULT_TNL_HOP_LIMIT 64 +#define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF) static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = { [NETDEV_IP6_TNL_MODE_IP6IP6] = "ip6ip6", @@ -184,6 +185,16 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netl if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TTL attribute: %m"); + if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) { + r = sd_netlink_message_append_u32(m, IFLA_GRE_FLOWINFO, t->ipv6_flowlabel); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLOWINFO attribute: %m"); + } + + r = sd_netlink_message_append_u32(m, IFLA_GRE_FLAGS, t->flags); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_FLAGS attribute: %m"); + return r; } @@ -264,6 +275,25 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m"); + if (t->ipv6_flowlabel != _NETDEV_IPV6_FLOWLABEL_INVALID) { + r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLOWINFO, t->ipv6_flowlabel); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLOWINFO attribute: %m"); + } + + if (t->copy_dscp) + t->flags |= IP6_TNL_F_RCV_DSCP_COPY; + + if (t->encap_limit != IPV6_DEFAULT_TNL_ENCAP_LIMIT) { + r = sd_netlink_message_append_u8(m, IFLA_IPTUN_ENCAP_LIMIT, t->encap_limit); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m"); + } + + r = sd_netlink_message_append_u32(m, IFLA_IPTUN_FLAGS, t->flags); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m"); + switch (t->ip6tnl_mode) { case NETDEV_IP6_TNL_MODE_IP6IP6: proto = IPPROTO_IPV6; @@ -365,12 +395,12 @@ int config_parse_tunnel_address(const char *unit, r = in_addr_from_string_auto(rvalue, &f, &buffer); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel address is invalid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel address is invalid, ignoring assignment: %s", rvalue); return 0; } if (t->family != AF_UNSPEC && t->family != f) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue); return 0; } @@ -380,6 +410,83 @@ int config_parse_tunnel_address(const char *unit, return 0; } +int config_parse_ipv6_flowlabel(const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + IPv6FlowLabel *ipv6_flowlabel = data; + Tunnel *t = userdata; + int k = 0; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(ipv6_flowlabel); + + if (streq(rvalue, "inherit")) { + *ipv6_flowlabel = IP6_FLOWINFO_FLOWLABEL; + t->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL; + } else { + r = config_parse_int(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &k, userdata); + if (r < 0) + return r; + + if (k > 0xFFFFF) + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue); + else { + *ipv6_flowlabel = htonl(k) & IP6_FLOWINFO_FLOWLABEL; + t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL; + } + } + + return 0; +} + +int config_parse_encap_limit(const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Tunnel *t = userdata; + int k = 0; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + if (streq(rvalue, "none")) + t->flags |= IP6_TNL_F_IGN_ENCAP_LIMIT; + else { + r = safe_atoi(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue); + return 0; + } + + if (k > 255 || k < 0) + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k); + else { + t->encap_limit = k; + t->flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT; + } + } + + return 0; +} + static void ipip_init(NetDev *n) { Tunnel *t = IPIP(n); @@ -452,6 +559,7 @@ static void ip6tnl_init(NetDev *n) { t->ttl = DEFAULT_TNL_HOP_LIMIT; t->encap_limit = IPV6_DEFAULT_TNL_ENCAP_LIMIT; t->ip6tnl_mode = _NETDEV_IP6_TNL_MODE_INVALID; + t->ipv6_flowlabel = _NETDEV_IPV6_FLOWLABEL_INVALID; } const NetDevVTable ipip_vtable = { diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h index 88f57ac105..fa7decce18 100644 --- a/src/network/networkd-netdev-tunnel.h +++ b/src/network/networkd-netdev-tunnel.h @@ -33,12 +33,19 @@ typedef enum Ip6TnlMode { _NETDEV_IP6_TNL_MODE_INVALID = -1, } Ip6TnlMode; +typedef enum IPv6FlowLabel { + NETDEV_IPV6_FLOWLABEL_INHERIT = 0xFFFFF + 1, + _NETDEV_IPV6_FLOWLABEL_MAX, + _NETDEV_IPV6_FLOWLABEL_INVALID = -1, +} IPv6FlowLabel; + struct Tunnel { NetDev meta; uint8_t encap_limit; int family; + int ipv6_flowlabel; unsigned ttl; unsigned tos; @@ -50,6 +57,7 @@ struct Tunnel { Ip6TnlMode ip6tnl_mode; bool pmtudisc; + bool copy_dscp; }; extern const NetDevVTable ipip_vtable; @@ -70,3 +78,26 @@ int config_parse_ip6tnl_mode(const char *unit, const char *filename, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +int config_parse_tunnel_address(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata); + +int config_parse_ipv6_flowlabel(const char *unit, const char *filename, + unsigned line, const char *section, + unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, + void *userdata); + +int config_parse_encap_limit(const char *unit, const char *filename, + unsigned line, const char *section, + unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, + void *userdata); diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c index ba84e802fc..6a808b6205 100644 --- a/src/network/networkd-netdev-tuntap.c +++ b/src/network/networkd-netdev-tuntap.c @@ -143,11 +143,8 @@ static void tuntap_done(NetDev *netdev) { assert(t); - free(t->user_name); - t->user_name = NULL; - - free(t->group_name); - t->group_name = NULL; + t->user_name = mfree(t->user_name); + t->group_name = mfree(t->group_name); } static int tuntap_verify(NetDev *netdev, const char *filename) { diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c index 2a5c5f0baa..03a599c0d4 100644 --- a/src/network/networkd-netdev-vxlan.c +++ b/src/network/networkd-netdev-vxlan.c @@ -3,7 +3,7 @@ /*** This file is part of systemd. - Copyright 2014 Susant Sahani <susant@redhat.com> + Copyright 2014 Susant Sahani 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 @@ -101,6 +101,12 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_UDP_ZERO_CSUM6_RX attribute: %m"); + if (v->group_policy) { + r = sd_netlink_message_append_flag(m, IFLA_VXLAN_GBP); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_GBP attribute: %m"); + } + return r; } @@ -125,14 +131,12 @@ int config_parse_vxlan_group_address(const char *unit, r = in_addr_from_string_auto(rvalue, &f, &buffer); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "vxlan multicast group address is invalid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "vxlan multicast group address is invalid, ignoring assignment: %s", rvalue); return 0; } - if(v->family != AF_UNSPEC && v->family != f) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "vxlan multicast group incompatible, ignoring assignment: %s", rvalue); + if (v->family != AF_UNSPEC && v->family != f) { + log_syntax(unit, LOG_ERR, filename, line, 0, "vxlan multicast group incompatible, ignoring assignment: %s", rvalue); return 0; } diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h index fe5254e91f..4ec33946cc 100644 --- a/src/network/networkd-netdev-vxlan.h +++ b/src/network/networkd-netdev-vxlan.h @@ -50,6 +50,18 @@ struct VxLan { bool udpcsum; bool udp6zerocsumtx; bool udp6zerocsumrx; + bool group_policy; }; extern const NetDevVTable vxlan_vtable; + +int config_parse_vxlan_group_address(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata); diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index 6949b403c8..ff1edf2c39 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -21,19 +21,23 @@ #include <net/if.h> -#include "networkd-netdev.h" -#include "networkd-link.h" -#include "network-internal.h" #include "conf-files.h" #include "conf-parser.h" #include "list.h" #include "siphash24.h" +#include "netlink-util.h" +#include "network-internal.h" + +#include "networkd.h" +#include "networkd-netdev.h" const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = { + [NETDEV_KIND_BRIDGE] = &bridge_vtable, [NETDEV_KIND_BOND] = &bond_vtable, [NETDEV_KIND_VLAN] = &vlan_vtable, [NETDEV_KIND_MACVLAN] = &macvlan_vtable, + [NETDEV_KIND_MACVTAP] = &macvtap_vtable, [NETDEV_KIND_IPVLAN] = &ipvlan_vtable, [NETDEV_KIND_VXLAN] = &vxlan_vtable, [NETDEV_KIND_IPIP] = &ipip_vtable, @@ -56,6 +60,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = { [NETDEV_KIND_BOND] = "bond", [NETDEV_KIND_VLAN] = "vlan", [NETDEV_KIND_MACVLAN] = "macvlan", + [NETDEV_KIND_MACVTAP] = "macvtap", [NETDEV_KIND_IPVLAN] = "ipvlan", [NETDEV_KIND_VXLAN] = "vxlan", [NETDEV_KIND_IPIP] = "ipip", diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index a004f2fe5f..1f8510c4f7 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -21,11 +21,14 @@ #pragma once -#include "networkd.h" #include "list.h" +typedef struct NetDev NetDev; typedef struct NetDevVTable NetDevVTable; +#include "networkd.h" +#include "networkd-link.h" + typedef struct netdev_join_callback netdev_join_callback; struct netdev_join_callback { @@ -40,6 +43,7 @@ typedef enum NetDevKind { NETDEV_KIND_BOND, NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, + NETDEV_KIND_MACVTAP, NETDEV_KIND_IPVLAN, NETDEV_KIND_VXLAN, NETDEV_KIND_IPIP, @@ -161,6 +165,7 @@ DEFINE_CAST(BRIDGE, Bridge); DEFINE_CAST(BOND, Bond); DEFINE_CAST(VLAN, VLan); DEFINE_CAST(MACVLAN, MacVlan); +DEFINE_CAST(MACVTAP, MacVlan); DEFINE_CAST(IPVLAN, IPVlan); DEFINE_CAST(VXLAN, VxLan); DEFINE_CAST(IPIP, Tunnel); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 787fc2ff5b..8257ab45da 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -15,70 +15,89 @@ struct ConfigPerfItem; %struct-type %includes %% -Match.MACAddress, config_parse_hwaddr, 0, offsetof(Network, match_mac) -Match.Path, config_parse_strv, 0, offsetof(Network, match_path) -Match.Driver, config_parse_strv, 0, offsetof(Network, match_driver) -Match.Type, config_parse_strv, 0, offsetof(Network, match_type) -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.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) -Network.Description, config_parse_string, 0, offsetof(Network, description) -Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) -Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) -Network.VLAN, config_parse_netdev, 0, 0 -Network.MACVLAN, config_parse_netdev, 0, 0 -Network.IPVLAN, config_parse_netdev, 0, 0 -Network.VXLAN, config_parse_netdev, 0, 0 -Network.Tunnel, config_parse_tunnel, 0, 0 -Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp) -Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server) -Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) -Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) -Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) -Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp) -Network.Address, config_parse_address, 0, 0 -Network.Gateway, config_parse_gateway, 0, 0 -Network.Domains, config_parse_domains, 0, offsetof(Network, domains) -Network.DNS, config_parse_strv, 0, offsetof(Network, dns) -Network.LLMNR, config_parse_llmnr, 0, offsetof(Network, llmnr) -Network.NTP, config_parse_strv, 0, offsetof(Network, ntp) -Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward) -Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) -Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions) -Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier) -Address.Address, config_parse_address, 0, 0 -Address.Peer, config_parse_address, 0, 0 -Address.Broadcast, config_parse_broadcast, 0, 0 -Address.Label, config_parse_label, 0, 0 -Route.Gateway, config_parse_gateway, 0, 0 -Route.Destination, config_parse_destination, 0, 0 -Route.Source, config_parse_destination, 0, 0 -Route.Metric, config_parse_route_priority, 0, 0 -Route.Scope, config_parse_route_scope, 0, 0 -DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier) -DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) -DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp) -DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) -DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) -DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains) -DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_routes) -DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_sendhost) -DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) -DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) -DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) -DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) -Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost) -BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0 -BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0 +Match.MACAddress, config_parse_hwaddr, 0, offsetof(Network, match_mac) +Match.Path, config_parse_strv, 0, offsetof(Network, match_path) +Match.Driver, config_parse_strv, 0, offsetof(Network, match_driver) +Match.Type, config_parse_strv, 0, offsetof(Network, match_type) +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.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) +Network.Description, config_parse_string, 0, offsetof(Network, description) +Network.Bridge, config_parse_netdev, 0, offsetof(Network, bridge) +Network.Bond, config_parse_netdev, 0, offsetof(Network, bond) +Network.VLAN, config_parse_netdev, 0, 0 +Network.MACVLAN, config_parse_netdev, 0, 0 +Network.MACVTAP, config_parse_netdev, 0, 0 +Network.IPVLAN, config_parse_netdev, 0, 0 +Network.VXLAN, config_parse_netdev, 0, 0 +Network.Tunnel, config_parse_tunnel, 0, 0 +Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp) +Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server) +Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) +Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) +Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) +Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp) +Network.Address, config_parse_address, 0, 0 +Network.Gateway, config_parse_gateway, 0, 0 +Network.Domains, config_parse_domains, 0, offsetof(Network, domains) +Network.DNS, config_parse_strv, 0, offsetof(Network, dns) +Network.LLMNR, config_parse_resolve, 0, offsetof(Network, llmnr) +Network.NTP, config_parse_strv, 0, offsetof(Network, ntp) +Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward) +Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) +Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions) +Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra) +Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier) +Address.Address, config_parse_address, 0, 0 +Address.Peer, config_parse_address, 0, 0 +Address.Broadcast, config_parse_broadcast, 0, 0 +Address.Label, config_parse_label, 0, 0 +Route.Gateway, config_parse_gateway, 0, 0 +Route.Destination, config_parse_destination, 0, 0 +Route.Source, config_parse_destination, 0, 0 +Route.Metric, config_parse_route_priority, 0, 0 +Route.Scope, config_parse_route_scope, 0, 0 +DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier) +DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) +DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp) +DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) +DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) +DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains) +DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_routes) +DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_sendhost) +DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, hostname) +DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) +DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) +DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) +DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) +DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_timezone) +DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) +DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec) +DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns) +DHCPServer.DNS, config_parse_dhcp_server_dns, 0, 0 +DHCPServer.EmitNTP, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_ntp) +DHCPServer.NTP, config_parse_dhcp_server_ntp, 0, 0 +DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone) +DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone) +DHCPServer.PoolOffset, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_offset) +DHCPServer.PoolSize, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_size) +Bridge.Cost, config_parse_unsigned, 0, offsetof(Network, cost) +Bridge.UseBPDU, config_parse_bool, 0, offsetof(Network, use_bpdu) +Bridge.HairPin, config_parse_bool, 0, offsetof(Network, hairpin) +Bridge.FastLeave, config_parse_bool, 0, offsetof(Network, fast_leave) +Bridge.AllowPortToBeRoot, config_parse_bool, 0, offsetof(Network, allow_port_to_be_root) +Bridge.UnicastFlood, config_parse_bool, 0, offsetof(Network, unicast_flood) +BridgeFDB.MACAddress, config_parse_fdb_hwaddr, 0, 0 +BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0 /* backwards compatibility: do not add new entries to this section */ -Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local) -DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) -DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) -DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) -DHCP.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) -DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) -DHCPv4.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) +Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local) +DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) +DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) +DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) +DHCP.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) +DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) +DHCPv4.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index a8e9ef909c..5d22598fc0 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -26,11 +26,11 @@ #include "conf-parser.h" #include "util.h" #include "hostname-util.h" -#include "networkd.h" -#include "networkd-netdev.h" -#include "networkd-link.h" -#include "network-internal.h" #include "dns-domain.h" +#include "network-internal.h" + +#include "networkd.h" +#include "networkd-network.h" static int network_load_one(Manager *manager, const char *filename) { _cleanup_network_free_ Network *network = NULL; @@ -107,11 +107,20 @@ static int network_load_one(Manager *manager, const char *filename) { network->dhcp_route_metric = DHCP_ROUTE_METRIC; network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID; - network->llmnr = LLMNR_SUPPORT_YES; + network->dhcp_server_emit_dns = true; + network->dhcp_server_emit_ntp = true; + network->dhcp_server_emit_timezone = true; + + network->use_bpdu = true; + network->allow_port_to_be_root = true; + network->unicast_flood = true; + + network->llmnr = RESOLVE_SUPPORT_YES; network->link_local = ADDRESS_FAMILY_IPV6; network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO; + network->ipv6_accept_ra = -1; r = config_parse(NULL, filename, file, "Match\0" @@ -120,7 +129,8 @@ static int network_load_one(Manager *manager, const char *filename) { "Address\0" "Route\0" "DHCP\0" - "DHCPv4\0" + "DHCPv4\0" /* compat */ + "DHCPServer\0" "Bridge\0" "BridgeFDB\0", config_item_perf_lookup, network_network_gperf_lookup, @@ -207,6 +217,7 @@ void network_free(Network *network) { free(network->description); free(network->dhcp_vendor_class_identifier); + free(network->hostname); free(network->mac); @@ -253,6 +264,10 @@ void network_free(Network *network) { condition_free_list(network->match_kernel); condition_free_list(network->match_arch); + free(network->dhcp_server_timezone); + free(network->dhcp_server_dns); + free(network->dhcp_server_ntp); + free(network); } @@ -394,21 +409,18 @@ int config_parse_netdev(const char *unit, kind = netdev_kind_from_string(kind_string); if (kind == _NETDEV_KIND_INVALID) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid NetDev kind: %s", lvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue); return 0; } r = netdev_get(network->manager, rvalue, &netdev); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "%s could not be found, ignoring assignment: %s", lvalue, rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue); return 0; } if (netdev->kind != kind) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue); return 0; } @@ -423,13 +435,12 @@ int config_parse_netdev(const char *unit, break; case NETDEV_KIND_VLAN: case NETDEV_KIND_MACVLAN: + case NETDEV_KIND_MACVTAP: case NETDEV_KIND_IPVLAN: case NETDEV_KIND_VXLAN: r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Can not add VLAN '%s' to network: %m", - rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Can not add VLAN '%s' to network: %m", rvalue); return 0; } @@ -468,7 +479,7 @@ int config_parse_domains(const char *unit, STRV_FOREACH(domain, *domains) { if (is_localhost(*domain)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain); + log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain); else { r = dns_name_is_valid(*domain); if (r <= 0 && !streq(*domain, "*")) { @@ -524,7 +535,7 @@ int config_parse_tunnel(const char *unit, netdev->kind != NETDEV_KIND_VTI6 && netdev->kind != NETDEV_KIND_IP6TNL ) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, + log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a tunnel, ignoring assignment: %s", rvalue); return 0; } @@ -609,7 +620,7 @@ int config_parse_dhcp( else if (streq(rvalue, "both")) s = ADDRESS_FAMILY_YES; else { - log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue); return 0; } } @@ -626,15 +637,58 @@ static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = { DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DCHPClientIdentifier); DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DCHPClientIdentifier, "Failed to parse client identifier type"); -static const char* const llmnr_support_table[_LLMNR_SUPPORT_MAX] = { - [LLMNR_SUPPORT_NO] = "no", - [LLMNR_SUPPORT_YES] = "yes", - [LLMNR_SUPPORT_RESOLVE] = "resolve", +int config_parse_ipv6token( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + union in_addr_union buffer; + struct in6_addr *token = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(token); + + r = in_addr_from_string(AF_INET6, rvalue, &buffer); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue); + return 0; + } + + r = in_addr_is_null(AF_INET6, &buffer); + if (r != 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue); + return 0; + } + + if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue); + return 0; + } + + *token = buffer.in6; + + return 0; +} + +static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = { + [IPV6_PRIVACY_EXTENSIONS_NO] = "no", + [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public", + [IPV6_PRIVACY_EXTENSIONS_YES] = "yes", }; -DEFINE_STRING_TABLE_LOOKUP(llmnr_support, LLMNRSupport); +DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions); -int config_parse_llmnr( +int config_parse_ipv6_privacy_extensions( const char* unit, const char *filename, unsigned line, @@ -646,39 +700,44 @@ int config_parse_llmnr( void *data, void *userdata) { - LLMNRSupport *llmnr = data; + IPv6PrivacyExtensions *ipv6_privacy_extensions = data; int k; assert(filename); assert(lvalue); assert(rvalue); - assert(llmnr); + assert(ipv6_privacy_extensions); /* Our enum shall be a superset of booleans, hence first try * to parse as boolean, and then as enum */ k = parse_boolean(rvalue); if (k > 0) - *llmnr = LLMNR_SUPPORT_YES; + *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES; else if (k == 0) - *llmnr = LLMNR_SUPPORT_NO; + *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO; else { - LLMNRSupport s; + IPv6PrivacyExtensions s; - s = llmnr_support_from_string(rvalue); - if (s < 0){ - log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse LLMNR option, ignoring: %s", rvalue); - return 0; + s = ipv6_privacy_extensions_from_string(rvalue); + if (s < 0) { + + if (streq(rvalue, "kernel")) + s = _IPV6_PRIVACY_EXTENSIONS_INVALID; + else { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue); + return 0; + } } - *llmnr = s; + *ipv6_privacy_extensions = s; } return 0; } -int config_parse_ipv6token( - const char* unit, +int config_parse_hostname( + const char *unit, const char *filename, unsigned line, const char *section, @@ -689,39 +748,65 @@ int config_parse_ipv6token( void *data, void *userdata) { - union in_addr_union buffer; - struct in6_addr *token = data; + char **hostname = data, *hn = NULL; int r; assert(filename); assert(lvalue); assert(rvalue); - assert(token); - r = in_addr_from_string(AF_INET6, rvalue, &buffer); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue); - return 0; - } + r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &hn, userdata); + if (r < 0) + return r; - r = in_addr_is_null(AF_INET6, &buffer); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue); + if (!hostname_is_valid(hn, false)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue); + free(hn); return 0; } - if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue); + free(*hostname); + *hostname = hostname_cleanup(hn); + return 0; +} + +int config_parse_timezone( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char **datap = data, *tz = NULL; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + r = config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &tz, userdata); + if (r < 0) + return r; + + if (!timezone_is_valid(tz)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue); + free(tz); return 0; } - *token = buffer.in6; + free(*datap); + *datap = tz; return 0; } -int config_parse_address_family_boolean_with_kernel( - const char* unit, +int config_parse_dhcp_server_dns( + const char *unit, const char *filename, unsigned line, const char *section, @@ -732,38 +817,43 @@ int config_parse_address_family_boolean_with_kernel( void *data, void *userdata) { - AddressFamilyBoolean *fwd = data, s; + Network *n = data; + const char *p = rvalue; + int r; assert(filename); assert(lvalue); assert(rvalue); - assert(data); - s = address_family_boolean_from_string(rvalue); - if (s < 0) { - if (streq(rvalue, "kernel")) - s = _ADDRESS_FAMILY_BOOLEAN_INVALID; - else { - log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPForwarding option, ignoring: %s", rvalue); + for (;;) { + _cleanup_free_ char *w = NULL; + struct in_addr a, *m; + + r = extract_first_word(&p, &w, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue); return 0; } - } - *fwd = s; + if (r == 0) + return 0; - return 0; -} + if (inet_pton(AF_INET, w, &a) <= 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w); + continue; + } -static const char* const ipv6_privacy_extensions_table[_IPV6_PRIVACY_EXTENSIONS_MAX] = { - [IPV6_PRIVACY_EXTENSIONS_NO] = "no", - [IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC] = "prefer-public", - [IPV6_PRIVACY_EXTENSIONS_YES] = "yes", -}; + m = realloc(n->dhcp_server_dns, (n->n_dhcp_server_dns + 1) * sizeof(struct in_addr)); + if (!m) + return log_oom(); -DEFINE_STRING_TABLE_LOOKUP(ipv6_privacy_extensions, IPv6PrivacyExtensions); + m[n->n_dhcp_server_dns++] = a; + n->dhcp_server_dns = m; + } +} -int config_parse_ipv6_privacy_extensions( - const char* unit, +int config_parse_dhcp_server_ntp( + const char *unit, const char *filename, unsigned line, const char *section, @@ -774,38 +864,37 @@ int config_parse_ipv6_privacy_extensions( void *data, void *userdata) { - IPv6PrivacyExtensions *ipv6_privacy_extensions = data; - int k; + Network *n = data; + const char *p = rvalue; + int r; assert(filename); assert(lvalue); assert(rvalue); - assert(ipv6_privacy_extensions); - /* Our enum shall be a superset of booleans, hence first try - * to parse as boolean, and then as enum */ + for (;;) { + _cleanup_free_ char *w = NULL; + struct in_addr a, *m; - k = parse_boolean(rvalue); - if (k > 0) - *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_YES; - else if (k == 0) - *ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO; - else { - IPv6PrivacyExtensions s; + r = extract_first_word(&p, &w, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue); + return 0; + } - s = ipv6_privacy_extensions_from_string(rvalue); - if (s < 0) { + if (r == 0) + return 0; - if (streq(rvalue, "kernel")) - s = _IPV6_PRIVACY_EXTENSIONS_INVALID; - else { - log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue); - return 0; - } + if (inet_pton(AF_INET, w, &a) <= 0) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w); + continue; } - *ipv6_privacy_extensions = s; - } + m = realloc(n->dhcp_server_ntp, (n->n_dhcp_server_ntp + 1) * sizeof(struct in_addr)); + if (!m) + return log_oom(); - return 0; + m[n->n_dhcp_server_ntp++] = a; + n->dhcp_server_ntp = m; + } } diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h new file mode 100644 index 0000000000..2a43b6b347 --- /dev/null +++ b/src/network/networkd-network.h @@ -0,0 +1,183 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + 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 "condition.h" + +typedef struct Network Network; + +#include "networkd.h" +#include "networkd-netdev.h" +#include "networkd-address.h" +#include "networkd-route.h" +#include "networkd-fdb.h" +#include "networkd-util.h" + +#define DHCP_ROUTE_METRIC 1024 +#define IPV4LL_ROUTE_METRIC 2048 + +typedef enum DCHPClientIdentifier { + DHCP_CLIENT_ID_MAC, + DHCP_CLIENT_ID_DUID, + _DHCP_CLIENT_ID_MAX, + _DHCP_CLIENT_ID_INVALID = -1, +} DCHPClientIdentifier; + +typedef enum IPv6PrivacyExtensions { + /* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */ + IPV6_PRIVACY_EXTENSIONS_NO, + IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC, + IPV6_PRIVACY_EXTENSIONS_YES, /* aka prefer-temporary */ + _IPV6_PRIVACY_EXTENSIONS_MAX, + _IPV6_PRIVACY_EXTENSIONS_INVALID = -1, +} IPv6PrivacyExtensions; + +struct Network { + Manager *manager; + + char *filename; + char *name; + + struct ether_addr *match_mac; + char **match_path; + char **match_driver; + char **match_type; + char **match_name; + + Condition *match_host; + Condition *match_virt; + Condition *match_kernel; + Condition *match_arch; + + char *description; + + NetDev *bridge; + NetDev *bond; + Hashmap *stacked_netdevs; + + /* DHCP Client Support */ + AddressFamilyBoolean dhcp; + DCHPClientIdentifier dhcp_client_identifier; + char *dhcp_vendor_class_identifier; + char *hostname; + bool dhcp_dns; + bool dhcp_ntp; + bool dhcp_mtu; + bool dhcp_hostname; + bool dhcp_domains; + bool dhcp_sendhost; + bool dhcp_broadcast; + bool dhcp_critical; + bool dhcp_routes; + bool dhcp_timezone; + unsigned dhcp_route_metric; + + /* DHCP Server Support */ + bool dhcp_server; + bool dhcp_server_emit_dns; + struct in_addr *dhcp_server_dns; + unsigned n_dhcp_server_dns; + bool dhcp_server_emit_ntp; + struct in_addr *dhcp_server_ntp; + unsigned n_dhcp_server_ntp; + bool dhcp_server_emit_timezone; + char *dhcp_server_timezone; + usec_t dhcp_server_default_lease_time_usec, dhcp_server_max_lease_time_usec; + uint32_t dhcp_server_pool_offset; + uint32_t dhcp_server_pool_size; + + /* IPV4LL Support */ + AddressFamilyBoolean link_local; + bool ipv4ll_route; + + /* Bridge Support */ + bool use_bpdu; + bool hairpin; + bool fast_leave; + bool allow_port_to_be_root; + bool unicast_flood; + unsigned cost; + + AddressFamilyBoolean ip_forward; + bool ip_masquerade; + + int ipv6_accept_ra; + + union in_addr_union ipv6_token; + IPv6PrivacyExtensions ipv6_privacy_extensions; + + struct ether_addr *mac; + unsigned mtu; + + bool lldp; + + LIST_HEAD(Address, static_addresses); + LIST_HEAD(Route, static_routes); + LIST_HEAD(FdbEntry, static_fdb_entries); + + Hashmap *addresses_by_section; + Hashmap *routes_by_section; + Hashmap *fdb_entries_by_section; + + bool wildcard_domain; + char **domains, **dns, **ntp, **bind_carrier; + + ResolveSupport llmnr; + + LIST_FIELDS(Network, networks); +}; + +void network_free(Network *network); + +DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_free); +#define _cleanup_network_free_ _cleanup_(network_freep) + +int network_load(Manager *manager); + +int network_get_by_name(Manager *manager, const char *name, Network **ret); +int network_get(Manager *manager, struct udev_device *device, const char *ifname, const struct ether_addr *mac, Network **ret); +int network_apply(Manager *manager, Network *network, Link *link); + +int config_parse_netdev(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_tunnel(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dhcp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dhcp_client_identifier(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_ipv6token(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_ipv6_privacy_extensions(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_hostname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_timezone(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dhcp_server_dns(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dhcp_server_ntp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +/* Legacy IPv4LL support */ +int config_parse_ipv4ll(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, unsigned length); + +extern const sd_bus_vtable network_vtable[]; + +int network_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); +int network_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); + +const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_; +IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_; diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 31b10c458d..1f09d95674 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -19,12 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - -#include "networkd.h" -#include "networkd-link.h" - #include "util.h" #include "conf-parser.h" +#include "netlink-util.h" + +#include "networkd.h" +#include "networkd-route.h" int route_new_static(Network *network, unsigned section, Route **ret) { _cleanup_route_free_ Route *route = NULL; @@ -294,8 +294,7 @@ int config_parse_gateway(const char *unit, r = in_addr_from_string_auto(rvalue, &f, &buffer); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Route is invalid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Route is invalid, ignoring assignment: %s", rvalue); return 0; } @@ -345,14 +344,12 @@ int config_parse_destination(const char *unit, r = in_addr_from_string_auto(address, &f, &buffer); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Destination is invalid, ignoring assignment: %s", address); + log_syntax(unit, LOG_ERR, filename, line, r, "Destination is invalid, ignoring assignment: %s", address); return 0; } if (f != AF_INET && f != AF_INET6) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Unknown address family, ignoring assignment: %s", address); + log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown address family, ignoring assignment: %s", address); return 0; } @@ -360,8 +357,7 @@ int config_parse_destination(const char *unit, if (e) { r = safe_atou8(e + 1, &prefixlen); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Route destination prefix length is invalid, ignoring assignment: %s", e + 1); + log_syntax(unit, LOG_ERR, filename, line, r, "Route destination prefix length is invalid, ignoring assignment: %s", e + 1); return 0; } } else { @@ -456,8 +452,7 @@ int config_parse_route_scope(const char *unit, else if (streq(rvalue, "global")) n->scope = RT_SCOPE_UNIVERSE; else { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Unknown route scope: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route scope: %s", rvalue); return 0; } diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h new file mode 100644 index 0000000000..d090b9c91e --- /dev/null +++ b/src/network/networkd-route.h @@ -0,0 +1,60 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + 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/>. +***/ + +typedef struct Route Route; + +#include "networkd.h" +#include "networkd-network.h" + +struct Route { + Network *network; + unsigned section; + + int family; + unsigned char dst_prefixlen; + unsigned char src_prefixlen; + unsigned char scope; + uint32_t metrics; + unsigned char protocol; /* RTPROT_* */ + + union in_addr_union in_addr; + union in_addr_union dst_addr; + union in_addr_union src_addr; + union in_addr_union prefsrc_addr; + + LIST_FIELDS(Route, routes); +}; + +int route_new_static(Network *network, unsigned section, Route **ret); +int route_new_dynamic(Route **ret, unsigned char rtm_protocol); +void route_free(Route *route); +int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback); +int route_drop(Route *route, Link *link, sd_netlink_message_handler_t callback); + +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, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_destination(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_route_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_route_scope(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c new file mode 100644 index 0000000000..dde6b327ed --- /dev/null +++ b/src/network/networkd-util.c @@ -0,0 +1,144 @@ +/*-*- 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 "util.h" +#include "conf-parser.h" + +#include "networkd-util.h" + +const char *address_family_boolean_to_string(AddressFamilyBoolean b) { + if (b == ADDRESS_FAMILY_YES || + b == ADDRESS_FAMILY_NO) + return yes_no(b == ADDRESS_FAMILY_YES); + + if (b == ADDRESS_FAMILY_IPV4) + return "ipv4"; + if (b == ADDRESS_FAMILY_IPV6) + return "ipv6"; + + return NULL; +} + +AddressFamilyBoolean address_family_boolean_from_string(const char *s) { + int r; + + /* Make this a true superset of a boolean */ + + r = parse_boolean(s); + if (r > 0) + return ADDRESS_FAMILY_YES; + if (r == 0) + return ADDRESS_FAMILY_NO; + + if (streq(s, "ipv4")) + return ADDRESS_FAMILY_IPV4; + if (streq(s, "ipv6")) + return ADDRESS_FAMILY_IPV6; + + return _ADDRESS_FAMILY_BOOLEAN_INVALID; +} + +DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option"); + +int config_parse_address_family_boolean_with_kernel( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + AddressFamilyBoolean *fwd = data, s; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + s = address_family_boolean_from_string(rvalue); + if (s < 0) { + if (streq(rvalue, "kernel")) + s = _ADDRESS_FAMILY_BOOLEAN_INVALID; + else { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPForwarding= option, ignoring: %s", rvalue); + return 0; + } + } + + *fwd = s; + + return 0; +} + +static const char* const resolve_support_table[_RESOLVE_SUPPORT_MAX] = { + [RESOLVE_SUPPORT_NO] = "no", + [RESOLVE_SUPPORT_YES] = "yes", + [RESOLVE_SUPPORT_RESOLVE] = "resolve", +}; + +DEFINE_STRING_TABLE_LOOKUP(resolve_support, ResolveSupport); + +int config_parse_resolve( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ResolveSupport *resolve = data; + int k; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(resolve); + + /* Our enum shall be a superset of booleans, hence first try + * to parse as boolean, and then as enum */ + + k = parse_boolean(rvalue); + if (k > 0) + *resolve = RESOLVE_SUPPORT_YES; + else if (k == 0) + *resolve = RESOLVE_SUPPORT_NO; + else { + ResolveSupport s; + + s = resolve_support_from_string(rvalue); + if (s < 0){ + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse %s= option, ignoring: %s", lvalue, rvalue); + return 0; + } + + *resolve = s; + } + + return 0; +} diff --git a/src/network/networkd-util.h b/src/network/networkd-util.h new file mode 100644 index 0000000000..cc41aae85a --- /dev/null +++ b/src/network/networkd-util.h @@ -0,0 +1,52 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + 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 "macro.h" + +typedef enum AddressFamilyBoolean { + /* This is a bitmask, though it usually doesn't feel that way! */ + ADDRESS_FAMILY_NO = 0, + ADDRESS_FAMILY_IPV4 = 1, + ADDRESS_FAMILY_IPV6 = 2, + ADDRESS_FAMILY_YES = 3, + _ADDRESS_FAMILY_BOOLEAN_MAX, + _ADDRESS_FAMILY_BOOLEAN_INVALID = -1, +} AddressFamilyBoolean; + +typedef enum ResolveSupport { + RESOLVE_SUPPORT_NO, + RESOLVE_SUPPORT_YES, + RESOLVE_SUPPORT_RESOLVE, + _RESOLVE_SUPPORT_MAX, + _RESOLVE_SUPPORT_INVALID = -1, +} ResolveSupport; + +int config_parse_resolve(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_address_family_boolean(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_address_family_boolean_with_kernel(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +const char* resolve_support_to_string(ResolveSupport i) _const_; +ResolveSupport resolve_support_from_string(const char *s) _pure_; + +const char *address_family_boolean_to_string(AddressFamilyBoolean b) _const_; +AddressFamilyBoolean address_family_boolean_from_string(const char *s) _const_; diff --git a/src/network/networkd-wait-online-link.c b/src/network/networkd-wait-online-link.c index 2d5123788c..cacb4c257e 100644 --- a/src/network/networkd-wait-online-link.c +++ b/src/network/networkd-wait-online-link.c @@ -120,13 +120,11 @@ int link_update_rtnl(Link *l, sd_netlink_message *m) { int link_update_monitor(Link *l) { assert(l); - free(l->operational_state); - l->operational_state = NULL; + l->operational_state = mfree(l->operational_state); sd_network_link_get_operational_state(l->ifindex, &l->operational_state); - free(l->state); - l->state = NULL; + l->state = mfree(l->state); sd_network_link_get_setup_state(l->ifindex, &l->state); diff --git a/src/network/networkd-wait-online-manager.c b/src/network/networkd-wait-online-manager.c index 1fc724f5a4..112d92a568 100644 --- a/src/network/networkd-wait-online-manager.c +++ b/src/network/networkd-wait-online-manager.c @@ -38,9 +38,15 @@ bool manager_ignore_link(Manager *m, Link *link) { assert(m); assert(link); + /* always ignore the loopback interface */ if (link->flags & IFF_LOOPBACK) return true; + /* if interfaces are given on the command line, ignore all others */ + if (m->interfaces && !strv_contains(m->interfaces, link->ifname)) + return true; + + /* ignore interfaces we explicitly are asked to ignore */ STRV_FOREACH(ignore, m->ignore) if (fnmatch(*ignore, link->ifname, 0) == 0) return true; @@ -77,7 +83,7 @@ bool manager_all_configured(Manager *m) { return false; } - if (streq(l->state, "configuring")) { + if (STR_IN_SET(l->state, "configuring", "pending")) { log_debug("link %s is being processed by networkd", l->ifname); return false; diff --git a/src/network/networkd-wait-online.c b/src/network/networkd-wait-online.c index 32c31fdf3d..3220c4b7ef 100644 --- a/src/network/networkd-wait-online.c +++ b/src/network/networkd-wait-online.c @@ -21,10 +21,10 @@ #include <getopt.h> #include "sd-daemon.h" -#include "strv.h" -#include "build.h" -#include "signal-util.h" + #include "networkd-wait-online.h" +#include "signal-util.h" +#include "strv.h" static bool arg_quiet = false; static usec_t arg_timeout = 120 * USEC_PER_SEC; @@ -66,7 +66,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "+hiq", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "+hi:q", options, NULL)) >= 0) switch (c) { @@ -79,9 +79,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case 'i': if (strv_extend(&arg_interfaces, optarg) < 0) diff --git a/src/network/networkd.h b/src/network/networkd.h index f98c640822..eea57ac158 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -26,207 +26,17 @@ #include "sd-event.h" #include "sd-netlink.h" #include "sd-bus.h" -#include "sd-dhcp-client.h" -#include "sd-dhcp-server.h" -#include "sd-ipv4ll.h" -#include "sd-icmp6-nd.h" -#include "sd-dhcp6-client.h" #include "udev.h" -#include "sd-lldp.h" -#include "netlink-util.h" #include "hashmap.h" #include "list.h" -#include "set.h" -#include "condition.h" -#include "in-addr-util.h" -#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU -#define DHCP_ROUTE_METRIC 1024 -#define IPV4LL_ROUTE_METRIC 2048 - -typedef struct NetDev NetDev; -typedef struct Network Network; -typedef struct Link Link; -typedef struct Address Address; -typedef struct Route Route; typedef struct Manager Manager; -typedef struct AddressPool AddressPool; -typedef struct FdbEntry FdbEntry; - -typedef enum AddressFamilyBoolean { - /* This is a bitmask, though it usually doesn't feel that way! */ - ADDRESS_FAMILY_NO = 0, - ADDRESS_FAMILY_IPV4 = 1, - ADDRESS_FAMILY_IPV6 = 2, - ADDRESS_FAMILY_YES = 3, - _ADDRESS_FAMILY_BOOLEAN_MAX, - _ADDRESS_FAMILY_BOOLEAN_INVALID = -1, -} AddressFamilyBoolean; - -typedef enum LLMNRSupport { - LLMNR_SUPPORT_NO, - LLMNR_SUPPORT_YES, - LLMNR_SUPPORT_RESOLVE, - _LLMNR_SUPPORT_MAX, - _LLMNR_SUPPORT_INVALID = -1, -} LLMNRSupport; - -typedef enum LinkOperationalState { - LINK_OPERSTATE_OFF, - LINK_OPERSTATE_NO_CARRIER, - LINK_OPERSTATE_DORMANT, - LINK_OPERSTATE_CARRIER, - LINK_OPERSTATE_DEGRADED, - LINK_OPERSTATE_ROUTABLE, - _LINK_OPERSTATE_MAX, - _LINK_OPERSTATE_INVALID = -1 -} LinkOperationalState; - -typedef enum DCHPClientIdentifier { - DHCP_CLIENT_ID_MAC, - DHCP_CLIENT_ID_DUID, - _DHCP_CLIENT_ID_MAX, - _DHCP_CLIENT_ID_INVALID = -1, -} DCHPClientIdentifier; - -typedef enum IPv6PrivacyExtensions { - /* The values map to the kernel's /proc/sys/net/ipv6/conf/xxx/use_tempaddr values */ - IPV6_PRIVACY_EXTENSIONS_NO, - IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC, - IPV6_PRIVACY_EXTENSIONS_YES, /* aka prefer-temporary */ - _IPV6_PRIVACY_EXTENSIONS_MAX, - _IPV6_PRIVACY_EXTENSIONS_INVALID = -1, -} IPv6PrivacyExtensions; - -struct FdbEntry { - Network *network; - unsigned section; - - struct ether_addr *mac_addr; - uint16_t vlan_id; - - LIST_FIELDS(FdbEntry, static_fdb_entries); -}; - -struct Network { - Manager *manager; - - char *filename; - char *name; - - struct ether_addr *match_mac; - char **match_path; - char **match_driver; - char **match_type; - char **match_name; - - Condition *match_host; - Condition *match_virt; - Condition *match_kernel; - Condition *match_arch; - - char *description; - NetDev *bridge; - NetDev *bond; - Hashmap *stacked_netdevs; - AddressFamilyBoolean dhcp; - DCHPClientIdentifier dhcp_client_identifier; - char *dhcp_vendor_class_identifier; - bool dhcp_dns; - bool dhcp_ntp; - bool dhcp_mtu; - bool dhcp_hostname; - bool dhcp_domains; - bool dhcp_sendhost; - bool dhcp_broadcast; - bool dhcp_critical; - bool dhcp_routes; - unsigned dhcp_route_metric; - AddressFamilyBoolean link_local; - bool ipv4ll_route; - union in_addr_union ipv6_token; - - bool dhcp_server; - - unsigned cost; - - AddressFamilyBoolean ip_forward; - bool ip_masquerade; - - IPv6PrivacyExtensions ipv6_privacy_extensions; - - struct ether_addr *mac; - unsigned mtu; - - bool lldp; - - LIST_HEAD(Address, static_addresses); - LIST_HEAD(Route, static_routes); - LIST_HEAD(FdbEntry, static_fdb_entries); - - Hashmap *addresses_by_section; - Hashmap *routes_by_section; - Hashmap *fdb_entries_by_section; - bool wildcard_domain; - char **domains, **dns, **ntp, **bind_carrier; - - LLMNRSupport llmnr; - - LIST_FIELDS(Network, networks); -}; - -struct Address { - Network *network; - unsigned section; - - int family; - unsigned char prefixlen; - unsigned char scope; - uint32_t flags; - char *label; - - struct in_addr broadcast; - struct ifa_cacheinfo cinfo; - - union in_addr_union in_addr; - union in_addr_union in_addr_peer; - - bool ip_masquerade_done; - - LIST_FIELDS(Address, addresses); -}; - -struct Route { - Network *network; - unsigned section; - - int family; - unsigned char dst_prefixlen; - unsigned char src_prefixlen; - unsigned char scope; - uint32_t metrics; - unsigned char protocol; /* RTPROT_* */ - - union in_addr_union in_addr; - union in_addr_union dst_addr; - union in_addr_union src_addr; - union in_addr_union prefsrc_addr; - - LIST_FIELDS(Route, routes); -}; - -struct AddressPool { - Manager *manager; - - int family; - unsigned prefixlen; - - union in_addr_union in_addr; - - LIST_FIELDS(AddressPool, address_pools); -}; +#include "networkd-network.h" +#include "networkd-address-pool.h" +#include "networkd-link.h" +#include "networkd-util.h" struct Manager { sd_netlink *rtnl; @@ -275,201 +85,7 @@ int manager_save(Manager *m); int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found); +Link* manager_find_uplink(Manager *m, Link *exclude); + DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); #define _cleanup_manager_free_ _cleanup_(manager_freep) - -/* Network */ - -int network_load(Manager *manager); - -void network_free(Network *network); - -DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_free); -#define _cleanup_network_free_ _cleanup_(network_freep) - -int network_get_by_name(Manager *manager, const char *name, Network **ret); -int network_get(Manager *manager, struct udev_device *device, - const char *ifname, const struct ether_addr *mac, - Network **ret); -int network_apply(Manager *manager, Network *network, Link *link); - -int config_parse_netdev(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_domains(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata); - -int config_parse_tunnel(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata); - -int config_parse_tunnel_address(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata); - -int config_parse_vxlan_group_address(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata); - -extern const sd_bus_vtable network_vtable[]; - -int network_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); -int network_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); - -/* gperf */ -const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, unsigned length); - -/* Route */ -int route_new_static(Network *network, unsigned section, Route **ret); -int route_new_dynamic(Route **ret, unsigned char rtm_protocol); -void route_free(Route *route); -int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback); -int route_drop(Route *route, Link *link, sd_netlink_message_handler_t callback); - - -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, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_destination(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_route_priority(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_route_scope(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); -/* Address */ -int address_new_static(Network *network, unsigned section, Address **ret); -int address_new_dynamic(Address **ret); -void address_free(Address *address); -int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback); -int address_update(Address *address, Link *link, sd_netlink_message_handler_t callback); -int address_drop(Address *address, Link *link, sd_netlink_message_handler_t callback); -int address_establish(Address *address, Link *link); -int address_release(Address *address, Link *link); -bool address_equal(Address *a1, Address *a2); - -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, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_broadcast(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_label(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -/* Forwarding database table. */ -int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry); -void fdb_entry_free(FdbEntry *fdb_entry); -int fdb_entry_new_static(Network *const network, const unsigned section, FdbEntry **ret); - -DEFINE_TRIVIAL_CLEANUP_FUNC(FdbEntry*, fdb_entry_free); -#define _cleanup_fdbentry_free_ _cleanup_(fdb_entry_freep) - -int config_parse_fdb_hwaddr(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_fdb_vlan_id(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -/* DHCP support */ - -int config_parse_dhcp(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_dhcp_client_identifier(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -/* IPv4LL support (legacy) */ - -int config_parse_ipv4ll(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -/* IPv6 support */ -int config_parse_ipv6token(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -/* LLMNR support */ - -const char* llmnr_support_to_string(LLMNRSupport i) _const_; -LLMNRSupport llmnr_support_from_string(const char *s) _pure_; - -int config_parse_llmnr(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -/* Address Pool */ - -int address_pool_new(Manager *m, AddressPool **ret, int family, const union in_addr_union *u, unsigned prefixlen); -int address_pool_new_from_string(Manager *m, AddressPool **ret, int family, const char *p, unsigned prefixlen); -void address_pool_free(AddressPool *p); - -int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found); - -const char *address_family_boolean_to_string(AddressFamilyBoolean b) _const_; -AddressFamilyBoolean address_family_boolean_from_string(const char *s) _const_; - -int config_parse_address_family_boolean(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); - -/* IPForwarding parser */ -int config_parse_address_family_boolean_with_kernel(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); - -/* Operational State */ - -const char* link_operstate_to_string(LinkOperationalState s) _const_; -LinkOperationalState link_operstate_from_string(const char *s) _pure_; - -/* IPv6 privacy extensions support */ - -const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_; -IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_; - -int config_parse_ipv6_privacy_extensions(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); |