#include "netlink.h"
#include "ofpbuf.h"
#include "openflow/openflow.h"
+#include "ovs-atomic.h"
#include "packets.h"
#include "poll-loop.h"
#include "rtnetlink-link.h"
* additional log messages. */
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20);
+/* Polling miimon status for all ports causes performance degradation when
+ * handling a large number of ports. If there are no devices using miimon, then
+ * we skip netdev_linux_miimon_run() and netdev_linux_miimon_wait(). */
+static atomic_int miimon_cnt = ATOMIC_VAR_INIT(0);
+
static void netdev_linux_run(void);
static int netdev_linux_do_ethtool(const char *name, struct ethtool_cmd *,
static int get_stats_via_netlink(int ifindex, struct netdev_stats *stats);
static int get_stats_via_proc(const char *netdev_name, struct netdev_stats *stats);
static int af_packet_sock(void);
+static bool netdev_linux_miimon_enabled(void);
static void netdev_linux_miimon_run(void);
static void netdev_linux_miimon_wait(void);
return sock;
}
+static bool
+netdev_linux_miimon_enabled(void)
+{
+ int miimon;
+
+ atomic_read(&miimon_cnt, &miimon);
+ return miimon > 0;
+}
+
static void
netdev_linux_run(void)
{
struct nl_sock *sock;
int error;
- netdev_linux_miimon_run();
+ if (netdev_linux_miimon_enabled()) {
+ netdev_linux_miimon_run();
+ }
sock = netdev_linux_notify_sock();
if (!sock) {
{
struct nl_sock *sock;
- netdev_linux_miimon_wait();
+ if (netdev_linux_miimon_enabled()) {
+ netdev_linux_miimon_wait();
+ }
sock = netdev_linux_notify_sock();
if (sock) {
nl_sock_wait(sock, POLLIN);
static void
netdev_linux_common_construct(struct netdev_linux *netdev)
{
- ovs_mutex_init(&netdev->mutex, PTHREAD_MUTEX_NORMAL);
+ ovs_mutex_init(&netdev->mutex);
netdev->change_seq = 1;
}
close(netdev->tap_fd);
}
+ if (netdev->miimon_interval > 0) {
+ int junk;
+ atomic_sub(&miimon_cnt, 1, &junk);
+ }
+
ovs_mutex_destroy(&netdev->mutex);
}
ovs_mutex_lock(&netdev->mutex);
interval = interval > 0 ? MAX(interval, 100) : 0;
if (netdev->miimon_interval != interval) {
+ int junk;
+
+ if (interval && !netdev->miimon_interval) {
+ atomic_add(&miimon_cnt, 1, &junk);
+ } else if (!interval && netdev->miimon_interval) {
+ atomic_sub(&miimon_cnt, 1, &junk);
+ }
+
netdev->miimon_interval = interval;
timer_set_expired(&netdev->miimon_timer);
}
return true;
}
+struct netdev_linux_queue_state {
+ unsigned int *queues;
+ size_t cur_queue;
+ size_t n_queues;
+};
+
static int
-netdev_linux_dump_queues(const struct netdev *netdev_,
- netdev_dump_queues_cb *cb, void *aux)
+netdev_linux_queue_dump_start(const struct netdev *netdev_, void **statep)
{
- struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ const struct netdev_linux *netdev = netdev_linux_cast(netdev_);
int error;
ovs_mutex_lock(&netdev->mutex);
error = tc_query_qdisc(netdev_);
if (!error) {
if (netdev->tc->ops->class_get) {
- struct tc_queue *queue, *next_queue;
- struct smap details;
-
- smap_init(&details);
- HMAP_FOR_EACH_SAFE (queue, next_queue, hmap_node,
- &netdev->tc->queues) {
- int retval;
-
- smap_clear(&details);
-
- retval = netdev->tc->ops->class_get(netdev_, queue, &details);
- if (!retval) {
- (*cb)(queue->queue_id, &details, aux);
- } else {
- error = retval;
- }
+ struct netdev_linux_queue_state *state;
+ struct tc_queue *queue;
+ size_t i;
+
+ *statep = state = xmalloc(sizeof *state);
+ state->n_queues = hmap_count(&netdev->tc->queues);
+ state->cur_queue = 0;
+ state->queues = xmalloc(state->n_queues * sizeof *state->queues);
+
+ i = 0;
+ HMAP_FOR_EACH (queue, hmap_node, &netdev->tc->queues) {
+ state->queues[i++] = queue->queue_id;
}
- smap_destroy(&details);
} else {
error = EOPNOTSUPP;
}
return error;
}
+static int
+netdev_linux_queue_dump_next(const struct netdev *netdev_, void *state_,
+ unsigned int *queue_idp, struct smap *details)
+{
+ const struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ struct netdev_linux_queue_state *state = state_;
+ int error = EOF;
+
+ ovs_mutex_lock(&netdev->mutex);
+ while (state->cur_queue < state->n_queues) {
+ unsigned int queue_id = state->queues[state->cur_queue++];
+ struct tc_queue *queue = tc_find_queue(netdev_, queue_id);
+
+ if (queue) {
+ *queue_idp = queue_id;
+ error = netdev->tc->ops->class_get(netdev_, queue, details);
+ break;
+ }
+ }
+ ovs_mutex_unlock(&netdev->mutex);
+
+ return error;
+}
+
+static int
+netdev_linux_queue_dump_done(const struct netdev *netdev OVS_UNUSED,
+ void *state_)
+{
+ struct netdev_linux_queue_state *state = state_;
+
+ free(state->queues);
+ free(state);
+ return 0;
+}
+
static int
netdev_linux_dump_queue_stats(const struct netdev *netdev_,
netdev_dump_queue_stats_cb *cb, void *aux)
{
uint8_t *s6 = in6->s6_addr;
#define X8 "%2"SCNx8
- return sscanf(line,
- " "X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8
- "%*x %*x %*x %*x %16s\n",
- &s6[0], &s6[1], &s6[2], &s6[3],
- &s6[4], &s6[5], &s6[6], &s6[7],
- &s6[8], &s6[9], &s6[10], &s6[11],
- &s6[12], &s6[13], &s6[14], &s6[15],
- ifname) == 17;
+ return ovs_scan(line,
+ " "X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8 X8
+ "%*x %*x %*x %*x %16s\n",
+ &s6[0], &s6[1], &s6[2], &s6[3],
+ &s6[4], &s6[5], &s6[6], &s6[7],
+ &s6[8], &s6[9], &s6[10], &s6[11],
+ &s6[12], &s6[13], &s6[14], &s6[15],
+ ifname);
}
/* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address (if
int refcnt, metric, mtu;
unsigned int flags, use, window, irtt;
- if (sscanf(line,
- "%16s %"SCNx32" %"SCNx32" %04X %d %u %d %"SCNx32
- " %d %u %u\n",
- iface, &dest, &gateway, &flags, &refcnt,
- &use, &metric, &mask, &mtu, &window, &irtt) != 11) {
-
+ if (!ovs_scan(line,
+ "%16s %"SCNx32" %"SCNx32" %04X %d %u %d %"SCNx32
+ " %d %u %u\n",
+ iface, &dest, &gateway, &flags, &refcnt,
+ &use, &metric, &mask, &mtu, &window, &irtt)) {
VLOG_WARN_RL(&rl, "%s: could not parse line %d: %s",
fn, ln, line);
continue;
if (nd & NETDEV_PROMISC) {
iff |= IFF_PROMISC;
}
+ if (nd & NETDEV_LOOPBACK) {
+ iff |= IFF_LOOPBACK;
+ }
return iff;
}
if (iff & IFF_PROMISC) {
nd |= NETDEV_PROMISC;
}
+ if (iff & IFF_LOOPBACK) {
+ nd |= NETDEV_LOOPBACK;
+ }
return nd;
}
netdev_linux_set_queue, \
netdev_linux_delete_queue, \
netdev_linux_get_queue_stats, \
- netdev_linux_dump_queues, \
+ netdev_linux_queue_dump_start, \
+ netdev_linux_queue_dump_next, \
+ netdev_linux_queue_dump_done, \
netdev_linux_dump_queue_stats, \
\
netdev_linux_get_in4, \
if (++ln >= 3) {
char devname[16];
#define X64 "%"SCNu64
- if (sscanf(line,
- " %15[^:]:"
- X64 X64 X64 X64 X64 X64 X64 "%*u"
- X64 X64 X64 X64 X64 X64 X64 "%*u",
- devname,
- &stats->rx_bytes,
- &stats->rx_packets,
- &stats->rx_errors,
- &stats->rx_dropped,
- &stats->rx_fifo_errors,
- &stats->rx_frame_errors,
- &stats->multicast,
- &stats->tx_bytes,
- &stats->tx_packets,
- &stats->tx_errors,
- &stats->tx_dropped,
- &stats->tx_fifo_errors,
- &stats->collisions,
- &stats->tx_carrier_errors) != 15) {
+ if (!ovs_scan(line,
+ " %15[^:]:"
+ X64 X64 X64 X64 X64 X64 X64 "%*u"
+ X64 X64 X64 X64 X64 X64 X64 "%*u",
+ devname,
+ &stats->rx_bytes,
+ &stats->rx_packets,
+ &stats->rx_errors,
+ &stats->rx_dropped,
+ &stats->rx_fifo_errors,
+ &stats->rx_frame_errors,
+ &stats->multicast,
+ &stats->tx_bytes,
+ &stats->tx_packets,
+ &stats->tx_errors,
+ &stats->tx_dropped,
+ &stats->tx_fifo_errors,
+ &stats->collisions,
+ &stats->tx_carrier_errors)) {
VLOG_WARN_RL(&rl, "%s:%d: parse error", fn, ln);
} else if (!strcmp(devname, netdev_name)) {
stats->rx_length_errors = UINT64_MAX;