[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