platform: clear all BASE types when setting advertised modes for ethernet autoneg

Get the list of supported flags from ethtool utility ([1]).

When we enable auto-negotiation, the user may select only one mode to
be advertised. But then we need to clear all other modes, the previous
define BASET_ALL_MODES did not cover them all.

[1] https://git.kernel.org/pub/scm/network/ethtool/ethtool.git/tree/ethtool.c?id=7cca9692b9b0c4e2c7eb7868a7791f97202014b0#n397
This commit is contained in:
Thomas Haller 2021-08-30 17:31:49 +02:00
parent 595099f27a
commit 34d48d2596
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
3 changed files with 144 additions and 12 deletions

View file

@ -9,7 +9,6 @@
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/ethtool.h>
#include <linux/sockios.h>
#include <linux/mii.h>
#include <linux/if.h>
@ -18,6 +17,7 @@
#include <fcntl.h>
#include <libudev.h>
#include "linux-headers/ethtool.h"
#include "libnm-base/nm-ethtool-base.h"
#include "libnm-log-core/nm-logging.h"
#include "libnm-glib-aux/nm-time-utils.h"
@ -1331,10 +1331,6 @@ nmp_utils_ethtool_get_link_settings(int ifindex,
}
#define ADVERTISED_INVALID 0
#define BASET_ALL_MODES \
(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half \
| ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full \
| ADVERTISED_10000baseT_Full)
static guint32
get_baset_mode(guint32 speed, NMPlatformLinkDuplexType duplex)
@ -1386,6 +1382,96 @@ platform_link_duplex_type_to_native(NMPlatformLinkDuplexType duplex_type, guint8
}
}
const guint8 _nmp_link_mode_all_advertised_modes_bits[] = {
ETHTOOL_LINK_MODE_10baseT_Half_BIT,
ETHTOOL_LINK_MODE_10baseT_Full_BIT,
ETHTOOL_LINK_MODE_100baseT_Half_BIT,
ETHTOOL_LINK_MODE_100baseT_Full_BIT,
ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
ETHTOOL_LINK_MODE_10000baseR_FEC_BIT,
ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT,
ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT,
ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT,
ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT,
ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT,
ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT,
ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT,
ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT,
ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT,
ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT,
ETHTOOL_LINK_MODE_25000baseCR_Full_BIT,
/* 32 bit flags start here. */
ETHTOOL_LINK_MODE_25000baseKR_Full_BIT,
ETHTOOL_LINK_MODE_25000baseSR_Full_BIT,
ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT,
ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT,
ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT,
ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT,
ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT,
ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT,
ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT,
ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
ETHTOOL_LINK_MODE_50000baseKR_Full_BIT,
ETHTOOL_LINK_MODE_50000baseSR_Full_BIT,
ETHTOOL_LINK_MODE_50000baseCR_Full_BIT,
ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
ETHTOOL_LINK_MODE_50000baseDR_Full_BIT,
ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT,
ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT,
ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT,
ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT,
ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT,
ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT,
ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT,
ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT,
ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT,
ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT,
ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT,
ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT,
ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT,
ETHTOOL_LINK_MODE_100000baseKR_Full_BIT,
ETHTOOL_LINK_MODE_100000baseSR_Full_BIT,
ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT,
ETHTOOL_LINK_MODE_100000baseCR_Full_BIT,
ETHTOOL_LINK_MODE_100000baseDR_Full_BIT,
ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT,
ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT,
ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT,
ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT,
ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT,
ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT,
ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT,
ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT,
ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT,
ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT,
ETHTOOL_LINK_MODE_100baseFX_Half_BIT,
ETHTOOL_LINK_MODE_100baseFX_Full_BIT,
};
/* these are the bits from _nmp_link_mode_all_advertised_modes_bits set. */
const guint32 _nmp_link_mode_all_advertised_modes[] = {
0xfffe903fu,
0xfff1ffffu,
0x0ffffbffu,
};
static NMOptionBool
set_link_settings_new(SocketHandle * shandle,
gboolean autoneg,
@ -1396,6 +1482,7 @@ set_link_settings_new(SocketHandle * shandle,
gs_free struct ethtool_link_settings *edata = NULL;
gsize edata_size;
guint nwords;
guint i;
edata0 = (struct ethtool_link_settings){
.cmd = ETHTOOL_GLINKSETTINGS,
@ -1445,7 +1532,6 @@ set_link_settings_new(SocketHandle * shandle,
return FALSE;
}
/* We only support BASE-T modes in the first word */
if (!(v_map_supported[0] & mode)) {
nm_log_trace(LOGD_PLATFORM,
"ethtool[%d]: device does not support %uBASE-T %s duplex mode",
@ -1455,7 +1541,9 @@ set_link_settings_new(SocketHandle * shandle,
return FALSE;
}
v_map_advertising[0] = (v_map_advertising[0] & ~BASET_ALL_MODES) | mode;
for (i = 0; i < (guint) G_N_ELEMENTS(_nmp_link_mode_all_advertised_modes); i++)
v_map_advertising[i] &= ~_nmp_link_mode_all_advertised_modes[i];
v_map_advertising[0] |= mode;
}
} else {
edata->autoneg = AUTONEG_DISABLE;
@ -1499,10 +1587,9 @@ nmp_utils_ethtool_set_link_settings(int ifindex,
/* then change the needed ones */
edata.cmd = ETHTOOL_SSET;
if (autoneg) {
edata.autoneg = AUTONEG_ENABLE;
if (speed == 0)
edata.advertising = edata.supported;
else {
edata.autoneg = AUTONEG_ENABLE;
edata.advertising = edata.supported;
if (speed != 0) {
guint32 mode;
mode = get_baset_mode(speed, duplex);
@ -1523,7 +1610,8 @@ nmp_utils_ethtool_set_link_settings(int ifindex,
nm_platform_link_duplex_type_to_string(duplex));
return FALSE;
}
edata.advertising = (edata.supported & ~BASET_ALL_MODES) | mode;
edata.advertising &= ~_nmp_link_mode_all_advertised_modes[0];
edata.advertising |= mode;
}
} else {
edata.autoneg = AUTONEG_DISABLE;

View file

@ -22,6 +22,9 @@ gboolean nmp_utils_ethtool_set_wake_on_lan(int ifindex,
const char *nm_platform_link_duplex_type_to_string(NMPlatformLinkDuplexType duplex);
extern const guint8 _nmp_link_mode_all_advertised_modes_bits[79];
extern const guint32 _nmp_link_mode_all_advertised_modes[3];
gboolean nmp_utils_ethtool_get_link_settings(int ifindex,
gboolean * out_autoneg,
guint32 * out_speed,

View file

@ -5,6 +5,7 @@
#include "libnm-log-core/nm-logging.h"
#include "libnm-platform/nm-netlink.h"
#include "libnm-platform/nmp-netns.h"
#include "libnm-platform/nm-platform-utils.h"
#include "libnm-glib-aux/nm-test-utils.h"
@ -103,6 +104,44 @@ test_use_symbols(void)
/*****************************************************************************/
static void
test_nmp_link_mode_all_advertised_modes_bits(void)
{
guint32 flags[(SCHAR_MAX + 1) / 32];
guint max_bit;
int i;
memset(flags, 0, sizeof(flags));
max_bit = 0;
for (i = 0; i < (int) G_N_ELEMENTS(_nmp_link_mode_all_advertised_modes_bits); i++) {
if (i > 0) {
g_assert_cmpint(_nmp_link_mode_all_advertised_modes_bits[i - 1],
<,
_nmp_link_mode_all_advertised_modes_bits[i]);
}
g_assert_cmpint(_nmp_link_mode_all_advertised_modes_bits[i], <, SCHAR_MAX);
g_assert_cmpint(_nmp_link_mode_all_advertised_modes_bits[i] / 32, <, G_N_ELEMENTS(flags));
flags[_nmp_link_mode_all_advertised_modes_bits[i] / 32] |=
(1u << (_nmp_link_mode_all_advertised_modes_bits[i] % 32u));
max_bit = NM_MAX(max_bit, _nmp_link_mode_all_advertised_modes_bits[i]);
}
g_assert_cmpint((max_bit + 31u) / 32u, ==, G_N_ELEMENTS(_nmp_link_mode_all_advertised_modes));
for (i = 0; i < (int) G_N_ELEMENTS(_nmp_link_mode_all_advertised_modes); i++) {
if (flags[i] != _nmp_link_mode_all_advertised_modes[i]) {
g_error("_nmp_link_mode_all_advertised_modes[%d] should be 0x%0x but is 0x%0x "
"(according to the bits in _nmp_link_mode_all_advertised_modes_bits)",
i,
flags[i],
_nmp_link_mode_all_advertised_modes[i]);
}
}
}
/*****************************************************************************/
NMTST_DEFINE();
int
@ -111,6 +150,8 @@ main(int argc, char **argv)
nmtst_init(&argc, &argv, TRUE);
g_test_add_func("/nm-platform/test_use_symbols", test_use_symbols);
g_test_add_func("/nm-platform/test_nmp_link_mode_all_advertised_modes_bits",
test_nmp_link_mode_all_advertised_modes_bits);
return g_test_run();
}