X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=ofproto%2Fofproto-dpif.c;h=7b3e1eb649c13ad4eb36ee3b9df138b3b0778038;hb=94b8c324a11de4e4ab7647e8ad87fd01a8163f6d;hp=52759b563a52b948139563329723268e8d782004;hpb=04b541dfe5c2b9027f365204b727133c9c574989;p=sliver-openvswitch.git diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 52759b563..7b3e1eb64 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. @@ -251,6 +251,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 +323,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 +567,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 +791,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 +892,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 +902,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_) { @@ -1044,9 +1189,9 @@ destruct(struct ofproto *ofproto_) 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); } @@ -2800,12 +2945,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 +2965,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 = 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; @@ -2919,11 +3068,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 +3091,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; } @@ -3367,6 +3518,7 @@ struct trace_ctx { struct xlate_out xout; struct xlate_in xin; struct flow flow; + struct flow_wildcards wc; struct ds *result; }; @@ -3442,6 +3594,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 +3618,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 +3715,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; } @@ -3730,18 +3897,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 +3923,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 +3937,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 +4100,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; }