X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-link.c;h=0b1cac1055ffaa055f010c2cc189c5ae3afa37b5;hb=e2acdb6b0f68d9b4152708a9f21bf9e11f8b9e7e;hp=310eb6c7347af89d99c8dc7dd0e9de870414f3d8;hpb=07e10d1a7c7535bd3938b09a11bf29b94a9dae77;p=elogind.git diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 310eb6c73..0b1cac105 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -35,7 +35,7 @@ #include "conf-parser.h" #include "dhcp-lease-internal.h" -static bool link_dhcp6_enabled(Link *link) { +bool link_dhcp6_enabled(Link *link) { if (link->flags & IFF_LOOPBACK) return false; @@ -45,7 +45,7 @@ static bool link_dhcp6_enabled(Link *link) { return IN_SET(link->network->dhcp, ADDRESS_FAMILY_IPV6, ADDRESS_FAMILY_YES); } -static bool link_dhcp4_enabled(Link *link) { +bool link_dhcp4_enabled(Link *link) { if (link->flags & IFF_LOOPBACK) return false; @@ -55,7 +55,7 @@ static bool link_dhcp4_enabled(Link *link) { return IN_SET(link->network->dhcp, ADDRESS_FAMILY_IPV4, ADDRESS_FAMILY_YES); } -static bool link_dhcp4_server_enabled(Link *link) { +bool link_dhcp4_server_enabled(Link *link) { if (link->flags & IFF_LOOPBACK) return false; @@ -65,17 +65,27 @@ static bool link_dhcp4_server_enabled(Link *link) { return link->network->dhcp_server; } -static bool link_ipv4ll_enabled(Link *link) { +bool link_ipv4ll_enabled(Link *link) { if (link->flags & IFF_LOOPBACK) return false; if (!link->network) return false; - return link->network->ipv4ll; + return IN_SET(link->network->link_local, ADDRESS_FAMILY_IPV4, ADDRESS_FAMILY_YES); } -static bool link_lldp_enabled(Link *link) { +bool link_ipv6ll_enabled(Link *link) { + if (link->flags & IFF_LOOPBACK) + return false; + + if (!link->network) + return false; + + return IN_SET(link->network->link_local, ADDRESS_FAMILY_IPV6, ADDRESS_FAMILY_YES); +} + +bool link_lldp_enabled(Link *link) { if (link->flags & IFF_LOOPBACK) return false; @@ -283,12 +293,10 @@ static void link_free(Link *link) { sd_dhcp_client_unref(link->dhcp_client); sd_dhcp_lease_unref(link->dhcp_lease); - unlink(link->lease_file); free(link->lease_file); sd_lldp_free(link->lldp); - unlink(link->lldp_file); free(link->lldp_file); sd_ipv4ll_unref(link->ipv4ll); @@ -300,7 +308,6 @@ static void link_free(Link *link) { free(link->ifname); - unlink(link->state_file); free(link->state_file); udev_device_unref(link->udev_device); @@ -338,11 +345,24 @@ int link_get(Manager *m, int ifindex, Link **ret) { return 0; } +static void link_set_state(Link *link, LinkState state) { + assert(link); + + if (link->state == state) + return; + + link->state = state; + + link_send_changed(link, "AdministrativeState", NULL); + + return; +} + void link_drop(Link *link) { if (!link || link->state == LINK_STATE_LINGER) return; - link->state = LINK_STATE_LINGER; + link_set_state(link, LINK_STATE_LINGER); log_link_debug(link, "link removed"); @@ -356,7 +376,7 @@ static void link_enter_unmanaged(Link *link) { log_link_debug(link, "unmanaged"); - link->state = LINK_STATE_UNMANAGED; + link_set_state(link, LINK_STATE_UNMANAGED); link_save(link); } @@ -430,7 +450,7 @@ void link_enter_failed(Link *link) { log_link_warning(link, "failed"); - link->state = LINK_STATE_FAILED; + link_set_state(link, LINK_STATE_FAILED); link_stop_clients(link); @@ -443,7 +463,7 @@ static Address* link_find_dhcp_server_address(Link *link) { assert(link); assert(link->network); - /* The the first statically configured address if there is any */ + /* The first statically configured address if there is any */ LIST_FOREACH(addresses, address, link->network->static_addresses) { if (address->family != AF_INET) @@ -467,66 +487,13 @@ static Address* link_find_dhcp_server_address(Link *link) { } static int link_enter_configured(Link *link) { - int r; - assert(link); assert(link->network); assert(link->state == LINK_STATE_SETTING_ROUTES); - if (link_dhcp4_server_enabled(link) && - !sd_dhcp_server_is_running(link->dhcp_server)) { - struct in_addr pool_start; - Address *address; - - address = link_find_dhcp_server_address(link); - if (!address) { - log_link_warning(link, - "Failed to find suitable address for DHCPv4 server instance."); - link_enter_failed(link); - return 0; - } - - log_link_debug(link, "offering DHCPv4 leases"); - - 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); - if (r < 0) - return r; - - /* TODO: - r = sd_dhcp_server_set_router(link->dhcp_server, - &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; - */ - - r = sd_dhcp_server_start(link->dhcp_server); - if (r < 0) { - log_link_warning(link, "could not start DHCPv4 server " - "instance: %s", strerror(-r)); - - link_enter_failed(link); - - return 0; - } - } - log_link_info(link, "link configured"); - link->state = LINK_STATE_CONFIGURED; + link_set_state(link, LINK_STATE_CONFIGURED); link_save(link); @@ -589,7 +556,7 @@ static int link_enter_set_routes(Link *link) { assert(link->network); assert(link->state == LINK_STATE_SETTING_ADDRESSES); - link->state = LINK_STATE_SETTING_ROUTES; + link_set_state(link, LINK_STATE_SETTING_ROUTES); LIST_FOREACH(routes, rt, link->network->static_routes) { r = route_configure(rt, link, &route_handler); @@ -670,7 +637,7 @@ static int link_enter_set_addresses(Link *link) { assert(link->network); assert(link->state != _LINK_STATE_INVALID); - link->state = LINK_STATE_SETTING_ADDRESSES; + link_set_state(link, LINK_STATE_SETTING_ADDRESSES); LIST_FOREACH(addresses, ad, link->network->static_addresses) { r = address_configure(ad, link, &address_handler); @@ -683,6 +650,58 @@ static int link_enter_set_addresses(Link *link) { link->link_messages ++; } + /* 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; + + address = link_find_dhcp_server_address(link); + if (!address) { + log_link_warning(link, + "Failed to find suitable address for DHCPv4 server instance."); + link_enter_failed(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); + if (r < 0) + return r; + + /* TODO: + r = sd_dhcp_server_set_router(link->dhcp_server, + &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; + */ + + r = sd_dhcp_server_start(link->dhcp_server); + if (r < 0) { + log_link_warning(link, "could not start DHCPv4 server " + "instance: %s", strerror(-r)); + + link_enter_failed(link); + + return 0; + } + + log_link_debug(link, "offering DHCPv4 leases"); + } + if (link->link_messages == 0) { link_enter_set_routes(link); } else @@ -1078,6 +1097,46 @@ static int link_up(Link *link) { } } + r = sd_rtnl_message_open_container(req, IFLA_AF_SPEC); + if (r < 0) { + log_link_error(link, "Could not open IFLA_AF_SPEC container: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_open_container(req, AF_INET6); + if (r < 0) { + log_link_error(link, "Could not open AF_INET6 container: %s", strerror(-r)); + return r; + } + + if (!link_ipv6ll_enabled(link)) { + r = sd_rtnl_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, IN6_ADDR_GEN_MODE_NONE); + if (r < 0) { + log_link_error(link, "Could not append IFLA_INET6_ADDR_GEN_MODE: %s", strerror(-r)); + return r; + } + } + + if (!in_addr_is_null(AF_INET6, &link->network->ipv6_token)) { + r = sd_rtnl_message_append_in6_addr(req, IFLA_INET6_TOKEN, &link->network->ipv6_token.in6); + if (r < 0) { + log_link_error(link, "Could not append IFLA_INET6_TOKEN: %s", strerror(-r)); + return r; + } + } + + r = sd_rtnl_message_close_container(req); + if (r < 0) { + log_link_error(link, "Could not close AF_INET6 container: %s", strerror(-r)); + return r; + } + + r = sd_rtnl_message_close_container(req); + if (r < 0) { + log_link_error(link, "Could not close IFLA_AF_SPEC container: %s", strerror(-r)); + return r; + } + r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL); if (r < 0) { @@ -1154,7 +1213,7 @@ static int link_enter_join_netdev(Link *link) { assert(link->network); assert(link->state == LINK_STATE_PENDING); - link->state = LINK_STATE_ENSLAVING; + link_set_state(link, LINK_STATE_ENSLAVING); link_save(link); @@ -1244,7 +1303,7 @@ static int link_set_ipv4_forward(Link *link) { b = link_ipv4_forward_enabled(link); - p = strappenda("/proc/sys/net/ipv4/conf/", link->ifname, "/forwarding"); + p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/forwarding"); r = write_string_file_no_create(p, one_zero(b)); if (r < 0) log_link_warning_errno(link, r, "Cannot configure IPv4 forwarding for interface %s: %m", link->ifname); @@ -1279,7 +1338,7 @@ static int link_set_ipv6_forward(Link *link) { const char *p = NULL; int r; - p = strappenda("/proc/sys/net/ipv6/conf/", link->ifname, "/forwarding"); + p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/forwarding"); r = write_string_file_no_create(p, one_zero(link_ipv6_forward_enabled(link))); if (r < 0) log_link_warning_errno(link, r, "Cannot configure IPv6 forwarding for interface: %m"); @@ -1382,8 +1441,8 @@ static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m, return r; if (link->flags & IFF_LOOPBACK) { - if (network->ipv4ll) - log_link_debug(link, "ignoring IPv4LL for loopback link"); + if (network->link_local != ADDRESS_FAMILY_NO) + log_link_debug(link, "ignoring link-local autoconfiguration for loopback link"); if (network->dhcp != ADDRESS_FAMILY_NO) log_link_debug(link, "ignoring DHCP clients for loopback link"); @@ -1493,7 +1552,10 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *use } else { r = link_get(m, ifindex, &link); if (r < 0 || !link) { - log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex); + /* when enumerating we might be out of sync, but we will + * get the address again, so just ignore it */ + if (!m->enumerating) + log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex); return 0; } } @@ -1657,6 +1719,57 @@ int link_add(Manager *m, sd_rtnl_message *message, Link **ret) { return 0; } +static int link_carrier_gained(Link *link) { + int r; + + assert(link); + + if (link->network) { + r = link_acquire_conf(link); + if (r < 0) { + link_enter_failed(link); + return r; + } + } + + return 0; +} + +static int link_carrier_lost(Link *link) { + int r; + + assert(link); + + r = link_stop_clients(link); + if (r < 0) { + link_enter_failed(link); + return r; + } + + return 0; +} + +int link_carrier_reset(Link *link) { + int r; + + assert(link); + + if (link_has_carrier(link)) { + r = link_carrier_lost(link); + if (r < 0) + return r; + + r = link_carrier_gained(link); + if (r < 0) + return r; + + log_link_info(link, "reset carrier"); + } + + return 0; +} + + int link_update(Link *link, sd_rtnl_message *m) { struct ether_addr mac; const char *ifname; @@ -1671,7 +1784,7 @@ int link_update(Link *link, sd_rtnl_message *m) { if (link->state == LINK_STATE_LINGER) { link_ref(link); log_link_info(link, "link readded"); - link->state = LINK_STATE_ENSLAVING; + link_set_state(link, LINK_STATE_ENSLAVING); } r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname); @@ -1774,32 +1887,27 @@ int link_update(Link *link, sd_rtnl_message *m) { if (carrier_gained) { log_link_info(link, "gained carrier"); - if (link->network) { - r = link_acquire_conf(link); - if (r < 0) { - link_enter_failed(link); - return r; - } - } + r = link_carrier_gained(link); + if (r < 0) + return r; } else if (carrier_lost) { log_link_info(link, "lost carrier"); - r = link_stop_clients(link); - if (r < 0) { - link_enter_failed(link); + r = link_carrier_lost(link); + if (r < 0) return r; - } + } return 0; } static void link_update_operstate(Link *link) { - + LinkOperationalState operstate; assert(link); if (link->kernel_operstate == IF_OPER_DORMANT) - link->operstate = LINK_OPERSTATE_DORMANT; + operstate = LINK_OPERSTATE_DORMANT; else if (link_has_carrier(link)) { Address *address; uint8_t scope = RT_SCOPE_NOWHERE; @@ -1815,17 +1923,22 @@ static void link_update_operstate(Link *link) { if (scope < RT_SCOPE_SITE) /* universally accessible addresses found */ - link->operstate = LINK_OPERSTATE_ROUTABLE; + operstate = LINK_OPERSTATE_ROUTABLE; else if (scope < RT_SCOPE_HOST) /* only link or site local addresses found */ - link->operstate = LINK_OPERSTATE_DEGRADED; + operstate = LINK_OPERSTATE_DEGRADED; else /* no useful addresses found */ - link->operstate = LINK_OPERSTATE_CARRIER; + operstate = LINK_OPERSTATE_CARRIER; } else if (link->flags & IFF_UP) - link->operstate = LINK_OPERSTATE_NO_CARRIER; + operstate = LINK_OPERSTATE_NO_CARRIER; else - link->operstate = LINK_OPERSTATE_OFF; + operstate = LINK_OPERSTATE_OFF; + + if (link->operstate != operstate) { + link->operstate = operstate; + link_send_changed(link, "OperationalState", NULL); + } } int link_save(Link *link) {