Skip to content

Commit

Permalink
ethtool: Refactor handling of independed ethtool ioctl
Browse files Browse the repository at this point in the history
One ioctl failing should not block the other ones.
  • Loading branch information
wipawel committed Oct 9, 2014
1 parent 055b6f1 commit f763505
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 104 deletions.
235 changes: 137 additions & 98 deletions src/ethernet.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@
ADVERTISED_40000baseSR4_Full | \
ADVERTISED_40000baseLR4_Full)

static int __ni_system_ethernet_get(const char *, ni_ethernet_t *);
static int __ni_system_ethernet_set(const char *, const ni_ethernet_t *);
static void __ni_system_ethernet_get(const char *, ni_ethernet_t *);
static void __ni_system_ethernet_set(const char *, ni_ethernet_t *);
static int __ni_ethtool_get_gset(const char *, ni_ethernet_t *);
static void ni_ethtool_offload_init(ni_ethtool_offload_t *);

/*
Expand Down Expand Up @@ -255,23 +256,9 @@ typedef struct __ni_ioctl_info {
#endif

static __ni_ioctl_info_t __ethtool_gflags = { ETHTOOL_GFLAGS, "GFLAGS" };
static __ni_ioctl_info_t __ethtool_grxcsum = { ETHTOOL_GRXCSUM, "GRXCSUM" };
static __ni_ioctl_info_t __ethtool_gtxcsum = { ETHTOOL_GTXCSUM, "GTXCSUM" };
static __ni_ioctl_info_t __ethtool_gsg = { ETHTOOL_GSG, "GSG" };
static __ni_ioctl_info_t __ethtool_gtso = { ETHTOOL_GTSO, "GTSO" };
static __ni_ioctl_info_t __ethtool_gufo = { ETHTOOL_GUFO, "GUFO" };
static __ni_ioctl_info_t __ethtool_ggso = { ETHTOOL_GGSO, "GGSO" };
static __ni_ioctl_info_t __ethtool_ggro = { ETHTOOL_GGRO, "GGRO" };
static __ni_ioctl_info_t __ethtool_sflags = { ETHTOOL_SFLAGS, "SFLAGS" };
static __ni_ioctl_info_t __ethtool_gstrings = { ETHTOOL_GSTRINGS, "GSTRINGS" };
static __ni_ioctl_info_t __ethtool_gstats = { ETHTOOL_GSTATS, "GSTATS" };
static __ni_ioctl_info_t __ethtool_sflags = { ETHTOOL_SFLAGS, "SFLAGS" };
static __ni_ioctl_info_t __ethtool_srxcsum = { ETHTOOL_SRXCSUM, "SRXCSUM" };
static __ni_ioctl_info_t __ethtool_stxcsum = { ETHTOOL_STXCSUM, "STXCSUM" };
static __ni_ioctl_info_t __ethtool_ssg = { ETHTOOL_SSG, "SSG" };
static __ni_ioctl_info_t __ethtool_stso = { ETHTOOL_STSO, "STSO" };
static __ni_ioctl_info_t __ethtool_sufo = { ETHTOOL_SUFO, "SUFO" };
static __ni_ioctl_info_t __ethtool_sgso = { ETHTOOL_SGSO, "SGSO" };
static __ni_ioctl_info_t __ethtool_sgro = { ETHTOOL_SGRO, "SGRO" };
static __ni_ioctl_info_t __ethtool_gwol = { ETHTOOL_GWOL, "GWOL" };
static __ni_ioctl_info_t __ethtool_swol = { ETHTOOL_SWOL, "SWOL" };

Expand Down Expand Up @@ -529,6 +516,102 @@ ni_ethtool_offload_init(ni_ethtool_offload_t *offload)
offload->lro = NI_TRISTATE_DEFAULT;
}
}

static int
__ni_ethtool_get_offload(const char *ifname, ni_ethtool_offload_t *offload)
{
__ni_ioctl_info_t __ethtool_grxcsum = { ETHTOOL_GRXCSUM, "GRXCSUM" };
__ni_ioctl_info_t __ethtool_gtxcsum = { ETHTOOL_GTXCSUM, "GTXCSUM" };
__ni_ioctl_info_t __ethtool_gsg = { ETHTOOL_GSG, "GSG" };
__ni_ioctl_info_t __ethtool_gtso = { ETHTOOL_GTSO, "GTSO" };
__ni_ioctl_info_t __ethtool_gufo = { ETHTOOL_GUFO, "GUFO" };
__ni_ioctl_info_t __ethtool_ggso = { ETHTOOL_GGSO, "GGSO" };
__ni_ioctl_info_t __ethtool_ggro = { ETHTOOL_GGRO, "GGRO" };

int value;

if (ni_string_empty(ifname) || !offload)
return -1;

offload->rx_csum = __ni_ethtool_get_tristate(ifname, &__ethtool_grxcsum);
offload->tx_csum = __ni_ethtool_get_tristate(ifname, &__ethtool_gtxcsum);
offload->scatter_gather = __ni_ethtool_get_tristate(ifname, &__ethtool_gsg);
offload->tso = __ni_ethtool_get_tristate(ifname, &__ethtool_gtso);
offload->ufo = __ni_ethtool_get_tristate(ifname, &__ethtool_gufo);
offload->gso = __ni_ethtool_get_tristate(ifname, &__ethtool_ggso);
offload->gro = __ni_ethtool_get_tristate(ifname, &__ethtool_ggro);

value = __ni_ethtool_get_value(ifname, &__ethtool_gflags);
if (value >= 0) {
offload->lro = (value & ETH_FLAG_LRO) ?
NI_TRISTATE_ENABLE : NI_TRISTATE_DISABLE;
}

return 0;
}

static int
__ni_ethtool_set_offload(const char *ifname, ni_ethtool_offload_t *offload)
{
__ni_ioctl_info_t __ethtool_srxcsum = { ETHTOOL_SRXCSUM, "SRXCSUM" };
__ni_ioctl_info_t __ethtool_stxcsum = { ETHTOOL_STXCSUM, "STXCSUM" };
__ni_ioctl_info_t __ethtool_ssg = { ETHTOOL_SSG, "SSG" };
__ni_ioctl_info_t __ethtool_stso = { ETHTOOL_STSO, "STSO" };
__ni_ioctl_info_t __ethtool_sufo = { ETHTOOL_SUFO, "SUFO" };
__ni_ioctl_info_t __ethtool_sgso = { ETHTOOL_SGSO, "SGSO" };
__ni_ioctl_info_t __ethtool_sgro = { ETHTOOL_SGRO, "SGRO" };

if (ni_string_empty(ifname) || !offload)
return -1;

__ni_ethtool_set_tristate(ifname, &__ethtool_srxcsum, offload->rx_csum);
__ni_ethtool_set_tristate(ifname, &__ethtool_stxcsum, offload->tx_csum);
__ni_ethtool_set_tristate(ifname, &__ethtool_ssg, offload->scatter_gather);
__ni_ethtool_set_tristate(ifname, &__ethtool_stso, offload->tso);
__ni_ethtool_set_tristate(ifname, &__ethtool_sufo, offload->ufo);
__ni_ethtool_set_tristate(ifname, &__ethtool_sgso, offload->gso);
__ni_ethtool_set_tristate(ifname, &__ethtool_sgro, offload->gro);

if (offload->lro != NI_TRISTATE_DEFAULT) {
int value = __ni_ethtool_get_value(ifname, &__ethtool_gflags);

if (value >= 0) {
if (offload->lro == NI_TRISTATE_ENABLE)
value |= ETH_FLAG_LRO;
else
value &= ~ETH_FLAG_LRO;
}

__ni_ethtool_set_value(ifname, &__ethtool_sflags, value);
}

return 0;
}

static int
__ni_ethtool_get_permanent_address(const char *ifname, ni_hwaddr_t *perm_addr)
{
struct {
struct ethtool_perm_addr h;
unsigned char data[NI_MAXHWADDRLEN];
} parm;

if (ni_string_empty(ifname) || !perm_addr)
return -1;

memset(&parm, 0, sizeof(parm));
parm.h.size = sizeof(parm.data);
if (__ni_ethtool(ifname, ETHTOOL_GPERMADDR, &parm) < 0) {
ni_debug_ifconfig("%s: ETHTOOL_GPERMADDR failed", ifname);
return -1;
}
else if (ni_link_address_length(perm_addr->type) == parm.h.size) {
ni_link_address_set(perm_addr, perm_addr->type, parm.data, parm.h.size);
}

return 0;
}

/*
* Handle ethtool stats
*/
Expand Down Expand Up @@ -569,27 +652,42 @@ __ni_ethtool_stats_free(ni_ethtool_stats_t *stats)
/*
* Get ethtool settings from the kernel
*/
int
void
__ni_system_ethernet_refresh(ni_netdev_t *dev)
{
ni_ethernet_t *ether;

ether = ni_ethernet_new();
ether->permanent_address.type = dev->link.hwaddr.type;
if (__ni_system_ethernet_get(dev->name, ether) < 0) {
ni_ethernet_free(ether);
return -1;
}
__ni_system_ethernet_get(dev->name, ether);

ni_netdev_set_ethernet(dev, ether);
return 0;
}

