#include "packets.h"
#include "poll-loop.h"
#include "random.h"
+#include "seq.h"
#include "shash.h"
#include "sset.h"
#include "timeval.h"
struct dp_netdev_queue queues[N_QUEUES];
struct hmap flow_table; /* Flow table. */
+ struct seq *queue_seq; /* Incremented whenever a packet is queued. */
/* Statistics. */
long long int n_hit; /* Number of flow table matches. */
/* Ports. */
struct dp_netdev_port *ports[MAX_PORTS];
struct list port_list;
- unsigned int serial;
+ struct seq *port_seq; /* Incremented whenever a port changes. */
};
/* A port in a netdev-based datapath. */
struct dpif_netdev {
struct dpif dpif;
struct dp_netdev *dp;
- unsigned int dp_serial;
+ uint64_t last_port_seq;
};
/* All netdev-based datapaths. */
static void dp_netdev_port_input(struct dp_netdev *dp,
struct dp_netdev_port *port,
struct ofpbuf *packet, uint32_t skb_priority,
- uint32_t skb_mark, const struct flow_tnl *tnl);
+ uint32_t pkt_mark, const struct flow_tnl *tnl);
static struct dpif_netdev *
dpif_netdev_cast(const struct dpif *dpif)
dpif = xmalloc(sizeof *dpif);
dpif_init(&dpif->dpif, dp->class, dp->name, netflow_id >> 8, netflow_id);
dpif->dp = dp;
- dpif->dp_serial = dp->serial;
+ dpif->last_port_seq = seq_read(dp->port_seq);
return &dpif->dpif;
}
for (i = 0; i < N_QUEUES; i++) {
dp->queues[i].head = dp->queues[i].tail = 0;
}
+ dp->queue_seq = seq_create();
hmap_init(&dp->flow_table);
list_init(&dp->port_list);
+ dp->port_seq = seq_create();
error = do_add_port(dp, name, "internal", ODPP_LOCAL);
if (error) {
do_del_port(dp, port->port_no);
}
dp_netdev_purge_queues(dp);
+ seq_destroy(dp->queue_seq);
hmap_destroy(&dp->flow_table);
+ seq_destroy(dp->port_seq);
free(dp->name);
free(dp);
}
list_push_back(&dp->port_list, &port->node);
dp->ports[odp_to_u32(port_no)] = port;
- dp->serial++;
+ seq_change(dp->port_seq);
return 0;
}
list_remove(&port->node);
dp->ports[odp_to_u32(port_no)] = NULL;
- dp->serial++;
+ seq_change(dp->port_seq);
netdev_close(port->netdev);
netdev_restore_flags(port->sf);
return error;
}
-static odp_port_t
+static uint32_t
dpif_netdev_get_max_ports(const struct dpif *dpif OVS_UNUSED)
{
- return u32_to_odp(MAX_PORTS);
+ return MAX_PORTS;
}
static void
dpif_netdev_port_poll(const struct dpif *dpif_, char **devnamep OVS_UNUSED)
{
struct dpif_netdev *dpif = dpif_netdev_cast(dpif_);
+ uint64_t new_port_seq;
int error;
ovs_mutex_lock(&dp_netdev_mutex);
- if (dpif->dp_serial != dpif->dp->serial) {
- dpif->dp_serial = dpif->dp->serial;
+ new_port_seq = seq_read(dpif->dp->port_seq);
+ if (dpif->last_port_seq != new_port_seq) {
+ dpif->last_port_seq = new_port_seq;
error = ENOBUFS;
} else {
error = EAGAIN;
{
struct dpif_netdev *dpif = dpif_netdev_cast(dpif_);
- /* XXX In a multithreaded process, there is a race window between this
- * function and the poll_block() in one thread and a change in
- * dpif->dp->serial in another thread. */
-
ovs_mutex_lock(&dp_netdev_mutex);
- if (dpif->dp_serial != dpif->dp->serial) {
- poll_immediate_wake();
- }
+ seq_wait(dpif->dp->port_seq, dpif->last_port_seq);
ovs_mutex_unlock(&dp_netdev_mutex);
}
static void
dpif_netdev_recv_wait(struct dpif *dpif)
{
- /* XXX In a multithreaded process, there is a race window between this
- * function and the poll_block() in one thread and a packet being queued in
- * another thread. */
+ struct dp_netdev *dp = get_dp_netdev(dpif);
+ uint64_t seq;
ovs_mutex_lock(&dp_netdev_mutex);
+ seq = seq_read(dp->queue_seq);
if (find_nonempty_queue(dpif)) {
poll_immediate_wake();
+ } else {
+ seq_wait(dp->queue_seq, seq);
}
ovs_mutex_unlock(&dp_netdev_mutex);
}
static void
dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
struct ofpbuf *packet, uint32_t skb_priority,
- uint32_t skb_mark, const struct flow_tnl *tnl)
+ uint32_t pkt_mark, const struct flow_tnl *tnl)
{
struct dp_netdev_flow *flow;
struct flow key;
return;
}
in_port_.odp_port = port->port_no;
- flow_extract(packet, skb_priority, skb_mark, tnl, &in_port_, &key);
+ flow_extract(packet, skb_priority, pkt_mark, tnl, &in_port_, &key);
flow = dp_netdev_lookup_flow(dp, &key);
if (flow) {
dp_netdev_flow_used(flow, packet);
buf->size = packet->size;
upcall->packet = buf;
+ seq_change(dp->queue_seq);
+
return 0;
} else {
dp->n_lost++;
dp->ports[odp_to_u32(port->port_no)] = NULL;
dp->ports[port_no] = port;
port->port_no = u32_to_odp(port_no);
- dp->serial++;
+ seq_change(dp->port_seq);
unixctl_command_reply(conn, NULL);
}