1
0
mirror of https://github.com/systemd/systemd synced 2026-03-16 18:14:46 +01:00

Compare commits

..

No commits in common. "2a5a844259bc0fc3230c7cd85c47ac89ef1c223a" and "986cdba9f8a38178611b006341951d5a017d69c9" have entirely different histories.

3 changed files with 254 additions and 198 deletions

View File

@ -158,20 +158,18 @@ assert_cc((ELEMENTSOF(ethtool_link_mode_bit_table)-1) / 32 < N_ADVERTISE);
DEFINE_STRING_TABLE_LOOKUP(ethtool_link_mode_bit, enum ethtool_link_mode_bit_indices); DEFINE_STRING_TABLE_LOOKUP(ethtool_link_mode_bit, enum ethtool_link_mode_bit_indices);
static int ethtool_connect(int *ethtool_fd) { static int ethtool_connect_or_warn(int *ret, bool warn) {
int fd; int fd;
assert(ethtool_fd); assert_return(ret, -EINVAL);
/* This does nothing if already connected. */
if (*ethtool_fd >= 0)
return 0;
fd = socket_ioctl_fd(); fd = socket_ioctl_fd();
if (fd < 0) if (fd < 0)
return log_debug_errno(fd, "ethtool: could not create control socket: %m"); return log_full_errno(warn ? LOG_WARNING: LOG_DEBUG, fd,
"ethtool: could not create control socket: %m");
*ret = fd;
*ethtool_fd = fd;
return 0; return 0;
} }
@ -189,9 +187,11 @@ int ethtool_get_driver(int *ethtool_fd, const char *ifname, char **ret) {
assert(ifname); assert(ifname);
assert(ret); assert(ret);
r = ethtool_connect(ethtool_fd); if (*ethtool_fd < 0) {
r = ethtool_connect_or_warn(ethtool_fd, true);
if (r < 0) if (r < 0)
return r; return r;
}
strscpy(ifr.ifr_name, IFNAMSIZ, ifname); strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
@ -229,9 +229,11 @@ int ethtool_get_link_info(
assert(ethtool_fd); assert(ethtool_fd);
assert(ifname); assert(ifname);
r = ethtool_connect(ethtool_fd); if (*ethtool_fd < 0) {
r = ethtool_connect_or_warn(ethtool_fd, false);
if (r < 0) if (r < 0)
return r; return r;
}
strscpy(ifr.ifr_name, IFNAMSIZ, ifname); strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
@ -278,9 +280,12 @@ int ethtool_get_permanent_macaddr(int *ethtool_fd, const char *ifname, struct et
if (!ethtool_fd) if (!ethtool_fd)
ethtool_fd = &fd; ethtool_fd = &fd;
r = ethtool_connect(ethtool_fd);
if (*ethtool_fd < 0) {
r = ethtool_connect_or_warn(ethtool_fd, false);
if (r < 0) if (r < 0)
return r; return r;
}
strscpy(ifr.ifr_name, IFNAMSIZ, ifname); strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
@ -302,13 +307,66 @@ int ethtool_get_permanent_macaddr(int *ethtool_fd, const char *ifname, struct et
return 0; return 0;
} }
#define UPDATE(dest, val, updated) \ int ethtool_set_speed(int *ethtool_fd, const char *ifname, unsigned speed, Duplex duplex) {
do { \ struct ethtool_cmd ecmd = {
typeof(val) _v = (val); \ .cmd = ETHTOOL_GSET,
if (dest != _v) \ };
updated = true; \ struct ifreq ifr = {
dest = _v; \ .ifr_data = (void*) &ecmd,
} while(false) };
bool need_update = false;
int r;
assert(ethtool_fd);
assert(ifname);
if (speed == 0 && duplex == _DUP_INVALID)
return 0;
if (*ethtool_fd < 0) {
r = ethtool_connect_or_warn(ethtool_fd, true);
if (r < 0)
return r;
}
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr);
if (r < 0)
return -errno;
if (ethtool_cmd_speed(&ecmd) != speed) {
ethtool_cmd_speed_set(&ecmd, speed);
need_update = true;
}
switch (duplex) {
case DUP_HALF:
if (ecmd.duplex != DUPLEX_HALF) {
ecmd.duplex = DUPLEX_HALF;
need_update = true;
}
break;
case DUP_FULL:
if (ecmd.duplex != DUPLEX_FULL) {
ecmd.duplex = DUPLEX_FULL;
need_update = true;
}
break;
default:
break;
}
if (need_update) {
ecmd.cmd = ETHTOOL_SSET;
r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr);
if (r < 0)
return -errno;
}
return 0;
}
int ethtool_set_wol(int *ethtool_fd, const char *ifname, WakeOnLan wol) { int ethtool_set_wol(int *ethtool_fd, const char *ifname, WakeOnLan wol) {
struct ethtool_wolinfo ecmd = { struct ethtool_wolinfo ecmd = {
@ -326,9 +384,11 @@ int ethtool_set_wol(int *ethtool_fd, const char *ifname, WakeOnLan wol) {
if (wol == _WOL_INVALID) if (wol == _WOL_INVALID)
return 0; return 0;
r = ethtool_connect(ethtool_fd); if (*ethtool_fd < 0) {
r = ethtool_connect_or_warn(ethtool_fd, true);
if (r < 0) if (r < 0)
return r; return r;
}
strscpy(ifr.ifr_name, IFNAMSIZ, ifname); strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
@ -414,15 +474,11 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netde
assert(ifname); assert(ifname);
assert(ring); assert(ring);
if (!ring->rx_pending_set && if (*ethtool_fd < 0) {
!ring->rx_mini_pending_set && r = ethtool_connect_or_warn(ethtool_fd, true);
!ring->rx_jumbo_pending_set &&
!ring->tx_pending_set)
return 0;
r = ethtool_connect(ethtool_fd);
if (r < 0) if (r < 0)
return r; return r;
}
strscpy(ifr.ifr_name, IFNAMSIZ, ifname); strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
@ -430,25 +486,33 @@ int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netde
if (r < 0) if (r < 0)
return -errno; return -errno;
if (ring->rx_pending_set) if (ring->rx_pending_set && ecmd.rx_pending != ring->rx_pending) {
UPDATE(ecmd.rx_pending, ring->rx_pending, need_update); ecmd.rx_pending = ring->rx_pending;
need_update = true;
}
if (ring->rx_mini_pending_set) if (ring->rx_mini_pending_set && ecmd.rx_mini_pending != ring->rx_mini_pending) {
UPDATE(ecmd.rx_mini_pending, ring->rx_mini_pending, need_update); ecmd.rx_mini_pending = ring->rx_mini_pending;
need_update = true;
}
if (ring->rx_jumbo_pending_set) if (ring->rx_jumbo_pending_set && ecmd.rx_jumbo_pending != ring->rx_jumbo_pending) {
UPDATE(ecmd.rx_jumbo_pending, ring->rx_jumbo_pending, need_update); ecmd.rx_jumbo_pending = ring->rx_jumbo_pending;
need_update = true;
}
if (ring->tx_pending_set) if (ring->tx_pending_set && ecmd.tx_pending != ring->tx_pending) {
UPDATE(ecmd.tx_pending, ring->tx_pending, need_update); ecmd.tx_pending = ring->tx_pending;
need_update = true;
if (!need_update) }
return 0;
if (need_update) {
ecmd.cmd = ETHTOOL_SRINGPARAM; ecmd.cmd = ETHTOOL_SRINGPARAM;
r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr);
if (r < 0) if (r < 0)
return -errno; return -errno;
}
return 0; return 0;
} }
@ -543,15 +607,17 @@ int ethtool_set_features(int *ethtool_fd, const char *ifname, const int *feature
assert(ifname); assert(ifname);
assert(features); assert(features);
r = ethtool_connect(ethtool_fd); if (*ethtool_fd < 0) {
r = ethtool_connect_or_warn(ethtool_fd, true);
if (r < 0) if (r < 0)
return r; return r;
}
strscpy(ifr.ifr_name, IFNAMSIZ, ifname); strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
r = get_stringset(*ethtool_fd, &ifr, ETH_SS_FEATURES, &strings); r = get_stringset(*ethtool_fd, &ifr, ETH_SS_FEATURES, &strings);
if (r < 0) if (r < 0)
return log_debug_errno(r, "ethtool: could not get ethtool features for %s", ifname); return log_warning_errno(r, "ethtool: could not get ethtool features for %s", ifname);
sfeatures = alloca0(sizeof(struct ethtool_sfeatures) + DIV_ROUND_UP(strings->len, 32U) * sizeof(sfeatures->features[0])); sfeatures = alloca0(sizeof(struct ethtool_sfeatures) + DIV_ROUND_UP(strings->len, 32U) * sizeof(sfeatures->features[0]));
sfeatures->cmd = ETHTOOL_SFEATURES; sfeatures->cmd = ETHTOOL_SFEATURES;
@ -561,7 +627,7 @@ int ethtool_set_features(int *ethtool_fd, const char *ifname, const int *feature
if (features[i] != -1) { if (features[i] != -1) {
r = set_features_bit(strings, netdev_feature_table[i], features[i], sfeatures); r = set_features_bit(strings, netdev_feature_table[i], features[i], sfeatures);
if (r < 0) { if (r < 0) {
log_debug_errno(r, "ethtool: could not find feature, ignoring: %s", netdev_feature_table[i]); log_warning_errno(r, "ethtool: could not find feature, ignoring: %s", netdev_feature_table[i]);
continue; continue;
} }
} }
@ -570,7 +636,7 @@ int ethtool_set_features(int *ethtool_fd, const char *ifname, const int *feature
r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr); r = ioctl(*ethtool_fd, SIOCETHTOOL, &ifr);
if (r < 0) if (r < 0)
return log_debug_errno(r, "ethtool: could not set ethtool features for %s", ifname); return log_warning_errno(r, "ethtool: could not set ethtool features for %s", ifname);
return 0; return 0;
} }
@ -752,6 +818,12 @@ static int set_sset(int fd, struct ifreq *ifr, const struct ethtool_link_usettin
return 0; return 0;
} }
/* If autonegotiation is disabled, the speed and duplex represent the fixed link
* mode and are writable if the driver supports multiple link modes. If it is
* enabled then they are read-only. If the link is up they represent the negotiated
* link mode; if the link is down, the speed is 0, %SPEED_UNKNOWN or the highest
* enabled speed and @duplex is %DUPLEX_UNKNOWN or the best enabled duplex mode.
*/
int ethtool_set_glinksettings( int ethtool_set_glinksettings(
int *fd, int *fd,
const char *ifname, const char *ifname,
@ -763,38 +835,22 @@ int ethtool_set_glinksettings(
_cleanup_free_ struct ethtool_link_usettings *u = NULL; _cleanup_free_ struct ethtool_link_usettings *u = NULL;
struct ifreq ifr = {}; struct ifreq ifr = {};
bool changed = false;
int r; int r;
assert(fd); assert(fd);
assert(ifname); assert(ifname);
assert(advertise); assert(advertise);
if (autonegotiation < 0 && memeqzero(advertise, sizeof(uint32_t) * N_ADVERTISE) && if (autonegotiation != AUTONEG_DISABLE && memeqzero(advertise, sizeof(uint32_t) * N_ADVERTISE)) {
speed == 0 && duplex < 0 && port < 0) log_info("ethtool: autonegotiation is unset or enabled, the speed and duplex are not writable.");
return 0; return 0;
/* If autonegotiation is disabled, the speed and duplex represent the fixed link mode and are
* writable if the driver supports multiple link modes. If it is enabled then they are
* read-only. If the link is up they represent the negotiated link mode; if the link is down,
* the speed is 0, %SPEED_UNKNOWN or the highest enabled speed and @duplex is %DUPLEX_UNKNOWN
* or the best enabled duplex mode. */
if (speed > 0 || duplex >= 0 || port >= 0) {
if (autonegotiation == AUTONEG_ENABLE || !memeqzero(advertise, sizeof(uint32_t) * N_ADVERTISE)) {
log_debug("ethtool: autonegotiation is enabled, ignoring speed, duplex, or port settings.");
speed = 0;
duplex = _DUP_INVALID;
port = _NET_DEV_PORT_INVALID;
} else {
log_debug("ethtool: setting speed, duplex, or port, disabling autonegotiation.");
autonegotiation = AUTONEG_DISABLE;
}
} }
r = ethtool_connect(fd); if (*fd < 0) {
r = ethtool_connect_or_warn(fd, true);
if (r < 0) if (r < 0)
return r; return r;
}
strscpy(ifr.ifr_name, IFNAMSIZ, ifname); strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
@ -802,42 +858,34 @@ int ethtool_set_glinksettings(
if (r < 0) { if (r < 0) {
r = get_gset(*fd, &ifr, &u); r = get_gset(*fd, &ifr, &u);
if (r < 0) if (r < 0)
return log_debug_errno(r, "ethtool: Cannot get device settings for %s : %m", ifname); return log_warning_errno(r, "ethtool: Cannot get device settings for %s : %m", ifname);
} }
if (speed > 0) if (speed > 0)
UPDATE(u->base.speed, DIV_ROUND_UP(speed, 1000000), changed); u->base.speed = DIV_ROUND_UP(speed, 1000000);
if (duplex >= 0) if (duplex != _DUP_INVALID)
UPDATE(u->base.duplex, duplex, changed); u->base.duplex = duplex;
if (port >= 0) if (port != _NET_DEV_PORT_INVALID)
UPDATE(u->base.port, port, changed); u->base.port = port;
if (autonegotiation >= 0) if (autonegotiation >= 0)
UPDATE(u->base.autoneg, autonegotiation, changed); u->base.autoneg = autonegotiation;
if (!memeqzero(advertise, sizeof(uint32_t) * N_ADVERTISE)) { if (!memeqzero(advertise, sizeof(uint32_t) * N_ADVERTISE)) {
UPDATE(u->base.autoneg, AUTONEG_ENABLE, changed); u->base.autoneg = AUTONEG_ENABLE;
changed = changed ||
memcmp(&u->link_modes.advertising, advertise, sizeof(uint32_t) * N_ADVERTISE) != 0 ||
!memeqzero((uint8_t*) &u->link_modes.advertising + sizeof(uint32_t) * N_ADVERTISE,
ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES - sizeof(uint32_t) * N_ADVERTISE);
memcpy(&u->link_modes.advertising, advertise, sizeof(uint32_t) * N_ADVERTISE); memcpy(&u->link_modes.advertising, advertise, sizeof(uint32_t) * N_ADVERTISE);
memzero((uint8_t*) &u->link_modes.advertising + sizeof(uint32_t) * N_ADVERTISE, memzero((uint8_t*) &u->link_modes.advertising + sizeof(uint32_t) * N_ADVERTISE,
ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES - sizeof(uint32_t) * N_ADVERTISE); ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES - sizeof(uint32_t) * N_ADVERTISE);
} }
if (!changed)
return 0;
if (u->base.cmd == ETHTOOL_GLINKSETTINGS) if (u->base.cmd == ETHTOOL_GLINKSETTINGS)
r = set_slinksettings(*fd, &ifr, u); r = set_slinksettings(*fd, &ifr, u);
else else
r = set_sset(*fd, &ifr, u); r = set_sset(*fd, &ifr, u);
if (r < 0) if (r < 0)
return log_debug_errno(r, "ethtool: Cannot set device settings for %s: %m", ifname); return log_warning_errno(r, "ethtool: Cannot set device settings for %s: %m", ifname);
return r; return r;
} }
@ -856,15 +904,11 @@ int ethtool_set_channels(int *fd, const char *ifname, const netdev_channels *cha
assert(ifname); assert(ifname);
assert(channels); assert(channels);
if (!channels->rx_count_set && if (*fd < 0) {
!channels->tx_count_set && r = ethtool_connect_or_warn(fd, true);
!channels->other_count_set &&
!channels->combined_count_set)
return 0;
r = ethtool_connect(fd);
if (r < 0) if (r < 0)
return r; return r;
}
strscpy(ifr.ifr_name, IFNAMSIZ, ifname); strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
@ -872,25 +916,33 @@ int ethtool_set_channels(int *fd, const char *ifname, const netdev_channels *cha
if (r < 0) if (r < 0)
return -errno; return -errno;
if (channels->rx_count_set) if (channels->rx_count_set && ecmd.rx_count != channels->rx_count) {
UPDATE(ecmd.rx_count, channels->rx_count, need_update); ecmd.rx_count = channels->rx_count;
need_update = true;
}
if (channels->tx_count_set) if (channels->tx_count_set && ecmd.tx_count != channels->tx_count) {
UPDATE(ecmd.tx_count, channels->tx_count, need_update); ecmd.tx_count = channels->tx_count;
need_update = true;
}
if (channels->other_count_set) if (channels->other_count_set && ecmd.other_count != channels->other_count) {
UPDATE(ecmd.other_count, channels->other_count, need_update); ecmd.other_count = channels->other_count;
need_update = true;
}
if (channels->combined_count_set) if (channels->combined_count_set && ecmd.combined_count != channels->combined_count) {
UPDATE(ecmd.combined_count, channels->combined_count, need_update); ecmd.combined_count = channels->combined_count;
need_update = true;
if (!need_update) }
return 0;
if (need_update) {
ecmd.cmd = ETHTOOL_SCHANNELS; ecmd.cmd = ETHTOOL_SCHANNELS;
r = ioctl(*fd, SIOCETHTOOL, &ifr); r = ioctl(*fd, SIOCETHTOOL, &ifr);
if (r < 0) if (r < 0)
return -errno; return -errno;
}
return 0; return 0;
} }
@ -908,12 +960,11 @@ int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int au
assert(fd); assert(fd);
assert(ifname); assert(ifname);
if (rx < 0 && tx < 0 && autoneg < 0) if (*fd < 0) {
return 0; r = ethtool_connect_or_warn(fd, true);
r = ethtool_connect(fd);
if (r < 0) if (r < 0)
return r; return r;
}
strscpy(ifr.ifr_name, IFNAMSIZ, ifname); strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
@ -921,28 +972,33 @@ int ethtool_set_flow_control(int *fd, const char *ifname, int rx, int tx, int au
if (r < 0) if (r < 0)
return -errno; return -errno;
if (rx >= 0) if (rx >= 0 && ecmd.rx_pause != (uint32_t) rx) {
UPDATE(ecmd.rx_pause, (uint32_t) rx, need_update); ecmd.rx_pause = rx;
need_update = true;
}
if (tx >= 0) if (tx >= 0 && ecmd.tx_pause != (uint32_t) tx) {
UPDATE(ecmd.tx_pause, (uint32_t) tx, need_update); ecmd.tx_pause = tx;
need_update = true;
}
if (autoneg >= 0) if (autoneg >= 0 && ecmd.autoneg != (uint32_t) autoneg) {
UPDATE(ecmd.autoneg, (uint32_t) autoneg, need_update); ecmd.autoneg = autoneg;
need_update = true;
if (!need_update) }
return 0;
if (need_update) {
ecmd.cmd = ETHTOOL_SPAUSEPARAM; ecmd.cmd = ETHTOOL_SPAUSEPARAM;
r = ioctl(*fd, SIOCETHTOOL, &ifr); r = ioctl(*fd, SIOCETHTOOL, &ifr);
if (r < 0) if (r < 0)
return -errno; return -errno;
}
return 0; return 0;
} }
int config_parse_channel( int config_parse_channel(const char *unit,
const char *unit,
const char *filename, const char *filename,
unsigned line, unsigned line,
const char *section, const char *section,
@ -952,7 +1008,6 @@ int config_parse_channel(
const char *rvalue, const char *rvalue,
void *data, void *data,
void *userdata) { void *userdata) {
netdev_channels *channels = data; netdev_channels *channels = data;
uint32_t k; uint32_t k;
int r; int r;
@ -992,8 +1047,7 @@ int config_parse_channel(
return 0; return 0;
} }
int config_parse_advertise( int config_parse_advertise(const char *unit,
const char *unit,
const char *filename, const char *filename,
unsigned line, unsigned line,
const char *section, const char *section,
@ -1003,7 +1057,6 @@ int config_parse_advertise(
const char *rvalue, const char *rvalue,
void *data, void *data,
void *userdata) { void *userdata) {
uint32_t *advertise = data; uint32_t *advertise = data;
const char *p; const char *p;
int r; int r;
@ -1048,8 +1101,7 @@ int config_parse_advertise(
} }
} }
int config_parse_nic_buffer_size( int config_parse_nic_buffer_size(const char *unit,
const char *unit,
const char *filename, const char *filename,
unsigned line, unsigned line,
const char *section, const char *section,
@ -1059,7 +1111,6 @@ int config_parse_nic_buffer_size(
const char *rvalue, const char *rvalue,
void *data, void *data,
void *userdata) { void *userdata) {
netdev_ring_param *ring = data; netdev_ring_param *ring = data;
uint32_t k; uint32_t k;
int r; int r;

View File

@ -99,6 +99,7 @@ int ethtool_get_link_info(int *ethtool_fd, const char *ifname,
int *ret_autonegotiation, uint64_t *ret_speed, int *ret_autonegotiation, uint64_t *ret_speed,
Duplex *ret_duplex, NetDevPort *ret_port); Duplex *ret_duplex, NetDevPort *ret_port);
int ethtool_get_permanent_macaddr(int *ethtool_fd, const char *ifname, struct ether_addr *ret); int ethtool_get_permanent_macaddr(int *ethtool_fd, const char *ifname, struct ether_addr *ret);
int ethtool_set_speed(int *ethtool_fd, const char *ifname, unsigned speed, Duplex duplex);
int ethtool_set_wol(int *ethtool_fd, const char *ifname, WakeOnLan wol); int ethtool_set_wol(int *ethtool_fd, const char *ifname, WakeOnLan wol);
int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netdev_ring_param *ring); int ethtool_set_nic_buffer_size(int *ethtool_fd, const char *ifname, const netdev_ring_param *ring);
int ethtool_set_features(int *ethtool_fd, const char *ifname, const int *features); int ethtool_set_features(int *ethtool_fd, const char *ifname, const int *features);

View File

@ -308,46 +308,50 @@ static int link_config_apply_ethtool_settings(int *ethtool_fd, const link_config
config->autonegotiation, config->advertise, config->autonegotiation, config->advertise,
config->speed, config->duplex, config->port); config->speed, config->duplex, config->port);
if (r < 0) { if (r < 0) {
if (config->autonegotiation >= 0) if (config->port != _NET_DEV_PORT_INVALID)
log_device_warning_errno(device, r, "Could not %s auto negotiation, ignoring: %m", log_device_warning_errno(device, r, "Could not set port '%s', ignoring: %m", port_to_string(config->port));
enable_disable(config->autonegotiation));
if (!eqzero(config->advertise)) if (!eqzero(config->advertise))
log_device_warning_errno(device, r, "Could not set advertise mode, ignoring: %m"); log_device_warning_errno(device, r, "Could not set advertise mode, ignoring: %m"); /* TODO: include modes in the log message. */
if (config->speed > 0) if (config->speed) {
log_device_warning_errno(device, r, "Could not set speed to %"PRIu64"Mbps, ignoring: %m", unsigned speed = DIV_ROUND_UP(config->speed, 1000000);
DIV_ROUND_UP(config->speed, 1000000)); if (r == -EOPNOTSUPP) {
r = ethtool_set_speed(ethtool_fd, name, speed, config->duplex);
if (r < 0)
log_device_warning_errno(device, r, "Could not set speed to %uMbps, ignoring: %m", speed);
}
}
if (config->duplex >= 0) if (config->duplex != _DUP_INVALID)
log_device_warning_errno(device, r, "Could not set duplex to %s, ignoring: %m", log_device_warning_errno(device, r, "Could not set duplex to %s, ignoring: %m", duplex_to_string(config->duplex));
duplex_to_string(config->duplex));
if (config->port >= 0)
log_device_warning_errno(device, r, "Could not set port to '%s', ignoring: %m",
port_to_string(config->port));
} }
r = ethtool_set_wol(ethtool_fd, name, config->wol); r = ethtool_set_wol(ethtool_fd, name, config->wol);
if (r < 0) if (r < 0)
log_device_warning_errno(device, r, "Could not set WakeOnLan to %s, ignoring: %m", log_device_warning_errno(device, r, "Could not set WakeOnLan to %s, ignoring: %m", wol_to_string(config->wol));
wol_to_string(config->wol));
r = ethtool_set_features(ethtool_fd, name, config->features); r = ethtool_set_features(ethtool_fd, name, config->features);
if (r < 0) if (r < 0)
log_device_warning_errno(device, r, "Could not set offload features, ignoring: %m"); log_device_warning_errno(device, r, "Could not set offload features, ignoring: %m");
if (config->channels.rx_count_set || config->channels.tx_count_set || config->channels.other_count_set || config->channels.combined_count_set) {
r = ethtool_set_channels(ethtool_fd, name, &config->channels); r = ethtool_set_channels(ethtool_fd, name, &config->channels);
if (r < 0) if (r < 0)
log_device_warning_errno(device, r, "Could not set channels, ignoring: %m"); log_device_warning_errno(device, r, "Could not set channels, ignoring: %m");
}
if (config->ring.rx_pending_set || config->ring.rx_mini_pending_set || config->ring.rx_jumbo_pending_set || config->ring.tx_pending_set) {
r = ethtool_set_nic_buffer_size(ethtool_fd, name, &config->ring); r = ethtool_set_nic_buffer_size(ethtool_fd, name, &config->ring);
if (r < 0) if (r < 0)
log_device_warning_errno(device, r, "Could not set ring buffer, ignoring: %m"); log_device_warning_errno(device, r, "Could not set ring buffer, ignoring: %m");
}
if (config->rx_flow_control >= 0 || config->tx_flow_control >= 0 || config->autoneg_flow_control >= 0) {
r = ethtool_set_flow_control(ethtool_fd, name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control); r = ethtool_set_flow_control(ethtool_fd, name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
if (r < 0) if (r < 0)
log_device_warning_errno(device, r, "Could not set flow control, ignoring: %m"); log_device_warning_errno(device, r, "Could not set flow control, ignoring: %m");
}
return 0; return 0;
} }