X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Fflow.c;h=407535063c717d6b0a48e2278375a10ed12b86c1;hb=b0fb94a346e52f36aeef238dd5f9bef9a10c14ef;hp=c6a90b93687addc8f9d045c9997fbfec623689ac;hpb=cc36576070df622d0fc7a6e26ce01027e12b5b59;p=sliver-openvswitch.git diff --git a/datapath/flow.c b/datapath/flow.c index c6a90b936..407535063 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -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) + | (1ULL << OVS_KEY_ATTR_ETHERTYPE)); /* Check key attributes. */ if (match->key->eth.type == htons(ETH_P_ARP) @@ -429,7 +428,7 @@ static struct flex_array *alloc_buckets(unsigned int n_buckets) struct flex_array *buckets; int i, err; - buckets = flex_array_alloc(sizeof(struct hlist_head *), + buckets = flex_array_alloc(sizeof(struct hlist_head), n_buckets, GFP_KERNEL); if (!buckets) return NULL; @@ -489,7 +488,7 @@ static void __flow_tbl_destroy(struct flow_table *table) int ver = table->node_ver; hlist_for_each_entry_safe(flow, n, head, hash_node[ver]) { - hlist_del_rcu(&flow->hash_node[ver]); + hlist_del(&flow->hash_node[ver]); ovs_flow_free(flow, false); } } @@ -1175,8 +1174,8 @@ static int parse_flow_nlattrs(const struct nlattr *attr, return __parse_flow_nlattrs(attr, a, attrsp, false); } -int ipv4_tun_from_nlattr(const struct nlattr *attr, - struct sw_flow_match *match, bool is_mask) +int ovs_ipv4_tun_from_nlattr(const struct nlattr *attr, + struct sw_flow_match *match, bool is_mask) { struct nlattr *a; int rem; @@ -1249,22 +1248,24 @@ int ipv4_tun_from_nlattr(const struct nlattr *attr, return -EINVAL; } - if (!match->key->tun_key.ipv4_dst) { - OVS_NLERR("IPv4 tunnel destination address is zero.\n"); - return -EINVAL; - } + if (!is_mask) { + if (!match->key->tun_key.ipv4_dst) { + OVS_NLERR("IPv4 tunnel destination address is zero.\n"); + return -EINVAL; + } - if (!ttl) { - OVS_NLERR("IPv4 tunnel TTL not specified.\n"); - return -EINVAL; + if (!ttl) { + OVS_NLERR("IPv4 tunnel TTL not specified.\n"); + return -EINVAL; + } } return 0; } -int ipv4_tun_to_nlattr(struct sk_buff *skb, - const struct ovs_key_ipv4_tunnel *tun_key, - const struct ovs_key_ipv4_tunnel *output) +int ovs_ipv4_tun_to_nlattr(struct sk_buff *skb, + const struct ovs_key_ipv4_tunnel *tun_key, + const struct ovs_key_ipv4_tunnel *output) { struct nlattr *nla; @@ -1310,8 +1311,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) { @@ -1330,7 +1334,7 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, *attrs &= ~(1ULL << OVS_KEY_ATTR_SKB_MARK); } if (*attrs & (1ULL << OVS_KEY_ATTR_TUNNEL)) { - if (ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match, + if (ovs_ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match, is_mask)) return -EINVAL; *attrs &= ~(1ULL << OVS_KEY_ATTR_TUNNEL); @@ -1363,21 +1367,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; @@ -1687,30 +1698,29 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, { struct ovs_key_ethernet *eth_key; struct nlattr *nla, *encap; + bool is_mask = (swkey != output); - 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 && - ipv4_tun_to_nlattr(skb, &swkey->tun_key, &output->tun_key)) + if ((swkey->tun_key.ipv4_dst || is_mask) && + ovs_ipv4_tun_to_nlattr(skb, &swkey->tun_key, &output->tun_key)) goto nla_put_failure; if (swkey->phy.in_port == DP_MAX_PORTS) { - if ((swkey != output) && (output->phy.in_port == 0xffff)) + if (is_mask && (output->phy.in_port == 0xffff)) if (nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, 0xffffffff)) goto nla_put_failure; } else { u16 upper_u16; - upper_u16 = (swkey == output) ? 0 : 0xffff; + upper_u16 = !is_mask ? 0 : 0xffff; if (nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, (upper_u16 << 16) | output->phy.in_port)) 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)); @@ -1723,7 +1733,7 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, if (swkey->eth.tci || swkey->eth.type == htons(ETH_P_8021Q)) { __be16 eth_type; - eth_type = (swkey == output) ? htons(ETH_P_8021Q) : htons(0xffff) ; + eth_type = !is_mask ? htons(ETH_P_8021Q) : htons(0xffff); if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, eth_type) || nla_put_be16(skb, OVS_KEY_ATTR_VLAN, output->eth.tci)) goto nla_put_failure; @@ -1740,7 +1750,7 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, * 0xffff in the mask attribute. Ethertype can also * be wildcarded. */ - if (swkey != output && output->eth.type) + if (is_mask && output->eth.type) if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, output->eth.type)) goto nla_put_failure;