OSDN Git Service

nfp: flower-ct: fill in ct merge check function
authorLouis Peens <louis.peens@corigine.com>
Wed, 16 Jun 2021 10:02:05 +0000 (12:02 +0200)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 Jun 2021 19:42:52 +0000 (12:42 -0700)
Replace merge check stub code with the actual implementation. This
checks that the match parts of two tc flows does not conflict.
Only overlapping keys needs to be checked, and only the narrowest
masked parts needs to be checked, so each key is masked with the
AND'd result of both masks before comparing.

Signed-off-by: Louis Peens <louis.peens@corigine.com>
Signed-off-by: Yinjun Zhang <yinjun.zhang@corigine.com>
Signed-off-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/flower/conntrack.c
drivers/net/ethernet/netronome/nfp/flower/conntrack.h

index e5d5ce7..8bab890 100644 (file)
@@ -75,7 +75,177 @@ bool is_post_ct_flow(struct flow_cls_offload *flow)
 static int nfp_ct_merge_check(struct nfp_fl_ct_flow_entry *entry1,
                              struct nfp_fl_ct_flow_entry *entry2)
 {
+       unsigned int ovlp_keys = entry1->rule->match.dissector->used_keys &
+                                entry2->rule->match.dissector->used_keys;
+       bool out;
+
+       /* check the overlapped fields one by one, the unmasked part
+        * should not conflict with each other.
+        */
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_CONTROL)) {
+               struct flow_match_control match1, match2;
+
+               flow_rule_match_control(entry1->rule, &match1);
+               flow_rule_match_control(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_BASIC)) {
+               struct flow_match_basic match1, match2;
+
+               flow_rule_match_basic(entry1->rule, &match1);
+               flow_rule_match_basic(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
+               struct flow_match_ipv4_addrs match1, match2;
+
+               flow_rule_match_ipv4_addrs(entry1->rule, &match1);
+               flow_rule_match_ipv4_addrs(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
+               struct flow_match_ipv6_addrs match1, match2;
+
+               flow_rule_match_ipv6_addrs(entry1->rule, &match1);
+               flow_rule_match_ipv6_addrs(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_PORTS)) {
+               struct flow_match_ports match1, match2;
+
+               flow_rule_match_ports(entry1->rule, &match1);
+               flow_rule_match_ports(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
+               struct flow_match_eth_addrs match1, match2;
+
+               flow_rule_match_eth_addrs(entry1->rule, &match1);
+               flow_rule_match_eth_addrs(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_VLAN)) {
+               struct flow_match_vlan match1, match2;
+
+               flow_rule_match_vlan(entry1->rule, &match1);
+               flow_rule_match_vlan(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_MPLS)) {
+               struct flow_match_mpls match1, match2;
+
+               flow_rule_match_mpls(entry1->rule, &match1);
+               flow_rule_match_mpls(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_TCP)) {
+               struct flow_match_tcp match1, match2;
+
+               flow_rule_match_tcp(entry1->rule, &match1);
+               flow_rule_match_tcp(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_IP)) {
+               struct flow_match_ip match1, match2;
+
+               flow_rule_match_ip(entry1->rule, &match1);
+               flow_rule_match_ip(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_KEYID)) {
+               struct flow_match_enc_keyid match1, match2;
+
+               flow_rule_match_enc_keyid(entry1->rule, &match1);
+               flow_rule_match_enc_keyid(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
+               struct flow_match_ipv4_addrs match1, match2;
+
+               flow_rule_match_enc_ipv4_addrs(entry1->rule, &match1);
+               flow_rule_match_enc_ipv4_addrs(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS)) {
+               struct flow_match_ipv6_addrs match1, match2;
+
+               flow_rule_match_enc_ipv6_addrs(entry1->rule, &match1);
+               flow_rule_match_enc_ipv6_addrs(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_CONTROL)) {
+               struct flow_match_control match1, match2;
+
+               flow_rule_match_enc_control(entry1->rule, &match1);
+               flow_rule_match_enc_control(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_IP)) {
+               struct flow_match_ip match1, match2;
+
+               flow_rule_match_enc_ip(entry1->rule, &match1);
+               flow_rule_match_enc_ip(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
+       if (ovlp_keys & BIT(FLOW_DISSECTOR_KEY_ENC_OPTS)) {
+               struct flow_match_enc_opts match1, match2;
+
+               flow_rule_match_enc_opts(entry1->rule, &match1);
+               flow_rule_match_enc_opts(entry2->rule, &match2);
+               COMPARE_UNMASKED_FIELDS(match1, match2, &out);
+               if (out)
+                       goto check_failed;
+       }
+
        return 0;
+
+check_failed:
+       return -EINVAL;
 }
 
 static int nfp_ct_merge_act_check(struct nfp_fl_ct_flow_entry *pre_ct_entry,
index 753a9ee..170b6cd 100644 (file)
@@ -9,6 +9,26 @@
 
 #define NFP_FL_CT_NO_TUN       0xff
 
+#define COMPARE_UNMASKED_FIELDS(__match1, __match2, __out)     \
+       do {                                                    \
+               typeof(__match1) _match1 = (__match1);          \
+               typeof(__match2) _match2 = (__match2);          \
+               bool *_out = (__out);           \
+               int i, size = sizeof(*(_match1).key);           \
+               char *k1, *m1, *k2, *m2;                        \
+               *_out = false;                                  \
+               k1 = (char *)_match1.key;                       \
+               m1 = (char *)_match1.mask;                      \
+               k2 = (char *)_match2.key;                       \
+               m2 = (char *)_match2.mask;                      \
+               for (i = 0; i < size; i++)                      \
+                       if ((k1[i] & m1[i] & m2[i]) ^           \
+                           (k2[i] & m1[i] & m2[i])) {          \
+                               *_out = true;                   \
+                               break;                          \
+                       }                                       \
+       } while (0)                                             \
+
 extern const struct rhashtable_params nfp_zone_table_params;
 extern const struct rhashtable_params nfp_ct_map_params;
 extern const struct rhashtable_params nfp_tc_ct_merge_params;