X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-link.c;h=1b7b1898c4e13bd4907ea2a5e353a3e94435a59e;hp=76e642758d5b14e7d532e26e17cf5651b7d0f5e7;hb=51d18171529dcdad1366e422e42d538434af0ff6;hpb=67272d157a35e5cda4e5c904eafdcc23d20541d1 diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 76e642758..1b7b1898c 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -35,6 +35,85 @@ #include "dhcp-lease-internal.h" +#define FLAG_STRING(string, flag, old, new) \ + (((old ^ new) & flag) \ + ? ((old & flag) ? (" -" string) : (" +" string)) \ + : "") + +static int link_update_flags(Link *link, sd_rtnl_message *m) { + unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags; + uint8_t operstate; + int r; + + assert(link); + + r = sd_rtnl_message_link_get_flags(m, &flags); + if (r < 0) { + log_warning_link(link, "Could not get link flags"); + return r; + } + + r = sd_rtnl_message_read_u8(m, IFLA_OPERSTATE, &operstate); + if (r < 0) + /* if we got a message without operstate, take it to mean + the state was unchanged */ + operstate = link->kernel_operstate; + + if ((link->flags == flags) && (link->kernel_operstate == operstate)) + return 0; + + if (link->flags != flags) { + log_debug_link(link, "flags change:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + FLAG_STRING("LOOPBACK", IFF_LOOPBACK, link->flags, flags), + FLAG_STRING("MASTER", IFF_MASTER, link->flags, flags), + FLAG_STRING("SLAVE", IFF_SLAVE, link->flags, flags), + FLAG_STRING("UP", IFF_UP, link->flags, flags), + FLAG_STRING("DORMANT", IFF_DORMANT, link->flags, flags), + FLAG_STRING("LOWER_UP", IFF_LOWER_UP, link->flags, flags), + FLAG_STRING("RUNNING", IFF_RUNNING, link->flags, flags), + FLAG_STRING("MULTICAST", IFF_MULTICAST, link->flags, flags), + FLAG_STRING("BROADCAST", IFF_BROADCAST, link->flags, flags), + FLAG_STRING("POINTOPOINT", IFF_POINTOPOINT, link->flags, flags), + FLAG_STRING("PROMISC", IFF_PROMISC, link->flags, flags), + FLAG_STRING("ALLMULTI", IFF_ALLMULTI, link->flags, flags), + FLAG_STRING("PORTSEL", IFF_PORTSEL, link->flags, flags), + FLAG_STRING("AUTOMEDIA", IFF_AUTOMEDIA, link->flags, flags), + FLAG_STRING("DYNAMIC", IFF_DYNAMIC, link->flags, flags), + FLAG_STRING("NOARP", IFF_NOARP, link->flags, flags), + FLAG_STRING("NOTRAILERS", IFF_NOTRAILERS, link->flags, flags), + FLAG_STRING("DEBUG", IFF_DEBUG, link->flags, flags), + FLAG_STRING("ECHO", IFF_ECHO, link->flags, flags)); + + unknown_flags = ~(IFF_LOOPBACK | IFF_MASTER | IFF_SLAVE | IFF_UP | + IFF_DORMANT | IFF_LOWER_UP | IFF_RUNNING | + IFF_MULTICAST | IFF_BROADCAST | IFF_POINTOPOINT | + IFF_PROMISC | IFF_ALLMULTI | IFF_PORTSEL | + IFF_AUTOMEDIA | IFF_DYNAMIC | IFF_NOARP | + IFF_NOTRAILERS | IFF_DEBUG | IFF_ECHO); + unknown_flags_added = ((link->flags ^ flags) & flags & unknown_flags); + unknown_flags_removed = ((link->flags ^ flags) & link->flags & unknown_flags); + + /* link flags are currently at most 18 bits, let's align to + * printing 20 */ + if (unknown_flags_added) + log_debug_link(link, + "unknown link flags gained: %#.5x (ignoring)", + unknown_flags_added); + + if (unknown_flags_removed) + log_debug_link(link, + "unknown link flags lost: %#.5x (ignoring)", + unknown_flags_removed); + } + + link->flags = flags; + link->kernel_operstate = operstate; + + link_save(link); + + return 0; +} + static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) { _cleanup_link_unref_ Link *link = NULL; uint16_t type; @@ -95,6 +174,10 @@ static int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) { if (r < 0) return r; + r = link_update_flags(link, message); + if (r < 0) + return r; + *ret = link; link = NULL; @@ -863,129 +946,20 @@ static int link_acquire_conf(Link *link) { return 0; } -bool link_has_carrier(unsigned flags, uint8_t operstate) { +bool link_has_carrier(Link *link) { /* see Documentation/networking/operstates.txt in the kernel sources */ - if (operstate == IF_OPER_UP) + if (link->kernel_operstate == IF_OPER_UP) return true; - if (operstate == IF_OPER_UNKNOWN) + if (link->kernel_operstate == IF_OPER_UNKNOWN) /* operstate may not be implemented, so fall back to flags */ - if ((flags & IFF_LOWER_UP) && !(flags & IFF_DORMANT)) + if ((link->flags & IFF_LOWER_UP) && !(link->flags & IFF_DORMANT)) return true; return false; } -#define FLAG_STRING(string, flag, old, new) \ - (((old ^ new) & flag) \ - ? ((old & flag) ? (" -" string) : (" +" string)) \ - : "") - -static int link_update_flags(Link *link, sd_rtnl_message *m) { - unsigned flags, unknown_flags_added, unknown_flags_removed, unknown_flags; - uint8_t operstate; - bool carrier_gained = false, carrier_lost = false; - int r; - - assert(link); - - r = sd_rtnl_message_link_get_flags(m, &flags); - if (r < 0) { - log_warning_link(link, "Could not get link flags"); - return r; - } - - r = sd_rtnl_message_read_u8(m, IFLA_OPERSTATE, &operstate); - if (r < 0) - /* if we got a message without operstate, take it to mean - the state was unchanged */ - operstate = link->kernel_operstate; - - if ((link->flags == flags) && (link->kernel_operstate == operstate)) - return 0; - - if (link->flags != flags) { - log_debug_link(link, "flags change:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", - FLAG_STRING("LOOPBACK", IFF_LOOPBACK, link->flags, flags), - FLAG_STRING("MASTER", IFF_MASTER, link->flags, flags), - FLAG_STRING("SLAVE", IFF_SLAVE, link->flags, flags), - FLAG_STRING("UP", IFF_UP, link->flags, flags), - FLAG_STRING("DORMANT", IFF_DORMANT, link->flags, flags), - FLAG_STRING("LOWER_UP", IFF_LOWER_UP, link->flags, flags), - FLAG_STRING("RUNNING", IFF_RUNNING, link->flags, flags), - FLAG_STRING("MULTICAST", IFF_MULTICAST, link->flags, flags), - FLAG_STRING("BROADCAST", IFF_BROADCAST, link->flags, flags), - FLAG_STRING("POINTOPOINT", IFF_POINTOPOINT, link->flags, flags), - FLAG_STRING("PROMISC", IFF_PROMISC, link->flags, flags), - FLAG_STRING("ALLMULTI", IFF_ALLMULTI, link->flags, flags), - FLAG_STRING("PORTSEL", IFF_PORTSEL, link->flags, flags), - FLAG_STRING("AUTOMEDIA", IFF_AUTOMEDIA, link->flags, flags), - FLAG_STRING("DYNAMIC", IFF_DYNAMIC, link->flags, flags), - FLAG_STRING("NOARP", IFF_NOARP, link->flags, flags), - FLAG_STRING("NOTRAILERS", IFF_NOTRAILERS, link->flags, flags), - FLAG_STRING("DEBUG", IFF_DEBUG, link->flags, flags), - FLAG_STRING("ECHO", IFF_ECHO, link->flags, flags)); - - unknown_flags = ~(IFF_LOOPBACK | IFF_MASTER | IFF_SLAVE | IFF_UP | - IFF_DORMANT | IFF_LOWER_UP | IFF_RUNNING | - IFF_MULTICAST | IFF_BROADCAST | IFF_POINTOPOINT | - IFF_PROMISC | IFF_ALLMULTI | IFF_PORTSEL | - IFF_AUTOMEDIA | IFF_DYNAMIC | IFF_NOARP | - IFF_NOTRAILERS | IFF_DEBUG | IFF_ECHO); - unknown_flags_added = ((link->flags ^ flags) & flags & unknown_flags); - unknown_flags_removed = ((link->flags ^ flags) & link->flags & unknown_flags); - - /* link flags are currently at most 18 bits, let's align to - * printing 20 */ - if (unknown_flags_added) - log_debug_link(link, - "unknown link flags gained: %#.5x (ignoring)", - unknown_flags_added); - - if (unknown_flags_removed) - log_debug_link(link, - "unknown link flags lost: %#.5x (ignoring)", - unknown_flags_removed); - } - - carrier_gained = !link_has_carrier(link->flags, link->kernel_operstate) && - link_has_carrier(flags, operstate); - carrier_lost = link_has_carrier(link->flags, link->kernel_operstate) && - !link_has_carrier(flags, operstate); - - link->flags = flags; - link->kernel_operstate = operstate; - - link_save(link); - - if (link->state == LINK_STATE_FAILED || - link->state == LINK_STATE_UNMANAGED) - return 0; - - if (carrier_gained) { - log_info_link(link, "gained carrier"); - - if (link->network) { - r = link_acquire_conf(link); - if (r < 0) { - link_enter_failed(link); - return r; - } - } - } else if (carrier_lost) { - log_info_link(link, "lost carrier"); - - r = link_stop_clients(link); - if (r < 0) { - link_enter_failed(link); - return r; - } - } - - return 0; -} - static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -1052,7 +1026,6 @@ static int link_joined(Link *link) { int r; assert(link); - assert(link->state == LINK_STATE_ENSLAVING); assert(link->network); if (!(link->flags & IFF_UP)) { @@ -1072,8 +1045,6 @@ static int netdev_join_handler(sd_rtnl *rtnl, sd_rtnl_message *m, int r; assert(link); - assert(IN_SET(link->state, LINK_STATE_ENSLAVING, LINK_STATE_FAILED, - LINK_STATE_LINGER)); assert(link->network); link->enslaving --; @@ -1247,7 +1218,7 @@ static int link_configure(Link *link) { return r; } - if (link_has_carrier(link->flags, link->kernel_operstate)) { + if (link_has_carrier(link)) { r = link_acquire_conf(link); if (r < 0) return r; @@ -1389,6 +1360,13 @@ int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, return 0; } + r = sd_rtnl_message_addr_get_flags(message, &address->flags); + if (r < 0) { + log_warning_link(link, + "rtnl: received address with invalid flags, ignoring"); + return 0; + } + switch (address->family) { case AF_INET: r = sd_rtnl_message_read_in_addr(message, IFA_LOCAL, @@ -1550,6 +1528,7 @@ int link_update(Link *link, sd_rtnl_message *m) { struct ether_addr mac; const char *ifname; uint32_t mtu; + bool had_carrier, carrier_gained, carrier_lost; int r; assert(link); @@ -1646,7 +1625,36 @@ int link_update(Link *link, sd_rtnl_message *m) { } } - return link_update_flags(link, m); + had_carrier = link_has_carrier(link); + + r = link_update_flags(link, m); + if (r < 0) + return r; + + carrier_gained = !had_carrier && link_has_carrier(link); + carrier_lost = had_carrier && !link_has_carrier(link); + + if (carrier_gained) { + log_info_link(link, "gained carrier"); + + if (link->network) { + r = link_acquire_conf(link); + if (r < 0) { + link_enter_failed(link); + return r; + } + } + } else if (carrier_lost) { + log_info_link(link, "lost carrier"); + + r = link_stop_clients(link); + if (r < 0) { + link_enter_failed(link); + return r; + } + } + + return 0; } static void link_update_operstate(Link *link) { @@ -1655,12 +1663,15 @@ static void link_update_operstate(Link *link) { if (link->kernel_operstate == IF_OPER_DORMANT) link->operstate = LINK_OPERSTATE_DORMANT; - else if (link_has_carrier(link->flags, link->kernel_operstate)) { + else if (link_has_carrier(link)) { Address *address; uint8_t scope = RT_SCOPE_NOWHERE; /* if we have carrier, check what addresses we have */ LIST_FOREACH(addresses, address, link->addresses) { + if (address->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED)) + continue; + if (address->scope < scope) scope = address->scope; } @@ -1721,10 +1732,17 @@ int link_save(Link *link) { admin_state, oper_state); if (link->network) { - char **address; - char **domain; + char **address, **domain; + bool space; fputs("DNS=", f); + space = false; + STRV_FOREACH(address, link->network->dns) { + if (space) + fputc(' ', f); + fputs(*address, f); + space = true; + } if (link->network->dhcp_dns && link->dhcp_lease) { @@ -1732,19 +1750,22 @@ int link_save(Link *link) { r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses); if (r > 0) { + if (space) + fputc(' ', f); serialize_in_addrs(f, addresses, r); - if (link->network->dns) - fputs(" ", f); } } - STRV_FOREACH(address, link->network->dns) - fprintf(f, "%s%s", *address, - (address + 1 ? " " : "")); - fputs("\n", f); fprintf(f, "NTP="); + space = false; + STRV_FOREACH(address, link->network->ntp) { + if (space) + fputc(' ', f); + fputs(*address, f); + space = true; + } if (link->network->dhcp_ntp && link->dhcp_lease) { @@ -1752,19 +1773,22 @@ int link_save(Link *link) { r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses); if (r > 0) { + if (space) + fputc(' ', f); serialize_in_addrs(f, addresses, r); - if (link->network->ntp) - fputs(" ", f); } } - STRV_FOREACH(address, link->network->ntp) - fprintf(f, "%s%s", *address, - (address + 1 ? " " : "")); - fputs("\n", f); fprintf(f, "DOMAINS="); + space = false; + STRV_FOREACH(domain, link->network->domains) { + if (space) + fputc(' ', f); + fputs(*domain, f); + space = true; + } if (link->network->dhcp_domains && link->dhcp_lease) { @@ -1772,16 +1796,12 @@ int link_save(Link *link) { r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname); if (r >= 0) { + if (space) + fputc(' ', f); fputs(domainname, f); - if (link->network->domains) - fputs(" ", f); } } - STRV_FOREACH(domain, link->network->domains) - fprintf(f, "%s%s", *domain, - (domain + 1 ? " " : "")); - fputs("\n", f); fprintf(f, "WILDCARD_DOMAIN=%s\n",