if (flow_format == NXFF_TUN_ID_FROM_COOKIE && !(ofpfw & NXFW_TUN_ID)) {
rule->flow.tun_id = htonll(ntohll(cookie) >> 32);
- } else {
- wc->wildcards |= FWW_TUN_ID;
- rule->flow.tun_id = htonll(0);
}
if (ofpfw & OFPFW_DL_DST) {
rule->flow.nw_dst = match->nw_dst;
rule->flow.in_port = (match->in_port == htons(OFPP_LOCAL) ? ODPP_LOCAL
: ntohs(match->in_port));
- rule->flow.dl_type = match->dl_type;
+ rule->flow.dl_type = ofputil_dl_type_from_openflow(match->dl_type);
rule->flow.tp_src = match->tp_src;
rule->flow.tp_dst = match->tp_dst;
memcpy(rule->flow.dl_src, match->dl_src, ETH_ADDR_LEN);
/* Tunnel ID. */
if (flow_format == NXFF_TUN_ID_FROM_COOKIE) {
- if (wc->wildcards & FWW_TUN_ID) {
+ if (wc->tun_id_mask == htonll(0)) {
ofpfw |= NXFW_TUN_ID;
} else {
uint32_t cookie_lo = ntohll(cookie_in);
: rule->flow.in_port);
memcpy(match->dl_src, rule->flow.dl_src, ETH_ADDR_LEN);
memcpy(match->dl_dst, rule->flow.dl_dst, ETH_ADDR_LEN);
- match->dl_type = rule->flow.dl_type;
+ match->dl_type = ofputil_dl_type_to_openflow(rule->flow.dl_type);
match->nw_src = rule->flow.nw_src;
match->nw_dst = rule->flow.nw_dst;
match->nw_tos = rule->flow.nw_tos;
memset(match->pad2, '\0', sizeof match->pad2);
}
+/* Given a 'dl_type' value in the format used in struct flow, returns the
+ * corresponding 'dl_type' value for use in an OpenFlow ofp_match structure. */
+ovs_be16
+ofputil_dl_type_to_openflow(ovs_be16 flow_dl_type)
+{
+ return (flow_dl_type == htons(FLOW_DL_TYPE_NONE)
+ ? htons(OFP_DL_TYPE_NOT_ETH_TYPE)
+ : flow_dl_type);
+}
+
+/* Given a 'dl_type' value in the format used in an OpenFlow ofp_match
+ * structure, returns the corresponding 'dl_type' value for use in struct
+ * flow. */
+ovs_be16
+ofputil_dl_type_from_openflow(ovs_be16 ofp_dl_type)
+{
+ return (ofp_dl_type == htons(OFP_DL_TYPE_NOT_ETH_TYPE)
+ ? htons(FLOW_DL_TYPE_NONE)
+ : ofp_dl_type);
+}
+
/* Returns a transaction ID to use for an outgoing OpenFlow message. */
static ovs_be32
alloc_xid(void)
return true;
}
+static inline bool
+is_nxm_required(const struct cls_rule *rule, bool cookie_support,
+ ovs_be64 cookie)
+{
+ const struct flow_wildcards *wc = &rule->wc;
+ ovs_be32 cookie_hi;
+
+ /* Only NXM supports separately wildcards the Ethernet multicast bit. */
+ if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)) {
+ return true;
+ }
+
+ /* Only NXM supports matching registers. */
+ if (!regs_fully_wildcarded(wc)) {
+ return true;
+ }
+
+ switch (wc->tun_id_mask) {
+ case CONSTANT_HTONLL(0):
+ /* Other formats can fully wildcard tun_id. */
+ break;
+
+ case CONSTANT_HTONLL(UINT64_MAX):
+ /* Only NXM supports matching tunnel ID, unless there is a cookie and
+ * the top 32 bits of the cookie are the desired tunnel ID value. */
+ cookie_hi = htonl(ntohll(cookie) >> 32);
+ if (!cookie_support
+ || (cookie_hi && cookie_hi != ntohll(rule->flow.tun_id))) {
+ return true;
+ }
+ break;
+
+ default:
+ /* Only NXM supports partial matches on tunnel ID. */
+ return true;
+ }
+
+ /* Other formats can express this rule. */
+ return false;
+}
+
/* Returns the minimum nx_flow_format to use for sending 'rule' to a switch
* (e.g. to add or remove a flow). 'cookie_support' should be true if the
* command to be sent includes a flow cookie (as OFPT_FLOW_MOD does, for
ofputil_min_flow_format(const struct cls_rule *rule, bool cookie_support,
ovs_be64 cookie)
{
- const struct flow_wildcards *wc = &rule->wc;
- ovs_be32 cookie_hi = htonl(ntohll(cookie) >> 32);
-
- if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)
- || !regs_fully_wildcarded(wc)
- || (!(wc->wildcards & FWW_TUN_ID)
- && (!cookie_support
- || (cookie_hi && cookie_hi != ntohll(rule->flow.tun_id))))) {
+ if (is_nxm_required(rule, cookie_support, cookie)) {
return NXFF_NXM;
- } else if (!(wc->wildcards & FWW_TUN_ID)) {
+ } else if (rule->wc.tun_id_mask != htonll(0)) {
return NXFF_TUN_ID_FROM_COOKIE;
} else {
return NXFF_OPENFLOW10;