Commit 8f256622 authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso Committed by David S. Miller

flow_offload: add flow_rule and flow_match structures and use them

This patch wraps the dissector key and mask - that flower uses to
represent the matching side - around the flow_match structure.

To avoid a follow up patch that would edit the same LoCs in the drivers,
this patch also wraps this new flow match structure around the flow rule
object. This new structure will also contain the flow actions in follow
up patches.

This introduces two new interfaces:

	bool flow_rule_match_key(rule, dissector_id)

that returns true if a given matching key is set on, and:

	flow_rule_match_XYZ(rule, &match);

To fetch the matching side XYZ into the match container structure, to
retrieve the key and the mask with one single call.
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
Acked-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d9b5a675
......@@ -177,18 +177,12 @@ static int bnxt_tc_parse_actions(struct bnxt *bp,
return 0;
}
#define GET_KEY(flow_cmd, key_type) \
skb_flow_dissector_target((flow_cmd)->dissector, key_type,\
(flow_cmd)->key)
#define GET_MASK(flow_cmd, key_type) \
skb_flow_dissector_target((flow_cmd)->dissector, key_type,\
(flow_cmd)->mask)
static int bnxt_tc_parse_flow(struct bnxt *bp,
struct tc_cls_flower_offload *tc_flow_cmd,
struct bnxt_tc_flow *flow)
{
struct flow_dissector *dissector = tc_flow_cmd->dissector;
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(tc_flow_cmd);
struct flow_dissector *dissector = rule->match.dissector;
/* KEY_CONTROL and KEY_BASIC are needed for forming a meaningful key */
if ((dissector->used_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL)) == 0 ||
......@@ -198,140 +192,120 @@ static int bnxt_tc_parse_flow(struct bnxt *bp,
return -EOPNOTSUPP;
}
if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_dissector_key_basic *key =
GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_BASIC);
struct flow_dissector_key_basic *mask =
GET_MASK(tc_flow_cmd, FLOW_DISSECTOR_KEY_BASIC);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_match_basic match;
flow->l2_key.ether_type = key->n_proto;
flow->l2_mask.ether_type = mask->n_proto;
flow_rule_match_basic(rule, &match);
flow->l2_key.ether_type = match.key->n_proto;
flow->l2_mask.ether_type = match.mask->n_proto;
if (key->n_proto == htons(ETH_P_IP) ||
key->n_proto == htons(ETH_P_IPV6)) {
flow->l4_key.ip_proto = key->ip_proto;
flow->l4_mask.ip_proto = mask->ip_proto;
if (match.key->n_proto == htons(ETH_P_IP) ||
match.key->n_proto == htons(ETH_P_IPV6)) {
flow->l4_key.ip_proto = match.key->ip_proto;
flow->l4_mask.ip_proto = match.mask->ip_proto;
}
}
if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
struct flow_dissector_key_eth_addrs *key =
GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_ETH_ADDRS);
struct flow_dissector_key_eth_addrs *mask =
GET_MASK(tc_flow_cmd, FLOW_DISSECTOR_KEY_ETH_ADDRS);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
struct flow_match_eth_addrs match;
flow_rule_match_eth_addrs(rule, &match);
flow->flags |= BNXT_TC_FLOW_FLAGS_ETH_ADDRS;
ether_addr_copy(flow->l2_key.dmac, key->dst);
ether_addr_copy(flow->l2_mask.dmac, mask->dst);
ether_addr_copy(flow->l2_key.smac, key->src);
ether_addr_copy(flow->l2_mask.smac, mask->src);
ether_addr_copy(flow->l2_key.dmac, match.key->dst);
ether_addr_copy(flow->l2_mask.dmac, match.mask->dst);
ether_addr_copy(flow->l2_key.smac, match.key->src);
ether_addr_copy(flow->l2_mask.smac, match.mask->src);
}
if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_dissector_key_vlan *key =
GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_VLAN);
struct flow_dissector_key_vlan *mask =
GET_MASK(tc_flow_cmd, FLOW_DISSECTOR_KEY_VLAN);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_match_vlan match;
flow_rule_match_vlan(rule, &match);
flow->l2_key.inner_vlan_tci =
cpu_to_be16(VLAN_TCI(key->vlan_id, key->vlan_priority));
cpu_to_be16(VLAN_TCI(match.key->vlan_id,
match.key->vlan_priority));
flow->l2_mask.inner_vlan_tci =
cpu_to_be16((VLAN_TCI(mask->vlan_id, mask->vlan_priority)));
cpu_to_be16((VLAN_TCI(match.mask->vlan_id,
match.mask->vlan_priority)));
flow->l2_key.inner_vlan_tpid = htons(ETH_P_8021Q);
flow->l2_mask.inner_vlan_tpid = htons(0xffff);
flow->l2_key.num_vlans = 1;
}
if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
struct flow_dissector_key_ipv4_addrs *key =
GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_IPV4_ADDRS);
struct flow_dissector_key_ipv4_addrs *mask =
GET_MASK(tc_flow_cmd, FLOW_DISSECTOR_KEY_IPV4_ADDRS);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
struct flow_match_ipv4_addrs match;
flow_rule_match_ipv4_addrs(rule, &match);
flow->flags |= BNXT_TC_FLOW_FLAGS_IPV4_ADDRS;
flow->l3_key.ipv4.daddr.s_addr = key->dst;
flow->l3_mask.ipv4.daddr.s_addr = mask->dst;
flow->l3_key.ipv4.saddr.s_addr = key->src;
flow->l3_mask.ipv4.saddr.s_addr = mask->src;
} else if (dissector_uses_key(dissector,
FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
struct flow_dissector_key_ipv6_addrs *key =
GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_IPV6_ADDRS);
struct flow_dissector_key_ipv6_addrs *mask =
GET_MASK(tc_flow_cmd, FLOW_DISSECTOR_KEY_IPV6_ADDRS);
flow->l3_key.ipv4.daddr.s_addr = match.key->dst;
flow->l3_mask.ipv4.daddr.s_addr = match.mask->dst;
flow->l3_key.ipv4.saddr.s_addr = match.key->src;
flow->l3_mask.ipv4.saddr.s_addr = match.mask->src;
} else if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
struct flow_match_ipv6_addrs match;
flow_rule_match_ipv6_addrs(rule, &match);
flow->flags |= BNXT_TC_FLOW_FLAGS_IPV6_ADDRS;
flow->l3_key.ipv6.daddr = key->dst;
flow->l3_mask.ipv6.daddr = mask->dst;
flow->l3_key.ipv6.saddr = key->src;
flow->l3_mask.ipv6.saddr = mask->src;
flow->l3_key.ipv6.daddr = match.key->dst;
flow->l3_mask.ipv6.daddr = match.mask->dst;
flow->l3_key.ipv6.saddr = match.key->src;
flow->l3_mask.ipv6.saddr = match.mask->src;
}
if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_PORTS)) {
struct flow_dissector_key_ports *key =
GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_PORTS);
struct flow_dissector_key_ports *mask =
GET_MASK(tc_flow_cmd, FLOW_DISSECTOR_KEY_PORTS);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
struct flow_match_ports match;
flow_rule_match_ports(rule, &match);
flow->flags |= BNXT_TC_FLOW_FLAGS_PORTS;
flow->l4_key.ports.dport = key->dst;
flow->l4_mask.ports.dport = mask->dst;
flow->l4_key.ports.sport = key->src;
flow->l4_mask.ports.sport = mask->src;
flow->l4_key.ports.dport = match.key->dst;
flow->l4_mask.ports.dport = match.mask->dst;
flow->l4_key.ports.sport = match.key->src;
flow->l4_mask.ports.sport = match.mask->src;
}
if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_ICMP)) {
struct flow_dissector_key_icmp *key =
GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_ICMP);
struct flow_dissector_key_icmp *mask =
GET_MASK(tc_flow_cmd, FLOW_DISSECTOR_KEY_ICMP);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ICMP)) {
struct flow_match_icmp match;
flow_rule_match_icmp(rule, &match);
flow->flags |= BNXT_TC_FLOW_FLAGS_ICMP;
flow->l4_key.icmp.type = key->type;
flow->l4_key.icmp.code = key->code;
flow->l4_mask.icmp.type = mask->type;
flow->l4_mask.icmp.code = mask->code;
flow->l4_key.icmp.type = match.key->type;
flow->l4_key.icmp.code = match.key->code;
flow->l4_mask.icmp.type = match.mask->type;
flow->l4_mask.icmp.code = match.mask->code;
}
if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
struct flow_dissector_key_ipv4_addrs *key =
GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS);
struct flow_dissector_key_ipv4_addrs *mask =
GET_MASK(tc_flow_cmd,
FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
struct flow_match_ipv4_addrs match;
flow_rule_match_enc_ipv4_addrs(rule, &match);
flow->flags |= BNXT_TC_FLOW_FLAGS_TUNL_IPV4_ADDRS;
flow->tun_key.u.ipv4.dst = key->dst;
flow->tun_mask.u.ipv4.dst = mask->dst;
flow->tun_key.u.ipv4.src = key->src;
flow->tun_mask.u.ipv4.src = mask->src;
} else if (dissector_uses_key(dissector,
flow->tun_key.u.ipv4.dst = match.key->dst;
flow->tun_mask.u.ipv4.dst = match.mask->dst;
flow->tun_key.u.ipv4.src = match.key->src;
flow->tun_mask.u.ipv4.src = match.mask->src;
} else if (flow_rule_match_key(rule,
FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS)) {
return -EOPNOTSUPP;
}
if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
struct flow_dissector_key_keyid *key =
GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_ENC_KEYID);
struct flow_dissector_key_keyid *mask =
GET_MASK(tc_flow_cmd, FLOW_DISSECTOR_KEY_ENC_KEYID);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
struct flow_match_enc_keyid match;
flow_rule_match_enc_keyid(rule, &match);
flow->flags |= BNXT_TC_FLOW_FLAGS_TUNL_ID;
flow->tun_key.tun_id = key32_to_tunnel_id(key->keyid);
flow->tun_mask.tun_id = key32_to_tunnel_id(mask->keyid);
flow->tun_key.tun_id = key32_to_tunnel_id(match.key->keyid);
flow->tun_mask.tun_id = key32_to_tunnel_id(match.mask->keyid);
}
if (dissector_uses_key(dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
struct flow_dissector_key_ports *key =
GET_KEY(tc_flow_cmd, FLOW_DISSECTOR_KEY_ENC_PORTS);
struct flow_dissector_key_ports *mask =
GET_MASK(tc_flow_cmd, FLOW_DISSECTOR_KEY_ENC_PORTS);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
struct flow_match_ports match;
flow_rule_match_enc_ports(rule, &match);
flow->flags |= BNXT_TC_FLOW_FLAGS_TUNL_PORTS;
flow->tun_key.tp_dst = key->dst;
flow->tun_mask.tp_dst = mask->dst;
flow->tun_key.tp_src = key->src;
flow->tun_mask.tp_src = mask->src;
flow->tun_key.tp_dst = match.key->dst;
flow->tun_mask.tp_dst = match.mask->dst;
flow->tun_key.tp_src = match.key->src;
flow->tun_mask.tp_src = match.mask->src;
}
return bnxt_tc_parse_actions(bp, &flow->actions, tc_flow_cmd->exts);
......
......@@ -83,28 +83,23 @@ static void cxgb4_process_flow_match(struct net_device *dev,
struct tc_cls_flower_offload *cls,
struct ch_filter_specification *fs)
{
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(cls);
u16 addr_type = 0;
if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
struct flow_dissector_key_control *key =
skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_CONTROL,
cls->key);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
struct flow_match_control match;
addr_type = key->addr_type;
flow_rule_match_control(rule, &match);
addr_type = match.key->addr_type;
}
if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_dissector_key_basic *key =
skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_BASIC,
cls->key);
struct flow_dissector_key_basic *mask =
skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_BASIC,
cls->mask);
u16 ethtype_key = ntohs(key->n_proto);
u16 ethtype_mask = ntohs(mask->n_proto);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_match_basic match;
u16 ethtype_key, ethtype_mask;
flow_rule_match_basic(rule, &match);
ethtype_key = ntohs(match.key->n_proto);
ethtype_mask = ntohs(match.mask->n_proto);
if (ethtype_key == ETH_P_ALL) {
ethtype_key = 0;
......@@ -116,115 +111,89 @@ static void cxgb4_process_flow_match(struct net_device *dev,
fs->val.ethtype = ethtype_key;
fs->mask.ethtype = ethtype_mask;
fs->val.proto = key->ip_proto;
fs->mask.proto = mask->ip_proto;
fs->val.proto = match.key->ip_proto;
fs->mask.proto = match.mask->ip_proto;
}
if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
struct flow_dissector_key_ipv4_addrs *key =
skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_IPV4_ADDRS,
cls->key);
struct flow_dissector_key_ipv4_addrs *mask =
skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_IPV4_ADDRS,
cls->mask);
struct flow_match_ipv4_addrs match;
flow_rule_match_ipv4_addrs(rule, &match);
fs->type = 0;
memcpy(&fs->val.lip[0], &key->dst, sizeof(key->dst));
memcpy(&fs->val.fip[0], &key->src, sizeof(key->src));
memcpy(&fs->mask.lip[0], &mask->dst, sizeof(mask->dst));
memcpy(&fs->mask.fip[0], &mask->src, sizeof(mask->src));
memcpy(&fs->val.lip[0], &match.key->dst, sizeof(match.key->dst));
memcpy(&fs->val.fip[0], &match.key->src, sizeof(match.key->src));
memcpy(&fs->mask.lip[0], &match.mask->dst, sizeof(match.mask->dst));
memcpy(&fs->mask.fip[0], &match.mask->src, sizeof(match.mask->src));
/* also initialize nat_lip/fip to same values */
memcpy(&fs->nat_lip[0], &key->dst, sizeof(key->dst));
memcpy(&fs->nat_fip[0], &key->src, sizeof(key->src));
memcpy(&fs->nat_lip[0], &match.key->dst, sizeof(match.key->dst));
memcpy(&fs->nat_fip[0], &match.key->src, sizeof(match.key->src));
}
if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
struct flow_dissector_key_ipv6_addrs *key =
skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_IPV6_ADDRS,
cls->key);
struct flow_dissector_key_ipv6_addrs *mask =
skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_IPV6_ADDRS,
cls->mask);
struct flow_match_ipv6_addrs match;
flow_rule_match_ipv6_addrs(rule, &match);
fs->type = 1;
memcpy(&fs->val.lip[0], key->dst.s6_addr, sizeof(key->dst));
memcpy(&fs->val.fip[0], key->src.s6_addr, sizeof(key->src));
memcpy(&fs->mask.lip[0], mask->dst.s6_addr, sizeof(mask->dst));
memcpy(&fs->mask.fip[0], mask->src.s6_addr, sizeof(mask->src));
memcpy(&fs->val.lip[0], match.key->dst.s6_addr,
sizeof(match.key->dst));
memcpy(&fs->val.fip[0], match.key->src.s6_addr,
sizeof(match.key->src));
memcpy(&fs->mask.lip[0], match.mask->dst.s6_addr,
sizeof(match.mask->dst));
memcpy(&fs->mask.fip[0], match.mask->src.s6_addr,
sizeof(match.mask->src));
/* also initialize nat_lip/fip to same values */
memcpy(&fs->nat_lip[0], key->dst.s6_addr, sizeof(key->dst));
memcpy(&fs->nat_fip[0], key->src.s6_addr, sizeof(key->src));
memcpy(&fs->nat_lip[0], match.key->dst.s6_addr,
sizeof(match.key->dst));
memcpy(&fs->nat_fip[0], match.key->src.s6_addr,
sizeof(match.key->src));
}
if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
struct flow_dissector_key_ports *key, *mask;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
struct flow_match_ports match;
key = skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_PORTS,
cls->key);
mask = skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_PORTS,
cls->mask);
fs->val.lport = cpu_to_be16(key->dst);
fs->mask.lport = cpu_to_be16(mask->dst);
fs->val.fport = cpu_to_be16(key->src);
fs->mask.fport = cpu_to_be16(mask->src);
flow_rule_match_ports(rule, &match);
fs->val.lport = cpu_to_be16(match.key->dst);
fs->mask.lport = cpu_to_be16(match.mask->dst);
fs->val.fport = cpu_to_be16(match.key->src);
fs->mask.fport = cpu_to_be16(match.mask->src);
/* also initialize nat_lport/fport to same values */
fs->nat_lport = cpu_to_be16(key->dst);
fs->nat_fport = cpu_to_be16(key->src);
fs->nat_lport = cpu_to_be16(match.key->dst);
fs->nat_fport = cpu_to_be16(match.key->src);
}
if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_IP)) {
struct flow_dissector_key_ip *key, *mask;
key = skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_IP,
cls->key);
mask = skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_IP,
cls->mask);
fs->val.tos = key->tos;
fs->mask.tos = mask->tos;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
struct flow_match_ip match;
flow_rule_match_ip(rule, &match);
fs->val.tos = match.key->tos;
fs->mask.tos = match.mask->tos;
}
if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
struct flow_dissector_key_keyid *key, *mask;
key = skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_ENC_KEYID,
cls->key);
mask = skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_ENC_KEYID,
cls->mask);
fs->val.vni = be32_to_cpu(key->keyid);
fs->mask.vni = be32_to_cpu(mask->keyid);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
struct flow_match_enc_keyid match;
flow_rule_match_enc_keyid(rule, &match);
fs->val.vni = be32_to_cpu(match.key->keyid);
fs->mask.vni = be32_to_cpu(match.mask->keyid);
if (fs->mask.vni) {
fs->val.encap_vld = 1;
fs->mask.encap_vld = 1;
}
}
if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_dissector_key_vlan *key, *mask;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_match_vlan match;
u16 vlan_tci, vlan_tci_mask;
key = skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_VLAN,
cls->key);
mask = skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_VLAN,
cls->mask);
vlan_tci = key->vlan_id | (key->vlan_priority <<
VLAN_PRIO_SHIFT);
vlan_tci_mask = mask->vlan_id | (mask->vlan_priority <<
VLAN_PRIO_SHIFT);
flow_rule_match_vlan(rule, &match);
vlan_tci = match.key->vlan_id | (match.key->vlan_priority <<
VLAN_PRIO_SHIFT);
vlan_tci_mask = match.mask->vlan_id | (match.mask->vlan_priority <<
VLAN_PRIO_SHIFT);
fs->val.ivlan = vlan_tci;
fs->mask.ivlan = vlan_tci_mask;
......@@ -255,10 +224,12 @@ static void cxgb4_process_flow_match(struct net_device *dev,
static int cxgb4_validate_flow_match(struct net_device *dev,
struct tc_cls_flower_offload *cls)
{
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(cls);
struct flow_dissector *dissector = rule->match.dissector;
u16 ethtype_mask = 0;
u16 ethtype_key = 0;
if (cls->dissector->used_keys &
if (dissector->used_keys &
~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
BIT(FLOW_DISSECTOR_KEY_BASIC) |
BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
......@@ -268,36 +239,29 @@ static int cxgb4_validate_flow_match(struct net_device *dev,
BIT(FLOW_DISSECTOR_KEY_VLAN) |
BIT(FLOW_DISSECTOR_KEY_IP))) {
netdev_warn(dev, "Unsupported key used: 0x%x\n",
cls->dissector->used_keys);
dissector->used_keys);
return -EOPNOTSUPP;
}
if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_dissector_key_basic *key =
skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_BASIC,
cls->key);
struct flow_dissector_key_basic *mask =
skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_BASIC,
cls->mask);
ethtype_key = ntohs(key->n_proto);
ethtype_mask = ntohs(mask->n_proto);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_match_basic match;
flow_rule_match_basic(rule, &match);
ethtype_key = ntohs(match.key->n_proto);
ethtype_mask = ntohs(match.mask->n_proto);
}
if (dissector_uses_key(cls->dissector, FLOW_DISSECTOR_KEY_IP)) {
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
u16 eth_ip_type = ethtype_key & ethtype_mask;
struct flow_dissector_key_ip *mask;
struct flow_match_ip match;
if (eth_ip_type != ETH_P_IP && eth_ip_type != ETH_P_IPV6) {
netdev_err(dev, "IP Key supported only with IPv4/v6");
return -EINVAL;
}
mask = skb_flow_dissector_target(cls->dissector,
FLOW_DISSECTOR_KEY_IP,
cls->mask);
if (mask->ttl) {
flow_rule_match_ip(rule, &match);
if (match.mask->ttl) {
netdev_warn(dev, "ttl match unsupported for offload");
return -EOPNOTSUPP;
}
......
......@@ -7169,11 +7169,13 @@ static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
struct tc_cls_flower_offload *f,
struct i40e_cloud_filter *filter)
{
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
struct flow_dissector *dissector = rule->match.dissector;
u16 n_proto_mask = 0, n_proto_key = 0, addr_type = 0;
struct i40e_pf *pf = vsi->back;
u8 field_flags = 0;
if (f->dissector->used_keys &
if (dissector->used_keys &
~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
BIT(FLOW_DISSECTOR_KEY_BASIC) |
BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
......@@ -7183,143 +7185,109 @@ static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
BIT(FLOW_DISSECTOR_KEY_PORTS) |
BIT(FLOW_DISSECTOR_KEY_ENC_KEYID))) {
dev_err(&pf->pdev->dev, "Unsupported key used: 0x%x\n",
f->dissector->used_keys);
dissector->used_keys);
return -EOPNOTSUPP;
}
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
struct flow_dissector_key_keyid *key =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_ENC_KEYID,
f->key);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
struct flow_match_enc_keyid match;
struct flow_dissector_key_keyid *mask =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_ENC_KEYID,
f->mask);
if (mask->keyid != 0)
flow_rule_match_enc_keyid(rule, &match);
if (match.mask->keyid != 0)
field_flags |= I40E_CLOUD_FIELD_TEN_ID;
filter->tenant_id = be32_to_cpu(key->keyid);
filter->tenant_id = be32_to_cpu(match.key->keyid);
}
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_dissector_key_basic *key =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_BASIC,
f->key);
struct flow_dissector_key_basic *mask =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_BASIC,
f->mask);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_match_basic match;
n_proto_key = ntohs(key->n_proto);
n_proto_mask = ntohs(mask->n_proto);
flow_rule_match_basic(rule, &match);
n_proto_key = ntohs(match.key->n_proto);
n_proto_mask = ntohs(match.mask->n_proto);
if (n_proto_key == ETH_P_ALL) {
n_proto_key = 0;
n_proto_mask = 0;
}
filter->n_proto = n_proto_key & n_proto_mask;
filter->ip_proto = key->ip_proto;
filter->ip_proto = match.key->ip_proto;
}
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
struct flow_dissector_key_eth_addrs *key =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_ETH_ADDRS,
f->key);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
struct flow_match_eth_addrs match;
struct flow_dissector_key_eth_addrs *mask =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_ETH_ADDRS,
f->mask);
flow_rule_match_eth_addrs(rule, &match);
/* use is_broadcast and is_zero to check for all 0xf or 0 */
if (!is_zero_ether_addr(mask->dst)) {
if (is_broadcast_ether_addr(mask->dst)) {
if (!is_zero_ether_addr(match.mask->dst)) {
if (is_broadcast_ether_addr(match.mask->dst)) {
field_flags |= I40E_CLOUD_FIELD_OMAC;
} else {
dev_err(&pf->pdev->dev, "Bad ether dest mask %pM\n",
mask->dst);
match.mask->dst);
return I40E_ERR_CONFIG;
}
}
if (!is_zero_ether_addr(mask->src)) {
if (is_broadcast_ether_addr(mask->src)) {
if (!is_zero_ether_addr(match.mask->src)) {
if (is_broadcast_ether_addr(match.mask->src)) {
field_flags |= I40E_CLOUD_FIELD_IMAC;
} else {
dev_err(&pf->pdev->dev, "Bad ether src mask %pM\n",
mask->src);
match.mask->src);
return I40E_ERR_CONFIG;
}
}
ether_addr_copy(filter->dst_mac, key->dst);
ether_addr_copy(filter->src_mac, key->src);
ether_addr_copy(filter->dst_mac, match.key->dst);
ether_addr_copy(filter->src_mac, match.key->src);
}
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_dissector_key_vlan *key =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_VLAN,
f->key);
struct flow_dissector_key_vlan *mask =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_VLAN,
f->mask);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_match_vlan match;
if (mask->vlan_id) {
if (mask->vlan_id == VLAN_VID_MASK) {
flow_rule_match_vlan(rule, &match);
if (match.mask->vlan_id) {
if (match.mask->vlan_id == VLAN_VID_MASK) {
field_flags |= I40E_CLOUD_FIELD_IVLAN;
} else {
dev_err(&pf->pdev->dev, "Bad vlan mask 0x%04x\n",
mask->vlan_id);
match.mask->vlan_id);
return I40E_ERR_CONFIG;
}
}
filter->vlan_id = cpu_to_be16(key->vlan_id);
filter->vlan_id = cpu_to_be16(match.key->vlan_id);
}
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
struct flow_dissector_key_control *key =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_CONTROL,
f->key);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
struct flow_match_control match;
addr_type = key->addr_type;
flow_rule_match_control(rule, &match);
addr_type = match.key->addr_type;
}
if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
struct flow_dissector_key_ipv4_addrs *key =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_IPV4_ADDRS,
f->key);
struct flow_dissector_key_ipv4_addrs *mask =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_IPV4_ADDRS,
f->mask);
if (mask->dst) {
if (mask->dst == cpu_to_be32(0xffffffff)) {
struct flow_match_ipv4_addrs match;
flow_rule_match_ipv4_addrs(rule, &match);
if (match.mask->dst) {
if (match.mask->dst == cpu_to_be32(0xffffffff)) {
field_flags |= I40E_CLOUD_FIELD_IIP;
} else {
dev_err(&pf->pdev->dev, "Bad ip dst mask %pI4b\n",
&mask->dst);
&match.mask->dst);
return I40E_ERR_CONFIG;
}
}
if (mask->src) {
if (mask->src == cpu_to_be32(0xffffffff)) {
if (match.mask->src) {
if (match.mask->src == cpu_to_be32(0xffffffff)) {
field_flags |= I40E_CLOUD_FIELD_IIP;
} else {
dev_err(&pf->pdev->dev, "Bad ip src mask %pI4b\n",
&mask->src);
&match.mask->src);
return I40E_ERR_CONFIG;
}
}
......@@ -7328,70 +7296,60 @@ static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
dev_err(&pf->pdev->dev, "Tenant id not allowed for ip filter\n");
return I40E_ERR_CONFIG;
}
filter->dst_ipv4 = key->dst;
filter->src_ipv4 = key->src;
filter->dst_ipv4 = match.key->dst;
filter->src_ipv4 = match.key->src;
}
if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
struct flow_dissector_key_ipv6_addrs *key =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_IPV6_ADDRS,
f->key);
struct flow_dissector_key_ipv6_addrs *mask =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_IPV6_ADDRS,
f->mask);
struct flow_match_ipv6_addrs match;
flow_rule_match_ipv6_addrs(rule, &match);
/* src and dest IPV6 address should not be LOOPBACK
* (0:0:0:0:0:0:0:1), which can be represented as ::1
*/
if (ipv6_addr_loopback(&key->dst) ||
ipv6_addr_loopback(&key->src)) {
if (ipv6_addr_loopback(&match.key->dst) ||
ipv6_addr_loopback(&match.key->src)) {
dev_err(&pf->pdev->dev,
"Bad ipv6, addr is LOOPBACK\n");
return I40E_ERR_CONFIG;
}
if (!ipv6_addr_any(&mask->dst) || !ipv6_addr_any(&mask->src))
if (!ipv6_addr_any(&match.mask->dst) ||
!ipv6_addr_any(&match.mask->src))
field_flags |= I40E_CLOUD_FIELD_IIP;
memcpy(&filter->src_ipv6, &key->src.s6_addr32,
memcpy(&filter->src_ipv6, &match.key->src.s6_addr32,
sizeof(filter->src_ipv6));
memcpy(&filter->dst_ipv6, &key->dst.s6_addr32,
memcpy(&filter->dst_ipv6, &match.key->dst.s6_addr32,
sizeof(filter->dst_ipv6));
}
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
struct flow_dissector_key_ports *key =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_PORTS,
f->key);
struct flow_dissector_key_ports *mask =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_PORTS,
f->mask);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
struct flow_match_ports match;
if (mask->src) {
if (mask->src == cpu_to_be16(0xffff)) {
flow_rule_match_ports(rule, &match);
if (match.mask->src) {
if (match.mask->src == cpu_to_be16(0xffff)) {
field_flags |= I40E_CLOUD_FIELD_IIP;
} else {
dev_err(&pf->pdev->dev, "Bad src port mask 0x%04x\n",
be16_to_cpu(mask->src));
be16_to_cpu(match.mask->src));
return I40E_ERR_CONFIG;
}
}
if (mask->dst) {
if (mask->dst == cpu_to_be16(0xffff)) {
if (match.mask->dst) {
if (match.mask->dst == cpu_to_be16(0xffff)) {
field_flags |= I40E_CLOUD_FIELD_IIP;
} else {
dev_err(&pf->pdev->dev, "Bad dst port mask 0x%04x\n",
be16_to_cpu(mask->dst));
be16_to_cpu(match.mask->dst));
return I40E_ERR_CONFIG;
}
}
filter->dst_port = key->dst;
filter->src_port = key->src;
filter->dst_port = match.key->dst;
filter->src_port = match.key->src;
switch (filter->ip_proto) {
case IPPROTO_TCP:
......
This diff is collapsed.
......@@ -2581,9 +2581,11 @@ static int igb_parse_cls_flower(struct igb_adapter *adapter,
int traffic_class,
struct igb_nfc_filter *input)
{
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
struct flow_dissector *dissector = rule->match.dissector;
struct netlink_ext_ack *extack = f->common.extack;
if (f->dissector->used_keys &
if (dissector->used_keys &
~(BIT(FLOW_DISSECTOR_KEY_BASIC) |
BIT(FLOW_DISSECTOR_KEY_CONTROL) |
BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
......@@ -2593,78 +2595,60 @@ static int igb_parse_cls_flower(struct igb_adapter *adapter,
return -EOPNOTSUPP;
}
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
struct flow_dissector_key_eth_addrs *key, *mask;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
struct flow_match_eth_addrs match;
key = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_ETH_ADDRS,
f->key);
mask = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_ETH_ADDRS,
f->mask);
if (!is_zero_ether_addr(mask->dst)) {
if (!is_broadcast_ether_addr(mask->dst)) {
flow_rule_match_eth_addrs(rule, &match);
if (!is_zero_ether_addr(match.mask->dst)) {
if (!is_broadcast_ether_addr(match.mask->dst)) {
NL_SET_ERR_MSG_MOD(extack, "Only full masks are supported for destination MAC address");
return -EINVAL;
}
input->filter.match_flags |=
IGB_FILTER_FLAG_DST_MAC_ADDR;
ether_addr_copy(input->filter.dst_addr, key->dst);
ether_addr_copy(input->filter.dst_addr, match.key->dst);
}
if (!is_zero_ether_addr(mask->src)) {
if (!is_broadcast_ether_addr(mask->src)) {
if (!is_zero_ether_addr(match.mask->src)) {
if (!is_broadcast_ether_addr(match.mask->src)) {
NL_SET_ERR_MSG_MOD(extack, "Only full masks are supported for source MAC address");
return -EINVAL;
}
input->filter.match_flags |=
IGB_FILTER_FLAG_SRC_MAC_ADDR;
ether_addr_copy(input->filter.src_addr, key->src);
ether_addr_copy(input->filter.src_addr, match.key->src);
}
}
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_dissector_key_basic *key, *mask;
key = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_BASIC,
f->key);
mask = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_BASIC,
f->mask);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_match_basic match;
if (mask->n_proto) {
if (mask->n_proto != ETHER_TYPE_FULL_MASK) {
flow_rule_match_basic(rule, &match);
if (match.mask->n_proto) {
if (match.mask->n_proto != ETHER_TYPE_FULL_MASK) {
NL_SET_ERR_MSG_MOD(extack, "Only full mask is supported for EtherType filter");
return -EINVAL;
}
input->filter.match_flags |= IGB_FILTER_FLAG_ETHER_TYPE;
input->filter.etype = key->n_proto;
input->filter.etype = match.key->n_proto;
}
}
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_dissector_key_vlan *key, *mask;
key = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_VLAN,
f->key);
mask = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_VLAN,
f->mask);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_match_vlan match;
if (mask->vlan_priority) {
if (mask->vlan_priority != VLAN_PRIO_FULL_MASK) {
flow_rule_match_vlan(rule, &match);
if (match.mask->vlan_priority) {
if (match.mask->vlan_priority != VLAN_PRIO_FULL_MASK) {
NL_SET_ERR_MSG_MOD(extack, "Only full mask is supported for VLAN priority");
return -EINVAL;
}
input->filter.match_flags |= IGB_FILTER_FLAG_VLAN_TCI;
input->filter.vlan_tci = key->vlan_priority;
input->filter.vlan_tci = match.key->vlan_priority;
}
}
......
......@@ -496,25 +496,21 @@ static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
void *headers_c,
void *headers_v)
{
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
struct netlink_ext_ack *extack = f->common.extack;
struct flow_dissector_key_ports *key =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_ENC_PORTS,
f->key);
struct flow_dissector_key_ports *mask =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_ENC_PORTS,
f->mask);
void *misc_c = MLX5_ADDR_OF(fte_match_param,
spec->match_criteria,
misc_parameters);
void *misc_v = MLX5_ADDR_OF(fte_match_param,
spec->match_value,
misc_parameters);
struct flow_match_ports enc_ports;
flow_rule_match_enc_ports(rule, &enc_ports);
/* Full udp dst port must be given */
if (!dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS) ||
memchr_inv(&mask->dst, 0xff, sizeof(mask->dst))) {
if (!flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_PORTS) ||
memchr_inv(&enc_ports.mask->dst, 0xff, sizeof(enc_ports.mask->dst))) {
NL_SET_ERR_MSG_MOD(extack,
"VXLAN decap filter must include enc_dst_port condition");
netdev_warn(priv->netdev,
......@@ -523,12 +519,12 @@ static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
}
/* udp dst port must be knonwn as a VXLAN port */
if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, be16_to_cpu(key->dst))) {
if (!mlx5_vxlan_lookup_port(priv->mdev->vxlan, be16_to_cpu(enc_ports.key->dst))) {
NL_SET_ERR_MSG_MOD(extack,
"Matched UDP port is not registered as a VXLAN port");
netdev_warn(priv->netdev,
"UDP port %d is not registered as a VXLAN port\n",
be16_to_cpu(key->dst));
be16_to_cpu(enc_ports.key->dst));
return -EOPNOTSUPP;
}
......@@ -536,26 +532,26 @@ static int mlx5e_tc_tun_parse_vxlan(struct mlx5e_priv *priv,
MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ip_protocol);
MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP);
MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_dport, ntohs(mask->dst));
MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, ntohs(key->dst));
MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_dport,
ntohs(enc_ports.mask->dst));
MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport,
ntohs(enc_ports.key->dst));
MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_sport, ntohs(mask->src));
MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport, ntohs(key->src));
MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_sport,
ntohs(enc_ports.mask->src));
MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport,
ntohs(enc_ports.key->src));
/* match on VNI */
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
struct flow_dissector_key_keyid *key =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_ENC_KEYID,
f->key);
struct flow_dissector_key_keyid *mask =
skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_ENC_KEYID,
f->mask);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
struct flow_match_enc_keyid enc_keyid;
flow_rule_match_enc_keyid(rule, &enc_keyid);
MLX5_SET(fte_match_set_misc, misc_c, vxlan_vni,
be32_to_cpu(mask->keyid));
be32_to_cpu(enc_keyid.mask->keyid));
MLX5_SET(fte_match_set_misc, misc_v, vxlan_vni,
be32_to_cpu(key->keyid));
be32_to_cpu(enc_keyid.key->keyid));
}
return 0;
}
......@@ -570,6 +566,7 @@ static int mlx5e_tc_tun_parse_gretap(struct mlx5e_priv *priv,
misc_parameters);
void *misc_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
misc_parameters);
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
if (!MLX5_CAP_ESW(priv->mdev, nvgre_encap_decap)) {
NL_SET_ERR_MSG_MOD(f->common.extack,
......@@ -587,21 +584,14 @@ static int mlx5e_tc_tun_parse_gretap(struct mlx5e_priv *priv,
MLX5_SET(fte_match_set_misc, misc_v, gre_protocol, ETH_P_TEB);
/* gre key */
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
struct flow_dissector_key_keyid *mask = NULL;
struct flow_dissector_key_keyid *key = NULL;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
struct flow_match_enc_keyid enc_keyid;
mask = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_ENC_KEYID,
f->mask);
flow_rule_match_enc_keyid(rule, &enc_keyid);
MLX5_SET(fte_match_set_misc, misc_c,
gre_key.key, be32_to_cpu(mask->keyid));
key = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_ENC_KEYID,
f->key);
gre_key.key, be32_to_cpu(enc_keyid.mask->keyid));
MLX5_SET(fte_match_set_misc, misc_v,
gre_key.key, be32_to_cpu(key->keyid));
gre_key.key, be32_to_cpu(enc_keyid.key->keyid));
}
return 0;
......
......@@ -587,6 +587,7 @@ static int
nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
char *nfp_action, int *a_len, u32 *csum_updated)
{
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(flow);
struct nfp_fl_set_ipv6_addr set_ip6_dst, set_ip6_src;
struct nfp_fl_set_ipv6_tc_hl_fl set_ip6_tc_hl_fl;
struct nfp_fl_set_ip4_ttl_tos set_ip_ttl_tos;
......@@ -643,13 +644,11 @@ nfp_fl_pedit(const struct tc_action *action, struct tc_cls_flower_offload *flow,
return err;
}
if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_dissector_key_basic *basic;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_match_basic match;
basic = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_BASIC,
flow->key);
ip_proto = basic->ip_proto;
flow_rule_match_basic(rule, &match);
ip_proto = match.key->ip_proto;
}
if (set_eth.head.len_lw) {
......
......@@ -102,23 +102,22 @@ nfp_flower_xmit_flow(struct nfp_app *app, struct nfp_fl_payload *nfp_flow,
static bool nfp_flower_check_higher_than_mac(struct tc_cls_flower_offload *f)
{
return dissector_uses_key(f->dissector,
FLOW_DISSECTOR_KEY_IPV4_ADDRS) ||
dissector_uses_key(f->dissector,
FLOW_DISSECTOR_KEY_IPV6_ADDRS) ||
dissector_uses_key(f->dissector,
FLOW_DISSECTOR_KEY_PORTS) ||
dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ICMP);
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
return flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) ||
flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) ||
flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS) ||
flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ICMP);
}
static int
nfp_flower_calc_opt_layer(struct flow_dissector_key_enc_opts *enc_opts,
nfp_flower_calc_opt_layer(struct flow_match_enc_opts *enc_opts,
u32 *key_layer_two, int *key_size)
{
if (enc_opts->len > NFP_FL_MAX_GENEVE_OPT_KEY)
if (enc_opts->key->len > NFP_FL_MAX_GENEVE_OPT_KEY)
return -EOPNOTSUPP;
if (enc_opts->len > 0) {
if (enc_opts->key->len > 0) {
*key_layer_two |= NFP_FLOWER_LAYER2_GENEVE_OP;
*key_size += sizeof(struct nfp_flower_geneve_options);
}
......@@ -133,20 +132,21 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
struct tc_cls_flower_offload *flow,
enum nfp_flower_tun_type *tun_type)
{
struct flow_dissector_key_basic *mask_basic = NULL;
struct flow_dissector_key_basic *key_basic = NULL;
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(flow);
struct flow_dissector *dissector = rule->match.dissector;
struct flow_match_basic basic = { NULL, NULL};
struct nfp_flower_priv *priv = app->priv;
u32 key_layer_two;
u8 key_layer;
int key_size;
int err;
if (flow->dissector->used_keys & ~NFP_FLOWER_WHITELIST_DISSECTOR)
if (dissector->used_keys & ~NFP_FLOWER_WHITELIST_DISSECTOR)
return -EOPNOTSUPP;
/* If any tun dissector is used then the required set must be used. */
if (flow->dissector->used_keys & NFP_FLOWER_WHITELIST_TUN_DISSECTOR &&
(flow->dissector->used_keys & NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R)
if (dissector->used_keys & NFP_FLOWER_WHITELIST_TUN_DISSECTOR &&
(dissector->used_keys & NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R)
!= NFP_FLOWER_WHITELIST_TUN_DISSECTOR_R)
return -EOPNOTSUPP;
......@@ -155,76 +155,53 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
key_size = sizeof(struct nfp_flower_meta_tci) +
sizeof(struct nfp_flower_in_port);
if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS) ||
dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_MPLS)) {
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS) ||
flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_MPLS)) {
key_layer |= NFP_FLOWER_LAYER_MAC;
key_size += sizeof(struct nfp_flower_mac_mpls);
}
if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_dissector_key_vlan *flow_vlan;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
struct flow_match_vlan vlan;
flow_vlan = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_VLAN,
flow->mask);
flow_rule_match_vlan(rule, &vlan);
if (!(priv->flower_ext_feats & NFP_FL_FEATS_VLAN_PCP) &&
flow_vlan->vlan_priority)
vlan.key->vlan_priority)
return -EOPNOTSUPP;
}
if (dissector_uses_key(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
struct flow_dissector_key_ipv4_addrs *mask_ipv4 = NULL;
struct flow_dissector_key_ports *mask_enc_ports = NULL;
struct flow_dissector_key_enc_opts *enc_op = NULL;
struct flow_dissector_key_ports *enc_ports = NULL;
struct flow_dissector_key_control *mask_enc_ctl =
skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_CONTROL,
flow->mask);
struct flow_dissector_key_control *enc_ctl =
skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_CONTROL,
flow->key);
if (mask_enc_ctl->addr_type != 0xffff ||
enc_ctl->addr_type != FLOW_DISSECTOR_KEY_IPV4_ADDRS)
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
struct flow_match_enc_opts enc_op = { NULL, NULL };
struct flow_match_ipv4_addrs ipv4_addrs;
struct flow_match_control enc_ctl;
struct flow_match_ports enc_ports;
flow_rule_match_enc_control(rule, &enc_ctl);
if (enc_ctl.mask->addr_type != 0xffff ||
enc_ctl.key->addr_type != FLOW_DISSECTOR_KEY_IPV4_ADDRS)
return -EOPNOTSUPP;
/* These fields are already verified as used. */
mask_ipv4 =
skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
flow->mask);
if (mask_ipv4->dst != cpu_to_be32(~0))
flow_rule_match_enc_ipv4_addrs(rule, &ipv4_addrs);
if (ipv4_addrs.mask->dst != cpu_to_be32(~0))
return -EOPNOTSUPP;
mask_enc_ports =
skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_PORTS,
flow->mask);
enc_ports =
skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_PORTS,
flow->key);
if (mask_enc_ports->dst != cpu_to_be16(~0))
flow_rule_match_enc_ports(rule, &enc_ports);
if (enc_ports.mask->dst != cpu_to_be16(~0))
return -EOPNOTSUPP;
if (dissector_uses_key(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_OPTS)) {
enc_op = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_ENC_OPTS,
flow->key);
}
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ENC_OPTS))
flow_rule_match_enc_opts(rule, &enc_op);
switch (enc_ports->dst) {
switch (enc_ports.key->dst) {
case htons(NFP_FL_VXLAN_PORT):
*tun_type = NFP_FL_TUNNEL_VXLAN;
key_layer |= NFP_FLOWER_LAYER_VXLAN;
key_size += sizeof(struct nfp_flower_ipv4_udp_tun);
if (enc_op)
if (enc_op.key)
return -EOPNOTSUPP;
break;
case htons(NFP_FL_GENEVE_PORT):
......@@ -236,11 +213,11 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
key_layer_two |= NFP_FLOWER_LAYER2_GENEVE;
key_size += sizeof(struct nfp_flower_ipv4_udp_tun);
if (!enc_op)
if (!enc_op.key)
break;
if (!(priv->flower_ext_feats & NFP_FL_FEATS_GENEVE_OPT))
return -EOPNOTSUPP;
err = nfp_flower_calc_opt_layer(enc_op, &key_layer_two,
err = nfp_flower_calc_opt_layer(&enc_op, &key_layer_two,
&key_size);
if (err)
return err;
......@@ -254,19 +231,12 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
return -EOPNOTSUPP;
}
if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
mask_basic = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_BASIC,
flow->mask);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC))
flow_rule_match_basic(rule, &basic);
key_basic = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_BASIC,
flow->key);
}
if (mask_basic && mask_basic->n_proto) {
if (basic.mask && basic.mask->n_proto) {
/* Ethernet type is present in the key. */
switch (key_basic->n_proto) {
switch (basic.key->n_proto) {
case cpu_to_be16(ETH_P_IP):
key_layer |= NFP_FLOWER_LAYER_IPV4;
key_size += sizeof(struct nfp_flower_ipv4);
......@@ -305,9 +275,9 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
}
}
if (mask_basic && mask_basic->ip_proto) {
if (basic.mask && basic.mask->ip_proto) {
/* Ethernet type is present in the key. */
switch (key_basic->ip_proto) {
switch (basic.key->ip_proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_SCTP:
......@@ -324,14 +294,12 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
}
}
if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_TCP)) {
struct flow_dissector_key_tcp *tcp;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_TCP)) {
struct flow_match_tcp tcp;
u32 tcp_flags;
tcp = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_TCP,
flow->key);
tcp_flags = be16_to_cpu(tcp->flags);
flow_rule_match_tcp(rule, &tcp);
tcp_flags = be16_to_cpu(tcp.key->flags);
if (tcp_flags & ~NFP_FLOWER_SUPPORTED_TCPFLAGS)
return -EOPNOTSUPP;
......@@ -347,12 +315,12 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
* space, thus we need to ensure we include a IPv4/IPv6 key
* layer if we have not done so already.
*/
if (!key_basic)
if (!basic.key)
return -EOPNOTSUPP;
if (!(key_layer & NFP_FLOWER_LAYER_IPV4) &&
!(key_layer & NFP_FLOWER_LAYER_IPV6)) {
switch (key_basic->n_proto) {
switch (basic.key->n_proto) {
case cpu_to_be16(ETH_P_IP):
key_layer |= NFP_FLOWER_LAYER_IPV4;
key_size += sizeof(struct nfp_flower_ipv4);
......@@ -369,14 +337,11 @@ nfp_flower_calculate_key_layers(struct nfp_app *app,
}
}
if (dissector_uses_key(flow->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
struct flow_dissector_key_control *key_ctl;
key_ctl = skb_flow_dissector_target(flow->dissector,
FLOW_DISSECTOR_KEY_CONTROL,
flow->key);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
struct flow_match_control ctl;
if (key_ctl->flags & ~NFP_FLOWER_SUPPORTED_CTLFLAGS)
flow_rule_match_control(rule, &ctl);
if (ctl.key->flags & ~NFP_FLOWER_SUPPORTED_CTLFLAGS)
return -EOPNOTSUPP;
}
......
......@@ -2033,24 +2033,20 @@ qede_tc_parse_ports(struct qede_dev *edev,
struct tc_cls_flower_offload *f,
struct qede_arfs_tuple *t)
{
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
struct flow_dissector_key_ports *key, *mask;
key = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_PORTS,
f->key);
mask = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_PORTS,
f->mask);
if ((key->src && mask->src != U16_MAX) ||
(key->dst && mask->dst != U16_MAX)) {
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
struct flow_match_ports match;
flow_rule_match_ports(rule, &match);
if ((match.key->src && match.mask->src != U16_MAX) ||
(match.key->dst && match.mask->dst != U16_MAX)) {
DP_NOTICE(edev, "Do not support ports masks\n");
return -EINVAL;
}
t->src_port = key->src;
t->dst_port = key->dst;
t->src_port = match.key->src;
t->dst_port = match.key->dst;
}
return 0;
......@@ -2061,32 +2057,27 @@ qede_tc_parse_v6_common(struct qede_dev *edev,
struct tc_cls_flower_offload *f,
struct qede_arfs_tuple *t)
{
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
struct in6_addr zero_addr, addr;
memset(&zero_addr, 0, sizeof(addr));
memset(&addr, 0xff, sizeof(addr));
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
struct flow_dissector_key_ipv6_addrs *key, *mask;
key = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_IPV6_ADDRS,
f->key);
mask = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_IPV6_ADDRS,
f->mask);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
struct flow_match_ipv6_addrs match;
if ((memcmp(&key->src, &zero_addr, sizeof(addr)) &&
memcmp(&mask->src, &addr, sizeof(addr))) ||
(memcmp(&key->dst, &zero_addr, sizeof(addr)) &&
memcmp(&mask->dst, &addr, sizeof(addr)))) {
flow_rule_match_ipv6_addrs(rule, &match);
if ((memcmp(&match.key->src, &zero_addr, sizeof(addr)) &&
memcmp(&match.mask->src, &addr, sizeof(addr))) ||
(memcmp(&match.key->dst, &zero_addr, sizeof(addr)) &&
memcmp(&match.mask->dst, &addr, sizeof(addr)))) {
DP_NOTICE(edev,
"Do not support IPv6 address prefix/mask\n");
return -EINVAL;
}
memcpy(&t->src_ipv6, &key->src, sizeof(addr));
memcpy(&t->dst_ipv6, &key->dst, sizeof(addr));
memcpy(&t->src_ipv6, &match.key->src, sizeof(addr));
memcpy(&t->dst_ipv6, &match.key->dst, sizeof(addr));
}
if (qede_tc_parse_ports(edev, f, t))
......@@ -2100,24 +2091,20 @@ qede_tc_parse_v4_common(struct qede_dev *edev,
struct tc_cls_flower_offload *f,
struct qede_arfs_tuple *t)
{
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
struct flow_dissector_key_ipv4_addrs *key, *mask;
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
key = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_IPV4_ADDRS,
f->key);
mask = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_IPV4_ADDRS,
f->mask);
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
struct flow_match_ipv4_addrs match;
if ((key->src && mask->src != U32_MAX) ||
(key->dst && mask->dst != U32_MAX)) {
flow_rule_match_ipv4_addrs(rule, &match);
if ((match.key->src && match.mask->src != U32_MAX) ||
(match.key->dst && match.mask->dst != U32_MAX)) {
DP_NOTICE(edev, "Do not support ipv4 prefix/masks\n");
return -EINVAL;
}
t->src_ipv4 = key->src;
t->dst_ipv4 = key->dst;
t->src_ipv4 = match.key->src;
t->dst_ipv4 = match.key->dst;
}
if (qede_tc_parse_ports(edev, f, t))
......@@ -2175,19 +2162,21 @@ qede_parse_flower_attr(struct qede_dev *edev, __be16 proto,
struct tc_cls_flower_offload *f,
struct qede_arfs_tuple *tuple)
{
struct flow_rule *rule = tc_cls_flower_offload_flow_rule(f);
struct flow_dissector *dissector = rule->match.dissector;
int rc = -EINVAL;
u8 ip_proto = 0;
memset(tuple, 0, sizeof(*tuple));
if (f->dissector->used_keys &
if (dissector->used_keys &
~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
BIT(FLOW_DISSECTOR_KEY_BASIC) |
BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
BIT(FLOW_DISSECTOR_KEY_PORTS))) {
DP_NOTICE(edev, "Unsupported key set:0x%x\n",
f->dissector->used_keys);
dissector->used_keys);
return -EOPNOTSUPP;
}
......@@ -2197,13 +2186,11 @@ qede_parse_flower_attr(struct qede_dev *edev, __be16 proto,
return -EPROTONOSUPPORT;
}
if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_dissector_key_basic *key;
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
struct flow_match_basic match;
key = skb_flow_dissector_target(f->dissector,
FLOW_DISSECTOR_KEY_BASIC,
f->key);
ip_proto = key->ip_proto;
flow_rule_match_basic(rule, &match);
ip_proto = match.key->ip_proto;
}
if (ip_proto == IPPROTO_TCP && proto == htons(ETH_P_IP))
......
#ifndef _NET_FLOW_OFFLOAD_H
#define _NET_FLOW_OFFLOAD_H
#include <net/flow_dissector.h>
struct flow_match {
struct flow_dissector *dissector;
void *mask;
void *key;
};
struct flow_match_basic {
struct flow_dissector_key_basic *key, *mask;
};
struct flow_match_control {
struct flow_dissector_key_control *key, *mask;
};
struct flow_match_eth_addrs {
struct flow_dissector_key_eth_addrs *key, *mask;
};
struct flow_match_vlan {
struct flow_dissector_key_vlan *key, *mask;
};
struct flow_match_ipv4_addrs {
struct flow_dissector_key_ipv4_addrs *key, *mask;
};
struct flow_match_ipv6_addrs {
struct flow_dissector_key_ipv6_addrs *key, *mask;
};
struct flow_match_ip {
struct flow_dissector_key_ip *key, *mask;
};
struct flow_match_ports {
struct flow_dissector_key_ports *key, *mask;
};
struct flow_match_icmp {
struct flow_dissector_key_icmp *key, *mask;
};
struct flow_match_tcp {
struct flow_dissector_key_tcp *key, *mask;
};
struct flow_match_mpls {
struct flow_dissector_key_mpls *key, *mask;
};
struct flow_match_enc_keyid {
struct flow_dissector_key_keyid *key, *mask;
};
struct flow_match_enc_opts {
struct flow_dissector_key_enc_opts *key, *mask;
};
struct flow_rule;
void flow_rule_match_basic(const struct flow_rule *rule,
struct flow_match_basic *out);
void flow_rule_match_control(const struct flow_rule *rule,
struct flow_match_control *out);
void flow_rule_match_eth_addrs(const struct flow_rule *rule,
struct flow_match_eth_addrs *out);
void flow_rule_match_vlan(const struct flow_rule *rule,
struct flow_match_vlan *out);
void flow_rule_match_ipv4_addrs(const struct flow_rule *rule,
struct flow_match_ipv4_addrs *out);
void flow_rule_match_ipv6_addrs(const struct flow_rule *rule,
struct flow_match_ipv6_addrs *out);
void flow_rule_match_ip(const struct flow_rule *rule,
struct flow_match_ip *out);
void flow_rule_match_ports(const struct flow_rule *rule,
struct flow_match_ports *out);
void flow_rule_match_tcp(const struct flow_rule *rule,
struct flow_match_tcp *out);
void flow_rule_match_icmp(const struct flow_rule *rule,
struct flow_match_icmp *out);
void flow_rule_match_mpls(const struct flow_rule *rule,
struct flow_match_mpls *out);
void flow_rule_match_enc_control(const struct flow_rule *rule,
struct flow_match_control *out);
void flow_rule_match_enc_ipv4_addrs(const struct flow_rule *rule,
struct flow_match_ipv4_addrs *out);
void flow_rule_match_enc_ipv6_addrs(const struct flow_rule *rule,
struct flow_match_ipv6_addrs *out);
void flow_rule_match_enc_ip(const struct flow_rule *rule,
struct flow_match_ip *out);
void flow_rule_match_enc_ports(const struct flow_rule *rule,
struct flow_match_ports *out);
void flow_rule_match_enc_keyid(const struct flow_rule *rule,
struct flow_match_enc_keyid *out);
void flow_rule_match_enc_opts(const struct flow_rule *rule,
struct flow_match_enc_opts *out);
struct flow_rule {
struct flow_match match;
};
struct flow_rule *flow_rule_alloc(void);
static inline bool flow_rule_match_key(const struct flow_rule *rule,
enum flow_dissector_key_id key)
{
return dissector_uses_key(rule->match.dissector, key);
}
#endif /* _NET_FLOW_OFFLOAD_H */
......@@ -6,6 +6,7 @@
#include <linux/workqueue.h>
#include <net/sch_generic.h>
#include <net/act_api.h>
#include <net/flow_offload.h>
/* TC action not accessible from user space */
#define TC_ACT_REINSERT (TC_ACT_VALUE_MAX + 1)
......@@ -760,13 +761,17 @@ struct tc_cls_flower_offload {
struct tc_cls_common_offload common;
enum tc_fl_command command;
unsigned long cookie;
struct flow_dissector *dissector;
struct fl_flow_key *mask;
struct fl_flow_key *key;
struct flow_rule *rule;
struct tcf_exts *exts;
u32 classid;
};
static inline struct flow_rule *
tc_cls_flower_offload_flow_rule(struct tc_cls_flower_offload *tc_flow_cmd)
{
return tc_flow_cmd->rule;
}
enum tc_matchall_command {
TC_CLSMATCHALL_REPLACE,
TC_CLSMATCHALL_DESTROY,
......
......@@ -11,7 +11,7 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.o
obj-y += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
fib_notifier.o xdp.o
fib_notifier.o xdp.o flow_offload.o
obj-y += net-sysfs.o
obj-$(CONFIG_PAGE_POOL) += page_pool.o
......
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/kernel.h>
#include <linux/slab.h>
#include <net/flow_offload.h>
struct flow_rule *flow_rule_alloc(void)
{
return kzalloc(sizeof(struct flow_rule), GFP_KERNEL);
}
EXPORT_SYMBOL(flow_rule_alloc);
#define FLOW_DISSECTOR_MATCH(__rule, __type, __out) \
const struct flow_match *__m = &(__rule)->match; \
struct flow_dissector *__d = (__m)->dissector; \
\
(__out)->key = skb_flow_dissector_target(__d, __type, (__m)->key); \
(__out)->mask = skb_flow_dissector_target(__d, __type, (__m)->mask); \
void flow_rule_match_basic(const struct flow_rule *rule,
struct flow_match_basic *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_BASIC, out);
}
EXPORT_SYMBOL(flow_rule_match_basic);
void flow_rule_match_control(const struct flow_rule *rule,
struct flow_match_control *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_CONTROL, out);
}
EXPORT_SYMBOL(flow_rule_match_control);
void flow_rule_match_eth_addrs(const struct flow_rule *rule,
struct flow_match_eth_addrs *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS, out);
}
EXPORT_SYMBOL(flow_rule_match_eth_addrs);
void flow_rule_match_vlan(const struct flow_rule *rule,
struct flow_match_vlan *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_VLAN, out);
}
EXPORT_SYMBOL(flow_rule_match_vlan);
void flow_rule_match_ipv4_addrs(const struct flow_rule *rule,
struct flow_match_ipv4_addrs *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS, out);
}
EXPORT_SYMBOL(flow_rule_match_ipv4_addrs);
void flow_rule_match_ipv6_addrs(const struct flow_rule *rule,
struct flow_match_ipv6_addrs *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS, out);
}
EXPORT_SYMBOL(flow_rule_match_ipv6_addrs);
void flow_rule_match_ip(const struct flow_rule *rule,
struct flow_match_ip *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_IP, out);
}
EXPORT_SYMBOL(flow_rule_match_ip);
void flow_rule_match_ports(const struct flow_rule *rule,
struct flow_match_ports *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_PORTS, out);
}
EXPORT_SYMBOL(flow_rule_match_ports);
void flow_rule_match_tcp(const struct flow_rule *rule,
struct flow_match_tcp *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_TCP, out);
}
EXPORT_SYMBOL(flow_rule_match_tcp);
void flow_rule_match_icmp(const struct flow_rule *rule,
struct flow_match_icmp *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ICMP, out);
}
EXPORT_SYMBOL(flow_rule_match_icmp);
void flow_rule_match_mpls(const struct flow_rule *rule,
struct flow_match_mpls *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_MPLS, out);
}
EXPORT_SYMBOL(flow_rule_match_mpls);
void flow_rule_match_enc_control(const struct flow_rule *rule,
struct flow_match_control *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_CONTROL, out);
}
EXPORT_SYMBOL(flow_rule_match_enc_control);
void flow_rule_match_enc_ipv4_addrs(const struct flow_rule *rule,
struct flow_match_ipv4_addrs *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, out);
}
EXPORT_SYMBOL(flow_rule_match_enc_ipv4_addrs);
void flow_rule_match_enc_ipv6_addrs(const struct flow_rule *rule,
struct flow_match_ipv6_addrs *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS, out);
}
EXPORT_SYMBOL(flow_rule_match_enc_ipv6_addrs);
void flow_rule_match_enc_ip(const struct flow_rule *rule,
struct flow_match_ip *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_IP, out);
}
EXPORT_SYMBOL(flow_rule_match_enc_ip);
void flow_rule_match_enc_ports(const struct flow_rule *rule,
struct flow_match_ports *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_PORTS, out);
}
EXPORT_SYMBOL(flow_rule_match_enc_ports);
void flow_rule_match_enc_keyid(const struct flow_rule *rule,
struct flow_match_enc_keyid *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_KEYID, out);
}
EXPORT_SYMBOL(flow_rule_match_enc_keyid);
void flow_rule_match_enc_opts(const struct flow_rule *rule,
struct flow_match_enc_opts *out)
{
FLOW_DISSECTOR_MATCH(rule, FLOW_DISSECTOR_KEY_ENC_OPTS, out);
}
EXPORT_SYMBOL(flow_rule_match_enc_opts);
......@@ -381,16 +381,22 @@ static int fl_hw_replace_filter(struct tcf_proto *tp,
bool skip_sw = tc_skip_sw(f->flags);
int err;
cls_flower.rule = flow_rule_alloc();
if (!cls_flower.rule)
return -ENOMEM;
tc_cls_common_offload_init(&cls_flower.common, tp, f->flags, extack);
cls_flower.command = TC_CLSFLOWER_REPLACE;
cls_flower.cookie = (unsigned long) f;
cls_flower.dissector = &f->mask->dissector;
cls_flower.mask = &f->mask->key;
cls_flower.key = &f->mkey;
cls_flower.rule->match.dissector = &f->mask->dissector;
cls_flower.rule->match.mask = &f->mask->key;
cls_flower.rule->match.key = &f->mkey;
cls_flower.exts = &f->exts;
cls_flower.classid = f->res.classid;
err = tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, skip_sw);
kfree(cls_flower.rule);
if (err < 0) {
fl_hw_destroy_filter(tp, f, NULL);
return err;
......@@ -1463,18 +1469,24 @@ static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
if (tc_skip_hw(f->flags))
continue;
cls_flower.rule = flow_rule_alloc();
if (!cls_flower.rule)
return -ENOMEM;
tc_cls_common_offload_init(&cls_flower.common, tp,
f->flags, extack);
cls_flower.command = add ?
TC_CLSFLOWER_REPLACE : TC_CLSFLOWER_DESTROY;
cls_flower.cookie = (unsigned long)f;
cls_flower.dissector = &mask->dissector;
cls_flower.mask = &mask->key;
cls_flower.key = &f->mkey;
cls_flower.rule->match.dissector = &mask->dissector;
cls_flower.rule->match.mask = &mask->key;
cls_flower.rule->match.key = &f->mkey;
cls_flower.exts = &f->exts;
cls_flower.classid = f->res.classid;
err = cb(TC_SETUP_CLSFLOWER, &cls_flower, cb_priv);
kfree(cls_flower.rule);
if (err) {
if (add && tc_skip_sw(f->flags))
return err;
......@@ -1489,25 +1501,32 @@ static int fl_reoffload(struct tcf_proto *tp, bool add, tc_setup_cb_t *cb,
return 0;
}
static void fl_hw_create_tmplt(struct tcf_chain *chain,
struct fl_flow_tmplt *tmplt)
static int fl_hw_create_tmplt(struct tcf_chain *chain,
struct fl_flow_tmplt *tmplt)
{
struct tc_cls_flower_offload cls_flower = {};
struct tcf_block *block = chain->block;
struct tcf_exts dummy_exts = { 0, };
cls_flower.rule = flow_rule_alloc();
if (!cls_flower.rule)
return -ENOMEM;
cls_flower.common.chain_index = chain->index;
cls_flower.command = TC_CLSFLOWER_TMPLT_CREATE;
cls_flower.cookie = (unsigned long) tmplt;
cls_flower.dissector = &tmplt->dissector;
cls_flower.mask = &tmplt->mask;
cls_flower.key = &tmplt->dummy_key;
cls_flower.rule->match.dissector = &tmplt->dissector;
cls_flower.rule->match.mask = &tmplt->mask;
cls_flower.rule->match.key = &tmplt->dummy_key;
cls_flower.exts = &dummy_exts;
/* We don't care if driver (any of them) fails to handle this
* call. It serves just as a hint for it.
*/
tc_setup_cb_call(block, TC_SETUP_CLSFLOWER, &cls_flower, false);
kfree(cls_flower.rule);
return 0;
}
static void fl_hw_destroy_tmplt(struct tcf_chain *chain,
......@@ -1551,12 +1570,14 @@ static void *fl_tmplt_create(struct net *net, struct tcf_chain *chain,
err = fl_set_key(net, tb, &tmplt->dummy_key, &tmplt->mask, extack);
if (err)
goto errout_tmplt;
kfree(tb);
fl_init_dissector(&tmplt->dissector, &tmplt->mask);
fl_hw_create_tmplt(chain, tmplt);
err = fl_hw_create_tmplt(chain, tmplt);
if (err)
goto errout_tmplt;
kfree(tb);
return tmplt;
errout_tmplt:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment