On 15/07/2020 11:02, Ilya Maximets wrote: > On 7/15/20 11:44 AM, Kevin Traynor wrote: >> On 14/07/2020 19:24, Ilya Maximets wrote: >>> On 7/14/20 7:52 PM, Ilya Maximets wrote: >>>> On 7/14/20 5:33 PM, Kevin Traynor wrote: >>>>> On 09/07/2020 16:19, Ilya Maximets wrote: >>>>>> @@ -3175,11 +3219,31 @@ dpif_netdev_get_flow_offload_status(const struct >>>>>> dp_netdev *dp, >>>>>> } >>>>>> ofpbuf_use_stack(&buf, &act_buf, sizeof act_buf); >>>>>> /* Taking a global 'port_mutex' to fulfill thread safety >>>>>> - * restrictions for the netdev-offload-dpdk module. */ >>>>>> - ovs_mutex_lock(&dp->port_mutex); >>>>>> - ret = netdev_flow_get(netdev, &match, &actions, >>>>>> &netdev_flow->mega_ufid, >>>>>> - stats, attrs, &buf); >>>>>> - ovs_mutex_unlock(&dp->port_mutex); >>>>>> + * restrictions for the netdev-offload-dpdk module. >>>>>> + * >>>>>> + * XXX: Main thread will try to pause/stop all revalidators during >>>>>> datapath >>>>>> + * reconfiguration via datapath purge callback (dp_purge_cb) >>>>>> while >>>>>> + * holding 'dp->port_mutex'. So we're not waiting for mutex >>>>>> here. >>>>>> + * Otherwise, deadlock is possible, bcause revalidators might >>>>>> sleep >>>>>> + * waiting for the main thread to release the lock and main >>>>>> thread >>>>>> + * will wait for them to stop processing. >>>>>> + * This workaround might make statistics less accurate. >>>>>> Especially >>>>>> + * for flow deletion case, since there will be no other >>>>>> attempt. */ >>>>>> + if (!ovs_mutex_trylock(&dp->port_mutex)) { >>>>>> + ret = netdev_flow_get(netdev, &match, &actions, >>>>>> + &netdev_flow->mega_ufid, stats, attrs, >>>>>> &buf); >>>>>> + /* Storing attributes from the last request for later use on >>>>>> mutex >>>>>> + * contention. */ >>>>> >>>>> Shouldn't you check 'ret' here before the set >>>> >>>> Yes. That makes sense. I'll move below call under 'if (!ret)'. >>> >>> Another option is to actually store 'ret' along with last_{stats,attrs}. >>> And return last return value that we actually had. That will protect >>> us from flapping in case the flow dissapeared from the HW (for example >>> with linux tc this might happen if someone removed flows from qdisk >>> externally). In case we're storing only on success, this will result >>> in returniing error if we took the mutex and sucess if we didn't but have >>> good attributes and statistics from one of the previous calls. >>> >>> What do you think? >>> >> >> Not sure if you're saying you don't want to update the stats/attrs >> anymore past last good value in case you got a ret error from flow_get() >> *anytime* in the past? > > Sorry for not being clear. I meant something like this: > > --- a/lib/dpif-netdev.c > +++ b/lib/dpif-netdev.c > @@ -557,6 +559,7 @@ struct dp_netdev_flow { > struct dp_netdev_flow_stats stats; > > /* Statistics and attributes received from the netdev offload provider. > */ > + atomic_int netdev_flow_get_result; > struct dp_netdev_flow_stats last_stats; > struct dp_netdev_flow_attrs last_attrs; > > @@ -3163,11 +3291,17 @@ dp_netdev_pmd_find_flow(const struct > dp_netdev_pmd_thread *pmd, > static void > dp_netdev_flow_set_last_stats_attrs(struct dp_netdev_flow *netdev_flow, > const struct dpif_flow_stats *stats, > - const struct dpif_flow_attrs *attrs) > + const struct dpif_flow_attrs *attrs, > + int result) > { > struct dp_netdev_flow_stats *last_stats = &netdev_flow->last_stats; > struct dp_netdev_flow_attrs *last_attrs = &netdev_flow->last_attrs; > > + atomic_store_relaxed(&netdev_flow->netdev_flow_get_result, result); > + if (result) { > + return; > + } > + > atomic_store_relaxed(&last_stats->used, stats->used); > atomic_store_relaxed(&last_stats->packet_count, stats->n_packets); > atomic_store_relaxed(&last_stats->byte_count, stats->n_bytes); > @@ -3175,16 +3309,23 @@ dp_netdev_flow_set_last_stats_attrs(struct > dp_netdev_flow *netdev_flow, > > atomic_store_relaxed(&last_attrs->offloaded, attrs->offloaded); > atomic_store_relaxed(&last_attrs->dp_layer, attrs->dp_layer); > + > } > > static void > dp_netdev_flow_get_last_stats_attrs(struct dp_netdev_flow *netdev_flow, > struct dpif_flow_stats *stats, > - struct dpif_flow_attrs *attrs) > + struct dpif_flow_attrs *attrs, > + int *result) > { > struct dp_netdev_flow_stats *last_stats = &netdev_flow->last_stats; > struct dp_netdev_flow_attrs *last_attrs = &netdev_flow->last_attrs; > > + atomic_read_relaxed(&netdev_flow->netdev_flow_get_result, result); > + if (*result) { > + return; > + } > + > atomic_read_relaxed(&last_stats->used, &stats->used); > atomic_read_relaxed(&last_stats->packet_count, &stats->n_packets); > atomic_read_relaxed(&last_stats->byte_count, &stats->n_bytes); > @@ -3232,13 +3373,13 @@ dpif_netdev_get_flow_offload_status(const struct > dp_netdev *dp, > if (!ovs_mutex_trylock(&dp->port_mutex)) { > ret = netdev_flow_get(netdev, &match, &actions, > &netdev_flow->mega_ufid, stats, attrs, &buf); > - /* Storing attributes from the last request for later use on mutex > - * contention. */ > - dp_netdev_flow_set_last_stats_attrs(netdev_flow, stats, attrs); > + /* Storing statistics and attributes from the last request for > + * later use on mutex contention. */ > + dp_netdev_flow_set_last_stats_attrs(netdev_flow, stats, attrs, ret); > ovs_mutex_unlock(&dp->port_mutex); > } else { > - dp_netdev_flow_get_last_stats_attrs(netdev_flow, stats, attrs); > - if (!attrs->dp_layer) { > + dp_netdev_flow_get_last_stats_attrs(netdev_flow, stats, attrs, &ret); > + if (!ret && !attrs->dp_layer) { > /* Flow was never reported as 'offloaded' so it's harmless > * to continue to think so. */ > ret = EAGAIN; > @@ -3512,6 +3653,7 @@ dp_netdev_flow_add(struct dp_netdev_pmd_thread *pmd, > /* Do not allocate extra space. */ > flow = xmalloc(sizeof *flow - sizeof flow->cr.flow.mf + mask.len); > memset(&flow->stats, 0, sizeof flow->stats); > + atomic_init(&flow->netdev_flow_get_result, 0); > memset(&flow->last_stats, 0, sizeof flow->last_stats); > memset(&flow->last_attrs, 0, sizeof flow->last_attrs); > flow->dead = false; > --- > > This should mimic the last call regardless of its success. >
got it, that looks good, thanks. > Best regards, Ilya Maximets. > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev