use error checking mutexs in pltap&tunnel
[sliver-openvswitch.git] / datapath / flow.c
index 62357b9..3dc1b44 100644 (file)
@@ -1005,10 +1005,11 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key)
        return 0;
 }
 
-static u32 ovs_flow_hash(const struct sw_flow_key *key, int key_start, int key_len)
+static u32 ovs_flow_hash(const struct sw_flow_key *key, int key_start,
+                        int key_end)
 {
        return jhash2((u32 *)((u8 *)key + key_start),
-                     DIV_ROUND_UP(key_len - key_start, sizeof(u32)), 0);
+                     DIV_ROUND_UP(key_end - key_start, sizeof(u32)), 0);
 }
 
 static int flow_key_start(const struct sw_flow_key *key)
@@ -1020,31 +1021,31 @@ static int flow_key_start(const struct sw_flow_key *key)
 }
 
 static bool __cmp_key(const struct sw_flow_key *key1,
-               const struct sw_flow_key *key2,  int key_start, int key_len)
+               const struct sw_flow_key *key2,  int key_start, int key_end)
 {
        return !memcmp((u8 *)key1 + key_start,
-                       (u8 *)key2 + key_start, (key_len - key_start));
+                       (u8 *)key2 + key_start, (key_end - key_start));
 }
 
 static bool __flow_cmp_key(const struct sw_flow *flow,
-               const struct sw_flow_key *key, int key_start, int key_len)
+               const struct sw_flow_key *key, int key_start, int key_end)
 {
-       return __cmp_key(&flow->key, key, key_start, key_len);
+       return __cmp_key(&flow->key, key, key_start, key_end);
 }
 
 static bool __flow_cmp_unmasked_key(const struct sw_flow *flow,
-                 const struct sw_flow_key *key, int key_start, int key_len)
+                 const struct sw_flow_key *key, int key_start, int key_end)
 {
-       return __cmp_key(&flow->unmasked_key, key, key_start, key_len);
+       return __cmp_key(&flow->unmasked_key, key, key_start, key_end);
 }
 
 bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow,
-               const struct sw_flow_key *key, int key_len)
+               const struct sw_flow_key *key, int key_end)
 {
        int key_start;
        key_start = flow_key_start(key);
 
-       return __flow_cmp_unmasked_key(flow, key, key_start, key_len);
+       return __flow_cmp_unmasked_key(flow, key, key_start, key_end);
 
 }
 
@@ -1052,11 +1053,11 @@ struct sw_flow *ovs_flow_lookup_unmasked_key(struct flow_table *table,
                                       struct sw_flow_match *match)
 {
        struct sw_flow_key *unmasked = match->key;
-       int key_len = match->range.end;
+       int key_end = match->range.end;
        struct sw_flow *flow;
 
        flow = ovs_flow_lookup(table, unmasked);
-       if (flow && (!ovs_flow_cmp_unmasked_key(flow, unmasked, key_len)))
+       if (flow && (!ovs_flow_cmp_unmasked_key(flow, unmasked, key_end)))
                flow = NULL;
 
        return flow;
@@ -1069,16 +1070,16 @@ static struct sw_flow *ovs_masked_flow_lookup(struct flow_table *table,
        struct sw_flow *flow;
        struct hlist_head *head;
        int key_start = mask->range.start;
-       int key_len = mask->range.end;
+       int key_end = mask->range.end;
        u32 hash;
        struct sw_flow_key masked_key;
 
        ovs_flow_key_mask(&masked_key, flow_key, mask);
-       hash = ovs_flow_hash(&masked_key, key_start, key_len);
+       hash = ovs_flow_hash(&masked_key, key_start, key_end);
        head = find_bucket(table, hash);
        hlist_for_each_entry_rcu(flow, head, hash_node[table->node_ver]) {
                if (flow->mask == mask &&
-                   __flow_cmp_key(flow, &masked_key, key_start, key_len))
+                   __flow_cmp_key(flow, &masked_key, key_start, key_end))
                        return flow;
        }
        return NULL;
@@ -1635,26 +1636,36 @@ int ovs_match_from_nlattrs(struct sw_flow_match *match,
        if (err)
                return err;
 
-       if (key_attrs & 1ULL << OVS_KEY_ATTR_ENCAP) {
-               encap = a[OVS_KEY_ATTR_ENCAP];
-               key_attrs &= ~(1ULL << OVS_KEY_ATTR_ENCAP);
-               if (nla_len(encap)) {
-                       __be16 eth_type = 0; /* ETH_P_8021Q */
+       if ((key_attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) &&
+           (key_attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)) &&
+           (nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]) == htons(ETH_P_8021Q))) {
+               __be16 tci;
 
-                       if (a[OVS_KEY_ATTR_ETHERTYPE])
-                               eth_type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
+               if (!((key_attrs & (1ULL << OVS_KEY_ATTR_VLAN)) &&
+                     (key_attrs & (1ULL << OVS_KEY_ATTR_ENCAP)))) {
+                       OVS_NLERR("Invalid Vlan frame.\n");
+                       return -EINVAL;
+               }
 
-                       if  ((eth_type == htons(ETH_P_8021Q)) && (a[OVS_KEY_ATTR_VLAN])) {
-                               encap_valid = true;
-                               key_attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE);
-                               err = parse_flow_nlattrs(encap, a, &key_attrs);
-                       } else {
-                               OVS_NLERR("Encap attribute is set for a non-VLAN frame.\n");
-                               err = -EINVAL;
-                       }
+               key_attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE);
+               tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
+               encap = a[OVS_KEY_ATTR_ENCAP];
+               key_attrs &= ~(1ULL << OVS_KEY_ATTR_ENCAP);
+               encap_valid = true;
 
