#include "local-addresses.h"
#include "netlink-util.h"
#include "network-internal.h"
+#include "networkd-dhcp-server-bus.h"
#include "networkd-dhcp6.h"
#include "networkd-link-bus.h"
#include "networkd-manager-bus.h"
#include "path-util.h"
#include "set.h"
#include "signal-util.h"
+#include "stat-util.h"
#include "strv.h"
#include "sysctl-util.h"
#include "tmpfile-util.h"
#include "udev-util.h"
-#include "virt.h"
/* use 128 MB for receive socket kernel queue. */
#define RCVBUF_SIZE (128*1024*1024)
static int manager_reset_all(Manager *m) {
Link *link;
- Iterator i;
int r;
assert(m);
- HASHMAP_FOREACH(link, m->links, i) {
+ HASHMAP_FOREACH(link, m->links) {
r = link_carrier_reset(link);
if (r < 0)
log_link_warning_errno(link, r, "Could not reset carrier: %m");
r = sd_bus_message_read(message, "b", &b);
if (r < 0) {
- log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
+ bus_log_parse_error(r);
return 0;
}
if (r < 0)
return log_error_errno(r, "Failed to add link object vtable: %m");
+ r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/link", "org.freedesktop.network1.DHCPServer", dhcp_server_vtable, link_object_find, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add link object vtable: %m");
+
r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/link", link_node_enumerator, m);
if (r < 0)
return log_error_errno(r, "Failed to add link enumerator: %m");
return 0;
}
- if (!IN_SET(action, DEVICE_ACTION_ADD, DEVICE_ACTION_CHANGE, DEVICE_ACTION_MOVE)) {
- log_device_debug(device, "Ignoring udev %s event for device.", device_action_to_string(action));
+ /* Ignore the "remove" uevent — let's remove a device only if rtnetlink says so. All other uevents
+ * are "positive" events in some form, i.e. inform us about a changed or new network interface, that
+ * still exists — and we are interested in that. */
+ if (action == DEVICE_ACTION_REMOVE)
return 0;
- }
r = sd_device_get_ifindex(device, &ifindex);
if (r < 0) {
- log_device_debug_errno(device, r, "Ignoring udev ADD event for device without ifindex or with invalid ifindex: %m");
+ log_device_debug_errno(device, r, "Ignoring udev %s event for device without ifindex or with invalid ifindex: %m",
+ device_action_to_string(action));
return 0;
}
return 0;
}
if (r > 0) {
- log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed: %m");
+ log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed.");
return 0;
}
static int manager_connect_udev(Manager *m) {
int r;
- /* udev does not initialize devices inside containers,
- * so we rely on them being already initialized before
- * entering the container */
- if (detect_container() > 0)
+ /* udev does not initialize devices inside containers, so we rely on them being already
+ * initialized before entering the container. */
+ if (path_is_read_only_fs("/sys") > 0)
return 0;
r = sd_device_monitor_new(&m->device_monitor);
if (r < 0)
return log_error_errno(r, "Failed to initialize device monitor: %m");
+ r = sd_device_monitor_set_receive_buffer_size(m->device_monitor, RCVBUF_SIZE);
+ if (r < 0)
+ log_warning_errno(r, "Failed to increase buffer size for device monitor, ignoring: %m");
+
r = sd_device_monitor_filter_add_match_subsystem_devtype(m->device_monitor, "net", NULL);
if (r < 0)
return log_error_errno(r, "Could not add device monitor filter: %m");
log_link_debug(link,
"%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s",
- (!route && !link->manager->manage_foreign_routes) || type == RTM_DELROUTE ? "Forgetting" :
+ (!route && !link->manager->manage_foreign_routes) ? "Ignoring received foreign" :
+ type == RTM_DELROUTE ? "Forgetting" :
route ? "Received remembered" : "Remembering",
strna(buf_dst), strempty(buf_dst_prefixlen),
strna(buf_src), strna(buf_gw), strna(buf_prefsrc),
valid_str ? "for " : "forever", strempty(valid_str));
}
- /* address_update() logs internally, so we don't need to. */
- (void) address_update(address, flags, scope, &cinfo);
+ /* address_update() logs internally, so we don't need to here. */
+ r = address_update(address, flags, scope, &cinfo);
+ if (r < 0)
+ link_enter_failed(link);
break;
if (r < 0 && r != -ENODATA) {
log_warning_errno(r, "rtnl: could not get NHA_OIF attribute, ignoring: %m");
return 0;
+ } else if (tmp->oif <= 0) {
+ log_warning("rtnl: received nexthop message with invalid ifindex %d, ignoring.", tmp->oif);
+ return 0;
}
r = link_get(m, tmp->oif, &link);
r = sd_netlink_inc_rcvbuf(m->genl, RCVBUF_SIZE);
if (r < 0)
- return r;
+ log_warning_errno(r, "Failed to increase receive buffer size for general netlink socket, ignoring: %m");
r = sd_netlink_attach_event(m->genl, m->event, 0);
if (r < 0)
if (r < 0)
return r;
- r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
- if (r < 0)
- return r;
+ /* Bump receiver buffer, but only if we are not called via socket activation, as in that
+ * case systemd sets the receive buffer size for us, and the value in the .socket unit
+ * should take full effect. */
+ if (fd < 0) {
+ r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
+ if (r < 0)
+ log_warning_errno(r, "Failed to increase receive buffer size for rtnl socket, ignoring: %m");
+ }
r = sd_netlink_attach_event(m->rtnl, m->event, 0);
if (r < 0)
return 0;
}
-static int ordered_set_put_in_addr_data(OrderedSet *s, const struct in_addr_data *address) {
- char *p;
+static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr_full *dns) {
+ const char *p;
int r;
assert(s);
- assert(address);
+ assert(dns);
- r = in_addr_to_string(address->family, &address->address, &p);
- if (r < 0)
- return r;
+ if (dns->ifindex != 0 && dns->ifindex != ifindex)
+ return 0;
- r = ordered_set_consume(s, p);
+ p = in_addr_full_to_string(dns);
+ if (!p)
+ return 0;
+
+ r = ordered_set_put_strdup(s, p);
if (r == -EEXIST)
return 0;
return r;
}
-static int ordered_set_put_in_addr_datav(OrderedSet *s, const struct in_addr_data *addresses, unsigned n) {
+static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_addr_full **dns, unsigned n) {
int r, c = 0;
unsigned i;
assert(s);
- assert(addresses || n == 0);
+ assert(dns || n == 0);
for (i = 0; i < n; i++) {
- r = ordered_set_put_in_addr_data(s, addresses+i);
+ r = ordered_set_put_dns_server(s, ifindex, dns[i]);
if (r < 0)
return r;
}
static int manager_save(Manager *m) {
- _cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *pop3 = NULL,
- *smtp = NULL, *lpr = NULL, *search_domains = NULL, *route_domains = NULL;
+ _cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
const char *operstate_str, *carrier_state_str, *address_state_str;
LinkOperationalState operstate = LINK_OPERSTATE_OFF;
LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
_cleanup_free_ char *temp_path = NULL;
_cleanup_strv_free_ char **p = NULL;
_cleanup_fclose_ FILE *f = NULL;
- const struct in_addr *addresses;
Link *link;
- Iterator i;
int r;
assert(m);
if (!sip)
return -ENOMEM;
- pop3 = ordered_set_new(&string_hash_ops);
- if (!pop3)
- return -ENOMEM;
-
- smtp = ordered_set_new(&string_hash_ops);
- if (!smtp)
- return -ENOMEM;
-
- lpr = ordered_set_new(&string_hash_ops);
- if (!lpr)
- return -ENOMEM;
-
search_domains = ordered_set_new(&dns_name_hash_ops);
if (!search_domains)
return -ENOMEM;
if (!route_domains)
return -ENOMEM;
- HASHMAP_FOREACH(link, m->links, i) {
+ HASHMAP_FOREACH(link, m->links) {
+ const struct in_addr *addresses;
+
if (link->flags & IFF_LOOPBACK)
continue;
continue;
/* First add the static configured entries */
- r = ordered_set_put_in_addr_datav(dns, link->network->dns, link->network->n_dns);
+ if (link->n_dns != (unsigned) -1)
+ r = ordered_set_put_dns_servers(dns, link->ifindex, link->dns, link->n_dns);
+ else
+ r = ordered_set_put_dns_servers(dns, link->ifindex, link->network->dns, link->network->n_dns);
if (r < 0)
return r;
return r;
}
- r = sd_dhcp_lease_get_pop3(link->dhcp_lease, &addresses);
- if (r > 0) {
- r = ordered_set_put_in4_addrv(pop3, addresses, r, in4_addr_is_non_local);
- if (r < 0)
- return r;
- } else if (r < 0 && r != -ENODATA)
- return r;
-
- r = sd_dhcp_lease_get_smtp(link->dhcp_lease, &addresses);
- if (r > 0) {
- r = ordered_set_put_in4_addrv(smtp, addresses, r, in4_addr_is_non_local);
- if (r < 0)
- return r;
- } else if (r < 0 && r != -ENODATA)
- return r;
-
- r = sd_dhcp_lease_get_lpr(link->dhcp_lease, &addresses);
- if (r > 0) {
- r = ordered_set_put_in4_addrv(lpr, addresses, r, in4_addr_is_non_local);
- if (r < 0)
- return r;
- } else if (r < 0 && r != -ENODATA)
- return r;
-
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
const char *domainname;
char **domains = NULL;
ordered_set_print(f, "DNS=", dns);
ordered_set_print(f, "NTP=", ntp);
ordered_set_print(f, "SIP=", sip);
- ordered_set_print(f, "POP3_SERVERS=", pop3);
- ordered_set_print(f, "SMTP_SERVERS=", smtp);
- ordered_set_print(f, "LPR_SERVERS=", lpr);
ordered_set_print(f, "DOMAINS=", search_domains);
ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
static int manager_dirty_handler(sd_event_source *s, void *userdata) {
Manager *m = userdata;
Link *link;
- Iterator i;
assert(m);
if (m->dirty)
manager_save(m);
- SET_FOREACH(link, m->dirty_links, i)
- if (link_save(link) >= 0)
- link_clean(link);
+ SET_FOREACH(link, m->dirty_links)
+ (void) link_save_and_clean(link);
return 1;
}
}
void manager_free(Manager *m) {
- struct in6_addr *a;
AddressPool *pool;
Link *link;
free(m->state_file);
- while ((a = hashmap_first_key(m->dhcp6_prefixes)))
- (void) dhcp6_prefix_remove(m, a);
- m->dhcp6_prefixes = hashmap_free(m->dhcp6_prefixes);
-
- while ((link = hashmap_steal_first(m->links))) {
- if (link->dhcp6_client)
- (void) dhcp6_lease_pd_prefix_lost(link->dhcp6_client, link);
-
+ HASHMAP_FOREACH(link, m->links)
(void) link_stop_clients(link, true);
- link_unref(link);
- }
+ m->dhcp6_prefixes = hashmap_free_with_destructor(m->dhcp6_prefixes, dhcp6_pd_free);
+ m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free);
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref);
/* routing_policy_rule_free() access m->rules and m->rules_foreign.
* So, it is necessary to set NULL after the sets are freed. */
- m->rules = set_free_with_destructor(m->rules, routing_policy_rule_free);
- m->rules_foreign = set_free_with_destructor(m->rules_foreign, routing_policy_rule_free);
- set_free_with_destructor(m->rules_saved, routing_policy_rule_free);
+ m->rules = set_free(m->rules);
+ m->rules_foreign = set_free(m->rules_foreign);
+ set_free(m->rules_saved);
sd_netlink_unref(m->rtnl);
sd_netlink_unref(m->genl);
int manager_start(Manager *m) {
Link *link;
- Iterator i;
int r;
assert(m);
manager_save(m);
- HASHMAP_FOREACH(link, m->links, i)
- link_save(link);
+ HASHMAP_FOREACH(link, m->links)
+ (void) link_save(link);
return 0;
}
assert(m);
assert(m->rtnl);
+ if (!m->manage_foreign_routes)
+ return 0;
+
r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0);
if (r < 0)
return r;
assert_se(duid = link_get_duid(link));
- r = set_ensure_allocated(&m->links_requesting_uuid, NULL);
- if (r < 0)
- return log_oom();
-
- r = set_ensure_allocated(&m->duids_requesting_uuid, NULL);
- if (r < 0)
- return log_oom();
-
- r = set_put(m->links_requesting_uuid, link);
+ r = set_ensure_put(&m->links_requesting_uuid, NULL, link);
if (r < 0)
return log_oom();
+ if (r > 0)
+ link_ref(link);
- r = set_put(m->duids_requesting_uuid, duid);
+ r = set_ensure_put(&m->duids_requesting_uuid, NULL, duid);
if (r < 0)
return log_oom();
-
- link_ref(link);
}
if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {