- return !memcmp(key1, key2, sizeof(struct sw_flow_key));
-}
-
-/**
- * flow_from_nlattrs - parses Netlink attributes into a flow key.
- * @swkey: receives the extracted flow key.
- * @key: start of %ODP_KEY_ATTR_* Netlink attribute sequence.
- * @key_len: number of bytes in @key.
- *
- * This state machine accepts the following forms, with [] for optional
- * elements and | for alternatives:
- *
- * [tun_id] in_port ethernet [8021q] [ethertype [IP [TCP|UDP|ICMP] | ARP]
- */
-static int flow_from_nlattrs(struct sw_flow_key *swkey, const struct nlattr *key, u32 key_len)
-{
- const struct nlattr *nla;
- u16 prev_type;
- int rem;
-
- memset(swkey, 0, sizeof(*swkey));
- swkey->dl_type = htons(ETH_P_802_2);
-
- prev_type = ODP_KEY_ATTR_UNSPEC;
- nla_for_each_attr(nla, key, key_len, rem) {
- static const u32 key_lens[ODP_KEY_ATTR_MAX + 1] = {
- [ODP_KEY_ATTR_TUN_ID] = 8,
- [ODP_KEY_ATTR_IN_PORT] = 4,
- [ODP_KEY_ATTR_ETHERNET] = sizeof(struct odp_key_ethernet),
- [ODP_KEY_ATTR_8021Q] = sizeof(struct odp_key_8021q),
- [ODP_KEY_ATTR_ETHERTYPE] = 2,
- [ODP_KEY_ATTR_IPV4] = sizeof(struct odp_key_ipv4),
- [ODP_KEY_ATTR_TCP] = sizeof(struct odp_key_tcp),
- [ODP_KEY_ATTR_UDP] = sizeof(struct odp_key_udp),
- [ODP_KEY_ATTR_ICMP] = sizeof(struct odp_key_icmp),
- [ODP_KEY_ATTR_ARP] = sizeof(struct odp_key_arp),
- };
-
- const struct odp_key_ethernet *eth_key;
- const struct odp_key_8021q *q_key;
- const struct odp_key_ipv4 *ipv4_key;
- const struct odp_key_tcp *tcp_key;
- const struct odp_key_udp *udp_key;
- const struct odp_key_icmp *icmp_key;
- const struct odp_key_arp *arp_key;
-
- int type = nla_type(nla);
-
- if (type > ODP_KEY_ATTR_MAX || nla_len(nla) != key_lens[type])
- return -EINVAL;
-
-#define TRANSITION(PREV_TYPE, TYPE) (((PREV_TYPE) << 16) | (TYPE))
- switch (TRANSITION(prev_type, type)) {
- case TRANSITION(ODP_KEY_ATTR_UNSPEC, ODP_KEY_ATTR_TUN_ID):
- swkey->tun_id = nla_get_be64(nla);
- break;
-
- case TRANSITION(ODP_KEY_ATTR_UNSPEC, ODP_KEY_ATTR_IN_PORT):
- case TRANSITION(ODP_KEY_ATTR_TUN_ID, ODP_KEY_ATTR_IN_PORT):
- if (nla_get_u32(nla) >= DP_MAX_PORTS)
- return -EINVAL;
- swkey->in_port = nla_get_u32(nla);
- break;
-
- case TRANSITION(ODP_KEY_ATTR_IN_PORT, ODP_KEY_ATTR_ETHERNET):
- eth_key = nla_data(nla);
- memcpy(swkey->dl_src, eth_key->eth_src, ETH_ALEN);
- memcpy(swkey->dl_dst, eth_key->eth_dst, ETH_ALEN);
- break;
-
- case TRANSITION(ODP_KEY_ATTR_ETHERNET, ODP_KEY_ATTR_8021Q):
- q_key = nla_data(nla);
- /* Only standard 0x8100 VLANs currently supported. */
- if (q_key->q_tpid != htons(ETH_P_8021Q))
- return -EINVAL;
- if (q_key->q_tci & htons(VLAN_TAG_PRESENT))
- return -EINVAL;
- swkey->dl_tci = q_key->q_tci | htons(VLAN_TAG_PRESENT);
- break;
-
- case TRANSITION(ODP_KEY_ATTR_8021Q, ODP_KEY_ATTR_ETHERTYPE):
- case TRANSITION(ODP_KEY_ATTR_ETHERNET, ODP_KEY_ATTR_ETHERTYPE):
- swkey->dl_type = nla_get_be16(nla);
- if (ntohs(swkey->dl_type) < 1536)
- return -EINVAL;
- break;
-
- case TRANSITION(ODP_KEY_ATTR_ETHERTYPE, ODP_KEY_ATTR_IPV4):
- if (swkey->dl_type != htons(ETH_P_IP))
- return -EINVAL;
- ipv4_key = nla_data(nla);
- swkey->nw_src = ipv4_key->ipv4_src;
- swkey->nw_dst = ipv4_key->ipv4_dst;
- swkey->nw_proto = ipv4_key->ipv4_proto;
- swkey->nw_tos = ipv4_key->ipv4_tos;
- if (swkey->nw_tos & INET_ECN_MASK)
- return -EINVAL;
- break;
-
- case TRANSITION(ODP_KEY_ATTR_IPV4, ODP_KEY_ATTR_TCP):
- if (swkey->nw_proto != IPPROTO_TCP)
- return -EINVAL;
- tcp_key = nla_data(nla);
- swkey->tp_src = tcp_key->tcp_src;
- swkey->tp_dst = tcp_key->tcp_dst;
- break;
-
- case TRANSITION(ODP_KEY_ATTR_IPV4, ODP_KEY_ATTR_UDP):
- if (swkey->nw_proto != IPPROTO_UDP)
- return -EINVAL;
- udp_key = nla_data(nla);
- swkey->tp_src = udp_key->udp_src;
- swkey->tp_dst = udp_key->udp_dst;
- break;
-
- case TRANSITION(ODP_KEY_ATTR_IPV4, ODP_KEY_ATTR_ICMP):
- if (swkey->nw_proto != IPPROTO_ICMP)
- return -EINVAL;
- icmp_key = nla_data(nla);
- swkey->tp_src = htons(icmp_key->icmp_type);
- swkey->tp_dst = htons(icmp_key->icmp_code);
- break;
-
- case TRANSITION(ODP_KEY_ATTR_ETHERTYPE, ODP_KEY_ATTR_ARP):
- if (swkey->dl_type != htons(ETH_P_ARP))
- return -EINVAL;
- arp_key = nla_data(nla);
- swkey->nw_src = arp_key->arp_sip;
- swkey->nw_dst = arp_key->arp_tip;
- if (arp_key->arp_op & htons(0xff00))
- return -EINVAL;
- swkey->nw_proto = ntohs(arp_key->arp_op);
- break;
-
- default:
- return -EINVAL;