X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=datapath%2Fflow.c;h=752c8d6b348f472d50a1915a3a14a9db03df3beb;hb=bbb8dee92d639331e8bd81823638267dcc895396;hp=2ac36b6fbf84efb8980b17c27755180f74e5c03e;hpb=85606e05b691be7c2f2d4bcf0e91170b71ec8fbb;p=sliver-openvswitch.git diff --git a/datapath/flow.c b/datapath/flow.c index 2ac36b6fb..752c8d6b3 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -133,6 +133,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); @@ -205,13 +209,19 @@ static bool ovs_match_validate(const struct sw_flow_match *match, } } - if ((key_attrs & key_expected) != key_expected) + if ((key_attrs & key_expected) != key_expected) { /* Key attributes check failed. */ + OVS_NLERR("Missing expected key attributes (key_attrs=%llx, expected=%llx).\n", + key_attrs, key_expected); return false; + } - if ((mask_attrs & mask_allowed) != mask_attrs) + if ((mask_attrs & mask_allowed) != mask_attrs) { /* Mask attributes check failed. */ + OVS_NLERR("Contain more than allowed mask fields (mask_attrs=%llx, mask_allowed=%llx).\n", + mask_attrs, mask_allowed); return false; + } return true; } @@ -339,9 +349,8 @@ static bool icmp6hdr_ok(struct sk_buff *skb) sizeof(struct icmp6hdr)); } -static void flow_key_mask(struct sw_flow_key *dst, - const struct sw_flow_key *src, - const struct sw_flow_mask *mask) +void ovs_flow_key_mask(struct sw_flow_key *dst, const struct sw_flow_key *src, + const struct sw_flow_mask *mask) { u8 *m = (u8 *)&mask->key + mask->range.start; u8 *s = (u8 *)src + mask->range.start; @@ -1035,7 +1044,7 @@ static struct sw_flow *ovs_masked_flow_lookup(struct flow_table *table, u32 hash; struct sw_flow_key masked_key; - flow_key_mask(&masked_key, flow_key, mask); + ovs_flow_key_mask(&masked_key, flow_key, mask); hash = ovs_flow_hash(&masked_key, key_start, key_len); head = find_bucket(table, hash); hlist_for_each_entry_rcu(flow, head, hash_node[table->node_ver]) { @@ -1061,11 +1070,8 @@ struct sw_flow *ovs_flow_lookup(struct flow_table *tbl, } -void ovs_flow_insert(struct flow_table *table, struct sw_flow *flow, - const struct sw_flow_key *key, int key_len) +void ovs_flow_insert(struct flow_table *table, struct sw_flow *flow) { - flow->unmasked_key = *key; - flow_key_mask(&flow->key, &flow->unmasked_key, ovsl_dereference(flow->mask)); flow->hash = ovs_flow_hash(&flow->key, ovsl_dereference(flow->mask)->range.start, ovsl_dereference(flow->mask)->range.end); @@ -1126,24 +1132,33 @@ static int __parse_flow_nlattrs(const struct nlattr *attr, u16 type = nla_type(nla); int expected_len; - if (type > OVS_KEY_ATTR_MAX || attrs & (1ULL << type)) - return -EINVAL; + if (type > OVS_KEY_ATTR_MAX) { + OVS_NLERR("Unknown key attribute (type=%d, max=%d).\n", + type, OVS_KEY_ATTR_MAX); + } - expected_len = ovs_key_lens[type]; - if (nla_len(nla) != expected_len && expected_len != -1) + if (attrs & (1ULL << type)) { + OVS_NLERR("Duplicate key attribute (type %d).\n", type); return -EINVAL; + } - if (attrs & (1ULL << type)) - /* Duplicated field. */ + expected_len = ovs_key_lens[type]; + if (nla_len(nla) != expected_len && expected_len != -1) { + OVS_NLERR("Key attribute has unexpected length (type=%d" + ", length=%d, expected=%d).\n", type, + nla_len(nla), expected_len); return -EINVAL; + } if (!nz || !is_all_zero(nla_data(nla), expected_len)) { attrs |= 1ULL << type; a[type] = nla; } } - if (rem) + if (rem) { + OVS_NLERR("Message has %d unknown bytes.\n", rem); return -EINVAL; + } *attrsp = attrs; return 0; @@ -1181,9 +1196,18 @@ int ipv4_tun_from_nlattr(const struct nlattr *attr, [OVS_TUNNEL_KEY_ATTR_CSUM] = 0, }; - if (type > OVS_TUNNEL_KEY_ATTR_MAX || - ovs_tunnel_key_lens[type] != nla_len(a)) + if (type > OVS_TUNNEL_KEY_ATTR_MAX) { + OVS_NLERR("Unknown IPv4 tunnel attribute (type=%d, max=%d).\n", + type, OVS_TUNNEL_KEY_ATTR_MAX); return -EINVAL; + } + + if (ovs_tunnel_key_lens[type] != nla_len(a)) { + OVS_NLERR("IPv4 tunnel attribute type has unexpected " + " legnth (type=%d, length=%d, expected=%d).\n", + type, nla_len(a), ovs_tunnel_key_lens[type]); + return -EINVAL; + } switch (type) { case OVS_TUNNEL_KEY_ATTR_ID: @@ -1221,14 +1245,20 @@ int ipv4_tun_from_nlattr(const struct nlattr *attr, SW_FLOW_KEY_PUT(match, tun_key.tun_flags, tun_flags, is_mask); - if (rem > 0) + if (rem > 0) { + OVS_NLERR("IPv4 tunnel attribute has %d unknown bytes.\n", rem); return -EINVAL; + } - if (!match->key->tun_key.ipv4_dst) + if (!match->key->tun_key.ipv4_dst) { + OVS_NLERR("IPv4 tunnel destination address is zero.\n"); return -EINVAL; + } - if (!ttl) + if (!ttl) { + OVS_NLERR("IPv4 tunnel TTL not specified.\n"); return -EINVAL; + } return 0; } @@ -1243,23 +1273,24 @@ int ipv4_tun_to_nlattr(struct sk_buff *skb, if (!nla) return -EMSGSIZE; - if (tun_key->tun_flags & TUNNEL_KEY && + if (output->tun_flags & TUNNEL_KEY && nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, output->tun_id)) return -EMSGSIZE; - if (tun_key->ipv4_src && - nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, output->ipv4_src)) + if (output->ipv4_src && + nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, output->ipv4_src)) return -EMSGSIZE; - if (nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST, output->ipv4_dst)) + if (output->ipv4_dst && + nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST, output->ipv4_dst)) return -EMSGSIZE; - if (tun_key->ipv4_tos && - nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->ipv4_tos)) + if (output->ipv4_tos && + nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, output->ipv4_tos)) return -EMSGSIZE; if (nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TTL, output->ipv4_ttl)) return -EMSGSIZE; - if ((tun_key->tun_flags & TUNNEL_DONT_FRAGMENT) && + if ((output->tun_flags & TUNNEL_DONT_FRAGMENT) && nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT)) return -EMSGSIZE; - if ((tun_key->tun_flags & TUNNEL_CSUM) && + if ((output->tun_flags & TUNNEL_CSUM) && nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM)) return -EMSGSIZE; @@ -1284,13 +1315,17 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, 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) { + SW_FLOW_KEY_PUT(match, phy.in_port, DP_MAX_PORTS, is_mask); } if (*attrs & (1ULL << OVS_KEY_ATTR_SKB_MARK)) { uint32_t mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && !defined(CONFIG_NETFILTER) - if (!is_mask && mark != 0) + if (!is_mask && mark != 0) { + OVS_NLERR("skb->mark must be zero on this kernel (mark=%d).\n", mark); return -EINVAL; + } #endif SW_FLOW_KEY_PUT(match, phy.skb_mark, mark, is_mask); *attrs &= ~(1ULL << OVS_KEY_ATTR_SKB_MARK); @@ -1330,8 +1365,10 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]); if (!is_mask) - if (!(tci & htons(VLAN_TAG_PRESENT))) + if (!(tci & htons(VLAN_TAG_PRESENT))) { + OVS_NLERR("VLAN TCI does not have VLAN_TAG_PRESENT bit set.\n"); return -EINVAL; + } SW_FLOW_KEY_PUT(match, eth.tci, tci, is_mask); attrs &= ~(1ULL << OVS_KEY_ATTR_VLAN); @@ -1341,8 +1378,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, __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 && 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; + } SW_FLOW_KEY_PUT(match, eth.type, eth_type, is_mask); attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE); @@ -1354,8 +1394,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, const struct ovs_key_ipv4 *ipv4_key; ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]); - if (!is_mask && ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) + if (!is_mask && ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) { + OVS_NLERR("Unknown IPv4 fragment type (value=%d, max=%d).\n", + ipv4_key->ipv4_frag, OVS_FRAG_TYPE_MAX); return -EINVAL; + } SW_FLOW_KEY_PUT(match, ip.proto, ipv4_key->ipv4_proto, is_mask); SW_FLOW_KEY_PUT(match, ip.tos, @@ -1375,8 +1418,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, const struct ovs_key_ipv6 *ipv6_key; ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]); - if (!is_mask && ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) + if (!is_mask && ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) { + OVS_NLERR("Unknown IPv6 fragment type (value=%d, max=%d).\n", + ipv6_key->ipv6_frag, OVS_FRAG_TYPE_MAX); return -EINVAL; + } SW_FLOW_KEY_PUT(match, ipv6.label, ipv6_key->ipv6_label, is_mask); SW_FLOW_KEY_PUT(match, ip.proto, @@ -1403,8 +1449,11 @@ static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, const struct ovs_key_arp *arp_key; arp_key = nla_data(a[OVS_KEY_ATTR_ARP]); - if (!is_mask && (arp_key->arp_op & htons(0xff00))) + if (!is_mask && (arp_key->arp_op & htons(0xff00))) { + OVS_NLERR("Unknown ARP opcode (opcode=%d).\n", + arp_key->arp_op); return -EINVAL; + } SW_FLOW_KEY_PUT(match, ipv4.addr.src, arp_key->arp_sip, is_mask); @@ -1539,8 +1588,10 @@ int ovs_match_from_nlattrs(struct sw_flow_match *match, encap_valid = true; key_attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE); err = parse_flow_nlattrs(encap, a, &key_attrs); - } else + } else { + OVS_NLERR("Encap attribute is set for a non-VLAN frame.\n"); err = -EINVAL; + } if (err) return err; @@ -1566,8 +1617,12 @@ int ovs_match_from_nlattrs(struct sw_flow_match *match, mask_attrs &= ~(1ULL << OVS_KEY_ATTR_ETHERTYPE); encap = a[OVS_KEY_ATTR_ENCAP]; err = parse_flow_mask_nlattrs(encap, a, &mask_attrs); - } else + } else { + OVS_NLERR("VLAN frames must have an exact match" + " on the TPID (mask=%x).\n", + ntohs(eth_type)); err = -EINVAL; + } if (err) return err; @@ -1634,26 +1689,29 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct ovs_key_ethernet *eth_key; struct nlattr *nla, *encap; - if (swkey->phy.priority && - nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, output->phy.priority)) + if (output->phy.priority && + 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)) goto nla_put_failure; - if (swkey->phy.in_port != DP_MAX_PORTS) { - /* Exact match upper 16 bits. */ + if (swkey->phy.in_port == DP_MAX_PORTS) { + if ((swkey != output) && (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; if (nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, - (upper_u16 << 16) | output->phy.in_port)) + (upper_u16 << 16) | output->phy.in_port)) goto nla_put_failure; } - if (swkey->phy.skb_mark && - nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, output->phy.skb_mark)) + if (output->phy.skb_mark && + 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)); @@ -1676,12 +1734,22 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, } else encap = NULL; - if ((swkey == output) && (swkey->eth.type == htons(ETH_P_802_2))) + if (swkey->eth.type == htons(ETH_P_802_2)) { + /* + * Ethertype 802.2 is represented in the netlink with omitted + * OVS_KEY_ATTR_ETHERTYPE in the flow key attribute, and + * 0xffff in the mask attribute. Ethertype can also + * be wildcarded. + */ + if (swkey != output && output->eth.type) + if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, + output->eth.type)) + goto nla_put_failure; goto unencap; + } - if (output->eth.type != 0) - if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, output->eth.type)) - goto nla_put_failure; + if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, output->eth.type)) + goto nla_put_failure; if (swkey->eth.type == htons(ETH_P_IP)) { struct ovs_key_ipv4 *ipv4_key;