struct in_addr gateway;
r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
- if (r < 0) {
- log_warning_link(link, "DHCP error: no router: %s",
- strerror(-r));
+ if (r < 0 && r != -ENOENT) {
+ log_warning_link(link, "DHCP error: %s", strerror(-r));
return r;
}
- r = route_new_dynamic(&route);
- if (r < 0) {
- log_error_link(link, "Could not allocate route: %s",
- strerror(-r));
- return r;
- }
+ if (r >= 0) {
+ r = route_new_dynamic(&route);
+ if (r < 0) {
+ log_error_link(link, "Could not allocate route: %s",
+ strerror(-r));
+ return r;
+ }
- r = route_new_dynamic(&route_gw);
- if (r < 0) {
- log_error_link(link, "Could not allocate route: %s",
- strerror(-r));
- return r;
- }
+ r = route_new_dynamic(&route_gw);
+ if (r < 0) {
+ log_error_link(link, "Could not allocate route: %s",
+ strerror(-r));
+ return r;
+ }
+
+ /* The dhcp netmask may mask out the gateway. Add an explicit
+ * route for the gw host so that we can route no matter the
+ * netmask or existing kernel route tables. */
+ route_gw->family = AF_INET;
+ route_gw->dst_addr.in = gateway;
+ route_gw->dst_prefixlen = 32;
+ route_gw->scope = RT_SCOPE_LINK;
- /* The dhcp netmask may mask out the gateway. Add an explicit
- * route for the gw host so that we can route no matter the
- * netmask or existing kernel route tables. */
- route_gw->family = AF_INET;
- route_gw->dst_addr.in = gateway;
- route_gw->dst_prefixlen = 32;
- route_gw->scope = RT_SCOPE_LINK;
+ r = route_configure(route_gw, link, &route_handler);
+ if (r < 0) {
+ log_warning_link(link,
+ "could not set host route: %s", strerror(-r));
+ return r;
+ }
- r = route_configure(route_gw, link, &route_handler);
- if (r < 0) {
- log_warning_link(link,
- "could not set host route: %s", strerror(-r));
- return r;
- }
+ link->route_messages ++;
- link->route_messages ++;
+ route->family = AF_INET;
+ route->in_addr.in = gateway;
- route->family = AF_INET;
- route->in_addr.in = gateway;
+ r = route_configure(route, link, &route_handler);
+ if (r < 0) {
+ log_warning_link(link,
+ "could not set routes: %s", strerror(-r));
+ link_enter_failed(link);
+ return r;
+ }
- r = route_configure(route, link, &route_handler);
- if (r < 0) {
- log_warning_link(link,
- "could not set routes: %s", strerror(-r));
- link_enter_failed(link);
- return r;
+ link->route_messages ++;
}
+ }
- link->route_messages ++;
+ if (link->route_messages == 0) {
+ link_enter_configured(link);
}
return 0;
r = address_new_dynamic(&address);
if (r >= 0) {
- sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
- sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
- sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
- prefixlen = net_netmask_to_prefixlen(&netmask);
-
- r = route_new_dynamic(&route_gw);
+ r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
if (r >= 0) {
- route_gw->family = AF_INET;
- route_gw->dst_addr.in = gateway;
- route_gw->dst_prefixlen = 32;
- route_gw->scope = RT_SCOPE_LINK;
+ r = route_new_dynamic(&route_gw);
+ if (r >= 0) {
+ route_gw->family = AF_INET;
+ route_gw->dst_addr.in = gateway;
+ route_gw->dst_prefixlen = 32;
+ route_gw->scope = RT_SCOPE_LINK;
- route_drop(route_gw, link, &route_drop_handler);
- }
+ route_drop(route_gw, link, &route_drop_handler);
+ }
- r = route_new_dynamic(&route);
- if (r >= 0) {
- route->family = AF_INET;
- route->in_addr.in = gateway;
+ r = route_new_dynamic(&route);
+ if (r >= 0) {
+ route->family = AF_INET;
+ route->in_addr.in = gateway;
- route_drop(route, link, &route_drop_handler);
+ route_drop(route, link, &route_drop_handler);
+ }
}
+ sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
+ sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
+ prefixlen = net_netmask_to_prefixlen(&netmask);
+
address->family = AF_INET;
address->in_addr.in = addr;
address->prefixlen = prefixlen;
prefixlen = net_netmask_to_prefixlen(&netmask);
r = sd_dhcp_lease_get_router(lease, &gateway);
- if (r < 0) {
- log_warning_link(link, "DHCP error: no router: %s",
- strerror(-r));
+ if (r < 0 && r != -ENOENT) {
+ log_warning_link(link, "DHCP error: %s", strerror(-r));
return r;
}
- log_struct_link(LOG_INFO, link,
- "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
- link->ifname,
- ADDRESS_FMT_VAL(address),
- prefixlen,
- ADDRESS_FMT_VAL(gateway),
- "ADDRESS=%u.%u.%u.%u",
- ADDRESS_FMT_VAL(address),
- "PREFIXLEN=%u",
- prefixlen,
- "GATEWAY=%u.%u.%u.%u",
- ADDRESS_FMT_VAL(gateway),
- NULL);
+ if (r >= 0)
+ log_struct_link(LOG_INFO, link,
+ "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
+ link->ifname,
+ ADDRESS_FMT_VAL(address),
+ prefixlen,
+ ADDRESS_FMT_VAL(gateway),
+ "ADDRESS=%u.%u.%u.%u",
+ ADDRESS_FMT_VAL(address),
+ "PREFIXLEN=%u",
+ prefixlen,
+ "GATEWAY=%u.%u.%u.%u",
+ ADDRESS_FMT_VAL(gateway),
+ NULL);
+ else
+ log_struct_link(LOG_INFO, link,
+ "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u",
+ link->ifname,
+ ADDRESS_FMT_VAL(address),
+ prefixlen,
+ "ADDRESS=%u.%u.%u.%u",
+ ADDRESS_FMT_VAL(address),
+ "PREFIXLEN=%u",
+ prefixlen,
+ NULL);
link->dhcp_lease = lease;
return 0;
}
+static bool link_has_carrier(unsigned flags, uint8_t operstate) {
+ /* see Documentation/networking/operstates.txt in the kernel sources */
+
+ if (operstate == IF_OPER_UP)
+ return true;
+
+ if (operstate == IF_OPER_UNKNOWN)
+ /* operstate may not be implemented, so fall back to flags */
+ if ((flags & IFF_LOWER_UP) && !(flags & IFF_DORMANT))
+ return true;
+
+ return false;
+}
+
static int link_update_flags(Link *link, sd_rtnl_message *m) {
unsigned flags, flags_added, flags_removed, generic_flags;
uint8_t operstate;
assert(link);
- if (link->state == LINK_STATE_FAILED)
- return 0;
-
r = sd_rtnl_message_link_get_flags(m, &flags);
if (r < 0) {
log_warning_link(link, "Could not get link flags");
link->flags = flags;
link->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");
r = sd_rtnl_message_get_errno(m);
if (r < 0) {
+ /* we warn but don't fail the link, as it may
+ be brought up later */
log_struct_link(LOG_WARNING, link,
"MESSAGE=%s: could not bring up interface: %s",
link->ifname, strerror(-r),
"ERRNO=%d", -r,
NULL);
- link_enter_failed(link);
}
return 1;
}
}
- if (link_has_carrier(link->flags, link->operstate))
- {
+ if (link_has_carrier(link->flags, link->operstate)) {
r = link_acquire_conf(link);
if (r < 0)
return r;
assert(link->ifname);
assert(m);
- if (link->state == LINK_STATE_FAILED || link->state == LINK_STATE_UNMANAGED)
- return 0;
-
r = sd_rtnl_message_read_string(m, IFLA_IFNAME, &ifname);
if (r >= 0 && !streq(ifname, link->ifname)) {
log_info_link(link, "renamed to %s", ifname);
}
int link_save(Link *link) {
- _cleanup_free_ char *temp_path = NULL;
+ _cleanup_free_ char *temp_path = NULL, *lease_file = NULL;
_cleanup_fclose_ FILE *f = NULL;
- const char *state;
+ const char *admin_state, *oper_state = "unknown";
int r;
assert(link);
assert(link->state_file);
- state = link_state_to_string(link->state);
- assert(state);
+ admin_state = link_state_to_string(link->state);
+ assert(admin_state);
+
+ if (link->operstate & IF_OPER_DORMANT)
+ oper_state = "dormant";
+ else if (link_has_carrier(link->flags, link->operstate))
+ oper_state = "carrier";
+
+ r = asprintf(&lease_file, "/run/systemd/network/leases/%"PRIu64,
+ link->ifindex);
+ if (r < 0)
+ return -ENOMEM;
r = fopen_temporary(link->state_file, &f, &temp_path);
if (r < 0)
fprintf(f,
"# This is private data. Do not parse.\n"
- "STATE=%s\n", state);
+ "ADMIN_STATE=%s\n"
+ "OPER_STATE=%s\n"
+ "FLAGS=%u\n",
+ admin_state, oper_state, link->flags);
if (link->dhcp_lease) {
- _cleanup_free_ char *lease_file = NULL;
-
- r = asprintf(&lease_file, "/run/systemd/network/leases/%"PRIu64,
- link->ifindex);
- if (r < 0)
- return -ENOMEM;
-
r = dhcp_lease_save(link->dhcp_lease, lease_file);
if (r < 0)
goto finish;
fprintf(f, "DHCP_LEASE=%s\n", lease_file);
- }
+ } else
+ unlink(lease_file);
fflush(f);
}
static const char* const link_state_table[_LINK_STATE_MAX] = {
- [LINK_STATE_INITIALIZING] = "configuring",
+ [LINK_STATE_INITIALIZING] = "initializing",
[LINK_STATE_ENSLAVING] = "configuring",
[LINK_STATE_SETTING_ADDRESSES] = "configuring",
[LINK_STATE_SETTING_ROUTES] = "configuring",