* 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. */
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 *,
ofproto->netflow, ofproto->up.frag_handling,
ofproto->up.forward_bpdu,
connmgr_has_in_band(ofproto->up.connmgr),
- ofproto->backer->variable_length_userdata);
+ 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,
};
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)
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);
}
}
+/* 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_)
{
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);
}
}
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. */
*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;
}
}
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;
}
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;
}