/* Initialize most of rule->wc. */
flow_wildcards_init_catchall(wc);
wc->wildcards = ofpfw & WC_INVARIANTS;
+
+ /* Wildcard fields that aren't defined by ofp_match or tun_id. */
+ wc->wildcards |= (FWW_ARP_SHA | FWW_ARP_THA | FWW_ND_TARGET);
+
if (ofpfw & OFPFW_NW_TOS) {
wc->wildcards |= FWW_NW_TOS;
}
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);
: 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)
ovs_be64 cookie)
{
const struct flow_wildcards *wc = &rule->wc;
- ovs_be32 cookie_hi;
+ uint32_t cookie_hi;
+ uint64_t tun_id;
/* 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 ARP hardware addresses. */
+ if (!(wc->wildcards & FWW_ARP_SHA) || !(wc->wildcards & FWW_ARP_THA)) {
+ return true;
+ }
+
+ /* Only NXM supports matching IPv6 traffic. */
+ if (!(wc->wildcards & FWW_DL_TYPE)
+ && (rule->flow.dl_type == htons(ETH_TYPE_IPV6))) {
+ return true;
+ }
+
/* Only NXM supports matching registers. */
if (!regs_fully_wildcarded(wc)) {
return true;
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))) {
+ /* Only NXM supports tunnel ID matching without a cookie. */
+ if (!cookie_support) {
+ return true;
+ }
+
+ /* Only NXM supports 64-bit tunnel IDs. */
+ tun_id = ntohll(rule->flow.tun_id);
+ if (tun_id > UINT32_MAX) {
+ return true;
+ }
+
+ /* Only NXM supports a cookie whose top 32 bits conflict with the
+ * tunnel ID. */
+ cookie_hi = ntohll(cookie) >> 32;
+ if (cookie_hi && cookie_hi != tun_id) {
return true;
}
break;
m->nw_dst &= ofputil_wcbits_to_netmask(wc >> OFPFW_NW_DST_SHIFT);
}
m->tp_src = m->tp_dst = m->nw_tos = 0;
+ } else if (m->dl_type == htons(ETH_TYPE_IPV6)) {
+ /* Don't normalize IPv6 traffic, since OpenFlow doesn't have a
+ * way to express it. */
} else {
/* Network and transport layer fields will always be extracted as
* zeros, so we can do an exact-match on those values. */