int
void
__ni_system_ethernet_get(const char *ifname, ni_ethernet_t *ether)
{
__ni_ethtool_get_wol(ifname, &ether->wol);
__ni_ethtool_get_offload(ifname, &ether->offload);
__ni_ethtool_get_permanent_address(ifname, &ether->permanent_address);
__ni_ethtool_get_gset(ifname, ether);
}

/*
* Write ethtool settings back to kernel
*/
void
__ni_system_ethernet_update(ni_netdev_t *dev, ni_ethernet_t *ether)
{
__ni_system_ethernet_set(dev->name, ether);
__ni_system_ethernet_refresh(dev);
}

static int
__ni_ethtool_get_gset(const char *ifname, ni_ethernet_t *ether)
{
struct ethtool_cmd ecmd;
int mapped, value;
int mapped;

memset(&ecmd, 0, sizeof(ecmd));
if (__ni_ethtool(ifname, ETHTOOL_GSET, &ecmd) < 0) {
Expand Down Expand Up @@ -618,60 +716,16 @@ __ni_system_ethernet_get(const char *ifname, ni_ethernet_t *ether)
else
ether->port_type = mapped;

ether->autoneg_enable = (ecmd.autoneg? NI_TRISTATE_ENABLE : NI_TRISTATE_DISABLE);
ether->autoneg_enable = (ecmd.autoneg ? NI_TRISTATE_ENABLE : NI_TRISTATE_DISABLE);

/* Not used yet:
phy_address
transceiver
*/

__ni_ethtool_get_wol(ifname, &ether->wol);

ether->offload.rx_csum = __ni_ethtool_get_tristate(ifname, &__ethtool_grxcsum);
ether->offload.tx_csum = __ni_ethtool_get_tristate(ifname, &__ethtool_gtxcsum);
ether->offload.scatter_gather = __ni_ethtool_get_tristate(ifname, &__ethtool_gsg);
ether->offload.tso = __ni_ethtool_get_tristate(ifname, &__ethtool_gtso);
ether->offload.ufo = __ni_ethtool_get_tristate(ifname, &__ethtool_gufo);
ether->offload.gso = __ni_ethtool_get_tristate(ifname, &__ethtool_ggso);
ether->offload.gro = __ni_ethtool_get_tristate(ifname, &__ethtool_ggro);

value = __ni_ethtool_get_value(ifname, &__ethtool_gflags);
if (value >= 0)
ether->offload.lro = (value & ETH_FLAG_LRO)? NI_TRISTATE_ENABLE : NI_TRISTATE_DISABLE;

/* Get the permanent address */
{
struct {
struct ethtool_perm_addr h;
unsigned char data[NI_MAXHWADDRLEN];
} parm;

memset(&parm, 0, sizeof(parm));
parm.h.size = sizeof(parm.data);
if (__ni_ethtool(ifname, ETHTOOL_GPERMADDR, &parm) < 0) {
ni_debug_ifconfig("%s: ETHTOOL_GPERMADDR failed", ifname);
} else
if (ni_link_address_length(ether->permanent_address.type) == parm.h.size) {
ni_link_address_set(&ether->permanent_address,
ether->permanent_address.type,
parm.data, parm.h.size);
}
}

return 0;
}

/*
* Write ethtool settings back to kernel
*/
int
__ni_system_ethernet_update(ni_netdev_t *dev, const ni_ethernet_t *ether)
{
__ni_system_ethernet_set(dev->name, ether);

return __ni_system_ethernet_refresh(dev);
}

/*
* Based on ecmd.speed and ecmd.duplex, determine ecmd.advertising.
*/
Expand Down Expand Up @@ -733,15 +787,11 @@ __ni_system_ethernet_set_advertising(const char *ifname, struct ethtool_cmd *ecm
}
}

