[ovs-dev] [PATCH v8 10/16] dpif-netdev: Use hmap for ports.
Ilya Maximets
i.maximets at samsung.com
Wed Apr 20 14:21:42 UTC 2016
On 20.04.2016 01:28, diproiettod at vmware.com (Daniele Di Proietto) wrote:
> netdev objects are hard to use with RCU, because it's not possible to
> split removal and reclamation. Postponing the removal means that the
> port is not removed and cannot be readded immediately. Waiting for
> reclamation means introducing a quiescent state, and that may introduce
> subtle bugs, due to the RCU model we use in userspace.
>
> This commit changes the port container from cmap to hmap. 'port_mutex'
> must be held by readers and writers. This shouldn't have performace
> impact, as readers in the fast path use a thread local cache.
>
> Signed-off-by: Daniele Di Proietto <diproiettod at vmware.com>
> ---
> lib/dpif-netdev.c | 96 +++++++++++++++++++++++++++++++++----------------------
> 1 file changed, 57 insertions(+), 39 deletions(-)
>
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index bd2249e..8cc37e2 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -195,9 +195,10 @@ struct dp_netdev {
>
> /* Ports.
> *
> - * Protected by RCU. Take the mutex to add or remove ports. */
> + * Any lookup into 'ports' or any access to the dp_netdev_ports found
> + * through 'ports' requires taking 'port_mutex'. */
> struct ovs_mutex port_mutex;
> - struct cmap ports;
> + struct hmap ports;
> struct seq *port_seq; /* Incremented whenever a port changes. */
>
> /* Protects access to ofproto-dpif-upcall interface during revalidator
> @@ -228,7 +229,8 @@ struct dp_netdev {
> };
>
> static struct dp_netdev_port *dp_netdev_lookup_port(const struct dp_netdev *dp,
> - odp_port_t);
> + odp_port_t)
> + OVS_REQUIRES(&dp->port_mutex);
OVS_REQUIRES(dp->port_mutex);
here and 2 times more below.
>
> enum dp_stat_type {
> DP_STAT_EXACT_HIT, /* Packets that had an exact match (emc). */
> @@ -248,7 +250,7 @@ enum pmd_cycles_counter_type {
> struct dp_netdev_port {
> odp_port_t port_no;
> struct netdev *netdev;
> - struct cmap_node node; /* Node in dp_netdev's 'ports'. */
> + struct hmap_node node; /* Node in dp_netdev's 'ports'. */
> struct netdev_saved_flags *sf;
> unsigned n_rxq; /* Number of elements in 'rxq' */
> struct netdev_rxq **rxq;
> @@ -476,9 +478,11 @@ struct dpif_netdev {
> };
>
> static int get_port_by_number(struct dp_netdev *dp, odp_port_t port_no,
> - struct dp_netdev_port **portp);
> + struct dp_netdev_port **portp)
> + OVS_REQUIRES(dp->port_mutex);
> static int get_port_by_name(struct dp_netdev *dp, const char *devname,
> - struct dp_netdev_port **portp);
> + struct dp_netdev_port **portp)
> + OVS_REQUIRES(dp->port_mutex);
> static void dp_netdev_free(struct dp_netdev *)
> OVS_REQUIRES(dp_netdev_mutex);
> static int do_add_port(struct dp_netdev *dp, const char *devname,
> @@ -522,7 +526,8 @@ dp_netdev_add_rxq_to_pmd(struct dp_netdev_pmd_thread *pmd,
> struct dp_netdev_port *port, struct netdev_rxq *rx);
> static struct dp_netdev_pmd_thread *
> dp_netdev_less_loaded_pmd_on_numa(struct dp_netdev *dp, int numa_id);
> -static void dp_netdev_reset_pmd_threads(struct dp_netdev *dp);
> +static void dp_netdev_reset_pmd_threads(struct dp_netdev *dp)
> + OVS_REQUIRES(dp->port_mutex);
> static bool dp_netdev_pmd_try_ref(struct dp_netdev_pmd_thread *pmd);
> static void dp_netdev_pmd_unref(struct dp_netdev_pmd_thread *pmd);
> static void dp_netdev_pmd_flow_flush(struct dp_netdev_pmd_thread *pmd);
> @@ -913,7 +918,7 @@ create_dp_netdev(const char *name, const struct dpif_class *class,
> atomic_flag_clear(&dp->destroyed);
>
> ovs_mutex_init(&dp->port_mutex);
> - cmap_init(&dp->ports);
> + hmap_init(&dp->ports);
> dp->port_seq = seq_create();
> fat_rwlock_init(&dp->upcall_rwlock);
>
> @@ -984,7 +989,7 @@ static void
> dp_netdev_free(struct dp_netdev *dp)
> OVS_REQUIRES(dp_netdev_mutex)
> {
> - struct dp_netdev_port *port;
> + struct dp_netdev_port *port, *next;
>
> shash_find_and_delete(&dp_netdevs, dp->name);
>
> @@ -993,15 +998,14 @@ dp_netdev_free(struct dp_netdev *dp)
> ovsthread_key_delete(dp->per_pmd_key);
>
> ovs_mutex_lock(&dp->port_mutex);
> - CMAP_FOR_EACH (port, node, &dp->ports) {
> - /* PMD threads are destroyed here. do_del_port() cannot quiesce */
> + HMAP_FOR_EACH_SAFE (port, next, node, &dp->ports) {
> do_del_port(dp, port);
> }
> ovs_mutex_unlock(&dp->port_mutex);
> cmap_destroy(&dp->poll_threads);
>
> seq_destroy(dp->port_seq);
> - cmap_destroy(&dp->ports);
> + hmap_destroy(&dp->ports);
> ovs_mutex_destroy(&dp->port_mutex);
>
> /* Upcalls must be disabled at this point */
> @@ -1222,7 +1226,7 @@ do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
> return error;
> }
>
> - cmap_insert(&dp->ports, &port->node, hash_port_no(port_no));
> + hmap_insert(&dp->ports, &port->node, hash_port_no(port_no));
>
> dp_netdev_add_port_to_pmds(dp, port);
> seq_change(dp->port_seq);
> @@ -1288,10 +1292,11 @@ 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_REQUIRES(&dp->port_mutex)
here
> {
> struct dp_netdev_port *port;
>
> - CMAP_FOR_EACH_WITH_HASH (port, node, hash_port_no(port_no), &dp->ports) {
> + HMAP_FOR_EACH_WITH_HASH (port, node, hash_port_no(port_no), &dp->ports) {
> if (port->port_no == port_no) {
> return port;
> }
> @@ -1302,6 +1307,7 @@ 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_REQUIRES(&dp->port_mutex)
and here.
> {
> if (!is_valid_port_number(port_no)) {
> *portp = NULL;
> @@ -1338,7 +1344,7 @@ get_port_by_name(struct dp_netdev *dp,
> {
> struct dp_netdev_port *port;
>
> - CMAP_FOR_EACH (port, node, &dp->ports) {
> + HMAP_FOR_EACH (port, node, &dp->ports) {
> if (!strcmp(netdev_get_name(port->netdev), devname)) {
> *portp = port;
> return 0;
> @@ -1373,10 +1379,11 @@ get_n_pmd_threads_on_numa(struct dp_netdev *dp, int numa_id)
> * is on numa node 'numa_id'. */
> static bool
> has_pmd_port_for_numa(struct dp_netdev *dp, int numa_id)
> + OVS_REQUIRES(dp->port_mutex)
> {
> struct dp_netdev_port *port;
>
> - CMAP_FOR_EACH (port, node, &dp->ports) {
> + HMAP_FOR_EACH (port, node, &dp->ports) {
> if (netdev_is_pmd(port->netdev)
> && netdev_get_numa_id(port->netdev) == numa_id) {
> return true;
> @@ -1391,7 +1398,7 @@ static void
> do_del_port(struct dp_netdev *dp, struct dp_netdev_port *port)
> OVS_REQUIRES(dp->port_mutex)
> {
> - cmap_remove(&dp->ports, &port->node, hash_odp_port(port->port_no));
> + hmap_remove(&dp->ports, &port->node);
> seq_change(dp->port_seq);
>
> dp_netdev_del_port_from_all_pmds(dp, port);
> @@ -1428,10 +1435,12 @@ dpif_netdev_port_query_by_number(const struct dpif *dpif, odp_port_t port_no,
> struct dp_netdev_port *port;
> int error;
>
> + ovs_mutex_lock(&dp->port_mutex);
> error = get_port_by_number(dp, port_no, &port);
> if (!error && dpif_port) {
> answer_port_query(port, dpif_port);
> }
> + ovs_mutex_unlock(&dp->port_mutex);
>
> return error;
> }
> @@ -1516,7 +1525,7 @@ dpif_netdev_flow_flush(struct dpif *dpif)
> }
>
> struct dp_netdev_port_state {
> - struct cmap_position position;
> + struct hmap_position position;
> char *name;
> };
>
> @@ -1533,10 +1542,11 @@ 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 cmap_node *node;
> + struct hmap_node *node;
> int retval;
>
> - node = cmap_next_position(&dp->ports, &state->position);
> + ovs_mutex_lock(&dp->port_mutex);
> + node = hmap_at_position(&dp->ports, &state->position);
> if (node) {
> struct dp_netdev_port *port;
>
> @@ -1552,6 +1562,7 @@ dpif_netdev_port_dump_next(const struct dpif *dpif, void *state_,
> } else {
> retval = EOF;
> }
> + ovs_mutex_unlock(&dp->port_mutex);
>
> return retval;
> }
> @@ -2407,8 +2418,8 @@ dpif_netdev_execute(struct dpif *dpif, struct dpif_execute *execute)
> dp_netdev_execute_actions(pmd, &pp, 1, false, execute->actions,
> execute->actions_len);
> if (pmd->core_id == NON_PMD_CORE_ID) {
> - dp_netdev_pmd_unref(pmd);
> ovs_mutex_unlock(&dp->non_pmd_mutex);
> + dp_netdev_pmd_unref(pmd);
> }
>
> return 0;
> @@ -2449,14 +2460,17 @@ pmd_config_changed(const struct dp_netdev *dp, const char *cmask)
> {
> struct dp_netdev_port *port;
>
> - CMAP_FOR_EACH (port, node, &dp->ports) {
> + ovs_mutex_lock(&dp->port_mutex);
> + HMAP_FOR_EACH (port, node, &dp->ports) {
> struct netdev *netdev = port->netdev;
> int requested_n_rxq = netdev_requested_n_rxq(netdev);
> if (netdev_is_pmd(netdev)
> && port->latest_requested_n_rxq != requested_n_rxq) {
> + ovs_mutex_unlock(&dp->port_mutex);
> return true;
> }
> }
> + ovs_mutex_unlock(&dp->port_mutex);
>
> if (dp->pmd_cmask != NULL && cmask != NULL) {
> return strcmp(dp->pmd_cmask, cmask);
> @@ -2476,7 +2490,8 @@ dpif_netdev_pmd_set(struct dpif *dpif, const char *cmask)
>
> dp_netdev_destroy_all_pmds(dp);
>
> - CMAP_FOR_EACH (port, node, &dp->ports) {
> + ovs_mutex_lock(&dp->port_mutex);
> + HMAP_FOR_EACH (port, node, &dp->ports) {
> struct netdev *netdev = port->netdev;
> int requested_n_rxq = netdev_requested_n_rxq(netdev);
> if (netdev_is_pmd(port->netdev)
> @@ -2498,6 +2513,7 @@ dpif_netdev_pmd_set(struct dpif *dpif, const char *cmask)
> VLOG_ERR("Failed to set dpdk interface %s rx_queue to:"
> " %u", netdev_get_name(port->netdev),
> requested_n_rxq);
> + ovs_mutex_unlock(&dp->port_mutex);
> return err;
> }
> port->latest_requested_n_rxq = requested_n_rxq;
> @@ -2518,6 +2534,7 @@ dpif_netdev_pmd_set(struct dpif *dpif, const char *cmask)
> dp_netdev_set_nonpmd(dp);
> /* Restores all pmd threads. */
> dp_netdev_reset_pmd_threads(dp);
> + ovs_mutex_unlock(&dp->port_mutex);
> }
>
> return 0;
> @@ -2627,8 +2644,9 @@ dpif_netdev_run(struct dpif *dpif)
> NON_PMD_CORE_ID);
> uint64_t new_tnl_seq;
>
> + ovs_mutex_lock(&dp->port_mutex);
> ovs_mutex_lock(&dp->non_pmd_mutex);
> - CMAP_FOR_EACH (port, node, &dp->ports) {
> + HMAP_FOR_EACH (port, node, &dp->ports) {
> if (!netdev_is_pmd(port->netdev)) {
> int i;
>
> @@ -2638,6 +2656,7 @@ dpif_netdev_run(struct dpif *dpif)
> }
> }
> ovs_mutex_unlock(&dp->non_pmd_mutex);
> + ovs_mutex_unlock(&dp->port_mutex);
> dp_netdev_pmd_unref(non_pmd);
>
> tnl_neigh_cache_run();
> @@ -2658,7 +2677,8 @@ dpif_netdev_wait(struct dpif *dpif)
> struct dp_netdev *dp = get_dp_netdev(dpif);
>
> ovs_mutex_lock(&dp_netdev_mutex);
> - CMAP_FOR_EACH (port, node, &dp->ports) {
> + ovs_mutex_lock(&dp->port_mutex);
> + HMAP_FOR_EACH (port, node, &dp->ports) {
> if (!netdev_is_pmd(port->netdev)) {
> int i;
>
> @@ -2667,6 +2687,7 @@ dpif_netdev_wait(struct dpif *dpif)
> }
> }
> }
> + ovs_mutex_unlock(&dp->port_mutex);
> ovs_mutex_unlock(&dp_netdev_mutex);
> seq_wait(tnl_conf_seq, dp->last_tnl_conf_seq);
> }
> @@ -3296,12 +3317,13 @@ dp_netdev_set_pmds_on_numa(struct dp_netdev *dp, int numa_id)
> * new configuration. */
> static void
> dp_netdev_reset_pmd_threads(struct dp_netdev *dp)
> + OVS_REQUIRES(dp->port_mutex)
> {
> struct dp_netdev_port *port;
> struct hmapx to_reload = HMAPX_INITIALIZER(&to_reload);
> struct hmapx_node *node;
>
> - CMAP_FOR_EACH (port, node, &dp->ports) {
> + HMAP_FOR_EACH (port, node, &dp->ports) {
> if (netdev_is_pmd(port->netdev)) {
> dp_netdev_add_port_to_pmds__(dp, port, &to_reload);
> }
> @@ -3857,7 +3879,6 @@ dp_netdev_clone_pkt_batch(struct dp_packet **dst_pkts,
> static void
> dp_execute_cb(void *aux_, struct dp_packet **packets, int cnt,
> const struct nlattr *a, bool may_steal)
> - OVS_NO_THREAD_SAFETY_ANALYSIS
> {
> struct dp_netdev_execute_aux *aux = aux_;
> uint32_t *depth = recirc_depth_get();
> @@ -4076,8 +4097,7 @@ 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 *old_port;
> - struct dp_netdev_port *new_port;
> + struct dp_netdev_port *port;
> struct dp_netdev *dp;
> odp_port_t port_no;
>
> @@ -4092,7 +4112,7 @@ dpif_dummy_change_port_number(struct unixctl_conn *conn, int argc OVS_UNUSED,
> ovs_mutex_unlock(&dp_netdev_mutex);
>
> ovs_mutex_lock(&dp->port_mutex);
> - if (get_port_by_name(dp, argv[2], &old_port)) {
> + if (get_port_by_name(dp, argv[2], &port)) {
> unixctl_command_reply_error(conn, "unknown port");
> goto exit;
> }
> @@ -4107,16 +4127,14 @@ dpif_dummy_change_port_number(struct unixctl_conn *conn, int argc OVS_UNUSED,
> goto exit;
> }
>
> - /* Remove old port. */
> - cmap_remove(&dp->ports, &old_port->node, hash_port_no(old_port->port_no));
> - dp_netdev_del_port_from_all_pmds(dp, old_port);
> - ovsrcu_postpone(free, old_port);
> + /* Remove port. */
> + hmap_remove(&dp->ports, &port->node);
> + dp_netdev_del_port_from_all_pmds(dp, 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_port_no(port_no));
> - dp_netdev_add_port_to_pmds(dp, new_port);
> + /* Reinsert with new port number. */
> + port->port_no = port_no;
> + hmap_insert(&dp->ports, &port->node, hash_port_no(port_no));
> + dp_netdev_add_port_to_pmds(dp, port);
>
> seq_change(dp->port_seq);
> unixctl_command_reply(conn, NULL);
>
More information about the dev
mailing list