mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
netdev: Add netdev_get_speed() to netdev API.
Currently, the netdev's speed is being calculated by taking the link's feature bits (using netdev_get_features()) and transforming them into bps. This mechanism can be both inaccurate and difficult to maintain, mainly because we currently use the feature bits supported by OpenFlow which would have to be extended to support all new feature bits of all netdev implementations while keeping the OpenFlow API intact. In order to expose the link speed accurately for all current and future hardware, add a new netdev API call that allows the implementations to provide the current and maximum link speeds in Mbps. Internally, the logic to get the maximum supported speed still relies on feature bits so it might still get out of sync in the future. However, the maximum configurable speed is not used as much as the current speed and these feature bits are not exposed through the netdev interface so it should be easier to add more. Use this new function instead of netdev_get_features() where the link speed is needed. As a consequence of this patch, link speeds of cards is properly reported (internally in OVSDB) even if not supported by OpenFlow. A test verifies this behavior using a tap device. Also, in order to avoid using the old, this patch adds a checkpatch.py warning if the old API is used. Reported-at: https://bugzilla.redhat.com/show_bug.cgi?id=2137567 Acked-by: Eelco Chaudron <echaudro@redhat.com> Signed-off-by: Adrian Moreno <amorenoz@redhat.com> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
This commit is contained in:
parent
1ef3f4f78a
commit
6240c0b4c8
@ -132,6 +132,7 @@ int netdev_get_features(const struct netdev *,
|
||||
enum netdev_features *advertised,
|
||||
enum netdev_features *supported,
|
||||
enum netdev_features *peer);
|
||||
int netdev_get_speed(const struct netdev *, uint32_t *current, uint32_t *max);
|
||||
uint64_t netdev_features_to_bps(enum netdev_features features,
|
||||
uint64_t default_bps);
|
||||
bool netdev_features_is_full_duplex(enum netdev_features features);
|
||||
|
@ -91,7 +91,9 @@
|
||||
*
|
||||
* - Carrier status (netdev_get_carrier()).
|
||||
*
|
||||
* - Speed (netdev_get_features()).
|
||||
* - Link features (netdev_get_features()).
|
||||
*
|
||||
* - Speed (netdev_get_speed()).
|
||||
*
|
||||
* - QoS queue configuration (netdev_get_queue(), netdev_set_queue() and
|
||||
* related functions.)
|
||||
|
@ -1168,6 +1168,27 @@ cleanup:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
netdev_bsd_get_speed(const struct netdev *netdev, uint32_t *current,
|
||||
uint32_t *max)
|
||||
{
|
||||
enum netdev_features f_current, f_supported, f_advertised, f_peer;
|
||||
int error;
|
||||
|
||||
error = netdev_bsd_get_features(netdev, &f_current, &f_advertised,
|
||||
&f_supported, &f_peer);
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
*current = MIN(UINT32_MAX,
|
||||
netdev_features_to_bps(f_current, 0) / 1000000ULL);
|
||||
*max = MIN(UINT32_MAX,
|
||||
netdev_features_to_bps(f_supported, 0) / 1000000ULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
@ -1493,6 +1514,7 @@ netdev_bsd_update_flags(struct netdev *netdev_, enum netdev_flags off,
|
||||
.get_carrier = netdev_bsd_get_carrier, \
|
||||
.get_stats = netdev_bsd_get_stats, \
|
||||
.get_features = netdev_bsd_get_features, \
|
||||
.get_speed = netdev_bsd_get_speed, \
|
||||
.set_in4 = netdev_bsd_set_in4, \
|
||||
.get_addr_list = netdev_bsd_get_addr_list, \
|
||||
.get_next_hop = netdev_bsd_get_next_hop, \
|
||||
|
@ -3686,6 +3686,57 @@ netdev_dpdk_get_features(const struct netdev *netdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
netdev_dpdk_get_speed(const struct netdev *netdev, uint32_t *current,
|
||||
uint32_t *max)
|
||||
{
|
||||
struct netdev_dpdk *dev = netdev_dpdk_cast(netdev);
|
||||
struct rte_eth_dev_info dev_info;
|
||||
struct rte_eth_link link;
|
||||
|
||||
ovs_mutex_lock(&dev->mutex);
|
||||
link = dev->link;
|
||||
rte_eth_dev_info_get(dev->port_id, &dev_info);
|
||||
ovs_mutex_unlock(&dev->mutex);
|
||||
|
||||
*current = link.link_speed != RTE_ETH_SPEED_NUM_UNKNOWN
|
||||
? link.link_speed : 0;
|
||||
|
||||
if (dev_info.speed_capa & RTE_ETH_LINK_SPEED_200G) {
|
||||
*max = RTE_ETH_SPEED_NUM_200G;
|
||||
} else if (dev_info.speed_capa & RTE_ETH_LINK_SPEED_100G) {
|
||||
*max = RTE_ETH_SPEED_NUM_100G;
|
||||
} else if (dev_info.speed_capa & RTE_ETH_LINK_SPEED_56G) {
|
||||
*max = RTE_ETH_SPEED_NUM_56G;
|
||||
} else if (dev_info.speed_capa & RTE_ETH_LINK_SPEED_50G) {
|
||||
*max = RTE_ETH_SPEED_NUM_50G;
|
||||
} else if (dev_info.speed_capa & RTE_ETH_LINK_SPEED_40G) {
|
||||
*max = RTE_ETH_SPEED_NUM_40G;
|
||||
} else if (dev_info.speed_capa & RTE_ETH_LINK_SPEED_25G) {
|
||||
*max = RTE_ETH_SPEED_NUM_25G;
|
||||
} else if (dev_info.speed_capa & RTE_ETH_LINK_SPEED_20G) {
|
||||
*max = RTE_ETH_SPEED_NUM_20G;
|
||||
} else if (dev_info.speed_capa & RTE_ETH_LINK_SPEED_10G) {
|
||||
*max = RTE_ETH_SPEED_NUM_10G;
|
||||
} else if (dev_info.speed_capa & RTE_ETH_LINK_SPEED_5G) {
|
||||
*max = RTE_ETH_SPEED_NUM_5G;
|
||||
} else if (dev_info.speed_capa & RTE_ETH_LINK_SPEED_2_5G) {
|
||||
*max = RTE_ETH_SPEED_NUM_2_5G;
|
||||
} else if (dev_info.speed_capa & RTE_ETH_LINK_SPEED_1G) {
|
||||
*max = RTE_ETH_SPEED_NUM_1G;
|
||||
} else if (dev_info.speed_capa & RTE_ETH_LINK_SPEED_100M ||
|
||||
dev_info.speed_capa & RTE_ETH_LINK_SPEED_100M_HD) {
|
||||
*max = RTE_ETH_SPEED_NUM_100M;
|
||||
} else if (dev_info.speed_capa & RTE_ETH_LINK_SPEED_10M ||
|
||||
dev_info.speed_capa & RTE_ETH_LINK_SPEED_10M_HD) {
|
||||
*max = RTE_ETH_SPEED_NUM_10M;
|
||||
} else {
|
||||
*max = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ingress_policer *
|
||||
netdev_dpdk_policer_construct(uint32_t rate, uint32_t burst)
|
||||
{
|
||||
@ -6332,6 +6383,7 @@ parse_vhost_config(const struct smap *ovs_other_config)
|
||||
.get_stats = netdev_dpdk_get_stats, \
|
||||
.get_custom_stats = netdev_dpdk_get_custom_stats, \
|
||||
.get_features = netdev_dpdk_get_features, \
|
||||
.get_speed = netdev_dpdk_get_speed, \
|
||||
.get_status = netdev_dpdk_get_status, \
|
||||
.reconfigure = netdev_dpdk_reconfigure, \
|
||||
.rxq_recv = netdev_dpdk_rxq_recv
|
||||
|
@ -92,6 +92,7 @@ struct netdev_linux {
|
||||
enum netdev_features current; /* Cached from ETHTOOL_GSET. */
|
||||
enum netdev_features advertised; /* Cached from ETHTOOL_GSET. */
|
||||
enum netdev_features supported; /* Cached from ETHTOOL_GSET. */
|
||||
uint32_t current_speed; /* Cached from ETHTOOL_GSET. */
|
||||
|
||||
struct ethtool_drvinfo drvinfo; /* Cached from ETHTOOL_GDRVINFO. */
|
||||
struct tc *tc;
|
||||
|
@ -2382,7 +2382,6 @@ static void
|
||||
netdev_linux_read_features(struct netdev_linux *netdev)
|
||||
{
|
||||
struct ethtool_cmd ecmd;
|
||||
uint32_t speed;
|
||||
int error;
|
||||
|
||||
if (netdev->cache_valid & VALID_FEATURES) {
|
||||
@ -2496,20 +2495,20 @@ netdev_linux_read_features(struct netdev_linux *netdev)
|
||||
}
|
||||
|
||||
/* Current settings. */
|
||||
speed = ethtool_cmd_speed(&ecmd);
|
||||
if (speed == SPEED_10) {
|
||||
netdev->current_speed = ethtool_cmd_speed(&ecmd);
|
||||
if (netdev->current_speed == SPEED_10) {
|
||||
netdev->current = ecmd.duplex ? NETDEV_F_10MB_FD : NETDEV_F_10MB_HD;
|
||||
} else if (speed == SPEED_100) {
|
||||
} else if (netdev->current_speed == SPEED_100) {
|
||||
netdev->current = ecmd.duplex ? NETDEV_F_100MB_FD : NETDEV_F_100MB_HD;
|
||||
} else if (speed == SPEED_1000) {
|
||||
} else if (netdev->current_speed == SPEED_1000) {
|
||||
netdev->current = ecmd.duplex ? NETDEV_F_1GB_FD : NETDEV_F_1GB_HD;
|
||||
} else if (speed == SPEED_10000) {
|
||||
} else if (netdev->current_speed == SPEED_10000) {
|
||||
netdev->current = NETDEV_F_10GB_FD;
|
||||
} else if (speed == 40000) {
|
||||
} else if (netdev->current_speed == 40000) {
|
||||
netdev->current = NETDEV_F_40GB_FD;
|
||||
} else if (speed == 100000) {
|
||||
} else if (netdev->current_speed == 100000) {
|
||||
netdev->current = NETDEV_F_100GB_FD;
|
||||
} else if (speed == 1000000) {
|
||||
} else if (netdev->current_speed == 1000000) {
|
||||
netdev->current = NETDEV_F_1TB_FD;
|
||||
} else {
|
||||
netdev->current = 0;
|
||||
@ -2563,6 +2562,33 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int
|
||||
netdev_linux_get_speed(const struct netdev *netdev_, uint32_t *current,
|
||||
uint32_t *max)
|
||||
{
|
||||
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
|
||||
int error;
|
||||
|
||||
ovs_mutex_lock(&netdev->mutex);
|
||||
if (netdev_linux_netnsid_is_remote(netdev)) {
|
||||
error = EOPNOTSUPP;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
netdev_linux_read_features(netdev);
|
||||
if (!netdev->get_features_error) {
|
||||
*current = netdev->current_speed == SPEED_UNKNOWN
|
||||
? 0 : netdev->current_speed;
|
||||
*max = MIN(UINT32_MAX,
|
||||
netdev_features_to_bps(netdev->supported, 0) / 1000000ULL);
|
||||
}
|
||||
error = netdev->get_features_error;
|
||||
|
||||
exit:
|
||||
ovs_mutex_unlock(&netdev->mutex);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Set the features advertised by 'netdev' to 'advertise'. */
|
||||
static int
|
||||
netdev_linux_set_advertisements(struct netdev *netdev_,
|
||||
@ -3697,6 +3723,7 @@ const struct netdev_class netdev_linux_class = {
|
||||
.destruct = netdev_linux_destruct,
|
||||
.get_stats = netdev_linux_get_stats,
|
||||
.get_features = netdev_linux_get_features,
|
||||
.get_speed = netdev_linux_get_speed,
|
||||
.get_status = netdev_linux_get_status,
|
||||
.get_block_id = netdev_linux_get_block_id,
|
||||
.send = netdev_linux_send,
|
||||
@ -3713,6 +3740,7 @@ const struct netdev_class netdev_tap_class = {
|
||||
.destruct = netdev_linux_destruct,
|
||||
.get_stats = netdev_tap_get_stats,
|
||||
.get_features = netdev_linux_get_features,
|
||||
.get_speed = netdev_linux_get_speed,
|
||||
.get_status = netdev_linux_get_status,
|
||||
.send = netdev_linux_send,
|
||||
.rxq_construct = netdev_linux_rxq_construct,
|
||||
|
@ -500,6 +500,15 @@ struct netdev_class {
|
||||
enum netdev_features *supported,
|
||||
enum netdev_features *peer);
|
||||
|
||||
/* Stores the current and maximum supported link speed by 'netdev' into
|
||||
* each of '*current' and '*max'. Each value represents the speed in Mbps.
|
||||
* If any of the speeds is unknown, a zero value must be stored.
|
||||
*
|
||||
* This function may be set to null if it would always return EOPNOTSUPP.
|
||||
*/
|
||||
int (*get_speed)(const struct netdev *netdev, uint32_t *current,
|
||||
uint32_t *max);
|
||||
|
||||
/* Set the features advertised by 'netdev' to 'advertise', which is a
|
||||
* set of NETDEV_F_* bits.
|
||||
*
|
||||
|
30
lib/netdev.c
30
lib/netdev.c
@ -1158,6 +1158,36 @@ netdev_get_features(const struct netdev *netdev,
|
||||
return error;
|
||||
}
|
||||
|
||||
int
|
||||
netdev_get_speed(const struct netdev *netdev, uint32_t *current, uint32_t *max)
|
||||
{
|
||||
uint32_t current_dummy, max_dummy;
|
||||
int error;
|
||||
|
||||
if (!current) {
|
||||
current = ¤t_dummy;
|
||||
}
|
||||
if (!max) {
|
||||
max = &max_dummy;
|
||||
}
|
||||
|
||||
error = netdev->netdev_class->get_speed
|
||||
? netdev->netdev_class->get_speed(netdev, current, max)
|
||||
: EOPNOTSUPP;
|
||||
|
||||
if (error == EOPNOTSUPP) {
|
||||
enum netdev_features current_f, supported_f;
|
||||
|
||||
error = netdev_get_features(netdev, ¤t_f, NULL,
|
||||
&supported_f, NULL);
|
||||
*current = netdev_features_to_bps(current_f, 0) / 1000000;
|
||||
*max = netdev_features_to_bps(supported_f, 0) / 1000000;
|
||||
} else if (error) {
|
||||
*current = *max = 0;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Returns the maximum speed of a network connection that has the NETDEV_F_*
|
||||
* bits in 'features', in bits per second. If no bits that indicate a speed
|
||||
* are set in 'features', returns 'default_bps'. */
|
||||
|
@ -306,6 +306,7 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
|
||||
struct netdev_stats stats;
|
||||
enum netdev_flags flags;
|
||||
struct lacp_member_stats lacp_stats;
|
||||
uint32_t curr_speed;
|
||||
const char *ifName;
|
||||
|
||||
dsp = dpif_sflow_find_port(ds, u32_to_odp(poller->bridgePort));
|
||||
@ -320,13 +321,19 @@ sflow_agent_get_counters(void *ds_, SFLPoller *poller,
|
||||
if (!netdev_get_features(dsp->ofport->netdev, ¤t, NULL, NULL, NULL)) {
|
||||
/* The values of ifDirection come from MAU MIB (RFC 2668): 0 = unknown,
|
||||
1 = full-duplex, 2 = half-duplex, 3 = in, 4=out */
|
||||
counters->ifSpeed = netdev_features_to_bps(current, 0);
|
||||
counters->ifDirection = (netdev_features_is_full_duplex(current)
|
||||
? 1 : 2);
|
||||
} else {
|
||||
counters->ifSpeed = 100000000;
|
||||
counters->ifDirection = 0;
|
||||
}
|
||||
|
||||
netdev_get_speed(dsp->ofport->netdev, &curr_speed, NULL);
|
||||
if (curr_speed) {
|
||||
counters->ifSpeed = curr_speed * 1000000;
|
||||
} else {
|
||||
counters->ifSpeed = 100000000;
|
||||
}
|
||||
|
||||
if (!netdev_get_flags(dsp->ofport->netdev, &flags) && flags & NETDEV_UP) {
|
||||
counters->ifStatus = 1; /* ifAdminStatus up. */
|
||||
if (netdev_get_carrier(dsp->ofport->netdev)) {
|
||||
|
@ -2476,6 +2476,7 @@ ofport_open(struct ofproto *ofproto,
|
||||
struct ofputil_phy_port *pp,
|
||||
struct netdev **p_netdev)
|
||||
{
|
||||
uint32_t curr_speed, max_speed;
|
||||
enum netdev_flags flags;
|
||||
struct netdev *netdev;
|
||||
int error;
|
||||
@ -2514,8 +2515,9 @@ ofport_open(struct ofproto *ofproto,
|
||||
pp->state = netdev_get_carrier(netdev) ? 0 : OFPUTIL_PS_LINK_DOWN;
|
||||
netdev_get_features(netdev, &pp->curr, &pp->advertised,
|
||||
&pp->supported, &pp->peer);
|
||||
pp->curr_speed = netdev_features_to_bps(pp->curr, 0) / 1000;
|
||||
pp->max_speed = netdev_features_to_bps(pp->supported, 0) / 1000;
|
||||
netdev_get_speed(netdev, &curr_speed, &max_speed);
|
||||
pp->curr_speed = curr_speed * 1000;
|
||||
pp->max_speed = max_speed * 1000;
|
||||
|
||||
*p_netdev = netdev;
|
||||
return 0;
|
||||
|
@ -180,6 +180,9 @@ find_command tcpdump
|
||||
# Set HAVE_LFTP
|
||||
find_command lftp
|
||||
|
||||
# Set HAVE_ETHTOOL
|
||||
find_command ethtool
|
||||
|
||||
CURL_OPT="-g -v --max-time 1 --retry 2 --retry-delay 1 --connect-timeout 1"
|
||||
|
||||
# Determine whether "diff" supports "normal" diffs. (busybox diff does not.)
|
||||
|
@ -122,3 +122,33 @@ AT_CHECK([ip link show | grep " genev_sys_[[0-9]]*: .* ovs-system " | diff -u -
|
||||
|
||||
OVS_TRAFFIC_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([interface - current speed])
|
||||
AT_SKIP_IF([test $HAVE_ETHTOOL = "no"])
|
||||
OVS_TRAFFIC_VSWITCHD_START()
|
||||
|
||||
AT_CHECK([ip tuntap add tap0 mode tap])
|
||||
on_exit 'ip tuntap del tap0 mode tap'
|
||||
|
||||
AT_CHECK([ip link set dev tap0 address aa:55:aa:55:00:01])
|
||||
AT_CHECK([ethtool -s tap0 speed 50000 duplex full])
|
||||
AT_CHECK([ip link set dev tap0 up])
|
||||
|
||||
AT_CHECK([ovs-vsctl add-port br0 tap0 -- set int tap0 type=tap])
|
||||
|
||||
AT_CHECK([ovs-ofctl -O OpenFlow15 -vwarn dump-ports-desc br0 tap0], [0], [stdout])
|
||||
AT_CHECK([strip_xids < stdout], [0], [dnl
|
||||
OFPST_PORT_DESC reply (OF1.5):
|
||||
1(tap0): addr:aa:55:aa:55:00:01
|
||||
config: 0
|
||||
state: LIVE
|
||||
current: COPPER
|
||||
speed: 50000 Mbps now, 0 Mbps max
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-vsctl get interface tap0 link_speed], [0], [dnl
|
||||
50000000000
|
||||
])
|
||||
|
||||
OVS_TRAFFIC_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
@ -671,18 +671,23 @@ checks += [
|
||||
|
||||
easy_to_misuse_api = [
|
||||
('ovsrcu_barrier',
|
||||
'lib/ovs-rcu.c',
|
||||
['lib/ovs-rcu.c'],
|
||||
'Are you sure you need to use ovsrcu_barrier(), '
|
||||
'in most cases ovsrcu_synchronize() will be fine?'),
|
||||
('netdev_features_to_bps',
|
||||
['lib/netdev.c', 'lib/netdev-bsd.c', 'lib/netdev-linux.c'],
|
||||
'Are you sure you need to use netdev_features_to_bps()? '
|
||||
'If you want to retrieve the current and/or maximum link speed, '
|
||||
'consider using netdev_get_speed() instead.'),
|
||||
]
|
||||
|
||||
checks += [
|
||||
{'regex': r'(\.c)(\.in)?$',
|
||||
'match_name': lambda x: x != location,
|
||||
'match_name': lambda x, loc=locations: x not in loc,
|
||||
'prereq': lambda x: not is_comment_line(x),
|
||||
'check': regex_function_factory(function_name),
|
||||
'print': regex_warn_factory(description)}
|
||||
for (function_name, location, description) in easy_to_misuse_api]
|
||||
for (function_name, locations, description) in easy_to_misuse_api]
|
||||
|
||||
|
||||
def regex_operator_factory(operator):
|
||||
|
@ -1694,11 +1694,12 @@ port_configure_stp(const struct ofproto *ofproto, struct port *port,
|
||||
if (config_str) {
|
||||
port_s->path_cost = strtoul(config_str, NULL, 10);
|
||||
} else {
|
||||
enum netdev_features current;
|
||||
unsigned int mbps;
|
||||
uint32_t mbps;
|
||||
|
||||
netdev_get_features(iface->netdev, ¤t, NULL, NULL, NULL);
|
||||
mbps = netdev_features_to_bps(current, NETDEV_DEFAULT_BPS) / 1000000;
|
||||
netdev_get_speed(iface->netdev, &mbps, NULL);
|
||||
if (!mbps) {
|
||||
mbps = NETDEV_DEFAULT_BPS / 1000000;
|
||||
}
|
||||
port_s->path_cost = stp_convert_speed_to_cost(mbps);
|
||||
}
|
||||
|
||||
@ -1777,11 +1778,12 @@ port_configure_rstp(const struct ofproto *ofproto, struct port *port,
|
||||
if (config_str) {
|
||||
port_s->path_cost = strtoul(config_str, NULL, 10);
|
||||
} else {
|
||||
enum netdev_features current;
|
||||
unsigned int mbps;
|
||||
uint32_t mbps;
|
||||
|
||||
netdev_get_features(iface->netdev, ¤t, NULL, NULL, NULL);
|
||||
mbps = netdev_features_to_bps(current, NETDEV_DEFAULT_BPS) / 1000000;
|
||||
netdev_get_speed(iface->netdev, &mbps, NULL);
|
||||
if (!mbps) {
|
||||
mbps = NETDEV_DEFAULT_BPS / 1000000;
|
||||
}
|
||||
port_s->path_cost = rstp_convert_speed_to_cost(mbps);
|
||||
}
|
||||
|
||||
@ -2418,6 +2420,7 @@ iface_refresh_netdev_status(struct iface *iface)
|
||||
struct eth_addr mac;
|
||||
int64_t bps, mtu_64, ifindex64, link_resets;
|
||||
int mtu, error;
|
||||
uint32_t mbps;
|
||||
|
||||
if (iface_is_synthetic(iface)) {
|
||||
return;
|
||||
@ -2456,14 +2459,19 @@ iface_refresh_netdev_status(struct iface *iface)
|
||||
ovsrec_interface_set_link_resets(iface->cfg, &link_resets, 1);
|
||||
|
||||
error = netdev_get_features(iface->netdev, ¤t, NULL, NULL, NULL);
|
||||
bps = !error ? netdev_features_to_bps(current, 0) : 0;
|
||||
if (bps) {
|
||||
if (!error) {
|
||||
ovsrec_interface_set_duplex(iface->cfg,
|
||||
netdev_features_is_full_duplex(current)
|
||||
? "full" : "half");
|
||||
ovsrec_interface_set_link_speed(iface->cfg, &bps, 1);
|
||||
} else {
|
||||
ovsrec_interface_set_duplex(iface->cfg, NULL);
|
||||
}
|
||||
|
||||
netdev_get_speed(iface->netdev, &mbps, NULL);
|
||||
if (mbps) {
|
||||
bps = mbps * 1000000ULL;
|
||||
ovsrec_interface_set_link_speed(iface->cfg, &bps, 1);
|
||||
} else {
|
||||
ovsrec_interface_set_link_speed(iface->cfg, NULL, 0);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user