[ovs-dev] [PATCHv5 05/12] upcall: Create ukeys in handler threads.

Ben Pfaff blp at nicira.com
Wed Sep 17 22:33:32 UTC 2014


On Mon, Sep 15, 2014 at 02:25:11PM +1200, Joe Stringer wrote:
> Currently, when a revalidator thread first dumps a flow, it creates a
> 'udpif_key' object and caches a copy of a kernel flow key. This allows
> us to perform lookups in the classifier to attribute stats and validate
> the correctness of the datapath flow.
> 
> This patch sets up this cache from the handler threads, during flow
> setup. This allows future patches to reduce the cost of flow dumping.
> 
> Signed-off-by: Joe Stringer <joestringer at nicira.com>

I wonder whether it would be better to always use poll_block() in
udpif_upcall_handler().  It would be more consistent with most code in
OVS, and it would mean that the code would not need special case calls
to ovsrcu_quiesce() and coverage_clear().  Here's one way:

    while (!latch_is_set(&handler->udpif->exit_latch)) {
        if (recv_upcalls(handler)) {
            poll_immediate_wake();
        } else {
            dpif_recv_wait(udpif->dpif, handler->handler_id);
            latch_wait(&udpif->exit_latch);
        }
        poll_block();
    }

upcall_receive() zeros an entire struct upcall.  On i386, it looks like
struct upcall is 620 bytes.  I guess that a large part of this is stub
buffers that do not need to be zeroed.  I think that it would be better
to initialize only what needs it; did you consider that?

Same note for ukey_new() calling xzalloc() for a struct udpif_key, which
is 616 bytes here with 512 of those bytes as a stub buffer.

ukey_new() has two cases:

    recirc = ofproto_dpif_get_enable_recirc(upcall->ofproto);
    ofpbuf_use_stack(&key, &ukey->key_buf, sizeof ukey->key_buf);
    if (upcall->key_len) {
        ofpbuf_put(&key, upcall->key, upcall->key_len);
    } else {
        odp_flow_key_from_flow(&key, upcall->flow, &upcall->xout.wc.masks,
                               upcall->flow->in_port.odp_port, recirc);
    }

I think that the second case will only be taken for dpif-netdev.  If so,
then I do not think it is necessary to check for recirculation, because
dpif-netdev is compiled in and always supports recirculation.  (In any
case, it might be worth a comment explaining when the two cases will
trigger, because it took me a while to figure it out.)

It looks to me like one of the cases where ukey_install_start() would
fail is when a number of packets in a single microflow show up all at
once (e.g. a large TCP packet sent to userspace gets broken up by TSO).
It seems like this might artificially increase handler_install_conflict.
I don't know whether that matters.

I tend to write functions like ukey_install() as just:
    return ukey_install_start(udpif, ukey) && ukey_install_finish(ukey, 0);
because it makes simple logic look simpler, in my opinion.

In ukey_acquire(), please don't break a format specifier across lines:
        VLOG_INFO("Dumped flow from datapath with no corresponding ukey: 0x%"
                  PRIx32, hash);
Instead, wrap the whole thing and the word that it's part of:
        VLOG_INFO("Dumped flow from datapath with no corresponding ukey: "
                  "0x%"PRIx32, hash);

revalidate() doesn't count or log flows that were unexpectedly found in
the datapath, that is:
            if (ukey_acquire(udpif, f, &ukey, &error)) {
                if (error == EBUSY) {
                    /* Another thread is processing this flow, so don't bother
                     * processing it.*/
                    COVERAGE_INC(upcall_ukey_contention);
                } else {
This case here:
                    delete_op_init(&ops[n_ops++], f->key, f->key_len, ukey);
                }
                continue;
            }
Should it?

Acked-by: Ben Pfaff <blp at nicira.com>



More information about the dev mailing list