2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 06:15:47 +00:00

datapath: Always use generic stats for devices (vports)

Currently ovs is using device stats for Linux devices and count them
itself in other situations. This leads to overlap with hardware stats,
inconsistencies, etc. It's much better to just always count the packets
flowing through the switch and let userspace do any merging that it wants.

Following patch removes vport->get_stats() interface. vport-stat is changed
to use new `struct ovs_vport_stat` rather than rtnl_link_stats64.
Definitions of rtnl_link_stats64 is removed from OVS.  dipf_port->stat is also
removed as aggregate stats are only available at netdev layer.

Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
This commit is contained in:
Pravin Shelar
2011-09-15 19:36:17 -07:00
parent 9197df76b4
commit f613a0d72c
26 changed files with 304 additions and 437 deletions

View File

@@ -115,9 +115,8 @@ enum {
VALID_IN6 = 1 << 3,
VALID_MTU = 1 << 4,
VALID_CARRIER = 1 << 5,
VALID_IS_PSEUDO = 1 << 6, /* Represents is_internal and is_tap. */
VALID_POLICING = 1 << 7,
VALID_HAVE_VPORT_STATS = 1 << 8
VALID_POLICING = 1 << 6,
VALID_HAVE_VPORT_STATS = 1 << 7
};
struct tap_state {
@@ -369,8 +368,6 @@ struct netdev_dev_linux {
struct in6_addr in6;
int mtu;
int carrier;
bool is_internal; /* Is this an openvswitch internal device? */
bool is_tap; /* Is this a tuntap device? */
uint32_t kbits_rate; /* Policing data. */
uint32_t kbits_burst;
bool have_vport_stats;
@@ -1246,21 +1243,6 @@ check_for_working_netlink_stats(void)
}
}
/* Brings the 'is_internal' and 'is_tap' members of 'netdev_dev' up-to-date. */
static void
netdev_linux_update_is_pseudo(struct netdev_dev_linux *netdev_dev)
{
if (!(netdev_dev->cache_valid & VALID_IS_PSEUDO)) {
const char *name = netdev_dev_get_name(&netdev_dev->netdev_dev);
const char *type = netdev_dev_get_type(&netdev_dev->netdev_dev);
netdev_dev->is_tap = !strcmp(type, "tap");
netdev_dev->is_internal = (!netdev_dev->is_tap
&& dpif_linux_is_internal_device(name));
netdev_dev->cache_valid |= VALID_IS_PSEUDO;
}
}
static void
swap_uint64(uint64_t *a, uint64_t *b)
{
@@ -1269,37 +1251,123 @@ swap_uint64(uint64_t *a, uint64_t *b)
*b = tmp;
}
/* Retrieves current device stats for 'netdev'. */
static void
get_stats_via_vport(const struct netdev *netdev_,
struct netdev_stats *stats)
{
struct netdev_dev_linux *netdev_dev =
netdev_dev_linux_cast(netdev_get_dev(netdev_));
if (netdev_dev->have_vport_stats ||
!(netdev_dev->cache_valid & VALID_HAVE_VPORT_STATS)) {
int error;
error = netdev_vport_get_stats(netdev_, stats);
if (error) {
VLOG_WARN_RL(&rl, "%s: obtaining netdev stats via vport failed %d",
netdev_get_name(netdev_), error);
}
netdev_dev->have_vport_stats = !error;
netdev_dev->cache_valid |= VALID_HAVE_VPORT_STATS;
}
}
static int
netdev_linux_sys_get_stats(const struct netdev *netdev_,
struct netdev_stats *stats)
{
static int use_netlink_stats = -1;
int error;
if (use_netlink_stats < 0) {
use_netlink_stats = check_for_working_netlink_stats();
}
if (use_netlink_stats) {
int ifindex;
error = get_ifindex(netdev_, &ifindex);
if (!error) {
error = get_stats_via_netlink(ifindex, stats);
}
} else {
error = get_stats_via_proc(netdev_get_name(netdev_), stats);
}
if (error) {
VLOG_WARN_RL(&rl, "%s: linux-sys get stats failed %d",
netdev_get_name(netdev_), error);
}
return error;
}
/* Retrieves current device stats for 'netdev-linux'. */
static int
netdev_linux_get_stats(const struct netdev *netdev_,
struct netdev_stats *stats)
{
struct netdev_dev_linux *netdev_dev =
netdev_dev_linux_cast(netdev_get_dev(netdev_));
static int use_netlink_stats = -1;
struct netdev_stats dev_stats;
int error;
if (netdev_dev->have_vport_stats ||
!(netdev_dev->cache_valid & VALID_HAVE_VPORT_STATS)) {
get_stats_via_vport(netdev_, stats);
error = netdev_vport_get_stats(netdev_, stats);
netdev_dev->have_vport_stats = !error;
netdev_dev->cache_valid |= VALID_HAVE_VPORT_STATS;
error = netdev_linux_sys_get_stats(netdev_, &dev_stats);
if (error) {
if (!netdev_dev->have_vport_stats) {
return error;
} else {
return 0;
}
}
if (!netdev_dev->have_vport_stats) {
if (use_netlink_stats < 0) {
use_netlink_stats = check_for_working_netlink_stats();
}
if (use_netlink_stats) {
int ifindex;
/* stats not available from OVS then use ioctl stats. */
*stats = dev_stats;
} else {
stats->rx_errors += dev_stats.rx_errors;
stats->tx_errors += dev_stats.tx_errors;
stats->rx_dropped += dev_stats.rx_dropped;
stats->tx_dropped += dev_stats.tx_dropped;
stats->multicast += dev_stats.multicast;
stats->collisions += dev_stats.collisions;
stats->rx_length_errors += dev_stats.rx_length_errors;
stats->rx_over_errors += dev_stats.rx_over_errors;
stats->rx_crc_errors += dev_stats.rx_crc_errors;
stats->rx_frame_errors += dev_stats.rx_frame_errors;
stats->rx_fifo_errors += dev_stats.rx_fifo_errors;
stats->rx_missed_errors += dev_stats.rx_missed_errors;
stats->tx_aborted_errors += dev_stats.tx_aborted_errors;
stats->tx_carrier_errors += dev_stats.tx_carrier_errors;
stats->tx_fifo_errors += dev_stats.tx_fifo_errors;
stats->tx_heartbeat_errors += dev_stats.tx_heartbeat_errors;
stats->tx_window_errors += dev_stats.tx_window_errors;
}
return 0;
}
error = get_ifindex(netdev_, &ifindex);
if (!error) {
error = get_stats_via_netlink(ifindex, stats);
}
/* Retrieves current device stats for 'netdev-tap' netdev or
* netdev-internal. */
static int
netdev_pseudo_get_stats(const struct netdev *netdev_,
struct netdev_stats *stats)
{
struct netdev_dev_linux *netdev_dev =
netdev_dev_linux_cast(netdev_get_dev(netdev_));
struct netdev_stats dev_stats;
int error;
get_stats_via_vport(netdev_, stats);
error = netdev_linux_sys_get_stats(netdev_, &dev_stats);
if (error) {
if (!netdev_dev->have_vport_stats) {
return error;
} else {
error = get_stats_via_proc(netdev_get_name(netdev_), stats);
return 0;
}
}
@@ -1309,9 +1377,8 @@ netdev_linux_get_stats(const struct netdev *netdev_,
* them back here. This does not apply if we are getting stats from the
* vport layer because it always tracks stats from the perspective of the
* switch. */
netdev_linux_update_is_pseudo(netdev_dev);
if (!error && !netdev_dev->have_vport_stats &&
(netdev_dev->is_internal || netdev_dev->is_tap)) {
if (!netdev_dev->have_vport_stats) {
*stats = dev_stats;
swap_uint64(&stats->rx_packets, &stats->tx_packets);
swap_uint64(&stats->rx_bytes, &stats->tx_bytes);
swap_uint64(&stats->rx_errors, &stats->tx_errors);
@@ -1327,9 +1394,17 @@ netdev_linux_get_stats(const struct netdev *netdev_,
stats->tx_fifo_errors = 0;
stats->tx_heartbeat_errors = 0;
stats->tx_window_errors = 0;
}
} else {
stats->rx_dropped += dev_stats.tx_dropped;
stats->tx_dropped += dev_stats.rx_dropped;
return error;
stats->rx_errors += dev_stats.tx_errors;
stats->tx_errors += dev_stats.rx_errors;
stats->multicast += dev_stats.multicast;
stats->collisions += dev_stats.collisions;
}
return 0;
}
/* Stores the features supported by 'netdev' into each of '*current',
@@ -2263,7 +2338,7 @@ netdev_linux_change_seq(const struct netdev *netdev)
return netdev_dev_linux_cast(netdev_get_dev(netdev))->change_seq;
}
#define NETDEV_LINUX_CLASS(NAME, CREATE, ENUMERATE, SET_STATS) \
#define NETDEV_LINUX_CLASS(NAME, CREATE, ENUMERATE, GET_STATS, SET_STATS) \
{ \
NAME, \
\
@@ -2296,7 +2371,7 @@ netdev_linux_change_seq(const struct netdev *netdev)
netdev_linux_get_ifindex, \
netdev_linux_get_carrier, \
netdev_linux_set_miimon_interval, \
netdev_linux_get_stats, \
GET_STATS, \
SET_STATS, \
\
netdev_linux_get_features, \
@@ -2333,6 +2408,7 @@ const struct netdev_class netdev_linux_class =
"system",
netdev_linux_create,
netdev_linux_enumerate,
netdev_linux_get_stats,
NULL); /* set_stats */
const struct netdev_class netdev_tap_class =
@@ -2340,6 +2416,7 @@ const struct netdev_class netdev_tap_class =
"tap",
netdev_linux_create_tap,
NULL, /* enumerate */
netdev_pseudo_get_stats,
NULL); /* set_stats */
const struct netdev_class netdev_internal_class =
@@ -2347,6 +2424,7 @@ const struct netdev_class netdev_internal_class =
"internal",
netdev_linux_create,
NULL, /* enumerate */
netdev_pseudo_get_stats,
netdev_vport_set_stats);
/* HTB traffic control class. */
@@ -3956,56 +4034,34 @@ tc_calc_buffer(unsigned int Bps, int mtu, uint64_t burst_bytes)
return tc_bytes_to_ticks(Bps, MAX(burst_bytes, min_burst));
}
/* Public utility functions. */
#define COPY_NETDEV_STATS \
dst->rx_packets = src->rx_packets; \
dst->tx_packets = src->tx_packets; \
dst->rx_bytes = src->rx_bytes; \
dst->tx_bytes = src->tx_bytes; \
dst->rx_errors = src->rx_errors; \
dst->tx_errors = src->tx_errors; \
dst->rx_dropped = src->rx_dropped; \
dst->tx_dropped = src->tx_dropped; \
dst->multicast = src->multicast; \
dst->collisions = src->collisions; \
dst->rx_length_errors = src->rx_length_errors; \
dst->rx_over_errors = src->rx_over_errors; \
dst->rx_crc_errors = src->rx_crc_errors; \
dst->rx_frame_errors = src->rx_frame_errors; \
dst->rx_fifo_errors = src->rx_fifo_errors; \
dst->rx_missed_errors = src->rx_missed_errors; \
dst->tx_aborted_errors = src->tx_aborted_errors; \
dst->tx_carrier_errors = src->tx_carrier_errors; \
dst->tx_fifo_errors = src->tx_fifo_errors; \
dst->tx_heartbeat_errors = src->tx_heartbeat_errors; \
dst->tx_window_errors = src->tx_window_errors
/* Copies 'src' into 'dst', performing format conversion in the process. */
void
static void
netdev_stats_from_rtnl_link_stats(struct netdev_stats *dst,
const struct rtnl_link_stats *src)
{
COPY_NETDEV_STATS;
dst->rx_packets = src->rx_packets;
dst->tx_packets = src->tx_packets;
dst->rx_bytes = src->rx_bytes;
dst->tx_bytes = src->tx_bytes;
dst->rx_errors = src->rx_errors;
dst->tx_errors = src->tx_errors;
dst->rx_dropped = src->rx_dropped;
dst->tx_dropped = src->tx_dropped;
dst->multicast = src->multicast;
dst->collisions = src->collisions;
dst->rx_length_errors = src->rx_length_errors;
dst->rx_over_errors = src->rx_over_errors;
dst->rx_crc_errors = src->rx_crc_errors;
dst->rx_frame_errors = src->rx_frame_errors;
dst->rx_fifo_errors = src->rx_fifo_errors;
dst->rx_missed_errors = src->rx_missed_errors;
dst->tx_aborted_errors = src->tx_aborted_errors;
dst->tx_carrier_errors = src->tx_carrier_errors;
dst->tx_fifo_errors = src->tx_fifo_errors;
dst->tx_heartbeat_errors = src->tx_heartbeat_errors;
dst->tx_window_errors = src->tx_window_errors;
}
/* Copies 'src' into 'dst', performing format conversion in the process. */
void
netdev_stats_from_rtnl_link_stats64(struct netdev_stats *dst,
const struct rtnl_link_stats64 *src)
{
COPY_NETDEV_STATS;
}
/* Copies 'src' into 'dst', performing format conversion in the process. */
void
netdev_stats_to_rtnl_link_stats64(struct rtnl_link_stats64 *dst,
const struct netdev_stats *src)
{
COPY_NETDEV_STATS;
dst->rx_compressed = 0;
dst->tx_compressed = 0;
}
/* Utility functions. */