Skip to content

Commit d923b2a

Browse files
david-marchandigsilya
authored andcommitted
netdev: Fix full duplex capability for 25G ports.
As OVS does not know of the 25G speed, matching on a list of known speed for deducing full duplex capability is broken. Add a new netdev op to retrieve the duplex status for the existing netdev implementations. Reported-at: https://issues.redhat.com/browse/FDP-883 Acked-by: Eelco Chaudron <[email protected]> Acked-by: Mike Pattrick <[email protected]> Signed-off-by: David Marchand <[email protected]> Signed-off-by: Ilya Maximets <[email protected]>
1 parent 4b71e1c commit d923b2a

File tree

10 files changed

+129
-10
lines changed

10 files changed

+129
-10
lines changed

include/openvswitch/netdev.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ int netdev_get_speed(const struct netdev *, uint32_t *current, uint32_t *max);
136136
uint64_t netdev_features_to_bps(enum netdev_features features,
137137
uint64_t default_bps);
138138
bool netdev_features_is_full_duplex(enum netdev_features features);
139+
int netdev_get_duplex(const struct netdev *, bool *full_duplex);
139140
int netdev_set_advertisements(struct netdev *, enum netdev_features advertise);
140141
void netdev_features_format(struct ds *, enum netdev_features);
141142

lib/netdev-bsd.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ struct netdev_bsd {
9797
enum netdev_features current;
9898
enum netdev_features advertised;
9999
enum netdev_features supported;
100+
bool full_duplex;
100101

101102
int tap_fd; /* TAP character device, if any, otherwise -1. */
102103

@@ -1155,6 +1156,7 @@ netdev_bsd_read_features(struct netdev_bsd *netdev)
11551156
if (!netdev->current) {
11561157
netdev->current = NETDEV_F_OTHER;
11571158
}
1159+
netdev->full_duplex = ifmr.ifm_active & IFM_FDX;
11581160

11591161
/* Advertised features. */
11601162
netdev->advertised = netdev_bsd_parse_media(ifmr.ifm_current);
@@ -1225,6 +1227,23 @@ netdev_bsd_get_speed(const struct netdev *netdev_, uint32_t *current,
12251227
return error;
12261228
}
12271229

1230+
static int
1231+
netdev_bsd_get_duplex(const struct netdev *netdev_, bool *full_duplex)
1232+
{
1233+
struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
1234+
int error;
1235+
1236+
ovs_mutex_lock(&netdev->mutex);
1237+
netdev_bsd_read_features(netdev);
1238+
if (!netdev->get_features_error) {
1239+
*full_duplex = netdev->full_duplex;
1240+
}
1241+
error = netdev->get_features_error;
1242+
ovs_mutex_unlock(&netdev->mutex);
1243+
1244+
return error;
1245+
}
1246+
12281247
/*
12291248
* Assigns 'addr' as 'netdev''s IPv4 address and 'mask' as its netmask. If
12301249
* 'addr' is INADDR_ANY, 'netdev''s IPv4 address is cleared. Returns a
@@ -1553,6 +1572,7 @@ netdev_bsd_update_flags(struct netdev *netdev_, enum netdev_flags off,
15531572
.get_stats = netdev_bsd_get_stats, \
15541573
.get_features = netdev_bsd_get_features, \
15551574
.get_speed = netdev_bsd_get_speed, \
1575+
.get_duplex = netdev_bsd_get_duplex, \
15561576
.set_in4 = netdev_bsd_set_in4, \
15571577
.get_addr_list = netdev_bsd_get_addr_list, \
15581578
.get_next_hop = netdev_bsd_get_next_hop, \

lib/netdev-dpdk.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4176,6 +4176,23 @@ netdev_dpdk_get_speed(const struct netdev *netdev, uint32_t *current,
41764176
return 0;
41774177
}
41784178

4179+
static int
4180+
netdev_dpdk_get_duplex(const struct netdev *netdev, bool *full_duplex)
4181+
{
4182+
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
4183+
int err = 0;
4184+
4185+
ovs_mutex_lock(&dev->mutex);
4186+
if (dev->link.link_speed != RTE_ETH_SPEED_NUM_UNKNOWN) {
4187+
*full_duplex = dev->link.link_duplex == RTE_ETH_LINK_FULL_DUPLEX;
4188+
} else {
4189+
err = EOPNOTSUPP;
4190+
}
4191+
ovs_mutex_unlock(&dev->mutex);
4192+
4193+
return err;
4194+
}
4195+
41794196
static struct ingress_policer *
41804197
netdev_dpdk_policer_construct(uint32_t rate, uint32_t burst)
41814198
{
@@ -6888,6 +6905,7 @@ parse_vhost_config(const struct smap *ovs_other_config)
68886905
.get_custom_stats = netdev_dpdk_get_custom_stats, \
68896906
.get_features = netdev_dpdk_get_features, \
68906907
.get_speed = netdev_dpdk_get_speed, \
6908+
.get_duplex = netdev_dpdk_get_duplex, \
68916909
.get_status = netdev_dpdk_get_status, \
68926910
.reconfigure = netdev_dpdk_reconfigure, \
68936911
.rxq_recv = netdev_dpdk_rxq_recv

lib/netdev-linux-private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ struct netdev_linux {
9494
enum netdev_features advertised; /* Cached from ETHTOOL_GSET. */
9595
enum netdev_features supported; /* Cached from ETHTOOL_GSET. */
9696
uint32_t current_speed; /* Cached from ETHTOOL_GSET. */
97+
uint8_t current_duplex; /* Cached from ETHTOOL_GSET. */
9798

9899
struct ethtool_drvinfo drvinfo; /* Cached from ETHTOOL_GDRVINFO. */
99100
struct tc *tc;

lib/netdev-linux.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,10 +175,13 @@ static inline uint32_t rpl_ethtool_cmd_speed(const struct ethtool_cmd *ep)
175175
#define ADVERTISED_10000baseR_FEC (1 << 20)
176176
#endif
177177

178-
/* Linux 3.2 introduced "unknown" speed. */
178+
/* Linux 3.2 introduced "unknown" speed and duplex. */
179179
#ifndef SPEED_UNKNOWN
180180
#define SPEED_UNKNOWN -1
181181
#endif
182+
#ifndef DUPLEX_UNKNOWN
183+
#define DUPLEX_UNKNOWN 0xff
184+
#endif
182185

183186
/* Linux 3.5 introduced supported and advertised flags for
184187
* 40G base KR4, CR4, SR4 and LR4. */
@@ -2700,6 +2703,7 @@ netdev_linux_read_features(struct netdev_linux *netdev)
27002703
} else {
27012704
netdev->current = 0;
27022705
}
2706+
netdev->current_duplex = ecmd.duplex;
27032707

