diff options
Diffstat (limited to 'src/network/networkd-manager.c')
-rw-r--r-- | src/network/networkd-manager.c | 372 |
1 files changed, 202 insertions, 170 deletions
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 1c4866077b..81c81f18af 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -12,17 +12,18 @@ #include "bus-util.h" #include "conf-parser.h" #include "def.h" +#include "device-util.h" #include "dns-domain.h" #include "fd-util.h" #include "fileio.h" -#include "libudev-private.h" #include "local-addresses.h" #include "netlink-util.h" #include "networkd-manager.h" #include "ordered-set.h" #include "path-util.h" #include "set.h" -#include "udev-util.h" +#include "strv.h" +#include "tmpfile-util.h" #include "virt.h" /* use 8 MB for receive socket kernel queue. */ @@ -114,6 +115,8 @@ static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *r (void) manager_set_hostname(m, m->dynamic_hostname); if (m->dynamic_timezone) (void) manager_set_timezone(m, m->dynamic_timezone); + if (m->links_requesting_uuid) + (void) manager_request_product_uuid(m, NULL); return 0; } @@ -150,7 +153,7 @@ int manager_connect_bus(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to add network enumerator: %m"); - r = bus_request_name_async_may_reload_dbus(m->bus, NULL, "org.freedesktop.network1", 0, NULL); + r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.network1", 0, NULL, NULL); if (r < 0) return log_error_errno(r, "Failed to request name: %m"); @@ -160,7 +163,7 @@ int manager_connect_bus(Manager *m) { r = sd_bus_match_signal_async( m->bus, - &m->connected_slot, + NULL, "org.freedesktop.DBus.Local", NULL, "org.freedesktop.DBus.Local", @@ -171,7 +174,7 @@ int manager_connect_bus(Manager *m) { r = sd_bus_match_signal_async( m->bus, - &m->prepare_for_sleep_slot, + NULL, "org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", @@ -183,45 +186,40 @@ int manager_connect_bus(Manager *m) { return 0; } -static int manager_udev_process_link(Manager *m, struct udev_device *device) { +static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata) { + Manager *m = userdata; + const char *action; Link *link = NULL; int r, ifindex; assert(m); assert(device); - if (!streq_ptr(udev_device_get_action(device), "add")) + r = sd_device_get_property_value(device, "ACTION", &action); + if (r < 0) { + log_device_debug_errno(device, r, "Failed to get 'ACTION' property, ignoring device: %m"); return 0; + } - ifindex = udev_device_get_ifindex(device); - if (ifindex <= 0) { - log_debug("Ignoring udev ADD event for device with invalid ifindex"); + if (!STR_IN_SET(action, "add", "change")) { + log_device_debug(device, "Ignoring udev %s event for device.", action); return 0; } - r = link_get(m, ifindex, &link); - if (r == -ENODEV) + 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"); return 0; - else if (r < 0) - return r; - - r = link_initialized(link, device); - if (r < 0) - return r; - - return 0; -} - -static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) { - Manager *m = userdata; - struct udev_monitor *monitor = m->udev_monitor; - _cleanup_(udev_device_unrefp) struct udev_device *device = NULL; + } - device = udev_monitor_receive_device(monitor); - if (!device) - return -ENOMEM; + r = link_get(m, ifindex, &link); + if (r < 0) { + if (r != -ENODEV) + log_debug_errno(r, "Failed to get link from ifindex %i, ignoring: %m", ifindex); + return 0; + } - (void) manager_udev_process_link(m, device); + (void) link_initialized(link, device); return 0; } @@ -235,35 +233,21 @@ static int manager_connect_udev(Manager *m) { if (detect_container() > 0) return 0; - m->udev = udev_new(); - if (!m->udev) - return -ENOMEM; - - m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); - if (!m->udev_monitor) - return -ENOMEM; - - r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL); + r = sd_device_monitor_new(&m->device_monitor); if (r < 0) - return log_error_errno(r, "Could not add udev monitor filter: %m"); + return log_error_errno(r, "Failed to initialize device monitor: %m"); - r = udev_monitor_enable_receiving(m->udev_monitor); - if (r < 0) { - log_error("Could not enable udev monitor"); - return r; - } + 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"); - r = sd_event_add_io(m->event, - &m->udev_event_source, - udev_monitor_get_fd(m->udev_monitor), - EPOLLIN, manager_dispatch_link_udev, - m); + r = sd_device_monitor_attach_event(m->device_monitor, m->event); if (r < 0) - return r; + return log_error_errno(r, "Failed to attach event to device monitor: %m"); - r = sd_event_source_set_description(m->udev_event_source, "networkd-udev"); + r = sd_device_monitor_start(m->device_monitor, manager_udev_process_link, m); if (r < 0) - return r; + return log_error_errno(r, "Failed to start device monitor: %m"); return 0; } @@ -714,11 +698,12 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa } int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) { - uint8_t tos = 0, to_prefixlen = 0, from_prefixlen = 0; + uint8_t tos = 0, to_prefixlen = 0, from_prefixlen = 0, protocol = 0; + struct fib_rule_port_range sport = {}, dport = {}; union in_addr_union to = {}, from = {}; RoutingPolicyRule *rule = NULL; uint32_t fwmark = 0, table = 0; - char *iif = NULL, *oif = NULL; + const char *iif = NULL, *oif = NULL; Manager *m = userdata; uint16_t type; int family; @@ -834,24 +819,42 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, voi return 0; } - r = sd_netlink_message_read_string(message, FRA_IIFNAME, (const char **) &iif); + r = sd_netlink_message_read_string(message, FRA_IIFNAME, &iif); if (r < 0 && r != -ENODATA) { log_warning_errno(r, "rtnl: could not get FRA_IIFNAME attribute, ignoring: %m"); return 0; } - r = sd_netlink_message_read_string(message, FRA_OIFNAME, (const char **) &oif); + r = sd_netlink_message_read_string(message, FRA_OIFNAME, &oif); if (r < 0 && r != -ENODATA) { log_warning_errno(r, "rtnl: could not get FRA_OIFNAME attribute, ignoring: %m"); return 0; } - (void) routing_policy_rule_get(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, &rule); + r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &protocol); + if (r < 0 && r != -ENODATA) { + log_warning_errno(r, "rtnl: could not get FRA_IP_PROTO attribute, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read(message, FRA_SPORT_RANGE, sizeof(sport), (void *) &sport); + if (r < 0 && r != -ENODATA) { + log_warning_errno(r, "rtnl: could not get FRA_SPORT_RANGE attribute, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read(message, FRA_DPORT_RANGE, sizeof(dport), (void *) &dport); + if (r < 0 && r != -ENODATA) { + log_warning_errno(r, "rtnl: could not get FRA_DPORT_RANGE attribute, ignoring: %m"); + return 0; + } + + (void) routing_policy_rule_get(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, &sport, &dport, &rule); switch (type) { case RTM_NEWRULE: if (!rule) { - r = routing_policy_rule_add_foreign(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, &rule); + r = routing_policy_rule_add_foreign(m, family, &from, from_prefixlen, &to, to_prefixlen, tos, fwmark, table, iif, oif, protocol, &sport, &dport, &rule); if (r < 0) { log_warning_errno(r, "Could not add rule, ignoring: %m"); return 0; @@ -930,35 +933,35 @@ static int manager_connect_rtnl(Manager *m) { if (r < 0) return r; - r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m); + r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); if (r < 0) return r; - r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m); + r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELLINK, &manager_rtnl_process_link, NULL, m, "network-rtnl_process_link"); if (r < 0) return r; - r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &manager_rtnl_process_address, m); + r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); if (r < 0) return r; - r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &manager_rtnl_process_address, m); + r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELADDR, &manager_rtnl_process_address, NULL, m, "network-rtnl_process_address"); if (r < 0) return r; - r = sd_netlink_add_match(m->rtnl, RTM_NEWROUTE, &manager_rtnl_process_route, m); + r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); if (r < 0) return r; - r = sd_netlink_add_match(m->rtnl, RTM_DELROUTE, &manager_rtnl_process_route, m); + r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELROUTE, &manager_rtnl_process_route, NULL, m, "network-rtnl_process_route"); if (r < 0) return r; - r = sd_netlink_add_match(m->rtnl, RTM_NEWRULE, &manager_rtnl_process_rule, m); + r = sd_netlink_add_match(m->rtnl, NULL, RTM_NEWRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); if (r < 0) return r; - r = sd_netlink_add_match(m->rtnl, RTM_DELRULE, &manager_rtnl_process_rule, m); + r = sd_netlink_add_match(m->rtnl, NULL, RTM_DELRULE, &manager_rtnl_process_rule, NULL, m, "network-rtnl_process_rule"); if (r < 0) return r; @@ -1215,62 +1218,56 @@ static int manager_dirty_handler(sd_event_source *s, void *userdata) { Manager *m = userdata; Link *link; Iterator i; - int r; assert(m); if (m->dirty) manager_save(m); - SET_FOREACH(link, m->dirty_links, i) { - r = link_save(link); - if (r >= 0) + SET_FOREACH(link, m->dirty_links, i) + if (link_save(link) >= 0) link_clean(link); - } return 1; } Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr) { assert_return(m, NULL); - assert_return(m->dhcp6_prefixes, NULL); assert_return(addr, NULL); return hashmap_get(m->dhcp6_prefixes, addr); } -static int dhcp6_route_add_callback(sd_netlink *nl, sd_netlink_message *m, - void *userdata) { - Link *l = userdata; +static int dhcp6_route_add_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) { int r; - union in_addr_union prefix; - _cleanup_free_ char *buf = NULL; + + assert(link); r = sd_netlink_message_get_errno(m); - if (r != 0) { - log_link_debug_errno(l, r, "Received error adding DHCPv6 Prefix Delegation route: %m"); - return 0; - } + if (r < 0 && r != -EEXIST) + log_link_debug_errno(link, r, "Received error adding DHCPv6 Prefix Delegation route: %m"); - r = sd_netlink_message_read_in6_addr(m, RTA_DST, &prefix.in6); - if (r < 0) { - log_link_debug_errno(l, r, "Could not read IPv6 address from DHCPv6 Prefix Delegation while adding route: %m"); - return 0; - } + return 0; +} - (void) in_addr_to_string(AF_INET6, &prefix, &buf); - log_link_debug(l, "Added DHCPv6 Prefix Deleagtion route %s/64", - strnull(buf)); +static void dhcp6_prefixes_hash_func(const struct in6_addr *addr, struct siphash *state) { + assert(addr); - return 0; + siphash24_compress(addr, sizeof(*addr), state); } +static int dhcp6_prefixes_compare_func(const struct in6_addr *a, const struct in6_addr *b) { + return memcmp(a, b, sizeof(*a)); +} + +DEFINE_PRIVATE_HASH_OPS(dhcp6_prefixes_hash_ops, struct in6_addr, dhcp6_prefixes_hash_func, dhcp6_prefixes_compare_func); + int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) { - int r; + _cleanup_free_ char *buf = NULL; Route *route; + int r; assert_return(m, -EINVAL); - assert_return(m->dhcp6_prefixes, -ENODATA); assert_return(addr, -EINVAL); r = route_add(link, AF_INET6, (union in_addr_union *) addr, 64, @@ -1278,46 +1275,39 @@ int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) { if (r < 0) return r; - r = route_configure(route, link, dhcp6_route_add_callback); + r = route_configure(route, link, dhcp6_route_add_handler); + if (r < 0) + return r; + + (void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf); + log_link_debug(link, "Adding prefix route %s/64", strnull(buf)); + + r = hashmap_ensure_allocated(&m->dhcp6_prefixes, &dhcp6_prefixes_hash_ops); if (r < 0) return r; return hashmap_put(m->dhcp6_prefixes, addr, link); } -static int dhcp6_route_remove_callback(sd_netlink *nl, sd_netlink_message *m, - void *userdata) { - Link *l = userdata; +static int dhcp6_route_remove_handler(sd_netlink *nl, sd_netlink_message *m, Link *link) { int r; - union in_addr_union prefix; - _cleanup_free_ char *buf = NULL; - r = sd_netlink_message_get_errno(m); - if (r != 0) { - log_link_debug_errno(l, r, "Received error on DHCPv6 Prefix Delegation route removal: %m"); - return 0; - } + assert(link); - r = sd_netlink_message_read_in6_addr(m, RTA_DST, &prefix.in6); - if (r < 0) { - log_link_debug_errno(l, r, "Could not read IPv6 address from DHCPv6 Prefix Delegation while removing route: %m"); - return 0; - } - - (void) in_addr_to_string(AF_INET6, &prefix, &buf); - log_link_debug(l, "Removed DHCPv6 Prefix Delegation route %s/64", - strnull(buf)); + r = sd_netlink_message_get_errno(m); + if (r < 0) + log_link_debug_errno(link, r, "Received error on DHCPv6 Prefix Delegation route removal: %m"); - return 0; + return 1; } -int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) { +static int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) { + _cleanup_free_ char *buf = NULL; + Route *route; Link *l; int r; - Route *route; assert_return(m, -EINVAL); - assert_return(m->dhcp6_prefixes, -ENODATA); assert_return(addr, -EINVAL); l = hashmap_remove(m->dhcp6_prefixes, addr); @@ -1327,16 +1317,23 @@ int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) { (void) sd_radv_remove_prefix(l->radv, addr, 64); r = route_get(l, AF_INET6, (union in_addr_union *) addr, 64, 0, 0, 0, &route); - if (r >= 0) - (void) route_remove(route, l, dhcp6_route_remove_callback); + if (r < 0) + return r; + + r = route_remove(route, l, dhcp6_route_remove_handler); + if (r < 0) + return r; + + (void) in_addr_to_string(AF_INET6, (union in_addr_union *) addr, &buf); + log_link_debug(l, "Removing prefix route %s/64", strnull(buf)); return 0; } int manager_dhcp6_prefix_remove_all(Manager *m, Link *link) { + struct in6_addr *addr; Iterator i; Link *l; - struct in6_addr *addr; assert_return(m, -EINVAL); assert_return(link, -EINVAL); @@ -1351,26 +1348,7 @@ int manager_dhcp6_prefix_remove_all(Manager *m, Link *link) { return 0; } -static void dhcp6_prefixes_hash_func(const void *p, struct siphash *state) { - const struct in6_addr *addr = p; - - assert(p); - - siphash24_compress(addr, sizeof(*addr), state); -} - -static int dhcp6_prefixes_compare_func(const void *_a, const void *_b) { - const struct in6_addr *a = _a, *b = _b; - - return memcmp(a, b, sizeof(*a)); -} - -static const struct hash_ops dhcp6_prefixes_hash_ops = { - .hash = dhcp6_prefixes_hash_func, - .compare = dhcp6_prefixes_compare_func, -}; - -int manager_new(Manager **ret, sd_event *event) { +int manager_new(Manager **ret) { _cleanup_(manager_freep) Manager *m = NULL; int r; @@ -1382,7 +1360,13 @@ int manager_new(Manager **ret, sd_event *event) { if (!m->state_file) return -ENOMEM; - m->event = sd_event_ref(event); + r = sd_event_default(&m->event); + if (r < 0) + return r; + + (void) sd_event_set_watchdog(m->event, true); + (void) sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL); + (void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL); r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m); if (r < 0) @@ -1400,10 +1384,6 @@ int manager_new(Manager **ret, sd_event *event) { if (r < 0) return r; - m->netdevs = hashmap_new(&string_hash_ops); - if (!m->netdevs) - return -ENOMEM; - LIST_HEAD_INIT(m->networks); r = sd_resolve_default(&m->resolve); @@ -1418,10 +1398,6 @@ int manager_new(Manager **ret, sd_event *event) { if (r < 0) return r; - m->dhcp6_prefixes = hashmap_new(&dhcp6_prefixes_hash_ops); - if (!m->dhcp6_prefixes) - return -ENOMEM; - m->duid.type = DUID_TYPE_EN; (void) routing_policy_load_rules(m->state_file, &m->rules_saved); @@ -1432,53 +1408,55 @@ int manager_new(Manager **ret, sd_event *event) { } void manager_free(Manager *m) { + AddressPool *pool; Network *network; - NetDev *netdev; Link *link; - AddressPool *pool; if (!m) return; free(m->state_file); + sd_netlink_unref(m->rtnl); + sd_netlink_unref(m->genl); + sd_resolve_unref(m->resolve); + while ((network = m->networks)) network_free(network); while ((link = hashmap_first(m->dhcp6_prefixes))) - link_unref(link); + manager_dhcp6_prefix_remove_all(m, link); hashmap_free(m->dhcp6_prefixes); - while ((link = hashmap_first(m->links))) + while ((link = hashmap_steal_first(m->links))) { + if (link->dhcp6_client) + (void) dhcp6_lease_pd_prefix_lost(link->dhcp6_client, link); link_unref(link); - hashmap_free(m->links); + } + + m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref); + m->links = hashmap_free(m->links); + m->links_requesting_uuid = set_free(m->links_requesting_uuid); + set_free(m->duids_requesting_uuid); hashmap_free(m->networks_by_name); - while ((netdev = hashmap_first(m->netdevs))) - netdev_unref(netdev); - hashmap_free(m->netdevs); + m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref); while ((pool = m->address_pools)) address_pool_free(pool); - set_free(m->rules); - set_free(m->rules_foreign); - + /* 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); - sd_netlink_unref(m->rtnl); sd_event_unref(m->event); - sd_resolve_unref(m->resolve); - - sd_event_source_unref(m->udev_event_source); - udev_monitor_unref(m->udev_monitor); - udev_unref(m->udev); + sd_device_monitor_unref(m->device_monitor); sd_bus_unref(m->bus); - sd_bus_slot_unref(m->prepare_for_sleep_slot); - sd_bus_slot_unref(m->connected_slot); free(m->dynamic_timezone); free(m->dynamic_hostname); @@ -1757,7 +1735,7 @@ int manager_set_hostname(Manager *m, const char *hostname) { return log_oom(); if (!m->bus || sd_bus_is_ready(m->bus) <= 0) { - log_info("Not connected to system bus, not setting hostname."); + log_debug("Not connected to system bus, setting hostname later."); return 0; } @@ -1805,7 +1783,7 @@ int manager_set_timezone(Manager *m, const char *tz) { return log_oom(); if (!m->bus || sd_bus_is_ready(m->bus) <= 0) { - log_info("Not connected to system bus, not setting timezone."); + log_debug("Not connected to system bus, setting timezone later."); return 0; } @@ -1826,3 +1804,57 @@ int manager_set_timezone(Manager *m, const char *tz) { return 0; } + +int manager_request_product_uuid(Manager *m, Link *link) { + int r; + + assert(m); + + if (m->has_product_uuid) + return 0; + + log_debug("Requesting product UUID"); + + if (link) { + DUID *duid; + + 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); + if (r < 0) + return log_oom(); + + r = set_put(m->duids_requesting_uuid, duid); + if (r < 0) + return log_oom(); + } + + if (!m->bus || sd_bus_is_ready(m->bus) <= 0) { + log_debug("Not connected to system bus, requesting product UUID later."); + return 0; + } + + r = sd_bus_call_method_async( + m->bus, + NULL, + "org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + "GetProductUUID", + get_product_uuid_handler, + m, + "b", + false); + if (r < 0) + return log_warning_errno(r, "Failed to get product UUID: %m"); + + return 0; +} |