diff options
Diffstat (limited to 'src/libnm-platform')
| -rw-r--r-- | src/libnm-platform/nm-platform-utils.c | 198 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform-utils.h | 3 | ||||
| -rw-r--r-- | src/libnm-platform/nm-platform.c | 39 | ||||
| -rw-r--r-- | src/libnm-platform/tests/test-nm-platform.c | 41 | ||||
| -rw-r--r-- | src/libnm-platform/wpan/nm-wpan-utils.c | 3 |
5 files changed, 238 insertions, 46 deletions
diff --git a/src/libnm-platform/nm-platform-utils.c b/src/libnm-platform/nm-platform-utils.c index 2470704a..ce847451 100644 --- a/src/libnm-platform/nm-platform-utils.c +++ b/src/libnm-platform/nm-platform-utils.c @@ -7,9 +7,10 @@ #include "nm-platform-utils.h" +#include "libnm-std-aux/nm-linux-compat.h" + #include <unistd.h> #include <sys/ioctl.h> -#include <linux/ethtool.h> #include <linux/sockios.h> #include <linux/mii.h> #include <linux/if.h> @@ -1331,10 +1332,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 +1383,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 +1483,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, @@ -1421,16 +1509,14 @@ set_link_settings_new(SocketHandle * shandle, /* then change the needed ones */ edata->cmd = ETHTOOL_SLINKSETTINGS; - if (autoneg) { - edata->autoneg = AUTONEG_ENABLE; - /* copy @map_supported to @map_advertising and @map_lp_advertising */ - memcpy(&edata->link_mode_masks[nwords], - &edata->link_mode_masks[0], - sizeof(guint32) * nwords); - memcpy(&edata->link_mode_masks[nwords * 2], - &edata->link_mode_masks[0], - sizeof(guint32) * nwords); + { + const guint32 *v_map_supported = &edata->link_mode_masks[0]; + guint32 * v_map_advertising = &edata->link_mode_masks[nwords]; + guint32 * v_map_lp_advertising = &edata->link_mode_masks[2 * nwords]; + + memcpy(v_map_advertising, v_map_supported, sizeof(guint32) * nwords); + (void) v_map_lp_advertising; if (speed != 0) { guint32 mode; @@ -1438,6 +1524,8 @@ set_link_settings_new(SocketHandle * shandle, mode = get_baset_mode(speed, duplex); if (mode == ADVERTISED_INVALID) { + if (!autoneg) + goto set_autoneg; nm_log_trace(LOGD_PLATFORM, "ethtool[%d]: %uBASE-T %s duplex mode cannot be advertised", shandle->ifindex, @@ -1446,8 +1534,9 @@ set_link_settings_new(SocketHandle * shandle, return FALSE; } - /* We only support BASE-T modes in the first word */ - if (!(edata->link_mode_masks[0] & mode)) { + if (!(v_map_supported[0] & mode)) { + if (!autoneg) + goto set_autoneg; nm_log_trace(LOGD_PLATFORM, "ethtool[%d]: device does not support %uBASE-T %s duplex mode", shandle->ifindex, @@ -1456,11 +1545,16 @@ set_link_settings_new(SocketHandle * shandle, return FALSE; } - edata->link_mode_masks[nwords] = - (edata->link_mode_masks[nwords] & ~BASET_ALL_MODES) | mode; - edata->link_mode_masks[nwords * 2] = edata->link_mode_masks[nwords]; + 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 { + } + +set_autoneg: + if (autoneg) + edata->autoneg = AUTONEG_ENABLE; + else { edata->autoneg = AUTONEG_DISABLE; if (speed) @@ -1489,6 +1583,13 @@ nmp_utils_ethtool_set_link_settings(int ifindex, || (!speed && duplex == NM_PLATFORM_LINK_DUPLEX_UNKNOWN), FALSE); + nm_log_trace(LOGD_PLATFORM, + "ethtool[%d]: set link: autoneg=%d, speed=%d, duplex=%s", + ifindex, + autoneg, + speed, + nm_platform_link_duplex_type_to_string(duplex)); + ret = set_link_settings_new(&shandle, autoneg, speed, duplex); if (ret != NM_OPTION_BOOL_DEFAULT) return ret; @@ -1501,34 +1602,41 @@ 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 { - guint32 mode; - mode = get_baset_mode(speed, duplex); + edata.advertising = edata.supported; + if (speed != 0) { + guint32 mode; - if (mode == ADVERTISED_INVALID) { - nm_log_trace(LOGD_PLATFORM, - "ethtool[%d]: %uBASE-T %s duplex mode cannot be advertised", - ifindex, - speed, - nm_platform_link_duplex_type_to_string(duplex)); - return FALSE; - } - if (!(edata.supported & mode)) { - nm_log_trace(LOGD_PLATFORM, - "ethtool[%d]: device does not support %uBASE-T %s duplex mode", - ifindex, - speed, - nm_platform_link_duplex_type_to_string(duplex)); - return FALSE; - } - edata.advertising = (edata.supported & ~BASET_ALL_MODES) | mode; + mode = get_baset_mode(speed, duplex); + + if (mode == ADVERTISED_INVALID) { + if (!autoneg) + goto set_autoneg; + nm_log_trace(LOGD_PLATFORM, + "ethtool[%d]: %uBASE-T %s duplex mode cannot be advertised", + ifindex, + speed, + nm_platform_link_duplex_type_to_string(duplex)); + return FALSE; } - } else { + if (!(edata.supported & mode)) { + if (!autoneg) + goto set_autoneg; + nm_log_trace(LOGD_PLATFORM, + "ethtool[%d]: device does not support %uBASE-T %s duplex mode", + ifindex, + speed, + nm_platform_link_duplex_type_to_string(duplex)); + return FALSE; + } + edata.advertising &= ~_nmp_link_mode_all_advertised_modes[0]; + edata.advertising |= mode; + } + +set_autoneg: + if (autoneg) + edata.autoneg = AUTONEG_ENABLE; + else { edata.autoneg = AUTONEG_DISABLE; if (speed) diff --git a/src/libnm-platform/nm-platform-utils.h b/src/libnm-platform/nm-platform-utils.h index d70f4385..5511e8af 100644 --- a/src/libnm-platform/nm-platform-utils.h +++ b/src/libnm-platform/nm-platform-utils.h @@ -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, diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c index 6c0d0015..b7a65df5 100644 --- a/src/libnm-platform/nm-platform.c +++ b/src/libnm-platform/nm-platform.c @@ -4304,6 +4304,7 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self, CList * iter; NMPlatformIP4Route rt_local4; NMPlatformIP6Route rt_local6; + NMPlatformIP6Route rt_mcast6; const NMPlatformLink * pllink; const NMPlatformLnkVrf * lnk_vrf; guint32 local_table; @@ -4328,6 +4329,7 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self, rt_local4.plen = 0; rt_local6.plen = 0; + rt_mcast6.plen = 0; routes_prune = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref); @@ -4420,6 +4422,43 @@ nm_platform_ip_route_get_prune_list(NMPlatform * self, == 0) continue; } + + /* Kernels < 5.11 add a route like: + * + * unicast ff00::/8 dev $IFACE proto boot scope global metric 256 pref medium + * + * to allow sending and receiving IPv6 multicast traffic. Don't remove it. + * Since kernel 5.11 the route looks like: + * + * multicast ff00::/8 dev $IFACE proto kernel metric 256 pref medium + * + * As NM ignores routes with rtm_type multicast, there is no need for the code + * below on newer kernels. + */ + if (nm_platform_ip_route_get_effective_table(&rt->rx) == local_table + && rt->rx.plen == 8 && rt->rx.rt_source == NM_IP_CONFIG_SOURCE_RTPROT_BOOT + && rt->rx.metric == 256 && rt->r6.rt_pref == NM_ICMPV6_ROUTER_PREF_MEDIUM + && IN6_IS_ADDR_UNSPECIFIED(&rt->r6.gateway)) { + if (rt_mcast6.plen == 0) { + rt_mcast6 = (NMPlatformIP6Route){ + .ifindex = ifindex, + .type_coerced = nm_platform_route_type_coerce(RTN_UNICAST), + .plen = 8, + .rt_source = NM_IP_CONFIG_SOURCE_RTPROT_BOOT, + .metric = 256, + .table_coerced = nm_platform_route_table_coerce(local_table), + .rt_pref = NM_ICMPV6_ROUTER_PREF_MEDIUM, + .gateway = IN6ADDR_ANY_INIT, + .network = {{{0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}}, + }; + } + + if (nm_platform_ip6_route_cmp(&rt->r6, + &rt_mcast6, + NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) + == 0) + continue; + } } break; diff --git a/src/libnm-platform/tests/test-nm-platform.c b/src/libnm-platform/tests/test-nm-platform.c index 5b1b8e87..d4de0dd5 100644 --- a/src/libnm-platform/tests/test-nm-platform.c +++ b/src/libnm-platform/tests/test-nm-platform.c @@ -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(); } diff --git a/src/libnm-platform/wpan/nm-wpan-utils.c b/src/libnm-platform/wpan/nm-wpan-utils.c index 5c2917b4..082cc3e7 100644 --- a/src/libnm-platform/wpan/nm-wpan-utils.c +++ b/src/libnm-platform/wpan/nm-wpan-utils.c @@ -7,11 +7,12 @@ #include "nm-wpan-utils.h" +#include "libnm-std-aux/nm-linux-compat.h" + #include <linux/if.h> #include "libnm-log-core/nm-logging.h" #include "libnm-platform/nm-netlink.h" -#include "linux-headers/nl802154.h" #include "libnm-platform/nm-platform-utils.h" #define _NMLOG_PREFIX_NAME "wpan-nl802154" |