int
__ni_system_ethernet_set(const char *ifname, const ni_ethernet_t *ether)
static int
__ni_ethtool_set_sset(const char *ifname, const ni_ethernet_t *ether)
{
struct ethtool_cmd ecmd;
int mapped, value;

if (__ni_ethtool_set_wol(ifname, &ether->wol) < 0) {
; /* do not fail completely, error is logged */
}
int mapped;

memset(&ecmd, 0, sizeof(ecmd));
if (__ni_ethtool(ifname, ETHTOOL_GSET, &ecmd) < 0) {
Expand Down Expand Up @@ -786,34 +836,23 @@ __ni_system_ethernet_set(const char *ifname, const ni_ethernet_t *ether)
transceiver
*/

__ni_ethtool_set_tristate(ifname, &__ethtool_srxcsum, ether->offload.rx_csum);
__ni_ethtool_set_tristate(ifname, &__ethtool_stxcsum, ether->offload.tx_csum);
__ni_ethtool_set_tristate(ifname, &__ethtool_ssg, ether->offload.scatter_gather);
__ni_ethtool_set_tristate(ifname, &__ethtool_stso, ether->offload.tso);
__ni_ethtool_set_tristate(ifname, &__ethtool_sufo, ether->offload.ufo);
__ni_ethtool_set_tristate(ifname, &__ethtool_sgso, ether->offload.gso);
__ni_ethtool_set_tristate(ifname, &__ethtool_sgro, ether->offload.gro);

if (ether->offload.lro != NI_TRISTATE_DEFAULT) {
value = __ni_ethtool_get_value(ifname, &__ethtool_gflags);
if (value >= 0) {
if (ether->offload.lro == NI_TRISTATE_ENABLE)
value |= ETH_FLAG_LRO;
else
value &= ~ETH_FLAG_LRO;
}
__ni_ethtool_set_value(ifname, &__ethtool_sflags, value);
}

__ni_system_ethernet_set_advertising(ifname, &ecmd);

if (__ni_ethtool(ifname, ETHTOOL_SSET, &ecmd) < 0) {
if (errno != EOPNOTSUPP)
ni_warn("%s: ETHTOOL_GSET failed: %m", ifname);
ni_warn("%s: ETHTOOL_SSET failed: %m", ifname);
else
ni_debug_ifconfig("%s: ETHTOOL_GSET: %m", ifname);
ni_debug_ifconfig("%s: ETHTOOL_SSET: %m", ifname);
return -1;
}

return 0;
}

void
__ni_system_ethernet_set(const char *ifname, ni_ethernet_t *ether)
{
__ni_ethtool_set_wol(ifname, &ether->wol);
__ni_ethtool_set_offload(ifname, &ether->offload);
__ni_ethtool_set_sset(ifname, ether);
}
5 changes: 1 addition & 4 deletions src/ifconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -1296,10 +1296,7 @@ ni_system_ethernet_setup(ni_netconfig_t *nc, ni_netdev_t *dev, const ni_netdev_t
if (!dev || !cfg || !cfg->ethernet)
return -1;

if (__ni_system_ethernet_update(dev, cfg->ethernet) < 0) {
ni_error("%s: failed to update ethernet device settings", dev->name);
return -1;
}
__ni_system_ethernet_update(dev, cfg->ethernet);
return 0;
}

Expand Down
4 changes: 2 additions & 2 deletions src/netinfo_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ extern int __ni_system_interface_delete(ni_netconfig_t *, const char *);
extern int __ni_system_interface_stats_refresh(ni_netconfig_t *, ni_netdev_t *);
extern int __ni_system_interface_flush_addrs(ni_netconfig_t *, ni_netdev_t *);
extern int __ni_system_interface_flush_routes(ni_netconfig_t *, ni_netdev_t *);
extern int __ni_system_ethernet_refresh(ni_netdev_t *);
extern int __ni_system_ethernet_update(ni_netdev_t *, const ni_ethernet_t *);
extern void __ni_system_ethernet_refresh(ni_netdev_t *);
extern void __ni_system_ethernet_update(ni_netdev_t *, ni_ethernet_t *);

/* FIXME: These should go elsewhere, maybe runtime.h */
extern int __ni_system_interface_update_lease(ni_netdev_t *, ni_addrconf_lease_t **);
Expand Down

0 comments on commit f763505

Please sign in to comment.