Skip to content

Commit e14d2e7

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 2c7a7bb commit e14d2e7

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
@@ -4131,6 +4131,23 @@ netdev_dpdk_get_speed(const struct netdev *netdev, uint32_t *current,
41314131
return 0;
41324132
}
41334133

4134+
static int
4135+
netdev_dpdk_get_duplex(const struct netdev *netdev, bool *full_duplex)
4136+
{
4137+
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
4138+
int err = 0;
4139+
4140+
ovs_mutex_lock(&dev->mutex);
4141+
if (dev->link.link_speed != RTE_ETH_SPEED_NUM_UNKNOWN) {
4142+
*full_duplex = dev->link.link_duplex == RTE_ETH_LINK_FULL_DUPLEX;
4143+
} else {
4144+
err = EOPNOTSUPP;
4145+
}
4146+
ovs_mutex_unlock(&dev->mutex);
4147+
4148+
return err;
4149+
}
4150+
41344151
static struct ingress_policer *
41354152
netdev_dpdk_policer_construct(uint32_t rate, uint32_t burst)
41364153
{
@@ -6839,6 +6856,7 @@ parse_vhost_config(const struct smap *ovs_other_config)
68396856
.get_custom_stats = netdev_dpdk_get_custom_stats, \
68406857
.get_features = netdev_dpdk_get_features, \
68416858
.get_speed = netdev_dpdk_get_speed, \
6859+
.get_duplex = netdev_dpdk_get_duplex, \
68426860
.get_status = netdev_dpdk_get_status, \
68436861
.reconfigure = netdev_dpdk_reconfigure, \
68446862
.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
@@ -173,10 +173,13 @@ static inline uint32_t rpl_ethtool_cmd_speed(const struct ethtool_cmd *ep)
173173
#define ADVERTISED_10000baseR_FEC (1 << 20)
174174
#endif
175175

176-
/* Linux 3.2 introduced "unknown" speed. */
176+
/* Linux 3.2 introduced "unknown" speed and duplex. */
177177
#ifndef SPEED_UNKNOWN
178178
#define SPEED_UNKNOWN -1
179179
#endif
180+
#ifndef DUPLEX_UNKNOWN
181+
#define DUPLEX_UNKNOWN 0xff
182+
#endif
180183

181184
/* Linux 3.5 introduced supported and advertised flags for
182185
* 40G base KR4, CR4, SR4 and LR4. */
@@ -2698,6 +2701,7 @@ netdev_linux_read_features(struct netdev_linux *netdev)
26982701
} else {
26992702
netdev->current = 0;
27002703
}
2704+
netdev->current_duplex = ecmd.duplex;
27012705

27022706
if (ecmd.port == PORT_TP) {
27032707
netdev->current |= NETDEV_F_COPPER;
@@ -2781,6 +2785,32 @@ netdev_linux_get_speed(const struct netdev *netdev_, uint32_t *current,
27812785
return error;
27822786
}
27832787

2788+
static int
2789+
netdev_linux_get_duplex(const struct netdev *netdev_, bool *full_duplex)
2790+
{
2791+
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
2792+
int err;
2793+
2794+
ovs_mutex_lock(&netdev->mutex);
2795+
2796+
if (netdev_linux_netnsid_is_remote(netdev)) {
2797+
err = EOPNOTSUPP;
2798+
goto exit;
2799+
}
2800+
2801+
netdev_linux_read_features(netdev);
2802+
err = netdev->get_features_error;
2803+
if (!err && netdev->current_duplex == DUPLEX_UNKNOWN) {
2804+
err = EOPNOTSUPP;
2805+
goto exit;
2806+
}
2807+
*full_duplex = netdev->current_duplex == DUPLEX_FULL;
2808+
2809+
exit:
2810+
ovs_mutex_unlock(&netdev->mutex);
2811+
return err;
2812+
}
2813+
27842814
/* Set the features advertised by 'netdev' to 'advertise'. */
27852815
static int
27862816
netdev_linux_set_advertisements(struct netdev *netdev_,
@@ -3905,6 +3935,7 @@ const struct netdev_class netdev_linux_class = {
39053935
.get_stats = netdev_linux_get_stats,
39063936
.get_features = netdev_linux_get_features,
39073937
.get_speed = netdev_linux_get_speed,
3938+
.get_duplex = netdev_linux_get_duplex,
39083939
.get_status = netdev_linux_get_status,
39093940
.get_block_id = netdev_linux_get_block_id,
39103941
.send = netdev_linux_send,
@@ -3922,6 +3953,7 @@ const struct netdev_class netdev_tap_class = {
39223953
.get_stats = netdev_tap_get_stats,
39233954
.get_features = netdev_linux_get_features,
39243955
.get_speed = netdev_linux_get_speed,
3956+
.get_duplex = netdev_linux_get_duplex,
39253957
.get_status = netdev_linux_get_status,
39263958
.send = netdev_linux_send,
39273959
.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
@@ -299,7 +299,6 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
299299
struct dpif_sflow *ds = ds_;
300300
SFLCounters_sample_element elem, lacp_elem, of_elem, name_elem;
301301
SFLCounters_sample_element eth_elem;
302-
enum netdev_features current;
303302
struct dpif_sflow_port *dsp;
304303
SFLIf_counters *counters;
305304
SFLEthernet_counters* eth_counters;
@@ -308,6 +307,7 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
308307
struct lacp_member_stats lacp_stats;
309308
uint32_t curr_speed;
310309
const char *ifName;
310+
bool full_duplex;
311311

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

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)