27042708
if (ecmd.port == PORT_TP) {
27052709
netdev->current |= NETDEV_F_COPPER;
@@ -2783,6 +2787,32 @@ netdev_linux_get_speed(const struct netdev *netdev_, uint32_t *current,
27832787
return error;
27842788
}
27852789

2790+
static int
2791+
netdev_linux_get_duplex(const struct netdev *netdev_, bool *full_duplex)
2792+
{
2793+
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
2794+
int err;
2795+
2796+
ovs_mutex_lock(&netdev->mutex);
2797+
2798+
if (netdev_linux_netnsid_is_remote(netdev)) {
2799+
err = EOPNOTSUPP;
2800+
goto exit;
2801+
}
2802+
2803+
netdev_linux_read_features(netdev);
2804+
err = netdev->get_features_error;
2805+
if (!err && netdev->current_duplex == DUPLEX_UNKNOWN) {
2806+
err = EOPNOTSUPP;
2807+
goto exit;
2808+
}
2809+
*full_duplex = netdev->current_duplex == DUPLEX_FULL;
2810+
2811+
exit:
2812+
ovs_mutex_unlock(&netdev->mutex);
2813+
return err;
2814+
}
2815+
27862816
/* Set the features advertised by 'netdev' to 'advertise'. */
27872817
static int
27882818
netdev_linux_set_advertisements(struct netdev *netdev_,
@@ -3907,6 +3937,7 @@ const struct netdev_class netdev_linux_class = {
39073937
.get_stats = netdev_linux_get_stats,
39083938
.get_features = netdev_linux_get_features,
39093939
.get_speed = netdev_linux_get_speed,
3940+
.get_duplex = netdev_linux_get_duplex,
39103941
.get_status = netdev_linux_get_status,
39113942
.get_block_id = netdev_linux_get_block_id,
39123943
.send = netdev_linux_send,
@@ -3924,6 +3955,7 @@ const struct netdev_class netdev_tap_class = {
39243955
.get_stats = netdev_tap_get_stats,
39253956
.get_features = netdev_linux_get_features,
39263957
.get_speed = netdev_linux_get_speed,
3958+
.get_duplex = netdev_linux_get_duplex,
39273959
.get_status = netdev_linux_get_status,
39283960
.send = netdev_linux_send,
39293961
.rxq_construct = netdev_linux_rxq_construct,

lib/netdev-provider.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,13 @@ struct netdev_class {
514514
int (*get_speed)(const struct netdev *netdev, uint32_t *current,
515515
uint32_t *max);
516516

517+
/* Stores the current duplex status of 'netdev' into '*full_duplex'.
518+
* 'true' means full duplex, 'false' means half duplex.
519+
*
520+
* This function may be set to null if it would always return EOPNOTSUPP.
521+
*/
522+
int (*get_duplex)(const struct netdev *netdev, bool *full_duplex);
523+
517524
/* Set the features advertised by 'netdev' to 'advertise', which is a
518525
* set of NETDEV_F_* bits.
519526
*

lib/netdev.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,37 @@ netdev_features_is_full_duplex(enum netdev_features features)
12981298
| NETDEV_F_100GB_FD | NETDEV_F_1TB_FD)) != 0;
12991299
}
13001300

1301+
/* Stores the duplex capability of 'netdev' into 'full_duplex'.
1302+
*
1303+
* Some network devices may not implement support for this function.
1304+
* In such cases this function will always return EOPNOTSUPP. */
1305+
int
1306+
netdev_get_duplex(const struct netdev *netdev, bool *full_duplex)
1307+
{
1308+
int error;
1309+
1310+
*full_duplex = false;
1311+
error = netdev->netdev_class->get_duplex
1312+
? netdev->netdev_class->get_duplex(netdev, full_duplex)
1313+
: EOPNOTSUPP;
1314+
1315+
if (error == EOPNOTSUPP) {
1316+
enum netdev_features current;
1317+
1318+
error = netdev_get_features(netdev, &current, NULL, NULL, NULL);
1319+
if (!error && (current & NETDEV_F_OTHER)) {
1320+
error = EOPNOTSUPP;
1321+
}
1322+
if (!error) {
1323+
*full_duplex = (current & (NETDEV_F_10MB_FD | NETDEV_F_100MB_FD
1324+
| NETDEV_F_1GB_FD | NETDEV_F_10GB_FD
1325+
| NETDEV_F_40GB_FD | NETDEV_F_100GB_FD
1326+
| NETDEV_F_1TB_FD)) != 0;
1327+
}
1328+
}
1329+
return error;
1330+
}
1331+
13011332
/* Set the features advertised by 'netdev' to 'advertise'. Returns 0 if
13021333
* successful, otherwise a positive errno value. */
13031334
int

ofproto/ofproto-dpif-sflow.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,6 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
298298
struct dpif_sflow *ds = ds_;
299299
SFLCounters_sample_element elem, lacp_elem, of_elem, name_elem;
300300
SFLCounters_sample_element eth_elem;
301-
enum netdev_features current;
302301
struct dpif_sflow_port *dsp;
303302
SFLIf_counters *counters;
304303
SFLEthernet_counters* eth_counters;
@@ -307,6 +306,7 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
307306
struct lacp_member_stats lacp_stats;
308307
uint32_t curr_speed;
309308
const char *ifName;
309+
bool full_duplex;
310310

311311
dsp = dpif_sflow_find_port(ds, u32_to_odp(poller->bridgePort));
312312
if (!dsp) {
@@ -317,11 +317,10 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
317317
counters = &elem.counterBlock.generic;
318318
counters->ifIndex = SFL_DS_INDEX(poller->dsi);
319319
counters->ifType = 6;
320-
if (!netdev_get_features(dsp->ofport->netdev, &current, NULL, NULL, NULL)) {
320+
if (!netdev_get_duplex(dsp->ofport->netdev, &full_duplex)) {
321321
/* The values of ifDirection come from MAU MIB (RFC 2668): 0 = unknown,
322322
1 = full-duplex, 2 = half-duplex, 3 = in, 4=out */
323-
counters->ifDirection = (netdev_features_is_full_duplex(current)
324-
? 1 : 2);
323+
counters->ifDirection = full_duplex ? 1 : 2;
325324
} else {
326325
counters->ifDirection = 0;
327326
}

tests/system-interface.at

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,5 +207,17 @@ AT_CHECK([ovs-vsctl get interface tap0 link_speed], [0], [dnl
207207
50000000000
208208
])
209209

210+
AT_CHECK([ovs-vsctl get interface tap0 duplex], [0], [dnl
211+
full
212+
])
213+
214+
AT_CHECK([ip link set dev tap0 down])
215+
AT_CHECK([ethtool -s tap0 duplex half])
216+
AT_CHECK([ip link set dev tap0 up])
217+
218+
AT_CHECK([ovs-vsctl get interface tap0 duplex], [0], [dnl
219+
half
220+
])
221+
210222
OVS_TRAFFIC_VSWITCHD_STOP
211223
AT_CLEANUP

vswitchd/bridge.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2532,11 +2532,11 @@ iface_refresh_netdev_status(struct iface *iface)
25322532
{
25332533
struct smap smap;
25342534

2535-
enum netdev_features current;
25362535
enum netdev_flags flags;
25372536
const char *link_state;
25382537
struct eth_addr mac;
25392538
int64_t bps, mtu_64, ifindex64, link_resets;
2539+
bool full_duplex;
25402540
int mtu, error;
25412541
uint32_t mbps;
25422542

@@ -2576,11 +2576,9 @@ iface_refresh_netdev_status(struct iface *iface)
25762576
link_resets = netdev_get_carrier_resets(iface->netdev);
25772577
ovsrec_interface_set_link_resets(iface->cfg, &link_resets, 1);
25782578

2579-
error = netdev_get_features(iface->netdev, &current, NULL, NULL, NULL);
2579+
error = netdev_get_duplex(iface->netdev, &full_duplex);
25802580
if (!error) {
2581-
ovsrec_interface_set_duplex(iface->cfg,
2582-
netdev_features_is_full_duplex(current)
2583-
? "full" : "half");
2581+
ovsrec_interface_set_duplex(iface->cfg, full_duplex ? "full" : "half");
25842582
} else {
25852583
ovsrec_interface_set_duplex(iface->cfg, NULL);
25862584
}

0 commit comments

Comments
 (0)