+               if (tci & htons(VLAN_TAG_PRESENT)) {
+                       err = parse_flow_nlattrs(encap, a, &key_attrs);
                        if (err)
                                return err;
+               } else if (!tci) {
+                       /* Corner case for truncated 802.1Q header. */
+                       if (nla_len(encap)) {
+                               OVS_NLERR("Truncated 802.1Q header has non-zero encap attribute.\n");
+                               return -EINVAL;
+                       }
+               } else {
+                       OVS_NLERR("Encap attribute is set for a non-VLAN frame.\n");
+                       return  -EINVAL;
                }
        }
 
@@ -1667,25 +1678,36 @@ int ovs_match_from_nlattrs(struct sw_flow_match *match,
                if (err)
                        return err;
 
-               if ((mask_attrs & 1ULL << OVS_KEY_ATTR_ENCAP) && encap_valid) {
+               if (mask_attrs & 1ULL << OVS_KEY_ATTR_ENCAP)  {
                        __be16 eth_type = 0;
+                       __be16 tci = 0;
+
+                       if (!encap_valid) {
+                               OVS_NLERR("Encap mask attribute is set for non-VLAN frame.\n");
+                               return  -EINVAL;
+                       }
 
                        mask_attrs &= ~(1ULL << OVS_KEY_ATTR_ENCAP);
                        if (a[OVS_KEY_ATTR_ETHERTYPE])
                                eth_type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
+
                        if (eth_type == htons(0xffff)) {
                                mask_attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE);
                                encap = a[OVS_KEY_ATTR_ENCAP];
                                err = parse_flow_mask_nlattrs(encap, a, &mask_attrs);
                        } else {
-                               OVS_NLERR("VLAN frames must have an exact match"
-                                        " on the TPID (mask=%x).\n",
-                                        ntohs(eth_type));
-                               err = -EINVAL;
+                               OVS_NLERR("VLAN frames must have an exact match on the TPID (mask=%x).\n",
+                                               ntohs(eth_type));
+                               return -EINVAL;
                        }
 
-                       if (err)
-                               return err;
+                       if (a[OVS_KEY_ATTR_VLAN])
+                               tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
+
+                       if (!(tci & htons(VLAN_TAG_PRESENT))) {
+                               OVS_NLERR("VLAN tag present bit must have an exact match (tci_mask=%x).\n", ntohs(tci));
+                               return -EINVAL;
+                       }
                }
 
                err = ovs_key_from_nlattrs(match, mask_attrs, a, true);