datapath: Accept any 802.2 eth_type mask but override to be exact match
[sliver-openvswitch.git] / datapath / flow.c
index 2c11408..0a6e040 100644 (file)
@@ -82,8 +82,9 @@ static void update_range__(struct sw_flow_match *match,
        do { \
                update_range__(match, offsetof(struct sw_flow_key, field),  \
                                     sizeof((match)->key->field), is_mask); \
-               if (is_mask && match->mask != NULL) {                       \
-                       (match)->mask->key.field = value;                   \
+               if (is_mask) {                                              \
+                       if ((match)->mask)                                  \
+                               (match)->mask->key.field = value;           \
                } else {                                                    \
                        (match)->key->field = value;                        \
                }                                                           \
@@ -93,8 +94,9 @@ static void update_range__(struct sw_flow_match *match,
        do { \
                update_range__(match, offsetof(struct sw_flow_key, field),  \
                                len, is_mask);                              \
-               if (is_mask && match->mask != NULL) {                       \
-                       memcpy(&(match)->mask->key.field, value_p, len);    \
+               if (is_mask) {                                              \
+                       if ((match)->mask)                                  \
+                               memcpy(&(match)->mask->key.field, value_p, len);\
                } else {                                                    \
                        memcpy(&(match)->key->field, value_p, len);         \
                }                                                           \
@@ -133,13 +135,10 @@ static bool ovs_match_validate(const struct sw_flow_match *match,
                        | (1ULL << OVS_KEY_ATTR_ARP)
                        | (1ULL << OVS_KEY_ATTR_ND));
 
-       if (match->key->phy.in_port == DP_MAX_PORTS &&
-           match->mask && (match->mask->key.phy.in_port == 0xffff))
-               mask_allowed |= (1ULL << OVS_KEY_ATTR_IN_PORT);
-
-       if (match->key->eth.type == htons(ETH_P_802_2) &&
-           match->mask && (match->mask->key.eth.type == htons(0xffff)))
-               mask_allowed |= (1ULL << OVS_KEY_ATTR_ETHERTYPE);
+       /* Always allowed mask fields. */
+       mask_allowed |= ((1ULL << OVS_KEY_ATTR_TUNNEL)
+                      | (1ULL << OVS_KEY_ATTR_IN_PORT)
+                      | (11ULL << OVS_KEY_ATTR_ETHERTYPE));
 
        /* Check key attributes. */
        if (match->key->eth.type == htons(ETH_P_ARP)
@@ -1310,8 +1309,11 @@ static int metadata_from_nlattrs(struct sw_flow_match *match,  u64 *attrs,
        if (*attrs & (1ULL << OVS_KEY_ATTR_IN_PORT)) {
                u32 in_port = nla_get_u32(a[OVS_KEY_ATTR_IN_PORT]);
 
-               if (!is_mask && in_port >= DP_MAX_PORTS)
+               if (is_mask)
+                       in_port = 0xffffffff; /* Always exact match in_port. */
+               else if (in_port >= DP_MAX_PORTS)
                        return -EINVAL;
+
                SW_FLOW_KEY_PUT(match, phy.in_port, in_port, is_mask);
                *attrs &= ~(1ULL << OVS_KEY_ATTR_IN_PORT);
        } else if (!is_mask) {
@@ -1363,21 +1365,28 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match,  u64 attrs,
                __be16 tci;
 
                tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
-               if (!is_mask)
-                       if (!(tci & htons(VLAN_TAG_PRESENT))) {
+               if (!(tci & htons(VLAN_TAG_PRESENT))) {
+                       if (is_mask)
+                               OVS_NLERR("VLAN TCI mask does not have exact match for VLAN_TAG_PRESENT bit.\n");
+                       else
                                OVS_NLERR("VLAN TCI does not have VLAN_TAG_PRESENT bit set.\n");
-                               return -EINVAL;
-                       }
+
+                       return -EINVAL;
+               }
 
                SW_FLOW_KEY_PUT(match, eth.tci, tci, is_mask);
                attrs &= ~(1ULL << OVS_KEY_ATTR_VLAN);
-       }
+       } else if (!is_mask)
+               SW_FLOW_KEY_PUT(match, eth.tci, htons(0xffff), true);
 
        if (attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)) {
                __be16 eth_type;
 
                eth_type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
-               if (!is_mask && ntohs(eth_type) < ETH_P_802_3_MIN) {
+               if (is_mask) {
+                       /* Always exact match EtherType. */
+                       eth_type = htons(0xffff);
+               } else if (ntohs(eth_type) < ETH_P_802_3_MIN) {
                        OVS_NLERR("EtherType is less than mimimum (type=%x, min=%x).\n",
                                        ntohs(eth_type), ETH_P_802_3_MIN);
                        return -EINVAL;
@@ -1688,8 +1697,7 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey,
        struct ovs_key_ethernet *eth_key;
        struct nlattr *nla, *encap;
 
-       if (output->phy.priority &&
-               nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority))
+       if (nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority))
                goto nla_put_failure;
 
        if (swkey->tun_key.ipv4_dst &&
@@ -1709,8 +1717,7 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey,
                        goto nla_put_failure;
        }
 
-       if (output->phy.skb_mark &&
-               nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, output->phy.skb_mark))
+       if (nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, output->phy.skb_mark))
                goto nla_put_failure;
 
        nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));