X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif.c;h=8c43ee9979e1ce51f392f51ad8f1e70b1e22f0ad;hb=813a8dd336d74465a27c05cfda124e2c91408a81;hp=befa9f7109f0e951194e40281a184e0a546b55cb;hpb=e79a6c833e0d72370951d6f8841098103cbb0b2d;p=sliver-openvswitch.git diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index befa9f710..8c43ee997 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc. + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -89,9 +89,11 @@ struct rule_dpif { struct ovs_mutex stats_mutex; uint64_t packet_count OVS_GUARDED; /* Number of packets received. */ uint64_t byte_count OVS_GUARDED; /* Number of bytes received. */ + long long int used; /* Last used time (msec). */ }; -static void rule_get_stats(struct rule *, uint64_t *packets, uint64_t *bytes); +static void rule_get_stats(struct rule *, uint64_t *packets, uint64_t *bytes, + long long int *used); static struct rule_dpif *rule_dpif_cast(const struct rule *); static void rule_expire(struct rule_dpif *); @@ -251,6 +253,15 @@ struct dpif_backer { enum revalidate_reason need_revalidate; /* Revalidate all flows. */ bool recv_set_enable; /* Enables or disables receiving packets. */ + + /* True if the datapath supports variable-length + * OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE actions. + * False if the datapath supports only 8-byte (or shorter) userdata. */ + bool variable_length_userdata; + + /* Maximum number of MPLS label stack entries that the datapath supports + * in a match */ + size_t max_mpls_depth; }; /* All existing ofproto_backer instances, indexed by ofproto->up.type. */ @@ -314,6 +325,12 @@ ofproto_dpif_cast(const struct ofproto *ofproto) return CONTAINER_OF(ofproto, struct ofproto_dpif, up); } +size_t +ofproto_dpif_get_max_mpls_depth(const struct ofproto_dpif *ofproto) +{ + return ofproto->backer->max_mpls_depth; +} + static struct ofport_dpif *get_ofp_port(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port); static void ofproto_trace(struct ofproto_dpif *, const struct flow *, @@ -552,7 +569,9 @@ type_run(const char *type) ofproto->sflow, ofproto->ipfix, ofproto->netflow, ofproto->up.frag_handling, ofproto->up.forward_bpdu, - connmgr_has_in_band(ofproto->up.connmgr)); + connmgr_has_in_band(ofproto->up.connmgr), + ofproto->backer->variable_length_userdata, + ofproto->backer->max_mpls_depth); HMAP_FOR_EACH (bundle, hmap_node, &ofproto->bundles) { xlate_bundle_set(ofproto, bundle, bundle->name, @@ -774,6 +793,9 @@ struct odp_garbage { odp_port_t odp_port; }; +static bool check_variable_length_userdata(struct dpif_backer *backer); +static size_t check_max_mpls_depth(struct dpif_backer *backer); + static int open_dpif_backer(const char *type, struct dpif_backer **backerp) { @@ -872,6 +894,8 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp) close_dpif_backer(backer); return error; } + backer->variable_length_userdata = check_variable_length_userdata(backer); + backer->max_mpls_depth = check_max_mpls_depth(backer); if (backer->recv_set_enable) { udpif_set_threads(backer->udpif, n_handlers, n_revalidators); @@ -880,6 +904,129 @@ open_dpif_backer(const char *type, struct dpif_backer **backerp) return error; } +/* Tests whether 'backer''s datapath supports variable-length + * OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE actions. We need + * to disable some features on older datapaths that don't support this + * feature. + * + * Returns false if 'backer' definitely does not support variable-length + * userdata, true if it seems to support them or if at least the error we get + * is ambiguous. */ +static bool +check_variable_length_userdata(struct dpif_backer *backer) +{ + struct eth_header *eth; + struct ofpbuf actions; + struct dpif_execute execute; + struct ofpbuf packet; + size_t start; + int error; + + /* Compose a userspace action that will cause an ERANGE error on older + * datapaths that don't support variable-length userdata. + * + * We really test for using userdata longer than 8 bytes, but older + * datapaths accepted these, silently truncating the userdata to 8 bytes. + * The same older datapaths rejected userdata shorter than 8 bytes, so we + * test for that instead as a proxy for longer userdata support. */ + ofpbuf_init(&actions, 64); + start = nl_msg_start_nested(&actions, OVS_ACTION_ATTR_USERSPACE); + nl_msg_put_u32(&actions, OVS_USERSPACE_ATTR_PID, + dpif_port_get_pid(backer->dpif, ODPP_NONE)); + nl_msg_put_unspec_zero(&actions, OVS_USERSPACE_ATTR_USERDATA, 4); + nl_msg_end_nested(&actions, start); + + /* Compose a dummy ethernet packet. */ + ofpbuf_init(&packet, ETH_HEADER_LEN); + eth = ofpbuf_put_zeros(&packet, ETH_HEADER_LEN); + eth->eth_type = htons(0x1234); + + /* Execute the actions. On older datapaths this fails with ERANGE, on + * newer datapaths it succeeds. */ + execute.actions = actions.data; + execute.actions_len = actions.size; + execute.packet = &packet; + execute.md = PKT_METADATA_INITIALIZER(0); + execute.needs_help = false; + + error = dpif_execute(backer->dpif, &execute); + + ofpbuf_uninit(&packet); + ofpbuf_uninit(&actions); + + switch (error) { + case 0: + /* Variable-length userdata is supported. + * + * Purge received packets to avoid processing the nonsense packet we + * sent to userspace, then report success. */ + dpif_recv_purge(backer->dpif); + return true; + + case ERANGE: + /* Variable-length userdata is not supported. */ + VLOG_WARN("%s: datapath does not support variable-length userdata " + "feature (needs Linux 3.10+ or kernel module from OVS " + "1..11+). The NXAST_SAMPLE action will be ignored.", + dpif_name(backer->dpif)); + return false; + + default: + /* Something odd happened. We're not sure whether variable-length + * userdata is supported. Default to "yes". */ + VLOG_WARN("%s: variable-length userdata feature probe failed (%s)", + dpif_name(backer->dpif), ovs_strerror(error)); + return true; + } +} + +/* Tests the MPLS label stack depth supported by 'backer''s datapath. + * + * Returns the number of elements in a struct flow's mpls_lse field + * if the datapath supports at least that many entries in an + * MPLS label stack. + * Otherwise returns the number of MPLS push actions supported by + * the datapath. */ +static size_t +check_max_mpls_depth(struct dpif_backer *backer) +{ + struct flow flow; + int n; + + for (n = 0; n < FLOW_MAX_MPLS_LABELS; n++) { + struct odputil_keybuf keybuf; + struct ofpbuf key; + int error; + + memset(&flow, 0, sizeof flow); + flow.dl_type = htons(ETH_TYPE_MPLS); + flow_set_mpls_bos(&flow, n, 1); + + ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); + odp_flow_key_from_flow(&key, &flow, 0); + + error = dpif_flow_put(backer->dpif, DPIF_FP_CREATE | DPIF_FP_MODIFY, + key.data, key.size, NULL, 0, NULL, 0, NULL); + if (error && error != EEXIST) { + if (error != EINVAL) { + VLOG_WARN("%s: MPLS stack length feature probe failed (%s)", + dpif_name(backer->dpif), ovs_strerror(error)); + } + break; + } + + error = dpif_flow_del(backer->dpif, key.data, key.size, NULL); + if (error) { + VLOG_WARN("%s: failed to delete MPLS feature probe flow", + dpif_name(backer->dpif)); + } + } + + VLOG_INFO("%s: MPLS label stack length probed as %d", + dpif_name(backer->dpif), n); + return n; +} + static int construct(struct ofproto *ofproto_) { @@ -902,7 +1049,7 @@ construct(struct ofproto *ofproto_) ofproto->mbridge = mbridge_create(); ofproto->has_bonded_bundles = false; ofproto->lacp_enabled = false; - ovs_mutex_init(&ofproto->stats_mutex); + ovs_mutex_init_adaptive(&ofproto->stats_mutex); ovs_mutex_init(&ofproto->vsp_mutex); guarded_list_init(&ofproto->pins); @@ -1035,18 +1182,18 @@ destruct(struct ofproto *ofproto_) xlate_remove_ofproto(ofproto); ovs_rwlock_unlock(&xlate_rwlock); - /* Discard any flow_miss_batches queued up for 'ofproto', avoiding a - * use-after-free error. */ - udpif_revalidate(ofproto->backer->udpif); + /* Ensure that the upcall processing threads have no remaining references + * to the ofproto or anything in it. */ + udpif_synchronize(ofproto->backer->udpif); hmap_remove(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node); OFPROTO_FOR_EACH_TABLE (table, &ofproto->up) { struct cls_cursor cursor; - ovs_rwlock_rdlock(&table->cls.rwlock); + fat_rwlock_rdlock(&table->cls.rwlock); cls_cursor_init(&cursor, &table->cls, NULL); - ovs_rwlock_unlock(&table->cls.rwlock); + fat_rwlock_unlock(&table->cls.rwlock); CLS_CURSOR_FOR_EACH_SAFE (rule, next_rule, up.cr, &cursor) { ofproto_rule_delete(&ofproto->up, &rule->up); } @@ -1257,14 +1404,16 @@ get_tables(struct ofproto *ofproto_, struct ofp12_table_stats *ots) struct dpif_dp_stats s; uint64_t n_miss, n_no_pkt_in, n_bytes, n_dropped_frags; uint64_t n_lookup; + long long int used; strcpy(ots->name, "classifier"); dpif_get_dp_stats(ofproto->backer->dpif, &s); - rule_get_stats(&ofproto->miss_rule->up, &n_miss, &n_bytes); - rule_get_stats(&ofproto->no_packet_in_rule->up, &n_no_pkt_in, &n_bytes); - rule_get_stats(&ofproto->drop_frags_rule->up, &n_dropped_frags, &n_bytes); - + rule_get_stats(&ofproto->miss_rule->up, &n_miss, &n_bytes, &used); + rule_get_stats(&ofproto->no_packet_in_rule->up, &n_no_pkt_in, &n_bytes, + &used); + rule_get_stats(&ofproto->drop_frags_rule->up, &n_dropped_frags, &n_bytes, + &used); n_lookup = s.n_hit + s.n_missed - n_dropped_frags; ots->lookup_count = htonll(n_lookup); ots->matched_count = htonll(n_lookup - n_miss - n_no_pkt_in); @@ -1401,6 +1550,9 @@ port_destruct(struct ofport *port_) bundle_remove(port_); set_cfm(port_, NULL); set_bfd(port_, NULL); + if (port->stp_port) { + stp_port_disable(port->stp_port); + } if (ofproto->sflow) { dpif_sflow_del_port(ofproto->sflow, port->odp_port); } @@ -2766,24 +2918,39 @@ static void rule_expire(struct rule_dpif *rule) OVS_REQUIRES(ofproto_mutex) { - uint16_t idle_timeout, hard_timeout; + uint16_t hard_timeout, idle_timeout; long long int now = time_msec(); - int reason; + int reason = -1; ovs_assert(!rule->up.pending); - /* Has 'rule' expired? */ - ovs_mutex_lock(&rule->up.mutex); hard_timeout = rule->up.hard_timeout; idle_timeout = rule->up.idle_timeout; - if (hard_timeout && now > rule->up.modified + hard_timeout * 1000) { - reason = OFPRR_HARD_TIMEOUT; - } else if (idle_timeout && now > rule->up.used + idle_timeout * 1000) { - reason = OFPRR_IDLE_TIMEOUT; - } else { - reason = -1; + + /* Has 'rule' expired? */ + if (hard_timeout) { + long long int modified; + + ovs_mutex_lock(&rule->up.mutex); + modified = rule->up.modified; + ovs_mutex_unlock(&rule->up.mutex); + + if (now > modified + hard_timeout * 1000) { + reason = OFPRR_HARD_TIMEOUT; + } + } + + if (reason < 0 && idle_timeout) { + long long int used; + + ovs_mutex_lock(&rule->stats_mutex); + used = rule->used; + ovs_mutex_unlock(&rule->stats_mutex); + + if (now > used + idle_timeout * 1000) { + reason = OFPRR_IDLE_TIMEOUT; + } } - ovs_mutex_unlock(&rule->up.mutex); if (reason >= 0) { COVERAGE_INC(ofproto_dpif_expired); @@ -2800,12 +2967,11 @@ ofproto_dpif_execute_actions(struct ofproto_dpif *ofproto, const struct ofpact *ofpacts, size_t ofpacts_len, struct ofpbuf *packet) { - struct odputil_keybuf keybuf; struct dpif_flow_stats stats; struct xlate_out xout; struct xlate_in xin; ofp_port_t in_port; - struct ofpbuf key; + struct dpif_execute execute; int error; ovs_assert((rule != NULL) != (ofpacts != NULL)); @@ -2821,16 +2987,21 @@ ofproto_dpif_execute_actions(struct ofproto_dpif *ofproto, xin.resubmit_stats = &stats; xlate_actions(&xin, &xout); - ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); in_port = flow->in_port.ofp_port; if (in_port == OFPP_NONE) { in_port = OFPP_LOCAL; } - odp_flow_key_from_flow(&key, flow, ofp_port_to_odp_port(ofproto, in_port)); + execute.actions = xout.odp_actions.data; + execute.actions_len = xout.odp_actions.size; + execute.packet = packet; + execute.md.tunnel = flow->tunnel; + execute.md.skb_priority = flow->skb_priority; + execute.md.pkt_mark = flow->pkt_mark; + execute.md.in_port.odp_port = ofp_port_to_odp_port(ofproto, in_port); + execute.needs_help = (xout.slow & SLOW_ACTION) != 0; + + error = dpif_execute(ofproto->backer->dpif, &execute); - error = dpif_execute(ofproto->backer->dpif, key.data, key.size, - xout.odp_actions.data, xout.odp_actions.size, packet, - (xout.slow & SLOW_ACTION) != 0); xlate_out_uninit(&xout); return error; @@ -2843,7 +3014,7 @@ rule_dpif_credit_stats(struct rule_dpif *rule, ovs_mutex_lock(&rule->stats_mutex); rule->packet_count += stats->n_packets; rule->byte_count += stats->n_bytes; - rule->up.used = MAX(rule->up.used, stats->used); + rule->used = MAX(rule->used, stats->used); ovs_mutex_unlock(&rule->stats_mutex); } @@ -2919,11 +3090,13 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto, if (wc) { memset(&wc->masks.dl_type, 0xff, sizeof wc->masks.dl_type); - wc->masks.nw_frag |= FLOW_NW_FRAG_MASK; + if (is_ip_any(flow)) { + wc->masks.nw_frag |= FLOW_NW_FRAG_MASK; + } } cls = &ofproto->up.tables[table_id].cls; - ovs_rwlock_rdlock(&cls->rwlock); + fat_rwlock_rdlock(&cls->rwlock); frag = (flow->nw_frag & FLOW_NW_FRAG_ANY) != 0; if (frag && ofproto->up.frag_handling == OFPC_FRAG_NORMAL) { /* We must pretend that transport ports are unavailable. */ @@ -2940,7 +3113,7 @@ rule_dpif_lookup_in_table(struct ofproto_dpif *ofproto, *rule = rule_dpif_cast(rule_from_cls_rule(cls_rule)); rule_dpif_ref(*rule); - ovs_rwlock_unlock(&cls->rwlock); + fat_rwlock_unlock(&cls->rwlock); return *rule != NULL; } @@ -3003,13 +3176,13 @@ rule_dealloc(struct rule *rule_) static enum ofperr rule_construct(struct rule *rule_) + OVS_NO_THREAD_SAFETY_ANALYSIS { struct rule_dpif *rule = rule_dpif_cast(rule_); - ovs_mutex_init(&rule->stats_mutex); - ovs_mutex_lock(&rule->stats_mutex); + ovs_mutex_init_adaptive(&rule->stats_mutex); rule->packet_count = 0; rule->byte_count = 0; - ovs_mutex_unlock(&rule->stats_mutex); + rule->used = rule->up.modified; return 0; } @@ -3037,13 +3210,15 @@ rule_destruct(struct rule *rule_) } static void -rule_get_stats(struct rule *rule_, uint64_t *packets, uint64_t *bytes) +rule_get_stats(struct rule *rule_, uint64_t *packets, uint64_t *bytes, + long long int *used) { struct rule_dpif *rule = rule_dpif_cast(rule_); ovs_mutex_lock(&rule->stats_mutex); *packets = rule->packet_count; *bytes = rule->byte_count; + *used = rule->used; ovs_mutex_unlock(&rule->stats_mutex); } @@ -3119,7 +3294,21 @@ static enum ofperr group_construct(struct ofgroup *group_) { struct group_dpif *group = group_dpif_cast(group_); - ovs_mutex_init(&group->stats_mutex); + const struct ofputil_bucket *bucket; + + /* Prevent group chaining because our locking structure makes it hard to + * implement deadlock-free. (See xlate_group_resource_check().) */ + LIST_FOR_EACH (bucket, list_node, &group->up.buckets) { + const struct ofpact *a; + + OFPACT_FOR_EACH (a, bucket->ofpacts, bucket->ofpacts_len) { + if (a->type == OFPACT_GROUP) { + return OFPERR_OFPGMFC_CHAINING_UNSUPPORTED; + } + } + } + + ovs_mutex_init_adaptive(&group->stats_mutex); ovs_mutex_lock(&group->stats_mutex); group_construct_stats(group); ovs_mutex_unlock(&group->stats_mutex); @@ -3367,6 +3556,7 @@ struct trace_ctx { struct xlate_out xout; struct xlate_in xin; struct flow flow; + struct flow_wildcards wc; struct ds *result; }; @@ -3442,6 +3632,20 @@ trace_format_odp(struct ds *result, int level, const char *title, ds_put_char(result, '\n'); } +static void +trace_format_megaflow(struct ds *result, int level, const char *title, + struct trace_ctx *trace) +{ + struct match match; + + ds_put_char_multiple(result, '\t', level); + ds_put_format(result, "%s: ", title); + flow_wildcards_or(&trace->wc, &trace->xout.wc, &trace->wc); + match_init(&match, &trace->flow, &trace->wc); + match_format(&match, result, OFP_DEFAULT_PRIORITY); + ds_put_char(result, '\n'); +} + static void trace_resubmit(struct xlate_in *xin, struct rule_dpif *rule, int recurse) { @@ -3452,6 +3656,7 @@ trace_resubmit(struct xlate_in *xin, struct rule_dpif *rule, int recurse) trace_format_flow(result, recurse + 1, "Resubmitted flow", trace); trace_format_regs(result, recurse + 1, "Resubmitted regs", trace); trace_format_odp(result, recurse + 1, "Resubmitted odp", trace); + trace_format_megaflow(result, recurse + 1, "Resubmitted megaflow", trace); trace_format_rule(result, recurse + 1, rule); } @@ -3548,7 +3753,7 @@ parse_flow_and_packet(int argc, const char *argv[], } if (xlate_receive(backer, NULL, odp_key.data, odp_key.size, flow, - NULL, ofprotop, NULL, NULL, NULL, NULL)) { + ofprotop, NULL, NULL, NULL, NULL)) { error = "Invalid datapath flow"; goto exit; } @@ -3579,11 +3784,14 @@ parse_flow_and_packet(int argc, const char *argv[], flow_compose(packet, flow); } else { union flow_in_port in_port = flow->in_port; + struct pkt_metadata md; /* Use the metadata from the flow and the packet argument * to reconstruct the flow. */ - flow_extract(packet, flow->skb_priority, flow->pkt_mark, NULL, - &in_port, flow); + pkt_metadata_init(&md, NULL, flow->skb_priority, + flow->pkt_mark, &in_port); + + flow_extract(packet, &md, flow); } } @@ -3730,18 +3938,18 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow, struct ds *ds) { struct rule_dpif *rule; - struct flow_wildcards wc; + struct trace_ctx trace; ds_put_format(ds, "Bridge: %s\n", ofproto->up.name); ds_put_cstr(ds, "Flow: "); flow_format(ds, flow); ds_put_char(ds, '\n'); - flow_wildcards_init_catchall(&wc); + flow_wildcards_init_catchall(&trace.wc); if (ofpacts) { rule = NULL; } else { - rule_dpif_lookup(ofproto, flow, &wc, &rule); + rule_dpif_lookup(ofproto, flow, &trace.wc, &rule); trace_format_rule(ds, 0, rule); if (rule == ofproto->miss_rule) { @@ -3756,17 +3964,11 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow, } if (rule || ofpacts) { - uint64_t odp_actions_stub[1024 / 8]; - struct ofpbuf odp_actions; - struct trace_ctx trace; - struct match match; uint16_t tcp_flags; tcp_flags = packet ? packet_get_tcp_flags(packet, flow) : 0; trace.result = ds; trace.flow = *flow; - ofpbuf_use_stub(&odp_actions, - odp_actions_stub, sizeof odp_actions_stub); xlate_in_init(&trace.xin, ofproto, flow, rule, tcp_flags, packet); if (ofpacts) { trace.xin.ofpacts = ofpacts; @@ -3776,15 +3978,10 @@ ofproto_trace(struct ofproto_dpif *ofproto, const struct flow *flow, trace.xin.report_hook = trace_report; xlate_actions(&trace.xin, &trace.xout); - flow_wildcards_or(&trace.xout.wc, &trace.xout.wc, &wc); ds_put_char(ds, '\n'); trace_format_flow(ds, 0, "Final flow", &trace); - - match_init(&match, flow, &trace.xout.wc); - ds_put_cstr(ds, "Relevant fields: "); - match_format(&match, ds, OFP_DEFAULT_PRIORITY); - ds_put_char(ds, '\n'); + trace_format_megaflow(ds, 0, "Megaflow", &trace); ds_put_cstr(ds, "Datapath actions: "); format_odp_actions(ds, trace.xout.odp_actions.data, @@ -3944,11 +4141,10 @@ static bool ofproto_dpif_contains_flow(const struct ofproto_dpif *ofproto, const struct nlattr *key, size_t key_len) { - enum odp_key_fitness fitness; struct ofproto_dpif *ofp; struct flow flow; - xlate_receive(ofproto->backer, NULL, key, key_len, &flow, &fitness, &ofp, + xlate_receive(ofproto->backer, NULL, key, key_len, &flow, &ofp, NULL, NULL, NULL, NULL); return ofp == ofproto; } @@ -3968,36 +4164,62 @@ ofproto_unixctl_dpif_dump_flows(struct unixctl_conn *conn, size_t actions_len; size_t mask_len; size_t key_len; + bool verbosity = false; + struct dpif_port dpif_port; + struct dpif_port_dump port_dump; + struct hmap portno_names; + void *state = NULL; + int error; - ofproto = ofproto_dpif_lookup(argv[1]); + ofproto = ofproto_dpif_lookup(argv[argc - 1]); if (!ofproto) { unixctl_command_reply_error(conn, "no such bridge"); return; } + if (argc > 2 && !strcmp(argv[1], "-m")) { + verbosity = true; + } + + hmap_init(&portno_names); + DPIF_PORT_FOR_EACH (&dpif_port, &port_dump, ofproto->backer->dpif) { + odp_portno_names_set(&portno_names, dpif_port.port_no, dpif_port.name); + } + ds_init(&ds); - dpif_flow_dump_start(&flow_dump, ofproto->backer->dpif); - while (dpif_flow_dump_next(&flow_dump, &key, &key_len, &mask, &mask_len, - &actions, &actions_len, &stats)) { + error = dpif_flow_dump_start(&flow_dump, ofproto->backer->dpif); + if (error) { + goto exit; + } + dpif_flow_dump_state_init(ofproto->backer->dpif, &state); + while (dpif_flow_dump_next(&flow_dump, state, &key, &key_len, + &mask, &mask_len, &actions, &actions_len, + &stats)) { if (!ofproto_dpif_contains_flow(ofproto, key, key_len)) { continue; } - odp_flow_format(key, key_len, mask, mask_len, NULL, &ds, false); + odp_flow_format(key, key_len, mask, mask_len, &portno_names, &ds, + verbosity); ds_put_cstr(&ds, ", "); dpif_flow_stats_format(stats, &ds); ds_put_cstr(&ds, ", actions:"); format_odp_actions(&ds, actions, actions_len); ds_put_char(&ds, '\n'); } + dpif_flow_dump_state_uninit(ofproto->backer->dpif, state); + error = dpif_flow_dump_done(&flow_dump); - if (dpif_flow_dump_done(&flow_dump)) { +exit: + if (error) { ds_clear(&ds); ds_put_format(&ds, "dpif/dump_flows failed: %s", ovs_strerror(errno)); unixctl_command_reply_error(conn, ds_cstr(&ds)); } else { unixctl_command_reply(conn, ds_cstr(&ds)); } + odp_portno_names_destroy(&portno_names); + hmap_destroy(&portno_names); ds_destroy(&ds); } @@ -4026,7 +4248,7 @@ ofproto_dpif_unixctl_init(void) ofproto_unixctl_dpif_dump_dps, NULL); unixctl_command_register("dpif/show", "", 0, 0, ofproto_unixctl_dpif_show, NULL); - unixctl_command_register("dpif/dump-flows", "bridge", 1, 1, + unixctl_command_register("dpif/dump-flows", "[-m] bridge", 1, 2, ofproto_unixctl_dpif_dump_flows, NULL); } @@ -4079,12 +4301,8 @@ bool ofproto_has_vlan_splinters(const struct ofproto_dpif *ofproto) OVS_EXCLUDED(ofproto->vsp_mutex) { - bool ret; - - ovs_mutex_lock(&ofproto->vsp_mutex); - ret = !hmap_is_empty(&ofproto->realdev_vid_map); - ovs_mutex_unlock(&ofproto->vsp_mutex); - return ret; + /* hmap_is_empty is thread safe. */ + return !hmap_is_empty(&ofproto->realdev_vid_map); } static ofp_port_t @@ -4122,6 +4340,10 @@ vsp_realdev_to_vlandev(const struct ofproto_dpif *ofproto, { ofp_port_t ret; + /* hmap_is_empty is thread safe, see if we can return immediately. */ + if (hmap_is_empty(&ofproto->realdev_vid_map)) { + return realdev_ofp_port; + } ovs_mutex_lock(&ofproto->vsp_mutex); ret = vsp_realdev_to_vlandev__(ofproto, realdev_ofp_port, vlan_tci); ovs_mutex_unlock(&ofproto->vsp_mutex); @@ -4185,6 +4407,11 @@ vsp_adjust_flow(const struct ofproto_dpif *ofproto, struct flow *flow) ofp_port_t realdev; int vid; + /* hmap_is_empty is thread safe. */ + if (hmap_is_empty(&ofproto->vlandev_map)) { + return false; + } + ovs_mutex_lock(&ofproto->vsp_mutex); realdev = vsp_vlandev_to_realdev(ofproto, flow->in_port.ofp_port, &vid); ovs_mutex_unlock(&ofproto->vsp_mutex);