From 30c4a9f4fe3f47ffa5783329fa5553f8baef3a76 Mon Sep 17 00:00:00 2001 From: Louis Peens Date: Wed, 16 Jun 2021 12:02:07 +0200 Subject: [PATCH] nfp: flower-ct: implement action_merge check Fill in code stub to check that the flow actions are valid for merge. The actions of the flow X should not conflict with the matches of flow X+1. For now this check is quite strict and set_actions are very limited, will need to update this when NAT support is added. Signed-off-by: Louis Peens Signed-off-by: Yinjun Zhang Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- .../ethernet/netronome/nfp/flower/conntrack.c | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/drivers/net/ethernet/netronome/nfp/flower/conntrack.c b/drivers/net/ethernet/netronome/nfp/flower/conntrack.c index 6aecaf41d9cd..9ea77bb3b69c 100644 --- a/drivers/net/ethernet/netronome/nfp/flower/conntrack.c +++ b/drivers/net/ethernet/netronome/nfp/flower/conntrack.c @@ -251,10 +251,129 @@ check_failed: return -EINVAL; } +static int nfp_ct_check_mangle_merge(struct flow_action_entry *a_in, + struct flow_rule *rule) +{ + enum flow_action_mangle_base htype = a_in->mangle.htype; + u32 offset = a_in->mangle.offset; + + switch (htype) { + case FLOW_ACT_MANGLE_HDR_TYPE_ETH: + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) + return -EOPNOTSUPP; + break; + case FLOW_ACT_MANGLE_HDR_TYPE_IP4: + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) { + struct flow_match_ip match; + + flow_rule_match_ip(rule, &match); + if (offset == offsetof(struct iphdr, ttl) && + match.mask->ttl) + return -EOPNOTSUPP; + if (offset == round_down(offsetof(struct iphdr, tos), 4) && + match.mask->tos) + return -EOPNOTSUPP; + } + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) { + struct flow_match_ipv4_addrs match; + + flow_rule_match_ipv4_addrs(rule, &match); + if (offset == offsetof(struct iphdr, saddr) && + match.mask->src) + return -EOPNOTSUPP; + if (offset == offsetof(struct iphdr, daddr) && + match.mask->dst) + return -EOPNOTSUPP; + } + break; + case FLOW_ACT_MANGLE_HDR_TYPE_IP6: + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) { + struct flow_match_ip match; + + flow_rule_match_ip(rule, &match); + if (offset == round_down(offsetof(struct ipv6hdr, hop_limit), 4) && + match.mask->ttl) + return -EOPNOTSUPP; + /* for ipv6, tos and flow_lbl are in the same word */ + if (offset == round_down(offsetof(struct ipv6hdr, flow_lbl), 4) && + match.mask->tos) + return -EOPNOTSUPP; + } + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS)) { + struct flow_match_ipv6_addrs match; + + flow_rule_match_ipv6_addrs(rule, &match); + if (offset >= offsetof(struct ipv6hdr, saddr) && + offset < offsetof(struct ipv6hdr, daddr) && + memchr_inv(&match.mask->src, 0, sizeof(match.mask->src))) + return -EOPNOTSUPP; + if (offset >= offsetof(struct ipv6hdr, daddr) && + offset < sizeof(struct ipv6hdr) && + memchr_inv(&match.mask->dst, 0, sizeof(match.mask->dst))) + return -EOPNOTSUPP; + } + break; + case FLOW_ACT_MANGLE_HDR_TYPE_TCP: + case FLOW_ACT_MANGLE_HDR_TYPE_UDP: + /* currently only can modify ports */ + if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) + return -EOPNOTSUPP; + break; + default: + break; + } + return 0; +} + static int nfp_ct_merge_act_check(struct nfp_fl_ct_flow_entry *pre_ct_entry, struct nfp_fl_ct_flow_entry *post_ct_entry, struct nfp_fl_ct_flow_entry *nft_entry) { + struct flow_action_entry *act; + int err, i; + + /* Check for pre_ct->action conflicts */ + flow_action_for_each(i, act, &pre_ct_entry->rule->action) { + switch (act->id) { + case FLOW_ACTION_MANGLE: + err = nfp_ct_check_mangle_merge(act, nft_entry->rule); + if (err) + return err; + err = nfp_ct_check_mangle_merge(act, post_ct_entry->rule); + if (err) + return err; + break; + case FLOW_ACTION_VLAN_PUSH: + case FLOW_ACTION_VLAN_POP: + case FLOW_ACTION_VLAN_MANGLE: + case FLOW_ACTION_MPLS_PUSH: + case FLOW_ACTION_MPLS_POP: + case FLOW_ACTION_MPLS_MANGLE: + return -EOPNOTSUPP; + default: + break; + } + } + + /* Check for nft->action conflicts */ + flow_action_for_each(i, act, &nft_entry->rule->action) { + switch (act->id) { + case FLOW_ACTION_MANGLE: + err = nfp_ct_check_mangle_merge(act, post_ct_entry->rule); + if (err) + return err; + break; + case FLOW_ACTION_VLAN_PUSH: + case FLOW_ACTION_VLAN_POP: + case FLOW_ACTION_VLAN_MANGLE: + case FLOW_ACTION_MPLS_PUSH: + case FLOW_ACTION_MPLS_POP: + case FLOW_ACTION_MPLS_MANGLE: + return -EOPNOTSUPP; + default: + break; + } + } return 0; }