uint64_t netdev_features_to_bps(enum netdev_features features,
uint64_t default_bps);
bool netdev_features_is_full_duplex(enum netdev_features features);
+int netdev_get_duplex(const struct netdev *, bool *full_duplex);
int netdev_set_advertisements(struct netdev *, enum netdev_features advertise);
void netdev_features_format(struct ds *, enum netdev_features);
enum netdev_features current;
enum netdev_features advertised;
enum netdev_features supported;
+ bool full_duplex;
int tap_fd; /* TAP character device, if any, otherwise -1. */
if (!netdev->current) {
netdev->current = NETDEV_F_OTHER;
}
+ netdev->full_duplex = ifmr.ifm_active & IFM_FDX;
/* Advertised features. */
netdev->advertised = netdev_bsd_parse_media(ifmr.ifm_current);
return error;
}
+static int
+netdev_bsd_get_duplex(const struct netdev *netdev_, bool *full_duplex)
+{
+ struct netdev_bsd *netdev = netdev_bsd_cast(netdev_);
+ int error;
+
+ ovs_mutex_lock(&netdev->mutex);
+ netdev_bsd_read_features(netdev);
+ if (!netdev->get_features_error) {
+ *full_duplex = netdev->full_duplex;
+ }
+ error = netdev->get_features_error;
+ ovs_mutex_unlock(&netdev->mutex);
+
+ return error;
+}
+
/*
* Assigns 'addr' as 'netdev''s IPv4 address and 'mask' as its netmask. If
* 'addr' is INADDR_ANY, 'netdev''s IPv4 address is cleared. Returns a
.get_stats = netdev_bsd_get_stats, \
.get_features = netdev_bsd_get_features, \
.get_speed = netdev_bsd_get_speed, \
+ .get_duplex = netdev_bsd_get_duplex, \
.set_in4 = netdev_bsd_set_in4, \
.get_addr_list = netdev_bsd_get_addr_list, \
.get_next_hop = netdev_bsd_get_next_hop, \
return 0;
}
+static int
+netdev_dpdk_get_duplex(const struct netdev *netdev, bool *full_duplex)
+{
+ struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
+ int err = 0;
+
+ ovs_mutex_lock(&dev->mutex);
+ if (dev->link.link_speed != RTE_ETH_SPEED_NUM_UNKNOWN) {
+ *full_duplex = dev->link.link_duplex == RTE_ETH_LINK_FULL_DUPLEX;
+ } else {
+ err = EOPNOTSUPP;
+ }
+ ovs_mutex_unlock(&dev->mutex);
+
+ return err;
+}
+
static struct ingress_policer *
netdev_dpdk_policer_construct(uint32_t rate, uint32_t burst)
{
.get_custom_stats = netdev_dpdk_get_custom_stats, \
.get_features = netdev_dpdk_get_features, \
.get_speed = netdev_dpdk_get_speed, \
+ .get_duplex = netdev_dpdk_get_duplex, \
.get_status = netdev_dpdk_get_status, \
.reconfigure = netdev_dpdk_reconfigure, \
.rxq_recv = netdev_dpdk_rxq_recv
enum netdev_features advertised; /* Cached from ETHTOOL_GSET. */
enum netdev_features supported; /* Cached from ETHTOOL_GSET. */
uint32_t current_speed; /* Cached from ETHTOOL_GSET. */
+ uint8_t current_duplex; /* Cached from ETHTOOL_GSET. */
struct ethtool_drvinfo drvinfo; /* Cached from ETHTOOL_GDRVINFO. */
struct tc *tc;
#define ADVERTISED_10000baseR_FEC (1 << 20)
#endif
-/* Linux 3.2 introduced "unknown" speed. */
+/* Linux 3.2 introduced "unknown" speed and duplex. */
#ifndef SPEED_UNKNOWN
#define SPEED_UNKNOWN -1
#endif
+#ifndef DUPLEX_UNKNOWN
+#define DUPLEX_UNKNOWN 0xff
+#endif
/* Linux 3.5 introduced supported and advertised flags for
* 40G base KR4, CR4, SR4 and LR4. */
} else {
netdev->current = 0;
}
+ netdev->current_duplex = ecmd.duplex;
if (ecmd.port == PORT_TP) {
netdev->current |= NETDEV_F_COPPER;
return error;
}
+static int
+netdev_linux_get_duplex(const struct netdev *netdev_, bool *full_duplex)
+{
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ int err;
+
+ ovs_mutex_lock(&netdev->mutex);
+
+ if (netdev_linux_netnsid_is_remote(netdev)) {
+ err = EOPNOTSUPP;
+ goto exit;
+ }
+
+ netdev_linux_read_features(netdev);
+ err = netdev->get_features_error;
+ if (!err && netdev->current_duplex == DUPLEX_UNKNOWN) {
+ err = EOPNOTSUPP;
+ goto exit;
+ }
+ *full_duplex = netdev->current_duplex == DUPLEX_FULL;
+
+exit:
+ ovs_mutex_unlock(&netdev->mutex);
+ return err;
+}
+
/* Set the features advertised by 'netdev' to 'advertise'. */
static int
netdev_linux_set_advertisements(struct netdev *netdev_,
.get_stats = netdev_linux_get_stats,
.get_features = netdev_linux_get_features,
.get_speed = netdev_linux_get_speed,
+ .get_duplex = netdev_linux_get_duplex,
.get_status = netdev_linux_get_status,
.get_block_id = netdev_linux_get_block_id,
.send = netdev_linux_send,
.get_stats = netdev_tap_get_stats,
.get_features = netdev_linux_get_features,
.get_speed = netdev_linux_get_speed,
+ .get_duplex = netdev_linux_get_duplex,
.get_status = netdev_linux_get_status,
.send = netdev_linux_send,
.rxq_construct = netdev_linux_rxq_construct,
int (*get_speed)(const struct netdev *netdev, uint32_t *current,
uint32_t *max);
+ /* Stores the current duplex status of 'netdev' into '*full_duplex'.
+ * 'true' means full duplex, 'false' means half duplex.
+ *
+ * This function may be set to null if it would always return EOPNOTSUPP.
+ */
+ int (*get_duplex)(const struct netdev *netdev, bool *full_duplex);
+
/* Set the features advertised by 'netdev' to 'advertise', which is a
* set of NETDEV_F_* bits.
*
| NETDEV_F_100GB_FD | NETDEV_F_1TB_FD)) != 0;
}
+/* Stores the duplex capability of 'netdev' into 'full_duplex'.
+ *
+ * Some network devices may not implement support for this function.
+ * In such cases this function will always return EOPNOTSUPP. */
+int
+netdev_get_duplex(const struct netdev *netdev, bool *full_duplex)
+{
+ int error;
+
+ *full_duplex = false;
+ error = netdev->netdev_class->get_duplex
+ ? netdev->netdev_class->get_duplex(netdev, full_duplex)
+ : EOPNOTSUPP;
+
+ if (error == EOPNOTSUPP) {
+ enum netdev_features current;
+
+ error = netdev_get_features(netdev, ¤t, NULL, NULL, NULL);
+ if (!error && (current & NETDEV_F_OTHER)) {
+ error = EOPNOTSUPP;
+ }
+ if (!error) {
+ *full_duplex = (current & (NETDEV_F_10MB_FD | NETDEV_F_100MB_FD
+ | NETDEV_F_1GB_FD | NETDEV_F_10GB_FD
+ | NETDEV_F_40GB_FD | NETDEV_F_100GB_FD
+ | NETDEV_F_1TB_FD)) != 0;
+ }
+ }
+ return error;
+}
+
/* Set the features advertised by 'netdev' to 'advertise'. Returns 0 if
* successful, otherwise a positive errno value. */
int
struct dpif_sflow *ds = ds_;
SFLCounters_sample_element elem, lacp_elem, of_elem, name_elem;
SFLCounters_sample_element eth_elem;
- enum netdev_features current;
struct dpif_sflow_port *dsp;
SFLIf_counters *counters;
SFLEthernet_counters* eth_counters;
struct lacp_member_stats lacp_stats;
uint32_t curr_speed;
const char *ifName;
+ bool full_duplex;
dsp = dpif_sflow_find_port(ds, u32_to_odp(poller->bridgePort));
if (!dsp) {
counters = &elem.counterBlock.generic;
counters->ifIndex = SFL_DS_INDEX(poller->dsi);
counters->ifType = 6;
- if (!netdev_get_features(dsp->ofport->netdev, ¤t, NULL, NULL, NULL)) {
+ if (!netdev_get_duplex(dsp->ofport->netdev, &full_duplex)) {
/* The values of ifDirection come from MAU MIB (RFC 2668): 0 = unknown,
1 = full-duplex, 2 = half-duplex, 3 = in, 4=out */
- counters->ifDirection = (netdev_features_is_full_duplex(current)
- ? 1 : 2);
+ counters->ifDirection = full_duplex ? 1 : 2;
} else {
counters->ifDirection = 0;
}
50000000000
])
+AT_CHECK([ovs-vsctl get interface tap0 duplex], [0], [dnl
+full
+])
+
+AT_CHECK([ip link set dev tap0 down])
+AT_CHECK([ethtool -s tap0 duplex half])
+AT_CHECK([ip link set dev tap0 up])
+
+AT_CHECK([ovs-vsctl get interface tap0 duplex], [0], [dnl
+half
+])
+
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
{
struct smap smap;
- enum netdev_features current;
enum netdev_flags flags;
const char *link_state;
struct eth_addr mac;
int64_t bps, mtu_64, ifindex64, link_resets;
+ bool full_duplex;
int mtu, error;
uint32_t mbps;
link_resets = netdev_get_carrier_resets(iface->netdev);
ovsrec_interface_set_link_resets(iface->cfg, &link_resets, 1);
- error = netdev_get_features(iface->netdev, ¤t, NULL, NULL, NULL);
+ error = netdev_get_duplex(iface->netdev, &full_duplex);
if (!error) {
- ovsrec_interface_set_duplex(iface->cfg,
- netdev_features_is_full_duplex(current)
- ? "full" : "half");
+ ovsrec_interface_set_duplex(iface->cfg, full_duplex ? "full" : "half");
} else {
ovsrec_interface_set_duplex(iface->cfg, NULL);
}