mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-22 13:33:56 +03:00
Merge pull request #12806 from yuwata/networkctl-ethtool-12657
networkctl: show speed, duplex, auto negotiation, and port
This commit is contained in:
commit
b19eab1f74
@ -1,5 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "format-util.h"
|
||||
#include "memory-util.h"
|
||||
|
||||
@ -8,3 +10,61 @@ char *format_ifname(int ifindex, char buf[static IF_NAMESIZE + 1]) {
|
||||
memzero(buf, IF_NAMESIZE + 1);
|
||||
return if_indextoname(ifindex, buf);
|
||||
}
|
||||
|
||||
char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) {
|
||||
typedef struct {
|
||||
const char *suffix;
|
||||
uint64_t factor;
|
||||
} suffix_table;
|
||||
static const suffix_table table_iec[] = {
|
||||
{ "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "M", UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "K", UINT64_C(1024) },
|
||||
}, table_non_iec[] = {
|
||||
{ "E", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
|
||||
{ "P", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
|
||||
{ "T", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
|
||||
{ "G", UINT64_C(1000)*UINT64_C(1000)*UINT64_C(1000) },
|
||||
{ "M", UINT64_C(1000)*UINT64_C(1000) },
|
||||
{ "K", UINT64_C(1000) },
|
||||
};
|
||||
const suffix_table *table;
|
||||
size_t n, i;
|
||||
|
||||
assert_cc(ELEMENTSOF(table_iec) == ELEMENTSOF(table_non_iec));
|
||||
|
||||
if (t == (uint64_t) -1)
|
||||
return NULL;
|
||||
|
||||
table = flag & FORMAT_BYTES_USE_IEC ? table_iec : table_non_iec;
|
||||
n = ELEMENTSOF(table_iec);
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (t >= table[i].factor) {
|
||||
if (flag & FORMAT_BYTES_BELOW_POINT) {
|
||||
snprintf(buf, l,
|
||||
"%" PRIu64 ".%" PRIu64 "%s",
|
||||
t / table[i].factor,
|
||||
i != n - 1 ?
|
||||
(t / table[i + 1].factor * UINT64_C(10) / table[n - 1].factor) % UINT64_C(10):
|
||||
(t * UINT64_C(10) / table[i].factor) % UINT64_C(10),
|
||||
table[i].suffix);
|
||||
} else
|
||||
snprintf(buf, l,
|
||||
"%" PRIu64 "%s",
|
||||
t / table[i].factor,
|
||||
table[i].suffix);
|
||||
|
||||
goto finish;
|
||||
}
|
||||
|
||||
snprintf(buf, l, "%" PRIu64 "%s", t, flag & FORMAT_BYTES_TRAILING_B ? "B" : "");
|
||||
|
||||
finish:
|
||||
buf[l-1] = 0;
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <net/if.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#if SIZEOF_PID_T == 4
|
||||
# define PID_PRI PRIi32
|
||||
@ -68,3 +69,15 @@
|
||||
#endif
|
||||
|
||||
char *format_ifname(int ifindex, char buf[static IF_NAMESIZE + 1]);
|
||||
|
||||
typedef enum {
|
||||
FORMAT_BYTES_USE_IEC = 1 << 0,
|
||||
FORMAT_BYTES_BELOW_POINT = 1 << 1,
|
||||
FORMAT_BYTES_TRAILING_B = 1 << 2,
|
||||
} FormatBytesFlag;
|
||||
|
||||
#define FORMAT_BYTES_MAX 8
|
||||
char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag);
|
||||
static inline char *format_bytes(char *buf, size_t l, uint64_t t) {
|
||||
return format_bytes_full(buf, l, t, FORMAT_BYTES_USE_IEC | FORMAT_BYTES_BELOW_POINT | FORMAT_BYTES_TRAILING_B);
|
||||
}
|
||||
|
@ -362,47 +362,6 @@ int parse_syscall_and_errno(const char *in, char **name, int *error) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *format_bytes(char *buf, size_t l, uint64_t t) {
|
||||
unsigned i;
|
||||
|
||||
/* This only does IEC units so far */
|
||||
|
||||
static const struct {
|
||||
const char *suffix;
|
||||
uint64_t factor;
|
||||
} table[] = {
|
||||
{ "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "M", UINT64_C(1024)*UINT64_C(1024) },
|
||||
{ "K", UINT64_C(1024) },
|
||||
};
|
||||
|
||||
if (t == (uint64_t) -1)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < ELEMENTSOF(table); i++) {
|
||||
|
||||
if (t >= table[i].factor) {
|
||||
snprintf(buf, l,
|
||||
"%" PRIu64 ".%" PRIu64 "%s",
|
||||
t / table[i].factor,
|
||||
((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10),
|
||||
table[i].suffix);
|
||||
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(buf, l, "%" PRIu64 "B", t);
|
||||
|
||||
finish:
|
||||
buf[l-1] = 0;
|
||||
return buf;
|
||||
|
||||
}
|
||||
|
||||
int safe_atou_full(const char *s, unsigned base, unsigned *ret_u) {
|
||||
char *x = NULL;
|
||||
unsigned long l;
|
||||
|
@ -22,9 +22,6 @@ int parse_range(const char *t, unsigned *lower, unsigned *upper);
|
||||
int parse_errno(const char *t);
|
||||
int parse_syscall_and_errno(const char *in, char **name, int *error);
|
||||
|
||||
#define FORMAT_BYTES_MAX 8
|
||||
char *format_bytes(char *buf, size_t l, uint64_t t);
|
||||
|
||||
int safe_atou_full(const char *s, unsigned base, unsigned *ret_u);
|
||||
|
||||
static inline int safe_atou(const char *s, unsigned *ret_u) {
|
||||
|
@ -6,13 +6,13 @@
|
||||
#include "alloc-util.h"
|
||||
#include "btrfs-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "hostname-util.h"
|
||||
#include "import-common.h"
|
||||
#include "import-util.h"
|
||||
#include "machine-image.h"
|
||||
#include "mkdir.h"
|
||||
#include "parse-util.h"
|
||||
#include "ratelimit.h"
|
||||
#include "rm-rf.h"
|
||||
#include "string-util.h"
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "gcrypt-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "import-util.h"
|
||||
|
@ -17,13 +17,13 @@
|
||||
#include "chattr-util.h"
|
||||
#include "compress.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "journal-authenticate.h"
|
||||
#include "journal-def.h"
|
||||
#include "journal-file.h"
|
||||
#include "lookup3.h"
|
||||
#include "memory-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "random-util.h"
|
||||
#include "set.h"
|
||||
|
@ -9,11 +9,11 @@
|
||||
#include "alloc-util.h"
|
||||
#include "dirent-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "journal-def.h"
|
||||
#include "journal-file.h"
|
||||
#include "journal-vacuum.h"
|
||||
#include "parse-util.h"
|
||||
#include "sort-util.h"
|
||||
#include "string-util.h"
|
||||
#include "time-util.h"
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "device-private.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "fsprg.h"
|
||||
#include "glob-util.h"
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "bus-util.h"
|
||||
#include "device-util.h"
|
||||
#include "ether-addr-util.h"
|
||||
#include "ethtool-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-table.h"
|
||||
#include "format-util.h"
|
||||
@ -119,8 +120,14 @@ typedef struct LinkInfo {
|
||||
struct rtnl_link_stats stats;
|
||||
};
|
||||
|
||||
double tx_bitrate;
|
||||
double rx_bitrate;
|
||||
uint64_t tx_bitrate;
|
||||
uint64_t rx_bitrate;
|
||||
|
||||
/* ethtool info */
|
||||
int autonegotiation;
|
||||
size_t speed;
|
||||
Duplex duplex;
|
||||
NetDevPort port;
|
||||
|
||||
bool has_mac_address:1;
|
||||
bool has_tx_queues:1;
|
||||
@ -128,6 +135,7 @@ typedef struct LinkInfo {
|
||||
bool has_stats64:1;
|
||||
bool has_stats:1;
|
||||
bool has_bitrates:1;
|
||||
bool has_ethtool_link_info:1;
|
||||
} LinkInfo;
|
||||
|
||||
static int link_info_compare(const LinkInfo *a, const LinkInfo *b) {
|
||||
@ -229,11 +237,11 @@ static int acquire_link_bitrates(sd_bus *bus, LinkInfo *link) {
|
||||
r, "Failed to query link bit rates: %s", bus_error_message(&error, r));
|
||||
}
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'v', "(dd)");
|
||||
r = sd_bus_message_enter_container(reply, 'v', "(tt)");
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
r = sd_bus_message_read(reply, "(dd)", &link->tx_bitrate, &link->rx_bitrate);
|
||||
r = sd_bus_message_read(reply, "(tt)", &link->tx_bitrate, &link->rx_bitrate);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
@ -241,7 +249,7 @@ static int acquire_link_bitrates(sd_bus *bus, LinkInfo *link) {
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
link->has_bitrates = link->tx_bitrate >= 0 && link->rx_bitrate >= 0;
|
||||
link->has_bitrates = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -249,6 +257,7 @@ static int acquire_link_bitrates(sd_bus *bus, LinkInfo *link) {
|
||||
static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, LinkInfo **ret) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
||||
_cleanup_free_ LinkInfo *links = NULL;
|
||||
_cleanup_close_ int fd = -1;
|
||||
size_t allocated = 0, c = 0, j;
|
||||
sd_netlink_message *i;
|
||||
int r;
|
||||
@ -275,8 +284,16 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin
|
||||
r = decode_link(i, links + c, patterns);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
c++;
|
||||
if (r == 0)
|
||||
continue;
|
||||
|
||||
r = ethtool_get_link_info(&fd, links[c].name,
|
||||
&links[c].autonegotiation, &links[c].speed,
|
||||
&links[c].duplex, &links[c].port);
|
||||
if (r >= 0)
|
||||
links[c].has_ethtool_link_info = true;
|
||||
|
||||
c++;
|
||||
}
|
||||
|
||||
typesafe_qsort(links, c, link_info_compare);
|
||||
@ -898,32 +915,6 @@ static int dump_statistics(Table *table, const LinkInfo *info) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
double val;
|
||||
const char *str;
|
||||
} prefix_table[] = {
|
||||
{ .val = 1e15, .str = "P" },
|
||||
{ .val = 1e12, .str = "T" },
|
||||
{ .val = 1e9, .str = "G" },
|
||||
{ .val = 1e6, .str = "M" },
|
||||
{ .val = 1e3, .str = "k" },
|
||||
};
|
||||
|
||||
static void get_prefix(double val, double *ret_div, const char **ret_prefix) {
|
||||
assert(ret_div);
|
||||
assert(ret_prefix);
|
||||
|
||||
for (size_t i = 0; i < ELEMENTSOF(prefix_table); i++)
|
||||
if (val > prefix_table[i].val) {
|
||||
*ret_div = prefix_table[i].val;
|
||||
*ret_prefix = prefix_table[i].str;
|
||||
return;
|
||||
}
|
||||
|
||||
*ret_div = 1;
|
||||
*ret_prefix = NULL;
|
||||
}
|
||||
|
||||
static int link_status_one(
|
||||
sd_netlink *rtnl,
|
||||
sd_hwdb *hwdb,
|
||||
@ -1140,11 +1131,7 @@ static int link_status_one(
|
||||
}
|
||||
|
||||
if (info->has_bitrates) {
|
||||
const char *tx_prefix, *rx_prefix;
|
||||
double tx_div, rx_div;
|
||||
|
||||
get_prefix(info->tx_bitrate, &tx_div, &tx_prefix);
|
||||
get_prefix(info->rx_bitrate, &rx_div, &rx_prefix);
|
||||
char tx[FORMAT_BYTES_MAX], rx[FORMAT_BYTES_MAX];
|
||||
|
||||
r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
|
||||
if (r < 0)
|
||||
@ -1153,9 +1140,9 @@ static int link_status_one(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = table_add_cell_stringf(table, NULL, "%.4g %sbps/%.4g %sbps",
|
||||
info->tx_bitrate / tx_div, strempty(tx_prefix),
|
||||
info->rx_bitrate / rx_div, strempty(rx_prefix));
|
||||
r = table_add_cell_stringf(table, NULL, "%sbps/%sbps",
|
||||
format_bytes_full(tx, sizeof tx, info->tx_bitrate, 0),
|
||||
format_bytes_full(rx, sizeof rx, info->rx_bitrate, 0));
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
@ -1172,6 +1159,59 @@ static int link_status_one(
|
||||
return r;
|
||||
}
|
||||
|
||||
if (info->has_ethtool_link_info) {
|
||||
const char *duplex = duplex_to_string(info->duplex);
|
||||
const char *port = port_to_string(info->port);
|
||||
|
||||
if (IN_SET(info->autonegotiation, AUTONEG_DISABLE, AUTONEG_ENABLE)) {
|
||||
r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = table_add_cell(table, NULL, TABLE_STRING, "Auto negotiation:");
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = table_add_cell(table, NULL, TABLE_BOOLEAN, &info->autonegotiation);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (info->speed > 0) {
|
||||
r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = table_add_cell(table, NULL, TABLE_STRING, "Speed:");
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = table_add_cell(table, NULL, TABLE_BPS, &info->speed);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (duplex) {
|
||||
r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = table_add_cell(table, NULL, TABLE_STRING, "Duplex:");
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = table_add_cell(table, NULL, TABLE_STRING, duplex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (port) {
|
||||
r = table_add_cell(table, NULL, TABLE_EMPTY, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = table_add_cell(table, NULL, TABLE_STRING, "Port:");
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = table_add_cell(table, NULL, TABLE_STRING, port);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = dump_addresses(rtnl, table, info->ifindex);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -22,7 +22,8 @@ static int property_get_bit_rates(
|
||||
|
||||
Link *link = userdata;
|
||||
Manager *manager;
|
||||
double tx, rx, interval_sec;
|
||||
double interval_sec;
|
||||
uint64_t tx, rx;
|
||||
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
@ -40,19 +41,19 @@ static int property_get_bit_rates(
|
||||
return sd_bus_error_set(error, BUS_ERROR_SPEED_METER_INACTIVE, "Failed to measure bit-rates.");
|
||||
|
||||
assert(manager->speed_meter_usec_new > manager->speed_meter_usec_old);
|
||||
interval_sec = (double) (manager->speed_meter_usec_new - manager->speed_meter_usec_old) / USEC_PER_SEC;
|
||||
interval_sec = (manager->speed_meter_usec_new - manager->speed_meter_usec_old) / USEC_PER_SEC;
|
||||
|
||||
if (link->stats_new.tx_bytes > link->stats_old.tx_bytes)
|
||||
tx = (link->stats_new.tx_bytes - link->stats_old.tx_bytes) / interval_sec;
|
||||
tx = (uint64_t) ((link->stats_new.tx_bytes - link->stats_old.tx_bytes) / interval_sec);
|
||||
else
|
||||
tx = (UINT64_MAX - (link->stats_old.tx_bytes - link->stats_new.tx_bytes)) / interval_sec;
|
||||
tx = (uint64_t) ((UINT64_MAX - (link->stats_old.tx_bytes - link->stats_new.tx_bytes)) / interval_sec);
|
||||
|
||||
if (link->stats_new.rx_bytes > link->stats_old.rx_bytes)
|
||||
rx = (link->stats_new.rx_bytes - link->stats_old.rx_bytes) / interval_sec;
|
||||
rx = (uint64_t) ((link->stats_new.rx_bytes - link->stats_old.rx_bytes) / interval_sec);
|
||||
else
|
||||
rx = (UINT64_MAX - (link->stats_old.rx_bytes - link->stats_new.rx_bytes)) / interval_sec;
|
||||
rx = (uint64_t) ((UINT64_MAX - (link->stats_old.rx_bytes - link->stats_new.rx_bytes)) / interval_sec);
|
||||
|
||||
return sd_bus_message_append(reply, "(dd)", tx, rx);
|
||||
return sd_bus_message_append(reply, "(tt)", tx, rx);
|
||||
}
|
||||
|
||||
const sd_bus_vtable link_vtable[] = {
|
||||
@ -60,7 +61,7 @@ const sd_bus_vtable link_vtable[] = {
|
||||
|
||||
SD_BUS_PROPERTY("OperationalState", "s", property_get_operational_state, offsetof(Link, operstate), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("AdministrativeState", "s", property_get_administrative_state, offsetof(Link, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
|
||||
SD_BUS_PROPERTY("BitRates", "(dd)", property_get_bit_rates, 0, 0),
|
||||
SD_BUS_PROPERTY("BitRates", "(tt)", property_get_bit_rates, 0, 0),
|
||||
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "ethtool-util.h"
|
||||
#include "link-config.h"
|
||||
#include "extract-word.h"
|
||||
#include "log.h"
|
||||
#include "memory-util.h"
|
||||
#include "missing.h"
|
||||
@ -111,18 +111,19 @@ static const char* const ethtool_link_mode_bit_table[] = {
|
||||
[ETHTOOL_LINK_MODE_FEC_BASER_BIT] = "fec-baser",
|
||||
};
|
||||
/* Make sure the array is large enough to fit all bits */
|
||||
assert_cc((ELEMENTSOF(ethtool_link_mode_bit_table)-1) / 32 < ELEMENTSOF(((struct link_config){}).advertise));
|
||||
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);
|
||||
|
||||
int ethtool_connect(int *ret) {
|
||||
static int ethtool_connect_or_warn(int *ret, bool warn) {
|
||||
int fd;
|
||||
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
fd = socket_ioctl_fd();
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
return log_full_errno(warn ? LOG_WARNING: LOG_DEBUG, fd,
|
||||
"ethtool: could not create control socket: %m");
|
||||
|
||||
*ret = fd;
|
||||
|
||||
@ -140,9 +141,9 @@ int ethtool_get_driver(int *fd, const char *ifname, char **ret) {
|
||||
int r;
|
||||
|
||||
if (*fd < 0) {
|
||||
r = ethtool_connect(fd);
|
||||
r = ethtool_connect_or_warn(fd, true);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
|
||||
return r;
|
||||
}
|
||||
|
||||
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
|
||||
@ -159,6 +160,44 @@ int ethtool_get_driver(int *fd, const char *ifname, char **ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ethtool_get_link_info(int *fd, const char *ifname,
|
||||
int *ret_autonegotiation, size_t *ret_speed,
|
||||
Duplex *ret_duplex, NetDevPort *ret_port) {
|
||||
struct ethtool_cmd ecmd = {
|
||||
.cmd = ETHTOOL_GSET,
|
||||
};
|
||||
struct ifreq ifr = {
|
||||
.ifr_data = (void*) &ecmd,
|
||||
};
|
||||
int r;
|
||||
|
||||
if (*fd < 0) {
|
||||
r = ethtool_connect_or_warn(fd, false);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
|
||||
|
||||
r = ioctl(*fd, SIOCETHTOOL, &ifr);
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
if (ret_autonegotiation)
|
||||
*ret_autonegotiation = ecmd.autoneg;
|
||||
|
||||
if (ret_speed)
|
||||
*ret_speed = ethtool_cmd_speed(&ecmd) * 1000 * 1000;
|
||||
|
||||
if (ret_duplex)
|
||||
*ret_duplex = ecmd.duplex;
|
||||
|
||||
if (ret_port)
|
||||
*ret_port = ecmd.port;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ethtool_set_speed(int *fd, const char *ifname, unsigned speed, Duplex duplex) {
|
||||
struct ethtool_cmd ecmd = {
|
||||
.cmd = ETHTOOL_GSET
|
||||
@ -173,9 +212,9 @@ int ethtool_set_speed(int *fd, const char *ifname, unsigned speed, Duplex duplex
|
||||
return 0;
|
||||
|
||||
if (*fd < 0) {
|
||||
r = ethtool_connect(fd);
|
||||
r = ethtool_connect_or_warn(fd, true);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
|
||||
return r;
|
||||
}
|
||||
|
||||
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
|
||||
@ -231,9 +270,9 @@ int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) {
|
||||
return 0;
|
||||
|
||||
if (*fd < 0) {
|
||||
r = ethtool_connect(fd);
|
||||
r = ethtool_connect_or_warn(fd, true);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
|
||||
return r;
|
||||
}
|
||||
|
||||
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
|
||||
@ -368,16 +407,16 @@ int ethtool_set_features(int *fd, const char *ifname, int *features) {
|
||||
struct ifreq ifr = {};
|
||||
|
||||
if (*fd < 0) {
|
||||
r = ethtool_connect(fd);
|
||||
r = ethtool_connect_or_warn(fd, true);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
|
||||
return r;
|
||||
}
|
||||
|
||||
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
|
||||
|
||||
r = get_stringset(*fd, &ifr, ETH_SS_FEATURES, &strings);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "link_config: 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->cmd = ETHTOOL_SFEATURES;
|
||||
@ -389,7 +428,7 @@ int ethtool_set_features(int *fd, const char *ifname, int *features) {
|
||||
|
||||
r = find_feature_index(strings, netdev_feature_table[i]);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "link_config: could not find feature: %s", netdev_feature_table[i]);
|
||||
log_warning_errno(r, "ethtool: could not find feature: %s", netdev_feature_table[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -409,7 +448,7 @@ int ethtool_set_features(int *fd, const char *ifname, int *features) {
|
||||
|
||||
r = ioctl(*fd, SIOCETHTOOL, &ifr);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "link_config: could not set ethtool features for %s", ifname);
|
||||
return log_warning_errno(r, "ethtool: could not set ethtool features for %s", ifname);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -453,11 +492,13 @@ static int get_glinksettings(int fd, struct ifreq *ifr, struct ethtool_link_uset
|
||||
if (ecmd.req.link_mode_masks_nwords <= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
u = new0(struct ethtool_link_usettings , 1);
|
||||
u = new(struct ethtool_link_usettings, 1);
|
||||
if (!u)
|
||||
return -ENOMEM;
|
||||
|
||||
u->base = ecmd.req;
|
||||
*u = (struct ethtool_link_usettings) {
|
||||
.base = ecmd.req,
|
||||
};
|
||||
|
||||
offset = 0;
|
||||
memcpy(u->link_modes.supported, &ecmd.link_mode_data[offset], 4 * ecmd.req.link_mode_masks_nwords);
|
||||
@ -486,23 +527,24 @@ static int get_gset(int fd, struct ifreq *ifr, struct ethtool_link_usettings **u
|
||||
if (r < 0)
|
||||
return -errno;
|
||||
|
||||
e = new0(struct ethtool_link_usettings, 1);
|
||||
e = new(struct ethtool_link_usettings, 1);
|
||||
if (!e)
|
||||
return -ENOMEM;
|
||||
|
||||
e->base.cmd = ETHTOOL_GSET;
|
||||
*e = (struct ethtool_link_usettings) {
|
||||
.base.cmd = ETHTOOL_GSET,
|
||||
.base.link_mode_masks_nwords = 1,
|
||||
.base.speed = ethtool_cmd_speed(&ecmd),
|
||||
.base.duplex = ecmd.duplex,
|
||||
.base.port = ecmd.port,
|
||||
.base.phy_address = ecmd.phy_address,
|
||||
.base.autoneg = ecmd.autoneg,
|
||||
.base.mdio_support = ecmd.mdio_support,
|
||||
|
||||
e->base.link_mode_masks_nwords = 1;
|
||||
e->base.speed = ethtool_cmd_speed(&ecmd);
|
||||
e->base.duplex = ecmd.duplex;
|
||||
e->base.port = ecmd.port;
|
||||
e->base.phy_address = ecmd.phy_address;
|
||||
e->base.autoneg = ecmd.autoneg;
|
||||
e->base.mdio_support = ecmd.mdio_support;
|
||||
|
||||
e->link_modes.supported[0] = ecmd.supported;
|
||||
e->link_modes.advertising[0] = ecmd.advertising;
|
||||
e->link_modes.lp_advertising[0] = ecmd.lp_advertising;
|
||||
.link_modes.supported[0] = ecmd.supported,
|
||||
.link_modes.advertising[0] = ecmd.advertising,
|
||||
.link_modes.lp_advertising[0] = ecmd.lp_advertising,
|
||||
};
|
||||
|
||||
*u = e;
|
||||
|
||||
@ -578,20 +620,27 @@ static int set_sset(int fd, struct ifreq *ifr, const struct ethtool_link_usettin
|
||||
* 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 *fd, const char *ifname, struct link_config *link) {
|
||||
int ethtool_set_glinksettings(
|
||||
int *fd,
|
||||
const char *ifname,
|
||||
int autonegotiation,
|
||||
uint32_t advertise[static N_ADVERTISE],
|
||||
size_t speed,
|
||||
Duplex duplex,
|
||||
NetDevPort port) {
|
||||
_cleanup_free_ struct ethtool_link_usettings *u = NULL;
|
||||
struct ifreq ifr = {};
|
||||
int r;
|
||||
|
||||
if (link->autonegotiation != AUTONEG_DISABLE && eqzero(link->advertise)) {
|
||||
log_info("link_config: autonegotiation is unset or enabled, the speed and duplex are not writable.");
|
||||
if (autonegotiation != AUTONEG_DISABLE && memeqzero(advertise, sizeof(uint32_t) * N_ADVERTISE)) {
|
||||
log_info("ethtool: autonegotiation is unset or enabled, the speed and duplex are not writable.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*fd < 0) {
|
||||
r = ethtool_connect(fd);
|
||||
r = ethtool_connect_or_warn(fd, true);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
|
||||
return r;
|
||||
}
|
||||
|
||||
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
|
||||
@ -600,26 +649,26 @@ int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *l
|
||||
if (r < 0) {
|
||||
r = get_gset(*fd, &ifr, &u);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "link_config: Cannot get device settings for %s : %m", ifname);
|
||||
return log_warning_errno(r, "ethtool: Cannot get device settings for %s : %m", ifname);
|
||||
}
|
||||
|
||||
if (link->speed)
|
||||
u->base.speed = DIV_ROUND_UP(link->speed, 1000000);
|
||||
if (speed > 0)
|
||||
u->base.speed = DIV_ROUND_UP(speed, 1000000);
|
||||
|
||||
if (link->duplex != _DUP_INVALID)
|
||||
u->base.duplex = link->duplex;
|
||||
if (duplex != _DUP_INVALID)
|
||||
u->base.duplex = duplex;
|
||||
|
||||
if (link->port != _NET_DEV_PORT_INVALID)
|
||||
u->base.port = link->port;
|
||||
if (port != _NET_DEV_PORT_INVALID)
|
||||
u->base.port = port;
|
||||
|
||||
if (link->autonegotiation >= 0)
|
||||
u->base.autoneg = link->autonegotiation;
|
||||
if (autonegotiation >= 0)
|
||||
u->base.autoneg = autonegotiation;
|
||||
|
||||
if (!eqzero(link->advertise)) {
|
||||
if (!memeqzero(advertise, sizeof(uint32_t) * N_ADVERTISE)) {
|
||||
u->base.autoneg = AUTONEG_ENABLE;
|
||||
memcpy(&u->link_modes.advertising, link->advertise, sizeof(link->advertise));
|
||||
memzero((uint8_t*) &u->link_modes.advertising + sizeof(link->advertise),
|
||||
ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES - sizeof(link->advertise));
|
||||
memcpy(&u->link_modes.advertising, advertise, 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);
|
||||
}
|
||||
|
||||
if (u->base.cmd == ETHTOOL_GLINKSETTINGS)
|
||||
@ -627,59 +676,11 @@ int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *l
|
||||
else
|
||||
r = set_sset(*fd, &ifr, u);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "link_config: Cannot set device settings for %s : %m", ifname);
|
||||
return log_warning_errno(r, "ethtool: Cannot set device settings for %s : %m", ifname);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int config_parse_channel(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
link_config *config = data;
|
||||
uint32_t k;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = safe_atou32(rvalue, &k);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse channel value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (k < 1) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Invalid %s value, ignoring: %s", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (streq(lvalue, "RxChannels")) {
|
||||
config->channels.rx_count = k;
|
||||
config->channels.rx_count_set = true;
|
||||
} else if (streq(lvalue, "TxChannels")) {
|
||||
config->channels.tx_count = k;
|
||||
config->channels.tx_count_set = true;
|
||||
} else if (streq(lvalue, "OtherChannels")) {
|
||||
config->channels.other_count = k;
|
||||
config->channels.other_count_set = true;
|
||||
} else if (streq(lvalue, "CombinedChannels")) {
|
||||
config->channels.combined_count = k;
|
||||
config->channels.combined_count_set = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels) {
|
||||
struct ethtool_channels ecmd = {
|
||||
.cmd = ETHTOOL_GCHANNELS
|
||||
@ -692,9 +693,9 @@ int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels)
|
||||
int r;
|
||||
|
||||
if (*fd < 0) {
|
||||
r = ethtool_connect(fd);
|
||||
r = ethtool_connect_or_warn(fd, true);
|
||||
if (r < 0)
|
||||
return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
|
||||
return r;
|
||||
}
|
||||
|
||||
strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
|
||||
@ -734,6 +735,54 @@ int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_channel(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
netdev_channels *channels = data;
|
||||
uint32_t k;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(section);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
r = safe_atou32(rvalue, &k);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse channel value, ignoring: %s", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (k < 1) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Invalid %s value, ignoring: %s", lvalue, rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (streq(lvalue, "RxChannels")) {
|
||||
channels->rx_count = k;
|
||||
channels->rx_count_set = true;
|
||||
} else if (streq(lvalue, "TxChannels")) {
|
||||
channels->tx_count = k;
|
||||
channels->tx_count_set = true;
|
||||
} else if (streq(lvalue, "OtherChannels")) {
|
||||
channels->other_count = k;
|
||||
channels->other_count_set = true;
|
||||
} else if (streq(lvalue, "CombinedChannels")) {
|
||||
channels->combined_count = k;
|
||||
channels->combined_count_set = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_advertise(const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
@ -744,7 +793,7 @@ int config_parse_advertise(const char *unit,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
link_config *config = data;
|
||||
uint32_t *advertise = data;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
@ -756,7 +805,7 @@ int config_parse_advertise(const char *unit,
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
/* Empty string resets the value. */
|
||||
zero(config->advertise);
|
||||
memzero(advertise, sizeof(uint32_t) * N_ADVERTISE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -782,7 +831,7 @@ int config_parse_advertise(const char *unit,
|
||||
continue;
|
||||
}
|
||||
|
||||
config->advertise[mode / 32] |= 1UL << (mode % 32);
|
||||
advertise[mode / 32] |= 1UL << (mode % 32);
|
||||
}
|
||||
|
||||
return 0;
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include "conf-parser.h"
|
||||
|
||||
struct link_config;
|
||||
#define N_ADVERTISE 2
|
||||
|
||||
/* we can't use DUPLEX_ prefix, as it
|
||||
* clashes with <linux/ethtool.h> */
|
||||
@ -79,13 +79,16 @@ typedef struct netdev_channels {
|
||||
bool combined_count_set;
|
||||
} netdev_channels;
|
||||
|
||||
int ethtool_connect(int *ret);
|
||||
|
||||
int ethtool_get_driver(int *fd, const char *ifname, char **ret);
|
||||
int ethtool_get_link_info(int *fd, const char *ifname,
|
||||
int *ret_autonegotiation, size_t *ret_speed,
|
||||
Duplex *ret_duplex, NetDevPort *ret_port);
|
||||
int ethtool_set_speed(int *fd, const char *ifname, unsigned speed, Duplex duplex);
|
||||
int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol);
|
||||
int ethtool_set_features(int *fd, const char *ifname, int *features);
|
||||
int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *link);
|
||||
int ethtool_set_glinksettings(int *fd, const char *ifname,
|
||||
int autonegotiation, uint32_t advertise[static N_ADVERTISE],
|
||||
size_t speed, Duplex duplex, NetDevPort port);
|
||||
int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels);
|
||||
|
||||
const char *duplex_to_string(Duplex d) _const_;
|
@ -15,6 +15,7 @@
|
||||
#include "pretty-print.h"
|
||||
#include "sort-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strxcpyx.h"
|
||||
#include "terminal-util.h"
|
||||
#include "time-util.h"
|
||||
#include "utf8.h"
|
||||
@ -235,6 +236,7 @@ static size_t table_data_size(TableDataType type, const void *data) {
|
||||
case TABLE_SIZE:
|
||||
case TABLE_INT64:
|
||||
case TABLE_UINT64:
|
||||
case TABLE_BPS:
|
||||
return sizeof(uint64_t);
|
||||
|
||||
case TABLE_INT32:
|
||||
@ -723,6 +725,7 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) {
|
||||
break;
|
||||
|
||||
case TABLE_SIZE:
|
||||
case TABLE_BPS:
|
||||
buffer.size = va_arg(ap, uint64_t);
|
||||
data = &buffer.size;
|
||||
break;
|
||||
@ -885,6 +888,7 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t
|
||||
return CMP(a->timespan, b->timespan);
|
||||
|
||||
case TABLE_SIZE:
|
||||
case TABLE_BPS:
|
||||
return CMP(a->size, b->size);
|
||||
|
||||
case TABLE_INT:
|
||||
@ -1023,6 +1027,24 @@ static const char *table_data_format(TableData *d) {
|
||||
break;
|
||||
}
|
||||
|
||||
case TABLE_BPS: {
|
||||
_cleanup_free_ char *p;
|
||||
size_t n;
|
||||
|
||||
p = new(char, FORMAT_BYTES_MAX+2);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
if (!format_bytes_full(p, FORMAT_BYTES_MAX, d->size, 0))
|
||||
return "n/a";
|
||||
|
||||
n = strlen(p);
|
||||
strscpy(p + n, FORMAT_BYTES_MAX + 2 - n, "bps");
|
||||
|
||||
d->formatted = TAKE_PTR(p);
|
||||
break;
|
||||
}
|
||||
|
||||
case TABLE_INT: {
|
||||
_cleanup_free_ char *p;
|
||||
|
||||
@ -1622,6 +1644,7 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) {
|
||||
return json_variant_new_unsigned(ret, d->timespan);
|
||||
|
||||
case TABLE_SIZE:
|
||||
case TABLE_BPS:
|
||||
if (d->size == (size_t) -1)
|
||||
return json_variant_new_null(ret);
|
||||
|
||||
|
@ -15,6 +15,7 @@ typedef enum TableDataType {
|
||||
TABLE_TIMESTAMP,
|
||||
TABLE_TIMESPAN,
|
||||
TABLE_SIZE,
|
||||
TABLE_BPS,
|
||||
TABLE_INT,
|
||||
TABLE_INT32,
|
||||
TABLE_INT64,
|
||||
|
@ -59,6 +59,8 @@ shared_sources = files('''
|
||||
enable-mempool.c
|
||||
env-file-label.c
|
||||
env-file-label.h
|
||||
ethtool-util.c
|
||||
ethtool-util.h
|
||||
exec-util.c
|
||||
exec-util.h
|
||||
exit-status.c
|
||||
|
@ -216,6 +216,10 @@ tests += [
|
||||
[],
|
||||
[]],
|
||||
|
||||
[['src/test/test-format-util.c'],
|
||||
[],
|
||||
[]],
|
||||
|
||||
[['src/test/test-ratelimit.c'],
|
||||
[],
|
||||
[]],
|
||||
|
@ -5,8 +5,8 @@
|
||||
#include "btrfs-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "format-util.h"
|
||||
#include "log.h"
|
||||
#include "parse-util.h"
|
||||
#include "string-util.h"
|
||||
#include "util.h"
|
||||
|
||||
|
38
src/test/test-format-util.c
Normal file
38
src/test/test-format-util.c
Normal file
@ -0,0 +1,38 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include "format-util.h"
|
||||
#include "macro.h"
|
||||
#include "string-util.h"
|
||||
|
||||
static void test_format_bytes_one(size_t val, bool trailing_B, const char *iec_with_p, const char *iec_without_p,
|
||||
const char *non_iec_with_p, const char *non_iec_without_p) {
|
||||
char buf[FORMAT_BYTES_MAX];
|
||||
|
||||
assert_se(streq_ptr(format_bytes_full(buf, sizeof buf, val, FORMAT_BYTES_USE_IEC | FORMAT_BYTES_BELOW_POINT | (trailing_B ? FORMAT_BYTES_TRAILING_B : 0)), iec_with_p));
|
||||
assert_se(streq_ptr(format_bytes_full(buf, sizeof buf, val, FORMAT_BYTES_USE_IEC | (trailing_B ? FORMAT_BYTES_TRAILING_B : 0)), iec_without_p));
|
||||
assert_se(streq_ptr(format_bytes_full(buf, sizeof buf, val, FORMAT_BYTES_BELOW_POINT | (trailing_B ? FORMAT_BYTES_TRAILING_B : 0)), non_iec_with_p));
|
||||
assert_se(streq_ptr(format_bytes_full(buf, sizeof buf, val, trailing_B ? FORMAT_BYTES_TRAILING_B : 0), non_iec_without_p));
|
||||
}
|
||||
|
||||
static void test_format_bytes(void) {
|
||||
test_format_bytes_one(900, true, "900B", "900B", "900B", "900B");
|
||||
test_format_bytes_one(900, false, "900", "900", "900", "900");
|
||||
test_format_bytes_one(1023, true, "1023B", "1023B", "1.0K", "1K");
|
||||
test_format_bytes_one(1023, false, "1023", "1023", "1.0K", "1K");
|
||||
test_format_bytes_one(1024, true, "1.0K", "1K", "1.0K", "1K");
|
||||
test_format_bytes_one(1024, false, "1.0K", "1K", "1.0K", "1K");
|
||||
test_format_bytes_one(1100, true, "1.0K", "1K", "1.1K", "1K");
|
||||
test_format_bytes_one(1500, true, "1.4K", "1K", "1.5K", "1K");
|
||||
test_format_bytes_one((size_t) 3*1024*1024, true, "3.0M", "3M", "3.1M", "3M");
|
||||
test_format_bytes_one((size_t) 3*1024*1024*1024, true, "3.0G", "3G", "3.2G", "3G");
|
||||
test_format_bytes_one((size_t) 3*1024*1024*1024*1024, true, "3.0T", "3T", "3.2T", "3T");
|
||||
test_format_bytes_one((size_t) 3*1024*1024*1024*1024*1024, true, "3.0P", "3P", "3.3P", "3P");
|
||||
test_format_bytes_one((size_t) 3*1024*1024*1024*1024*1024*1024, true, "3.0E", "3E", "3.4E", "3E");
|
||||
test_format_bytes_one(SIZE_MAX, true, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
test_format_bytes();
|
||||
|
||||
return 0;
|
||||
}
|
@ -2,8 +2,8 @@
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "format-util.h"
|
||||
#include "log.h"
|
||||
#include "parse-util.h"
|
||||
#include "procfs-util.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
@ -40,8 +40,6 @@ libudev_core_sources = '''
|
||||
udev-builtin-usb_id.c
|
||||
net/link-config.c
|
||||
net/link-config.h
|
||||
net/ethtool-util.c
|
||||
net/ethtool-util.h
|
||||
net/naming-scheme.c
|
||||
net/naming-scheme.h
|
||||
'''.split()
|
||||
|
@ -47,8 +47,8 @@ Link.TCP6SegmentationOffload, config_parse_tristate, 0,
|
||||
Link.UDPSegmentationOffload, config_parse_warn_compat, DISABLED_LEGACY, 0
|
||||
Link.GenericReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GRO])
|
||||
Link.LargeReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_LRO])
|
||||
Link.RxChannels, config_parse_channel, 0, 0
|
||||
Link.TxChannels, config_parse_channel, 0, 0
|
||||
Link.OtherChannels, config_parse_channel, 0, 0
|
||||
Link.CombinedChannels, config_parse_channel, 0, 0
|
||||
Link.Advertise, config_parse_advertise, 0, 0
|
||||
Link.RxChannels, config_parse_channel, 0, offsetof(link_config, channels)
|
||||
Link.TxChannels, config_parse_channel, 0, offsetof(link_config, channels)
|
||||
Link.OtherChannels, config_parse_channel, 0, offsetof(link_config, channels)
|
||||
Link.CombinedChannels, config_parse_channel, 0, offsetof(link_config, channels)
|
||||
Link.Advertise, config_parse_advertise, 0, offsetof(link_config, advertise)
|
||||
|
@ -354,7 +354,9 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ethtool_set_glinksettings(&ctx->ethtool_fd, old_name, config);
|
||||
r = ethtool_set_glinksettings(&ctx->ethtool_fd, old_name,
|
||||
config->autonegotiation, config->advertise,
|
||||
config->speed, config->duplex, config->port);
|
||||
if (r < 0) {
|
||||
|
||||
if (config->port != _NET_DEV_PORT_INVALID)
|
||||
|
@ -52,7 +52,7 @@ struct link_config {
|
||||
size_t speed;
|
||||
Duplex duplex;
|
||||
int autonegotiation;
|
||||
uint32_t advertise[2];
|
||||
uint32_t advertise[N_ADVERTISE];
|
||||
WakeOnLan wol;
|
||||
NetDevPort port;
|
||||
int features[_NET_DEV_FEAT_MAX];
|
||||
|
Loading…
Reference in New Issue
Block a user