[ovs-dev] [cmap 2/2] dpif-netdev: Use cmap for ports.
Ben Pfaff
blp at nicira.com
Fri May 2 00:14:56 UTC 2014
Signed-off-by: Ben Pfaff <blp at nicira.com>
---
lib/dpif-netdev.c | 153 +++++++++++++++++++++++++----------------------------
1 file changed, 73 insertions(+), 80 deletions(-)
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 55712dd..2dddad5 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -32,6 +32,7 @@
#include <unistd.h>
#include "classifier.h"
+#include "cmap.h"
#include "csum.h"
#include "dpif.h"
#include "dpif-provider.h"
@@ -120,7 +121,7 @@ struct dp_netdev_queue {
* Acquisition order is, from outermost to innermost:
*
* dp_netdev_mutex (global)
- * port_rwlock
+ * port_mutex
* flow_mutex
* cls.rwlock
* queue_rwlock
@@ -159,10 +160,9 @@ struct dp_netdev {
/* Ports.
*
- * Any lookup into 'ports' or any access to the dp_netdev_ports found
- * through 'ports' requires taking 'port_rwlock'. */
- struct ovs_rwlock port_rwlock;
- struct hmap ports OVS_GUARDED;
+ * Protected by RCU. Take the mutex to add or remove ports. */
+ struct ovs_mutex port_mutex;
+ struct cmap ports;
struct seq *port_seq; /* Incremented whenever a port changes. */
/* Forwarding threads. */
@@ -173,8 +173,7 @@ struct dp_netdev {
};
static struct dp_netdev_port *dp_netdev_lookup_port(const struct dp_netdev *dp,
- odp_port_t)
- OVS_REQ_RDLOCK(dp->port_rwlock);
+ odp_port_t);
enum dp_stat_type {
DP_STAT_HIT, /* Packets that matched in the flow table. */
@@ -194,7 +193,7 @@ struct dp_netdev_stats {
/* A port in a netdev-based datapath. */
struct dp_netdev_port {
- struct hmap_node node; /* Node in dp_netdev's 'ports'. */
+ struct cmap_node node; /* Node in dp_netdev's 'ports'. */
odp_port_t port_no;
struct netdev *netdev;
struct netdev_saved_flags *sf;
@@ -333,19 +332,17 @@ struct dpif_netdev {
};
static int get_port_by_number(struct dp_netdev *dp, odp_port_t port_no,
- struct dp_netdev_port **portp)
- OVS_REQ_RDLOCK(dp->port_rwlock);
+ struct dp_netdev_port **portp);
static int get_port_by_name(struct dp_netdev *dp, const char *devname,
- struct dp_netdev_port **portp)
- OVS_REQ_RDLOCK(dp->port_rwlock);
+ struct dp_netdev_port **portp);
static void dp_netdev_free(struct dp_netdev *)
OVS_REQUIRES(dp_netdev_mutex);
static void dp_netdev_flow_flush(struct dp_netdev *);
static int do_add_port(struct dp_netdev *dp, const char *devname,
const char *type, odp_port_t port_no)
- OVS_REQ_WRLOCK(dp->port_rwlock);
+ OVS_REQ_WRLOCK(dp->port_mutex);
static int do_del_port(struct dp_netdev *dp, odp_port_t port_no)
- OVS_REQ_WRLOCK(dp->port_rwlock);
+ OVS_REQ_WRLOCK(dp->port_mutex);
static void dp_netdev_destroy_all_queues(struct dp_netdev *dp)
OVS_REQ_WRLOCK(dp->queue_rwlock);
static int dpif_netdev_open(const struct dpif_class *, const char *name,
@@ -426,7 +423,7 @@ create_dpif_netdev(struct dp_netdev *dp)
* Return ODPP_NONE on failure. */
static odp_port_t
choose_port(struct dp_netdev *dp, const char *name)
- OVS_REQ_RDLOCK(dp->port_rwlock)
+ OVS_REQ_RDLOCK(dp->port_mutex)
{
uint32_t port_no;
@@ -488,14 +485,14 @@ create_dp_netdev(const char *name, const struct dpif_class *class,
ovsthread_stats_init(&dp->stats);
- ovs_rwlock_init(&dp->port_rwlock);
- hmap_init(&dp->ports);
+ ovs_mutex_init(&dp->port_mutex);
+ cmap_init(&dp->ports);
dp->port_seq = seq_create();
latch_init(&dp->exit_latch);
- ovs_rwlock_wrlock(&dp->port_rwlock);
+ ovs_mutex_lock(&dp->port_mutex);
error = do_add_port(dp, name, "internal", ODPP_LOCAL);
- ovs_rwlock_unlock(&dp->port_rwlock);
+ ovs_mutex_unlock(&dp->port_mutex);
if (error) {
dp_netdev_free(dp);
return error;
@@ -554,8 +551,9 @@ static void
dp_netdev_free(struct dp_netdev *dp)
OVS_REQUIRES(dp_netdev_mutex)
{
- struct dp_netdev_port *port, *next;
+ struct dp_netdev_port *port;
struct dp_netdev_stats *bucket;
+ struct cmap_cursor cursor;
int i;
shash_find_and_delete(&dp_netdevs, dp->name);
@@ -564,11 +562,11 @@ dp_netdev_free(struct dp_netdev *dp)
free(dp->pmd_threads);
dp_netdev_flow_flush(dp);
- ovs_rwlock_wrlock(&dp->port_rwlock);
- HMAP_FOR_EACH_SAFE (port, next, node, &dp->ports) {
+ ovs_mutex_lock(&dp->port_mutex);
+ CMAP_FOR_EACH (port, node, &cursor, &dp->ports) {
do_del_port(dp, port->port_no);
}
- ovs_rwlock_unlock(&dp->port_rwlock);
+ ovs_mutex_unlock(&dp->port_mutex);
OVSTHREAD_STATS_FOR_EACH_BUCKET (bucket, i, &dp->stats) {
ovs_mutex_destroy(&bucket->mutex);
@@ -586,7 +584,7 @@ dp_netdev_free(struct dp_netdev *dp)
hmap_destroy(&dp->flow_table);
ovs_mutex_destroy(&dp->flow_mutex);
seq_destroy(dp->port_seq);
- hmap_destroy(&dp->ports);
+ cmap_destroy(&dp->ports);
latch_destroy(&dp->exit_latch);
free(CONST_CAST(char *, dp->name));
free(dp);
@@ -671,7 +669,7 @@ dp_netdev_reload_pmd_threads(struct dp_netdev *dp)
static int
do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
odp_port_t port_no)
- OVS_REQ_WRLOCK(dp->port_rwlock)
+ OVS_REQ_WRLOCK(dp->port_mutex)
{
struct netdev_saved_flags *sf;
struct dp_netdev_port *port;
@@ -733,7 +731,7 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
}
ovs_refcount_init(&port->ref_cnt);
- hmap_insert(&dp->ports, &port->node, hash_int(odp_to_u32(port_no), 0));
+ cmap_insert(&dp->ports, &port->node, hash_int(odp_to_u32(port_no), 0));
seq_change(dp->port_seq);
return 0;
@@ -749,7 +747,7 @@ dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
odp_port_t port_no;
int error;
- ovs_rwlock_wrlock(&dp->port_rwlock);
+ ovs_mutex_lock(&dp->port_mutex);
dpif_port = netdev_vport_get_dpif_port(netdev, namebuf, sizeof namebuf);
if (*port_nop != ODPP_NONE) {
port_no = *port_nop;
@@ -762,7 +760,7 @@ dpif_netdev_port_add(struct dpif *dpif, struct netdev *netdev,
*port_nop = port_no;
error = do_add_port(dp, dpif_port, netdev_get_type(netdev), port_no);
}
- ovs_rwlock_unlock(&dp->port_rwlock);
+ ovs_mutex_unlock(&dp->port_mutex);
return error;
}
@@ -773,9 +771,9 @@ dpif_netdev_port_del(struct dpif *dpif, odp_port_t port_no)
struct dp_netdev *dp = get_dp_netdev(dpif);
int error;
- ovs_rwlock_wrlock(&dp->port_rwlock);
+ ovs_mutex_lock(&dp->port_mutex);
error = port_no == ODPP_LOCAL ? EINVAL : do_del_port(dp, port_no);
- ovs_rwlock_unlock(&dp->port_rwlock);
+ ovs_mutex_unlock(&dp->port_mutex);
return error;
}
@@ -788,11 +786,10 @@ is_valid_port_number(odp_port_t port_no)
static struct dp_netdev_port *
dp_netdev_lookup_port(const struct dp_netdev *dp, odp_port_t port_no)
- OVS_REQ_RDLOCK(dp->port_rwlock)
{
struct dp_netdev_port *port;
- HMAP_FOR_EACH_IN_BUCKET (port, node, hash_int(odp_to_u32(port_no), 0),
+ CMAP_FOR_EACH_WITH_HASH (port, node, hash_int(odp_to_u32(port_no), 0),
&dp->ports) {
if (port->port_no == port_no) {
return port;
@@ -804,7 +801,6 @@ dp_netdev_lookup_port(const struct dp_netdev *dp, odp_port_t port_no)
static int
get_port_by_number(struct dp_netdev *dp,
odp_port_t port_no, struct dp_netdev_port **portp)
- OVS_REQ_RDLOCK(dp->port_rwlock)
{
if (!is_valid_port_number(port_no)) {
*portp = NULL;
@@ -824,30 +820,36 @@ port_ref(struct dp_netdev_port *port)
}
static void
-port_unref(struct dp_netdev_port *port)
+port_destroy__(struct dp_netdev_port *port)
{
- if (port && ovs_refcount_unref(&port->ref_cnt) == 1) {
- int i;
+ int i;
- netdev_close(port->netdev);
- netdev_restore_flags(port->sf);
+ netdev_close(port->netdev);
+ netdev_restore_flags(port->sf);
- for (i = 0; i < netdev_n_rxq(port->netdev); i++) {
- netdev_rxq_close(port->rxq[i]);
- }
- free(port->type);
- free(port);
+ for (i = 0; i < netdev_n_rxq(port->netdev); i++) {
+ netdev_rxq_close(port->rxq[i]);
+ }
+ free(port->type);
+ free(port);
+}
+
+static void
+port_unref(struct dp_netdev_port *port)
+{
+ if (port && ovs_refcount_unref(&port->ref_cnt) == 1) {
+ ovsrcu_postpone(port_destroy__, port);
}
}
static int
get_port_by_name(struct dp_netdev *dp,
const char *devname, struct dp_netdev_port **portp)
- OVS_REQ_RDLOCK(dp->port_rwlock)
{
struct dp_netdev_port *port;
+ struct cmap_cursor cursor;
- HMAP_FOR_EACH (port, node, &dp->ports) {
+ CMAP_FOR_EACH (port, node, &cursor, &dp->ports) {
if (!strcmp(netdev_get_name(port->netdev), devname)) {
*portp = port;
return 0;
@@ -858,7 +860,7 @@ get_port_by_name(struct dp_netdev *dp,
static int
do_del_port(struct dp_netdev *dp, odp_port_t port_no)
- OVS_REQ_WRLOCK(dp->port_rwlock)
+ OVS_REQUIRES(dp->port_mutex)
{
struct dp_netdev_port *port;
int error;
@@ -868,7 +870,7 @@ do_del_port(struct dp_netdev *dp, odp_port_t port_no)
return error;
}
- hmap_remove(&dp->ports, &port->node);
+ cmap_remove(&dp->ports, &port->node);
seq_change(dp->port_seq);
if (netdev_is_pmd(port->netdev)) {
dp_netdev_reload_pmd_threads(dp);
@@ -895,12 +897,10 @@ dpif_netdev_port_query_by_number(const struct dpif *dpif, odp_port_t port_no,
struct dp_netdev_port *port;
int error;
- ovs_rwlock_rdlock(&dp->port_rwlock);
error = get_port_by_number(dp, port_no, &port);
if (!error && dpif_port) {
answer_port_query(port, dpif_port);
}
- ovs_rwlock_unlock(&dp->port_rwlock);
return error;
}
@@ -913,12 +913,10 @@ dpif_netdev_port_query_by_name(const struct dpif *dpif, const char *devname,
struct dp_netdev_port *port;
int error;
- ovs_rwlock_rdlock(&dp->port_rwlock);
error = get_port_by_name(dp, devname, &port);
if (!error && dpif_port) {
answer_port_query(port, dpif_port);
}
- ovs_rwlock_unlock(&dp->port_rwlock);
return error;
}
@@ -978,8 +976,7 @@ dpif_netdev_flow_flush(struct dpif *dpif)
}
struct dp_netdev_port_state {
- uint32_t bucket;
- uint32_t offset;
+ struct cmap_position position;
char *name;
};
@@ -996,11 +993,10 @@ dpif_netdev_port_dump_next(const struct dpif *dpif, void *state_,
{
struct dp_netdev_port_state *state = state_;
struct dp_netdev *dp = get_dp_netdev(dpif);
- struct hmap_node *node;
+ struct cmap_node *node;
int retval;
- ovs_rwlock_rdlock(&dp->port_rwlock);
- node = hmap_at_position(&dp->ports, &state->bucket, &state->offset);
+ node = cmap_next_position(&dp->ports, &state->position);
if (node) {
struct dp_netdev_port *port;
@@ -1016,7 +1012,6 @@ dpif_netdev_port_dump_next(const struct dpif *dpif, void *state_,
} else {
retval = EOF;
}
- ovs_rwlock_unlock(&dp->port_rwlock);
return retval;
}
@@ -1541,10 +1536,8 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute)
miniflow_initialize(&key.flow, key.buf);
miniflow_extract(execute->packet, md, &key.flow);
- ovs_rwlock_rdlock(&dp->port_rwlock);
dp_netdev_execute_actions(dp, &key.flow, execute->packet, false, md,
execute->actions, execute->actions_len);
- ovs_rwlock_unlock(&dp->port_rwlock);
return 0;
}
@@ -1783,10 +1776,9 @@ dpif_netdev_run(struct dpif *dpif)
{
struct dp_netdev_port *port;
struct dp_netdev *dp = get_dp_netdev(dpif);
+ struct cmap_cursor cursor;
- ovs_rwlock_rdlock(&dp->port_rwlock);
-
- HMAP_FOR_EACH (port, node, &dp->ports) {
+ CMAP_FOR_EACH (port, node, &cursor, &dp->ports) {
if (!netdev_is_pmd(port->netdev)) {
int i;
@@ -1795,8 +1787,6 @@ dpif_netdev_run(struct dpif *dpif)
}
}
}
-
- ovs_rwlock_unlock(&dp->port_rwlock);
}
static void
@@ -1804,10 +1794,9 @@ dpif_netdev_wait(struct dpif *dpif)
{
struct dp_netdev_port *port;
struct dp_netdev *dp = get_dp_netdev(dpif);
+ struct cmap_cursor cursor;
- ovs_rwlock_rdlock(&dp->port_rwlock);
-
- HMAP_FOR_EACH (port, node, &dp->ports) {
+ CMAP_FOR_EACH (port, node, &cursor, &dp->ports) {
if (!netdev_is_pmd(port->netdev)) {
int i;
@@ -1816,7 +1805,6 @@ dpif_netdev_wait(struct dpif *dpif)
}
}
}
- ovs_rwlock_unlock(&dp->port_rwlock);
}
struct rxq_poll {
@@ -1831,12 +1819,12 @@ pmd_load_queues(struct pmd_thread *f,
struct dp_netdev *dp = f->dp;
struct rxq_poll *poll_list = *ppoll_list;
struct dp_netdev_port *port;
+ struct cmap_cursor cursor;
int id = f->id;
int index;
int i;
/* Simple scheduler for netdev rx polling. */
- ovs_rwlock_rdlock(&dp->port_rwlock);
for (i = 0; i < poll_cnt; i++) {
port_unref(poll_list[i].port);
}
@@ -1844,7 +1832,7 @@ pmd_load_queues(struct pmd_thread *f,
poll_cnt = 0;
index = 0;
- HMAP_FOR_EACH (port, node, &f->dp->ports) {
+ CMAP_FOR_EACH (port, node, &cursor, &f->dp->ports) {
if (netdev_is_pmd(port->netdev)) {
int i;
@@ -1862,7 +1850,6 @@ pmd_load_queues(struct pmd_thread *f,
}
}
- ovs_rwlock_unlock(&dp->port_rwlock);
*ppoll_list = poll_list;
return poll_cnt;
}
@@ -2008,7 +1995,6 @@ dp_netdev_count_packet(struct dp_netdev *dp, enum dp_stat_type type)
static void
dp_netdev_input(struct dp_netdev *dp, struct ofpbuf *packet,
struct pkt_metadata *md)
- OVS_REQ_RDLOCK(dp->port_rwlock)
{
struct dp_netdev_flow *netdev_flow;
struct {
@@ -2046,7 +2032,6 @@ dp_netdev_input(struct dp_netdev *dp, struct ofpbuf *packet,
static void
dp_netdev_port_input(struct dp_netdev *dp, struct ofpbuf *packet,
struct pkt_metadata *md)
- OVS_REQ_RDLOCK(dp->port_rwlock)
{
uint32_t *recirc_depth = recirc_depth_get();
@@ -2260,7 +2245,8 @@ static void
dpif_dummy_change_port_number(struct unixctl_conn *conn, int argc OVS_UNUSED,
const char *argv[], void *aux OVS_UNUSED)
{
- struct dp_netdev_port *port;
+ struct dp_netdev_port *old_port;
+ struct dp_netdev_port *new_port;
struct dp_netdev *dp;
odp_port_t port_no;
@@ -2274,8 +2260,8 @@ dpif_dummy_change_port_number(struct unixctl_conn *conn, int argc OVS_UNUSED,
ovs_refcount_ref(&dp->ref_cnt);
ovs_mutex_unlock(&dp_netdev_mutex);
- ovs_rwlock_wrlock(&dp->port_rwlock);
- if (get_port_by_name(dp, argv[2], &port)) {
+ ovs_mutex_lock(&dp->port_mutex);
+ if (get_port_by_name(dp, argv[2], &old_port)) {
unixctl_command_reply_error(conn, "unknown port");
goto exit;
}
@@ -2289,14 +2275,21 @@ dpif_dummy_change_port_number(struct unixctl_conn *conn, int argc OVS_UNUSED,
unixctl_command_reply_error(conn, "port number already in use");
goto exit;
}
- hmap_remove(&dp->ports, &port->node);
- port->port_no = port_no;
- hmap_insert(&dp->ports, &port->node, hash_int(odp_to_u32(port_no), 0));
+
+ /* Remove old port. */
+ cmap_remove(&dp->ports, &old_port->node);
+ ovsrcu_postpone(free, old_port);
+
+ /* Insert new port (cmap semantics mean we cannot re-insert 'old_port'). */
+ new_port = xmemdup(old_port, sizeof *old_port);
+ new_port->port_no = port_no;
+ cmap_insert(&dp->ports, &new_port->node, hash_int(odp_to_u32(port_no), 0));
+
seq_change(dp->port_seq);
unixctl_command_reply(conn, NULL);
exit:
- ovs_rwlock_unlock(&dp->port_rwlock);
+ ovs_mutex_unlock(&dp->port_mutex);
dp_netdev_unref(dp);
}
--
1.7.10.4
More information about the dev
mailing list