This patch refactors the netlink flow handling code to make the processing, error checking and prerequisite checking more stream lined.
Signed-off-by: Andy Zhou <az...@nicira.com> --- datapath/datapath.c | 44 +++- datapath/flow.c | 652 ++++++++++++++++++++++++++++----------------------- datapath/flow.h | 16 +- 3 files changed, 411 insertions(+), 301 deletions(-) diff --git a/datapath/datapath.c b/datapath/datapath.c index 42af315..8cf75bf 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -619,10 +619,14 @@ static int validate_tp_port(const struct sw_flow_key *flow_key) static int validate_and_copy_set_tun(const struct nlattr *attr, struct sw_flow_actions **sfa) { - struct ovs_key_ipv4_tunnel tun_key; + struct sw_flow_match match; + struct sw_flow_key key; int err, start; - err = ipv4_tun_from_nlattr(nla_data(attr), &tun_key); + memset(&key, 0, sizeof key); + ovs_match_init(&match, &key); + + err = ipv4_tun_from_nlattr(nla_data(attr), &match); if (err) return err; @@ -630,7 +634,8 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, if (start < 0) return start; - err = add_action(sfa, OVS_KEY_ATTR_IPV4_TUNNEL, &tun_key, sizeof(tun_key)); + err = add_action(sfa, OVS_KEY_ATTR_IPV4_TUNNEL, &match.key->tun_key, + sizeof(match.key->tun_key)); add_nested_action_end(*sfa, start); return err; @@ -1234,6 +1239,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) struct datapath *dp; struct flow_table *table; struct sw_flow_actions *acts = NULL; + struct sw_flow_match match; int error; int key_len; @@ -1241,10 +1247,18 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) error = -EINVAL; if (!a[OVS_FLOW_ATTR_KEY]) goto error; - error = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]); + + memset(&key, 0, sizeof key); + ovs_match_init(&match, &key); + error = ovs_match_from_nlattrs(&match, a[OVS_FLOW_ATTR_KEY]); if (error) goto error; + if (ovs_match_check_prerequisite(&match) == false) + goto error; + + key_len = ovs_match_get_len(&match); + /* Validate actions. */ if (a[OVS_FLOW_ATTR_ACTIONS]) { acts = ovs_flow_actions_alloc(nla_len(a[OVS_FLOW_ATTR_ACTIONS])); @@ -1358,15 +1372,24 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) struct sw_flow *flow; struct datapath *dp; struct flow_table *table; + struct sw_flow_match match; int err; int key_len; + memset(&key, 0, sizeof key); + ovs_match_init(&match, &key); + if (!a[OVS_FLOW_ATTR_KEY]) return -EINVAL; - err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]); + err = ovs_match_from_nlattrs(&match, a[OVS_FLOW_ATTR_KEY]); if (err) return err; + if (ovs_match_check_prerequisite(&match) == false) + return -EINVAL; + + key_len = ovs_match_get_len(&match); + ovs_lock(); dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); if (!dp) { @@ -1404,6 +1427,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) struct sw_flow *flow; struct datapath *dp; struct flow_table *table; + struct sw_flow_match match; int err; int key_len; @@ -1418,10 +1442,18 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) err = flush_flows(dp); goto unlock; } - err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]); + + memset(&key, 0, sizeof key); + ovs_match_init(&match, &key); + err = ovs_match_from_nlattrs(&match, a[OVS_FLOW_ATTR_KEY]); if (err) goto unlock; + if (ovs_match_check_prerequisite(&match) == false) + goto unlock; + + key_len = ovs_match_get_len(&match); + table = ovsl_dereference(dp->table); flow = ovs_flow_tbl_lookup(table, &key, key_len); if (!flow) { diff --git a/datapath/flow.c b/datapath/flow.c index 3ce926e..914051d 100644 --- a/datapath/flow.c +++ b/datapath/flow.c @@ -47,6 +47,110 @@ static struct kmem_cache *flow_cache; +static void field_add_writes__(struct sw_flow_match *match, + size_t offset, size_t size) +{ + int i; + u8 *op = &(match->n_writes[offset]); + + for (i = 0; i < size; i++, op++) { + ++*op; + } +} + +#define SW_FLOW_KEY_PUT(match, field, value) \ + do { \ + field_add_writes__(match, offsetof(struct sw_flow_key, field), \ + sizeof (match)->key->field ); \ + (match)->key->field = value; \ + } while (0) + +#define SW_FLOW_KEY_MEMCPY(match, field, value_p, len) \ + do { \ + field_add_writes__(match, \ + offsetof(struct sw_flow_key, field), len); \ + memcpy(&(match)->key->field, value_p, len); \ + } while (0) + +void ovs_match_init(struct sw_flow_match *match, struct sw_flow_key *key) +{ + memset(match, 0, sizeof *match); + match->key = key; +} + +bool ovs_match_check_prerequisite(const struct sw_flow_match *match) +{ + int i; + u64 expected = 0; + + /* Any duplicate writes to the matching key is invalid. */ + for (i=0; i< sizeof *(match->key); i++) + if (match->n_writes[i] >= 2) { + return false; + } + + if (match->key->eth.type == htons(ETH_P_ARP)) + expected |= 1ULL << OVS_KEY_ATTR_ARP; + + if (match->key->eth.type == htons(ETH_P_RARP)) + expected |= 1ULL << OVS_KEY_ATTR_ARP; + + if (match->key->eth.type == htons(ETH_P_IP)) { + expected |= 1ULL << OVS_KEY_ATTR_IPV4; + + if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) { + if (match->key->ip.proto == IPPROTO_UDP) + expected |= 1ULL << OVS_KEY_ATTR_UDP; + + if (match->key->ip.proto == IPPROTO_TCP) + expected |= 1ULL << OVS_KEY_ATTR_TCP; + + if (match->key->ip.proto == IPPROTO_ICMP) + expected |= 1ULL << OVS_KEY_ATTR_ICMP; + } + } + + if (match->key->eth.type == htons(ETH_P_IPV6)) { + expected |= 1ULL << OVS_KEY_ATTR_IPV6; + + if (match->key->ip.frag != OVS_FRAG_TYPE_LATER) { + if (match->key->ip.proto == IPPROTO_UDP) + expected |= 1ULL << OVS_KEY_ATTR_UDP; + + if (match->key->ip.proto == IPPROTO_TCP) + expected |= 1ULL << OVS_KEY_ATTR_TCP; + + if (match->key->ip.proto == IPPROTO_ICMPV6) { + expected |= 1ULL << OVS_KEY_ATTR_ICMPV6; + + if (match->key->ipv6.tp.src == htons(NDISC_NEIGHBOUR_SOLICITATION)) + expected |= 1ULL << OVS_KEY_ATTR_ND; + + if (match->key->ipv6.tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) + expected |= 1ULL << OVS_KEY_ATTR_ND; + } + } + } + + if ((match->key_attrs & expected) != expected) + return false; + + return true; +} + +int ovs_match_get_len(struct sw_flow_match *match) +{ + int len; + + for (len = sizeof *(match->key); len >0; len--) { + if (match->n_writes[len-1] > 0) { + return len; + } + } + + return 0; +} + static int check_header(struct sk_buff *skb, int len) { if (unlikely(skb->len < len)) @@ -850,112 +954,6 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { [OVS_KEY_ATTR_TUNNEL] = -1, }; -static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, - const struct nlattr *a[], u64 *attrs) -{ - const struct ovs_key_icmp *icmp_key; - const struct ovs_key_tcp *tcp_key; - const struct ovs_key_udp *udp_key; - - switch (swkey->ip.proto) { - case IPPROTO_TCP: - if (!(*attrs & (1 << OVS_KEY_ATTR_TCP))) - return -EINVAL; - *attrs &= ~(1 << OVS_KEY_ATTR_TCP); - - *key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); - tcp_key = nla_data(a[OVS_KEY_ATTR_TCP]); - swkey->ipv4.tp.src = tcp_key->tcp_src; - swkey->ipv4.tp.dst = tcp_key->tcp_dst; - break; - - case IPPROTO_UDP: - if (!(*attrs & (1 << OVS_KEY_ATTR_UDP))) - return -EINVAL; - *attrs &= ~(1 << OVS_KEY_ATTR_UDP); - - *key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); - udp_key = nla_data(a[OVS_KEY_ATTR_UDP]); - swkey->ipv4.tp.src = udp_key->udp_src; - swkey->ipv4.tp.dst = udp_key->udp_dst; - break; - - case IPPROTO_ICMP: - if (!(*attrs & (1 << OVS_KEY_ATTR_ICMP))) - return -EINVAL; - *attrs &= ~(1 << OVS_KEY_ATTR_ICMP); - - *key_len = SW_FLOW_KEY_OFFSET(ipv4.tp); - icmp_key = nla_data(a[OVS_KEY_ATTR_ICMP]); - swkey->ipv4.tp.src = htons(icmp_key->icmp_type); - swkey->ipv4.tp.dst = htons(icmp_key->icmp_code); - break; - } - - return 0; -} - -static int ipv6_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len, - const struct nlattr *a[], u64 *attrs) -{ - const struct ovs_key_icmpv6 *icmpv6_key; - const struct ovs_key_tcp *tcp_key; - const struct ovs_key_udp *udp_key; - - switch (swkey->ip.proto) { - case IPPROTO_TCP: - if (!(*attrs & (1 << OVS_KEY_ATTR_TCP))) - return -EINVAL; - *attrs &= ~(1 << OVS_KEY_ATTR_TCP); - - *key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); - tcp_key = nla_data(a[OVS_KEY_ATTR_TCP]); - swkey->ipv6.tp.src = tcp_key->tcp_src; - swkey->ipv6.tp.dst = tcp_key->tcp_dst; - break; - - case IPPROTO_UDP: - if (!(*attrs & (1 << OVS_KEY_ATTR_UDP))) - return -EINVAL; - *attrs &= ~(1 << OVS_KEY_ATTR_UDP); - - *key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); - udp_key = nla_data(a[OVS_KEY_ATTR_UDP]); - swkey->ipv6.tp.src = udp_key->udp_src; - swkey->ipv6.tp.dst = udp_key->udp_dst; - break; - - case IPPROTO_ICMPV6: - if (!(*attrs & (1 << OVS_KEY_ATTR_ICMPV6))) - return -EINVAL; - *attrs &= ~(1 << OVS_KEY_ATTR_ICMPV6); - - *key_len = SW_FLOW_KEY_OFFSET(ipv6.tp); - icmpv6_key = nla_data(a[OVS_KEY_ATTR_ICMPV6]); - swkey->ipv6.tp.src = htons(icmpv6_key->icmpv6_type); - swkey->ipv6.tp.dst = htons(icmpv6_key->icmpv6_code); - - if (swkey->ipv6.tp.src == htons(NDISC_NEIGHBOUR_SOLICITATION) || - swkey->ipv6.tp.src == htons(NDISC_NEIGHBOUR_ADVERTISEMENT)) { - const struct ovs_key_nd *nd_key; - - if (!(*attrs & (1 << OVS_KEY_ATTR_ND))) - return -EINVAL; - *attrs &= ~(1 << OVS_KEY_ATTR_ND); - - *key_len = SW_FLOW_KEY_OFFSET(ipv6.nd); - nd_key = nla_data(a[OVS_KEY_ATTR_ND]); - memcpy(&swkey->ipv6.nd.target, nd_key->nd_target, - sizeof(swkey->ipv6.nd.target)); - memcpy(swkey->ipv6.nd.sll, nd_key->nd_sll, ETH_ALEN); - memcpy(swkey->ipv6.nd.tll, nd_key->nd_tll, ETH_ALEN); - } - break; - } - - return 0; -} - static int parse_flow_nlattrs(const struct nlattr *attr, const struct nlattr *a[], u64 *attrsp) { @@ -986,13 +984,12 @@ static int parse_flow_nlattrs(const struct nlattr *attr, } int ipv4_tun_from_nlattr(const struct nlattr *attr, - struct ovs_key_ipv4_tunnel *tun_key) + struct sw_flow_match *match) { struct nlattr *a; int rem; bool ttl = false; - - memset(tun_key, 0, sizeof(*tun_key)); + u16 tun_flags = 0; nla_for_each_nested(a, attr, rem) { int type = nla_type(a); @@ -1012,37 +1009,39 @@ int ipv4_tun_from_nlattr(const struct nlattr *attr, switch (type) { case OVS_TUNNEL_KEY_ATTR_ID: - tun_key->tun_id = nla_get_be64(a); - tun_key->tun_flags |= OVS_TNL_F_KEY; + SW_FLOW_KEY_PUT(match, tun_key.tun_id, nla_get_be64(a)); + tun_flags |= OVS_TNL_F_KEY; break; case OVS_TUNNEL_KEY_ATTR_IPV4_SRC: - tun_key->ipv4_src = nla_get_be32(a); + SW_FLOW_KEY_PUT(match, tun_key.ipv4_src, nla_get_be32(a)); break; case OVS_TUNNEL_KEY_ATTR_IPV4_DST: - tun_key->ipv4_dst = nla_get_be32(a); + SW_FLOW_KEY_PUT(match, tun_key.ipv4_dst, nla_get_be32(a)); break; case OVS_TUNNEL_KEY_ATTR_TOS: - tun_key->ipv4_tos = nla_get_u8(a); + SW_FLOW_KEY_PUT(match, tun_key.ipv4_tos, nla_get_u8(a)); break; case OVS_TUNNEL_KEY_ATTR_TTL: - tun_key->ipv4_ttl = nla_get_u8(a); + SW_FLOW_KEY_PUT(match, tun_key.ipv4_ttl, nla_get_u8(a)); ttl = true; break; case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT: - tun_key->tun_flags |= OVS_TNL_F_DONT_FRAGMENT; + tun_flags |= OVS_TNL_F_DONT_FRAGMENT; break; case OVS_TUNNEL_KEY_ATTR_CSUM: - tun_key->tun_flags |= OVS_TNL_F_CSUM; + tun_flags |= OVS_TNL_F_CSUM; break; default: return -EINVAL; } } + SW_FLOW_KEY_PUT(match, tun_key.tun_flags, tun_flags); + if (rem > 0) return -EINVAL; - if (!tun_key->ipv4_dst) + if (!match->key->tun_key.ipv4_dst) return -EINVAL; if (!ttl) @@ -1086,180 +1085,267 @@ int ipv4_tun_to_nlattr(struct sk_buff *skb, /** * ovs_flow_from_nlattrs - parses Netlink attributes into a flow key. - * @swkey: receives the extracted flow key. - * @key_lenp: number of bytes used in @swkey. + * @match: receives the extracted flow match information. * @attr: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute * sequence. */ -int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, - const struct nlattr *attr) +int ovs_match_from_nlattrs(struct sw_flow_match *match, + const struct nlattr *attr) { const struct nlattr *a[OVS_KEY_ATTR_MAX + 1]; - const struct ovs_key_ethernet *eth_key; - int key_len; + const struct nlattr *encap; u64 attrs; int err; - - memset(swkey, 0, sizeof(struct sw_flow_key)); - key_len = SW_FLOW_KEY_OFFSET(eth); + int k; err = parse_flow_nlattrs(attr, a, &attrs); if (err) return err; - /* Metadata attributes. */ - if (attrs & (1 << OVS_KEY_ATTR_PRIORITY)) { - swkey->phy.priority = nla_get_u32(a[OVS_KEY_ATTR_PRIORITY]); - attrs &= ~(1 << OVS_KEY_ATTR_PRIORITY); - } - if (attrs & (1 << OVS_KEY_ATTR_IN_PORT)) { - u32 in_port = nla_get_u32(a[OVS_KEY_ATTR_IN_PORT]); - if (in_port >= DP_MAX_PORTS) - return -EINVAL; - swkey->phy.in_port = in_port; - attrs &= ~(1 << OVS_KEY_ATTR_IN_PORT); - } else { - swkey->phy.in_port = DP_MAX_PORTS; + if (attrs & 1ULL << OVS_KEY_ATTR_ENCAP) { + encap = a[OVS_KEY_ATTR_ENCAP]; + attrs &= ~(1ULL << OVS_KEY_ATTR_ENCAP); + if (nla_len(encap)) { + __be16 tci = 0; + __be16 eth_type = 0; /* ETH_P_8021Q */ + + if (a[OVS_KEY_ATTR_ETHERTYPE]) + eth_type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]); + if (a[OVS_KEY_ATTR_VLAN]) + tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]); + + if ( (eth_type == htons(ETH_P_8021Q)) + && (tci & htons(VLAN_TAG_PRESENT)) ) + err = parse_flow_nlattrs(encap, a, &attrs); + else + err = -EINVAL; + + if (err) + return err; + } } - if (attrs & (1 << OVS_KEY_ATTR_SKB_MARK)) { - uint32_t mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]); + + /* Save all attributes specified for prerequisite check */ + match->key_attrs = attrs; + + /* Set default values if not specified. */ + if ((attrs & (1 << OVS_KEY_ATTR_IN_PORT)) == 0) + SW_FLOW_KEY_PUT(match, phy.in_port, DP_MAX_PORTS); + + if ((attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) == 0) + SW_FLOW_KEY_PUT(match, eth.type, htons(ETH_P_802_2)); + + while (attrs) { + k = fls64(attrs) -1; + attrs &= ~(1ULL << k); + + switch(k) { + case OVS_KEY_ATTR_PRIORITY: + SW_FLOW_KEY_PUT(match, phy.priority, + nla_get_u32(a[OVS_KEY_ATTR_PRIORITY])); + break; + + case OVS_KEY_ATTR_IN_PORT: + { + u32 in_port = nla_get_u32(a[OVS_KEY_ATTR_IN_PORT]); + + if (in_port >= DP_MAX_PORTS) + return -EINVAL; + SW_FLOW_KEY_PUT(match, phy.in_port, in_port); + } + break; + + case 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 (mark != 0) - return -EINVAL; + if (mark != 0) + return -EINVAL; #endif - swkey->phy.skb_mark = mark; - attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK); - } + SW_FLOW_KEY_PUT(match, phy.skb_mark, mark); + } + break; - if (attrs & (1ULL << OVS_KEY_ATTR_TUNNEL)) { - err = ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], &swkey->tun_key); - if (err) - return err; + case OVS_KEY_ATTR_TUNNEL: + if (ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], match)) + return -EINVAL; - attrs &= ~(1ULL << OVS_KEY_ATTR_TUNNEL); - } + break; - /* Data attributes. */ - if (!(attrs & (1 << OVS_KEY_ATTR_ETHERNET))) - return -EINVAL; - attrs &= ~(1 << OVS_KEY_ATTR_ETHERNET); + case OVS_KEY_ATTR_ETHERNET: + { + const struct ovs_key_ethernet *eth_key; - eth_key = nla_data(a[OVS_KEY_ATTR_ETHERNET]); - memcpy(swkey->eth.src, eth_key->eth_src, ETH_ALEN); - memcpy(swkey->eth.dst, eth_key->eth_dst, ETH_ALEN); + eth_key = nla_data(a[OVS_KEY_ATTR_ETHERNET]); + SW_FLOW_KEY_MEMCPY(match, eth.src, + eth_key->eth_src, ETH_ALEN); + SW_FLOW_KEY_MEMCPY(match, eth.dst, + eth_key->eth_dst, ETH_ALEN); + } + break; - if (attrs & (1u << OVS_KEY_ATTR_ETHERTYPE) && - nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]) == htons(ETH_P_8021Q)) { - const struct nlattr *encap; - __be16 tci; + case OVS_KEY_ATTR_VLAN: + { + __be16 tci; - if (attrs != ((1 << OVS_KEY_ATTR_VLAN) | - (1 << OVS_KEY_ATTR_ETHERTYPE) | - (1 << OVS_KEY_ATTR_ENCAP))) - return -EINVAL; + tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]); + SW_FLOW_KEY_PUT(match, eth.tci, tci); + } + break; - encap = a[OVS_KEY_ATTR_ENCAP]; - tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]); - if (tci & htons(VLAN_TAG_PRESENT)) { - swkey->eth.tci = tci; + case OVS_KEY_ATTR_ETHERTYPE: + { + __be16 eth_type; - err = parse_flow_nlattrs(encap, a, &attrs); - if (err) - return err; - } else if (!tci) { - /* Corner case for truncated 802.1Q header. */ - if (nla_len(encap)) - return -EINVAL; + eth_type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]); - swkey->eth.type = htons(ETH_P_8021Q); - *key_lenp = key_len; - return 0; - } else { - return -EINVAL; - } - } + if (ntohs(eth_type) < ETH_P_802_3_MIN) + return -EINVAL; - if (attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) { - swkey->eth.type = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]); - if (ntohs(swkey->eth.type) < ETH_P_802_3_MIN) - return -EINVAL; - attrs &= ~(1 << OVS_KEY_ATTR_ETHERTYPE); - } else { - swkey->eth.type = htons(ETH_P_802_2); - } + SW_FLOW_KEY_PUT(match, eth.type, eth_type); + } + break; - if (swkey->eth.type == htons(ETH_P_IP)) { - const struct ovs_key_ipv4 *ipv4_key; + case OVS_KEY_ATTR_IPV4: + { + const struct ovs_key_ipv4 *ipv4_key; - if (!(attrs & (1 << OVS_KEY_ATTR_IPV4))) - return -EINVAL; - attrs &= ~(1 << OVS_KEY_ATTR_IPV4); + ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]); + if (ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) + return -EINVAL; + SW_FLOW_KEY_PUT(match, ip.proto, + ipv4_key->ipv4_proto); + SW_FLOW_KEY_PUT(match, ip.tos, + ipv4_key->ipv4_tos); + SW_FLOW_KEY_PUT(match, ip.ttl, + ipv4_key->ipv4_ttl); + SW_FLOW_KEY_PUT(match, ip.frag, + ipv4_key->ipv4_frag); + SW_FLOW_KEY_PUT(match, ipv4.addr.src, + ipv4_key->ipv4_src); + SW_FLOW_KEY_PUT(match, ipv4.addr.dst, + ipv4_key->ipv4_dst); + } + break; - key_len = SW_FLOW_KEY_OFFSET(ipv4.addr); - ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]); - if (ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX) - return -EINVAL; - swkey->ip.proto = ipv4_key->ipv4_proto; - swkey->ip.tos = ipv4_key->ipv4_tos; - swkey->ip.ttl = ipv4_key->ipv4_ttl; - swkey->ip.frag = ipv4_key->ipv4_frag; - swkey->ipv4.addr.src = ipv4_key->ipv4_src; - swkey->ipv4.addr.dst = ipv4_key->ipv4_dst; - - if (swkey->ip.frag != OVS_FRAG_TYPE_LATER) { - err = ipv4_flow_from_nlattrs(swkey, &key_len, a, &attrs); - if (err) - return err; - } - } else if (swkey->eth.type == htons(ETH_P_IPV6)) { - const struct ovs_key_ipv6 *ipv6_key; + case OVS_KEY_ATTR_IPV6: + { + const struct ovs_key_ipv6 *ipv6_key; - if (!(attrs & (1 << OVS_KEY_ATTR_IPV6))) - return -EINVAL; - attrs &= ~(1 << OVS_KEY_ATTR_IPV6); + ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]); + if (ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) + return -EINVAL; + SW_FLOW_KEY_PUT(match, ipv6.label, + ipv6_key->ipv6_label); + SW_FLOW_KEY_PUT(match, ip.proto, + ipv6_key->ipv6_proto); + SW_FLOW_KEY_PUT(match, ip.tos, + ipv6_key->ipv6_tclass); + SW_FLOW_KEY_PUT(match, ip.ttl, + ipv6_key->ipv6_hlimit); + SW_FLOW_KEY_PUT(match, ip.frag, + ipv6_key->ipv6_frag); + SW_FLOW_KEY_MEMCPY(match, ipv6.addr.src, + ipv6_key->ipv6_src, + sizeof(match->key->ipv6.addr.src)); + SW_FLOW_KEY_MEMCPY(match, ipv6.addr.dst, + ipv6_key->ipv6_dst, + sizeof(match->key->ipv6.addr.dst)); - key_len = SW_FLOW_KEY_OFFSET(ipv6.label); - ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]); - if (ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX) - return -EINVAL; - swkey->ipv6.label = ipv6_key->ipv6_label; - swkey->ip.proto = ipv6_key->ipv6_proto; - swkey->ip.tos = ipv6_key->ipv6_tclass; - swkey->ip.ttl = ipv6_key->ipv6_hlimit; - swkey->ip.frag = ipv6_key->ipv6_frag; - memcpy(&swkey->ipv6.addr.src, ipv6_key->ipv6_src, - sizeof(swkey->ipv6.addr.src)); - memcpy(&swkey->ipv6.addr.dst, ipv6_key->ipv6_dst, - sizeof(swkey->ipv6.addr.dst)); - - if (swkey->ip.frag != OVS_FRAG_TYPE_LATER) { - err = ipv6_flow_from_nlattrs(swkey, &key_len, a, &attrs); - if (err) - return err; - } - } else if (swkey->eth.type == htons(ETH_P_ARP) || - swkey->eth.type == htons(ETH_P_RARP)) { - const struct ovs_key_arp *arp_key; + } + break; - if (!(attrs & (1 << OVS_KEY_ATTR_ARP))) - return -EINVAL; - attrs &= ~(1 << OVS_KEY_ATTR_ARP); + case OVS_KEY_ATTR_ARP: + { + const struct ovs_key_arp *arp_key; - key_len = SW_FLOW_KEY_OFFSET(ipv4.arp); - arp_key = nla_data(a[OVS_KEY_ATTR_ARP]); - swkey->ipv4.addr.src = arp_key->arp_sip; - swkey->ipv4.addr.dst = arp_key->arp_tip; - if (arp_key->arp_op & htons(0xff00)) + arp_key = nla_data(a[OVS_KEY_ATTR_ARP]); + SW_FLOW_KEY_PUT(match, ipv4.addr.src, + arp_key->arp_sip); + SW_FLOW_KEY_PUT(match, ipv4.addr.dst, + arp_key->arp_tip); + if (arp_key->arp_op & htons(0xff00)) + return -EINVAL; + SW_FLOW_KEY_PUT(match, ip.proto, + ntohs(arp_key->arp_op)); + SW_FLOW_KEY_MEMCPY(match, ipv4.arp.sha, + arp_key->arp_sha, + ETH_ALEN); + SW_FLOW_KEY_MEMCPY(match, ipv4.arp.tha, + arp_key->arp_tha, + ETH_ALEN); + } + break; + + case OVS_KEY_ATTR_TCP: + { + const struct ovs_key_tcp *tcp_key; + + tcp_key = nla_data(a[OVS_KEY_ATTR_TCP]); + SW_FLOW_KEY_PUT(match, ipv4.tp.src, + tcp_key->tcp_src); + SW_FLOW_KEY_PUT(match, ipv4.tp.dst, + tcp_key->tcp_dst); + } + break; + + case OVS_KEY_ATTR_UDP: + { + const struct ovs_key_udp *udp_key; + + udp_key = nla_data(a[OVS_KEY_ATTR_UDP]); + SW_FLOW_KEY_PUT(match, ipv4.tp.src, + udp_key->udp_src); + SW_FLOW_KEY_PUT(match, ipv4.tp.dst, + udp_key->udp_dst); + } + break; + + case OVS_KEY_ATTR_ICMP: + { + const struct ovs_key_icmp *icmp_key; + + icmp_key = nla_data(a[OVS_KEY_ATTR_ICMP]); + SW_FLOW_KEY_PUT(match, ipv4.tp.src, + htons(icmp_key->icmp_type)); + SW_FLOW_KEY_PUT(match, ipv4.tp.dst, + htons(icmp_key->icmp_code)); + } + break; + + case OVS_KEY_ATTR_ICMPV6: + { + const struct ovs_key_icmpv6 *icmpv6_key; + + icmpv6_key = nla_data(a[OVS_KEY_ATTR_ICMPV6]); + SW_FLOW_KEY_PUT(match, ipv6.tp.src, + htons(icmpv6_key->icmpv6_type)); + SW_FLOW_KEY_PUT(match, ipv6.tp.dst, + htons(icmpv6_key->icmpv6_code)); + } + break; + + case OVS_KEY_ATTR_ND: + { + const struct ovs_key_nd *nd_key; + + nd_key = nla_data(a[OVS_KEY_ATTR_ND]); + SW_FLOW_KEY_MEMCPY(match, ipv6.nd.target, + nd_key->nd_target, + sizeof(match->key->ipv6.nd.target)); + SW_FLOW_KEY_MEMCPY(match, ipv6.nd.sll, + nd_key->nd_sll, ETH_ALEN); + SW_FLOW_KEY_MEMCPY(match, ipv6.nd.tll, + nd_key->nd_tll, ETH_ALEN); + } + break; + + default: return -EINVAL; - swkey->ip.proto = ntohs(arp_key->arp_op); - memcpy(swkey->ipv4.arp.sha, arp_key->arp_sha, ETH_ALEN); - memcpy(swkey->ipv4.arp.tha, arp_key->arp_tha, ETH_ALEN); + } } - if (attrs) - return -EINVAL; - *key_lenp = key_len; - return 0; } @@ -1279,51 +1365,31 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const struct nlattr *attr) { struct ovs_key_ipv4_tunnel *tun_key = &flow->key.tun_key; - const struct nlattr *nla; - int rem; + const struct nlattr *a[OVS_KEY_ATTR_MAX + 1]; + u64 attrs; + int err; + struct sw_flow_match match; flow->key.phy.in_port = DP_MAX_PORTS; flow->key.phy.priority = 0; flow->key.phy.skb_mark = 0; memset(tun_key, 0, sizeof(flow->key.tun_key)); - nla_for_each_nested(nla, attr, rem) { - int type = nla_type(nla); - - if (type <= OVS_KEY_ATTR_MAX && ovs_key_lens[type] > 0) { - int err; - - if (nla_len(nla) != ovs_key_lens[type]) - return -EINVAL; - - switch (type) { - case OVS_KEY_ATTR_PRIORITY: - flow->key.phy.priority = nla_get_u32(nla); - break; + err = parse_flow_nlattrs(attr, a, &attrs); + if (err) + return -EINVAL; - case OVS_KEY_ATTR_TUNNEL: - err = ipv4_tun_from_nlattr(nla, tun_key); - if (err) - return err; - break; + attrs &= (1 << OVS_KEY_ATTR_PRIORITY); + attrs &= (1 << OVS_KEY_ATTR_TUNNEL); + attrs &= (1 << OVS_KEY_ATTR_IN_PORT); + attrs &= (1 << OVS_KEY_ATTR_SKB_MARK); - case OVS_KEY_ATTR_IN_PORT: - if (nla_get_u32(nla) >= DP_MAX_PORTS) - return -EINVAL; - flow->key.phy.in_port = nla_get_u32(nla); - break; + if (attrs) + return -EINVAL; - case OVS_KEY_ATTR_SKB_MARK: -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && !defined(CONFIG_NETFILTER) - if (nla_get_u32(nla) != 0) - return -EINVAL; -#endif - flow->key.phy.skb_mark = nla_get_u32(nla); - break; - } - } - } - if (rem) + ovs_match_init(&match, &flow->key); + err = ovs_match_from_nlattrs(&match, attr); + if (err) return -EINVAL; flow->hash = ovs_flow_hash(&flow->key, diff --git a/datapath/flow.h b/datapath/flow.h index dba66cf..09b1482 100644 --- a/datapath/flow.h +++ b/datapath/flow.h @@ -129,6 +129,16 @@ struct sw_flow { u8 tcp_flags; /* Union of seen TCP flags. */ }; +struct sw_flow_match { + struct sw_flow_key *key; + u8 n_writes[sizeof(struct sw_flow_key)]; /* Per byte write count. */ + u64 key_attrs; /* OVS_KEY_ATTR_XXXs used to populate the keys */ +}; + +void ovs_match_init(struct sw_flow_match *match, struct sw_flow_key *key); +bool ovs_match_check_prerequisite(const struct sw_flow_match *match); +int ovs_match_get_len(struct sw_flow_match *match); + struct arp_eth_header { __be16 ar_hrd; /* format of hardware address */ __be16 ar_pro; /* format of protocol address */ @@ -159,7 +169,7 @@ void ovs_flow_used(struct sw_flow *, struct sk_buff *); u64 ovs_flow_used_time(unsigned long flow_jiffies); int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *); -int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, +int ovs_match_from_nlattrs(struct sw_flow_match *match, const struct nlattr *); int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const struct nlattr *attr); @@ -176,6 +186,8 @@ struct flow_table { bool keep_flows; }; + + static inline int ovs_flow_tbl_count(struct flow_table *table) { return table->count; @@ -200,7 +212,7 @@ void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow); struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *idx); extern const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1]; int ipv4_tun_from_nlattr(const struct nlattr *attr, - struct ovs_key_ipv4_tunnel *tun_key); + struct sw_flow_match *match); int ipv4_tun_to_nlattr(struct sk_buff *skb, const struct ovs_key_ipv4_tunnel *tun_key); -- 1.7.9.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev