[ovs-dev] [PATCH 2/4] connmgr: Use 'ofproto_mutex' to protect ofconns from being destroyed.
Ethan Jackson
ethan at nicira.com
Fri Oct 11 15:58:20 UTC 2013
I guess the only thing I'm wondering about is how you know when
ofproto_mutex is required and when it isn't. In particular, why do we
need to hold it for the entire connmgr_set_controllers()? That's not
totally clear from the comment at the top of the file.
Acked-by: Ethan Jackson <ethan at nicira.com>
On Fri, Oct 11, 2013 at 12:23 AM, Ben Pfaff <blp at nicira.com> wrote:
> Code in the ofproto-dpif miss handler threads can currently access
> ofconns, sending flow_removed and flow monitor messages due to NXAST_LEARN
> actions. Nothing currently protects those threads from accessing ofconns
> that are in the process of being destroyed. This commit adds protection
> 'ofproto_mutex', which NXAST_LEARN already takes.
>
> Later patches will address other races that remain.
>
> Signed-off-by: Ben Pfaff <blp at nicira.com>
> ---
> ofproto/connmgr.c | 35 ++++++++++++++++++++++++++++++-----
> 1 file changed, 30 insertions(+), 5 deletions(-)
>
> diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
> index ab9a556..d6233e0 100644
> --- a/ofproto/connmgr.c
> +++ b/ofproto/connmgr.c
> @@ -44,7 +44,15 @@
> VLOG_DEFINE_THIS_MODULE(connmgr);
> static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
>
> -/* An OpenFlow connection. */
> +/* An OpenFlow connection.
> + *
> + *
> + * Thread-safety
> + * =============
> + *
> + * 'ofproto_mutex' must be held whenever an ofconn is created or destroyed or,
> + * more or less equivalently, whenever an ofconn is added to or removed from a
> + * connmgr. 'ofproto_mutex' doesn't protect the data inside the ofconn. */
> struct ofconn {
> /* Configuration that persists from one connection to the next. */
>
> @@ -99,9 +107,10 @@ struct ofconn {
> };
>
> static struct ofconn *ofconn_create(struct connmgr *, struct rconn *,
> - enum ofconn_type, bool enable_async_msgs);
> -static void ofconn_destroy(struct ofconn *);
> -static void ofconn_flush(struct ofconn *);
> + enum ofconn_type, bool enable_async_msgs)
> + OVS_REQUIRES(ofproto_mutex);
> +static void ofconn_destroy(struct ofconn *) OVS_REQUIRES(ofproto_mutex);
> +static void ofconn_flush(struct ofconn *) OVS_REQUIRES(ofproto_mutex);
>
> static void ofconn_reconfigure(struct ofconn *,
> const struct ofproto_controller *);
> @@ -226,9 +235,12 @@ connmgr_destroy(struct connmgr *mgr)
> return;
> }
>
> + ovs_mutex_lock(&ofproto_mutex);
> LIST_FOR_EACH_SAFE (ofconn, next_ofconn, node, &mgr->all_conns) {
> ofconn_destroy(ofconn);
> }
> + ovs_mutex_unlock(&ofproto_mutex);
> +
> hmap_destroy(&mgr->controllers);
>
> HMAP_FOR_EACH_SAFE (ofservice, next_ofservice, node, &mgr->services) {
> @@ -311,8 +323,11 @@ connmgr_run(struct connmgr *mgr,
> rconn_connect_unreliably(rconn, vconn, name);
> free(name);
>
> + ovs_mutex_lock(&ofproto_mutex);
> ofconn = ofconn_create(mgr, rconn, OFCONN_SERVICE,
> ofservice->enable_async_msgs);
> + ovs_mutex_unlock(&ofproto_mutex);
> +
> ofconn_set_rate_limit(ofconn, ofservice->rate_limit,
> ofservice->burst_limit);
> } else if (retval != EAGAIN) {
> @@ -410,7 +425,8 @@ connmgr_retry(struct connmgr *mgr)
> /* OpenFlow configuration. */
>
> static void add_controller(struct connmgr *, const char *target, uint8_t dscp,
> - uint32_t allowed_versions);
> + uint32_t allowed_versions)
> + OVS_REQUIRES(ofproto_mutex);
> static struct ofconn *find_controller_by_target(struct connmgr *,
> const char *target);
> static void update_fail_open(struct connmgr *);
> @@ -502,6 +518,7 @@ void
> connmgr_set_controllers(struct connmgr *mgr,
> const struct ofproto_controller *controllers,
> size_t n_controllers, uint32_t allowed_versions)
> + OVS_EXCLUDED(ofproto_mutex)
> {
> bool had_controllers = connmgr_has_controllers(mgr);
> struct shash new_controllers;
> @@ -509,6 +526,8 @@ connmgr_set_controllers(struct connmgr *mgr,
> struct ofservice *ofservice, *next_ofservice;
> size_t i;
>
> + ovs_mutex_lock(&ofproto_mutex);
> +
> /* Create newly configured controllers and services.
> * Create a name to ofproto_controller mapping in 'new_controllers'. */
> shash_init(&new_controllers);
> @@ -596,6 +615,7 @@ connmgr_set_controllers(struct connmgr *mgr,
> if (had_controllers != connmgr_has_controllers(mgr)) {
> ofproto_flush_flows(mgr->ofproto);
> }
> + ovs_mutex_unlock(&ofproto_mutex);
> }
>
> /* Drops the connections between 'mgr' and all of its primary and secondary
> @@ -643,6 +663,7 @@ connmgr_has_snoops(const struct connmgr *mgr)
> static void
> add_controller(struct connmgr *mgr, const char *target, uint8_t dscp,
> uint32_t allowed_versions)
> + OVS_REQUIRES(ofproto_mutex)
> {
> char *name = ofconn_make_name(mgr, target);
> struct ofconn *ofconn;
> @@ -1110,6 +1131,7 @@ ofconn_create(struct connmgr *mgr, struct rconn *rconn, enum ofconn_type type,
> * connection to the next. */
> static void
> ofconn_flush(struct ofconn *ofconn)
> + OVS_REQUIRES(ofproto_mutex)
> {
> struct ofmonitor *monitor, *next_monitor;
> int i;
> @@ -1192,6 +1214,7 @@ ofconn_flush(struct ofconn *ofconn)
>
> static void
> ofconn_destroy(struct ofconn *ofconn)
> + OVS_REQUIRES(ofproto_mutex)
> {
> ofconn_flush(ofconn);
>
> @@ -1281,11 +1304,13 @@ ofconn_run(struct ofconn *ofconn,
> }
> }
>
> + ovs_mutex_lock(&ofproto_mutex);
> if (!rconn_is_alive(ofconn->rconn)) {
> ofconn_destroy(ofconn);
> } else if (!rconn_is_connected(ofconn->rconn)) {
> ofconn_flush(ofconn);
> }
> + ovs_mutex_unlock(&ofproto_mutex);
> }
>
> static void
> --
> 1.7.10.4
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
More information about the dev
mailing list