Your call either way.  I don't feel strongly.

Ethan

On Thu, Aug 6, 2015 at 1:07 PM, Justin Pettit <jpet...@nicira.com> wrote:
> This is cleaner than I was expecting.  Do you think we want to backport it to 
> 2.3?
>
> --Justin
>
>
>> On Aug 6, 2015, at 12:30 PM, Jarno Rajahalme <jrajaha...@nicira.com> wrote:
>>
>> Ethan,
>>
>> This ended up being a very clean patch, thank you!
>>
>> IMO this is good to go, but I’d like to see a test case that shows the 
>> modify operation in the logs to prevent regression in the future. Maybe work 
>> off some of the bond rebalance test cases to prove that modify is used in 
>> the case we currently know suffers from the lack of modify support?
>>
>> Also, there are some minor comments below you could address at the same time.
>>
>>  Jarno
>>
>>> On Aug 5, 2015, at 4:07 PM, Ethan Jackson <et...@nicira.com> wrote:
>>>
>>> There are certain use cases (such as bond rebalancing) where a
>>> datapath flow's actions may change, while it's wildcard pattern
>>> remains the same.  Before this patch, revalidators would note the
>>> change, delete the flow, and wait for the handlers to install an
>>> updated version.  This is inefficient, as many packets could get
>>> punted to userspace before the new flow is finally installed.
>>>
>>> To improve the situation, this patch implements in place modification
>>> of datapath flows.  If the revalidators detect the only change to a
>>> given ukey is its actions, instead of deleting it, it does a put with
>>> the MODIFY flag set.
>>>
>>> Signed-off-by: Ethan Jackson <et...@nicira.com>
>>> ---
>>> ofproto/ofproto-dpif-upcall.c | 118 
>>> +++++++++++++++++++++++++++++++-----------
>>> 1 file changed, 87 insertions(+), 31 deletions(-)
>>>
>>> diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
>>> index 59010c2..7abc97d 100644
>>> --- a/ofproto/ofproto-dpif-upcall.c
>>> +++ b/ofproto/ofproto-dpif-upcall.c
>>> @@ -150,6 +150,12 @@ enum upcall_type {
>>>    IPFIX_UPCALL                /* Per-bridge sampling. */
>>> };
>>>
>>> +enum reval_result {
>>> +    UKEY_KEEP,
>>> +    UKEY_DELETE,
>>> +    UKEY_MODIFY
>>> +};
>>> +
>>> struct upcall {
>>>    struct ofproto_dpif *ofproto;  /* Parent ofproto. */
>>>    const struct recirc_id_node *recirc; /* Recirculation context. */
>>> @@ -1663,33 +1669,41 @@ should_revalidate(const struct udpif *udpif, 
>>> uint64_t packets,
>>>    return false;
>>> }
>>>
>>> -static bool
>>> +/* Verifies that the datapath actions of 'ukey' are still correct, and 
>>> pushes
>>> + * 'stats' for it.
>>> + *
>>> + * Returns a recommended action for 'ukey', options include: UKEY_DELETE,
>>> + * meaning the ukey should be deleted.  UKEY_KEEP, meaning the ukey is 
>>> fine as
>>> + * is.  Or UKEY_MODIFY, meaning the ukey's actions should be changed but is
>>> + * otherwise fine.  If UKEY_MODIFY, is returned, callers should change the
>>> + * ukey's actions to those found in the caller supplied 'odp_actions' 
>>> buffer.
>>> + * */
>>
>> This would be easier to read if you reformat this with each option listed in 
>> it’s own line, and drop the repeating “meaning the”.
>>
>>> +static enum reval_result
>>> revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
>>> -                const struct dpif_flow_stats *stats, uint64_t reval_seq)
>>> +                const struct dpif_flow_stats *stats,
>>> +                struct ofpbuf *odp_actions, uint64_t reval_seq)
>>>    OVS_REQUIRES(ukey->mutex)
>>> {
>>> -    uint64_t odp_actions_stub[1024 / 8];
>>> -    struct ofpbuf odp_actions = OFPBUF_STUB_INITIALIZER(odp_actions_stub);
>>> -
>>>    struct xlate_out xout, *xoutp;
>>>    struct netflow *netflow;
>>>    struct ofproto_dpif *ofproto;
>>>    struct dpif_flow_stats push;
>>>    struct flow flow, dp_mask;
>>>    struct flow_wildcards wc;
>>> +    enum reval_result result;
>>>    uint64_t *dp64, *xout64;
>>>    ofp_port_t ofp_in_port;
>>>    struct xlate_in xin;
>>>    long long int last_used;
>>>    int error;
>>>    size_t i;
>>> -    bool ok;
>>>    bool need_revalidate;
>>>
>>> -    ok = false;
>>> +    result = UKEY_DELETE;
>>>    xoutp = NULL;
>>>    netflow = NULL;
>>>
>>> +    ofpbuf_clear(odp_actions);
>>>    need_revalidate = (ukey->reval_seq != reval_seq);
>>>    last_used = ukey->stats.used;
>>>    push.used = stats->used;
>>> @@ -1703,20 +1717,19 @@ revalidate_ukey(struct udpif *udpif, struct 
>>> udpif_key *ukey,
>>>
>>>    if (need_revalidate && last_used
>>>        && !should_revalidate(udpif, push.n_packets, last_used)) {
>>> -        ok = false;
>>>        goto exit;
>>>    }
>>>
>>>    /* We will push the stats, so update the ukey stats cache. */
>>>    ukey->stats = *stats;
>>>    if (!push.n_packets && !need_revalidate) {
>>> -        ok = true;
>>> +        result = UKEY_KEEP;
>>>        goto exit;
>>>    }
>>>
>>>    if (ukey->xcache && !need_revalidate) {
>>>        xlate_push_stats(ukey->xcache, &push);
>>> -        ok = true;
>>> +        result = UKEY_KEEP;
>>>        goto exit;
>>>    }
>>>
>>> @@ -1739,7 +1752,7 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key 
>>> *ukey,
>>>    }
>>>
>>>    xlate_in_init(&xin, ofproto, &flow, ofp_in_port, NULL, push.tcp_flags,
>>> -                  NULL, need_revalidate ? &wc : NULL, &odp_actions);
>>> +                  NULL, need_revalidate ? &wc : NULL, odp_actions);
>>>    if (push.n_packets) {
>>>        xin.resubmit_stats = &push;
>>>        xin.may_learn = true;
>>> @@ -1749,18 +1762,14 @@ revalidate_ukey(struct udpif *udpif, struct 
>>> udpif_key *ukey,
>>>    xoutp = &xout;
>>>
>>>    if (!need_revalidate) {
>>> -        ok = true;
>>> +        result = UKEY_KEEP;
>>>        goto exit;
>>>    }
>>>
>>>    if (xout.slow) {
>>> -        ofpbuf_clear(&odp_actions);
>>> +        ofpbuf_clear(odp_actions);
>>>        compose_slow_path(udpif, &xout, &flow, flow.in_port.odp_port,
>>> -                          &odp_actions);
>>> -    }
>>> -
>>> -    if (!ofpbuf_equal(&odp_actions, ukey->actions)) {
>>> -        goto exit;
>>> +                          odp_actions);
>>>    }
>>>
>>>    if (odp_flow_key_to_mask(ukey->mask, ukey->mask_len, ukey->key,
>>> @@ -1781,18 +1790,24 @@ revalidate_ukey(struct udpif *udpif, struct 
>>> udpif_key *ukey,
>>>        }
>>>    }
>>>
>>> -    ok = true;
>>> +    if (!ofpbuf_equal(odp_actions, ukey->actions)) {
>>> +        /* The datpaath mask was OK, but the actions seem to have changed.
>>
>> Typo on “datpaath”
>>
>>> +         * Let's modify it in place. */
>>> +        result = UKEY_MODIFY;
>>> +        goto exit;
>>> +    }
>>> +
>>> +    result = UKEY_KEEP;
>>>
>>> exit:
>>> -    if (ok) {
>>> +    if (result != UKEY_DELETE) {
>>>        ukey->reval_seq = reval_seq;
>>>    }
>>> -    if (netflow && !ok) {
>>> +    if (netflow && result != UKEY_DELETE) {
>>>        netflow_flow_clear(netflow, &flow);
>>>    }
>>>    xlate_out_uninit(xoutp);
>>> -    ofpbuf_uninit(&odp_actions);
>>> -    return ok;
>>> +    return result;
>>> }
>>>
>>> static void
>>> @@ -1823,6 +1838,23 @@ delete_op_init(struct udpif *udpif, struct ukey_op 
>>> *op, struct udpif_key *ukey)
>>> }
>>>
>>> static void
>>> +modify_op_init(struct ukey_op *op, struct udpif_key *ukey)
>>> +{
>>> +    op->ukey = ukey;
>>> +    op->dop.type = DPIF_OP_FLOW_PUT;
>>> +    op->dop.u.flow_put.flags = DPIF_FP_MODIFY;
>>> +    op->dop.u.flow_put.key = ukey->key;
>>> +    op->dop.u.flow_put.key_len = ukey->key_len;
>>> +    op->dop.u.flow_put.mask = ukey->mask;
>>> +    op->dop.u.flow_put.mask_len = ukey->mask_len;
>>> +    op->dop.u.flow_put.ufid = &ukey->ufid;
>>> +    op->dop.u.flow_put.pmd_id = ukey->pmd_id;
>>> +    op->dop.u.flow_put.stats = NULL;
>>> +    op->dop.u.flow_put.actions = ukey->actions->data;
>>> +    op->dop.u.flow_put.actions_len = ukey->actions->size;
>>> +}
>>> +
>>> +static void
>>> push_ukey_ops__(struct udpif *udpif, struct ukey_op *ops, size_t n_ops)
>>> {
>>>    struct dpif_op *opsp[REVALIDATE_MAX_BATCH];
>>> @@ -1841,6 +1873,12 @@ push_ukey_ops__(struct udpif *udpif, struct ukey_op 
>>> *ops, size_t n_ops)
>>>        stats = op->dop.u.flow_del.stats;
>>>        push = &push_buf;
>>>
>>> +        if (op->dop.type == DPIF_OP_FLOW_PUT) {
>>> +            /* This was an in place modification.  Don't bother pushing 
>>> stats
>>> +             * for now. */
>>
>> As the stats were just pushed in revalidate_ukey()? If so, mention it here.
>>
>>> +            continue;
>>> +        }
>>> +
>>>        if (op->ukey) {
>>>            ovs_mutex_lock(&op->ukey->mutex);
>>>            push->used = MAX(stats->used, op->ukey->stats.used);
>>> @@ -1926,6 +1964,9 @@ log_unexpected_flow(const struct dpif_flow *flow, int 
>>> error)
>>> static void
>>> revalidate(struct revalidator *revalidator)
>>> {
>>> +    uint64_t odp_actions_stub[1024 / 8];
>>> +    struct ofpbuf odp_actions = OFPBUF_STUB_INITIALIZER(odp_actions_stub);
>>> +
>>>    struct udpif *udpif = revalidator->udpif;
>>>    struct dpif_flow_dump_thread *dump_thread;
>>>    uint64_t dump_seq, reval_seq;
>>> @@ -1973,8 +2014,9 @@ revalidate(struct revalidator *revalidator)
>>>
>>>        for (f = flows; f < &flows[n_dumped]; f++) {
>>>            long long int used = f->stats.used;
>>> +            enum reval_result result;
>>>            struct udpif_key *ukey;
>>> -            bool already_dumped, keep;
>>> +            bool already_dumped;
>>>            int error;
>>>
>>>            if (ukey_acquire(udpif, f, &ukey, &error)) {
>>> @@ -2008,15 +2050,20 @@ revalidate(struct revalidator *revalidator)
>>>                used = ukey->created;
>>>            }
>>>            if (kill_them_all || (used && used < now - max_idle)) {
>>> -                keep = false;
>>> +                result = UKEY_DELETE;
>>>            } else {
>>> -                keep = revalidate_ukey(udpif, ukey, &f->stats, reval_seq);
>>> +                result = revalidate_ukey(udpif, ukey, &f->stats, 
>>> &odp_actions,
>>> +                                         reval_seq);
>>>            }
>>>            ukey->dump_seq = dump_seq;
>>> -            ukey->flow_exists = keep;
>>> +            ukey->flow_exists = result != UKEY_DELETE;
>>>
>>> -            if (!keep) {
>>> +            if (result == UKEY_DELETE) {
>>>                delete_op_init(udpif, &ops[n_ops++], ukey);
>>> +            } else if (result == UKEY_MODIFY){
>>
>> Add space between “){“
>>
>>> +                ofpbuf_delete(ukey->actions);
>>> +                ukey->actions = ofpbuf_clone(&odp_actions);
>>> +                modify_op_init(&ops[n_ops++], ukey);
>>>            }
>>>            ovs_mutex_unlock(&ukey->mutex);
>>>        }
>>> @@ -2027,23 +2074,32 @@ revalidate(struct revalidator *revalidator)
>>>        ovsrcu_quiesce();
>>>    }
>>>    dpif_flow_dump_thread_destroy(dump_thread);
>>> +    ofpbuf_uninit(&odp_actions);
>>> }
>>>
>>> static bool
>>> handle_missed_revalidation(struct udpif *udpif, uint64_t reval_seq,
>>>                           struct udpif_key *ukey)
>>> {
>>> +    uint64_t odp_actions_stub[1024 / 8];
>>> +    struct ofpbuf odp_actions = OFPBUF_STUB_INITIALIZER(odp_actions_stub);
>>> +
>>>    struct dpif_flow_stats stats;
>>> -    bool keep;
>>> +    enum reval_result result;
>>>
>>>    COVERAGE_INC(revalidate_missed_dp_flow);
>>>
>>>    memset(&stats, 0, sizeof stats);
>>>    ovs_mutex_lock(&ukey->mutex);
>>> -    keep = revalidate_ukey(udpif, ukey, &stats, reval_seq);
>>> +    result = revalidate_ukey(udpif, ukey, &stats, &odp_actions, reval_seq);
>>>    ovs_mutex_unlock(&ukey->mutex);
>>>
>>> -    return keep;
>>> +    ofpbuf_uninit(&odp_actions);
>>> +
>>> +    /* XXX: We somewhat conversvatively don't bother with in place
>>> +     * modifications in this case.  Probably could be made to work, but 
>>> this is
>>> +     * simpler, and the edge case is rare. */
>>> +    return result == UKEY_KEEP;
>>
>> There is only one caller of this function, and the call site seems simple 
>> enough to support modification, it would be nice if it did. If for nothing 
>> else than getting rid of one extra “XXX” (and the typo in the comment at the 
>> same time :-).
>>
>>> }
>>>
>>> static void
>>> --
>>> 2.1.0
>>>
>>> _______________________________________________
>>> dev mailing list
>>> dev@openvswitch.org
>>> http://openvswitch.org/mailman/listinfo/dev
>>
>> _______________________________________________
>> dev mailing list
>> dev@openvswitch.org
>> http://openvswitch.org/mailman/listinfo/dev
>
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to