net: microchip: sparx5: Support for copying and modifying rules in the API
authorSteen Hegelund <steen.hegelund@microchip.com>
Wed, 23 Nov 2022 15:25:42 +0000 (16:25 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 25 Nov 2022 09:42:13 +0000 (09:42 +0000)
This adds support for making a copy of a rule and modify keys and actions
to differentiate the copy.

Signed-off-by: Steen Hegelund <steen.hegelund@microchip.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/microchip/vcap/vcap_api.c
drivers/net/ethernet/microchip/vcap/vcap_api_client.h
drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c
drivers/net/ethernet/microchip/vcap/vcap_api_private.h

index ac7a32f..2f171d0 100644 (file)
@@ -173,6 +173,7 @@ const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl,
                return NULL;
        return kset;
 }
+EXPORT_SYMBOL_GPL(vcap_keyfieldset);
 
 /* Return the typegroup table for the matching keyset (using subword size) */
 const struct vcap_typegroup *
@@ -824,8 +825,8 @@ vcap_find_keyset_keyfield(struct vcap_control *vctrl,
 }
 
 /* Match a list of keys against the keysets available in a vcap type */
-static bool vcap_rule_find_keysets(struct vcap_rule_internal *ri,
-                                  struct vcap_keyset_list *matches)
+static bool _vcap_rule_find_keysets(struct vcap_rule_internal *ri,
+                                   struct vcap_keyset_list *matches)
 {
        const struct vcap_client_keyfield *ckf;
        int keyset, found, keycount, map_size;
@@ -864,6 +865,16 @@ static bool vcap_rule_find_keysets(struct vcap_rule_internal *ri,
        return matches->cnt > 0;
 }
 
+/* Match a list of keys against the keysets available in a vcap type */
+bool vcap_rule_find_keysets(struct vcap_rule *rule,
+                           struct vcap_keyset_list *matches)
+{
+       struct vcap_rule_internal *ri = to_intrule(rule);
+
+       return _vcap_rule_find_keysets(ri, matches);
+}
+EXPORT_SYMBOL_GPL(vcap_rule_find_keysets);
+
 /* Validate a rule with respect to available port keys */
 int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto)
 {
@@ -888,7 +899,7 @@ int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto)
        matches.max = ARRAY_SIZE(keysets);
        if (ri->data.keyset == VCAP_KFS_NO_VALUE) {
                /* Iterate over rule keyfields and select keysets that fits */
-               if (!vcap_rule_find_keysets(ri, &matches)) {
+               if (!_vcap_rule_find_keysets(ri, &matches)) {
                        ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH;
                        return -EINVAL;
                }
@@ -1270,6 +1281,19 @@ int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin)
 }
 EXPORT_SYMBOL_GPL(vcap_del_rules);
 
+/* Find a client key field in a rule */
+static struct vcap_client_keyfield *
+vcap_find_keyfield(struct vcap_rule *rule, enum vcap_key_field key)
+{
+       struct vcap_rule_internal *ri = to_intrule(rule);
+       struct vcap_client_keyfield *ckf;
+
+       list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list)
+               if (ckf->ctrl.key == key)
+                       return ckf;
+       return NULL;
+}
+
 /* Find information on a key field in a rule */
 const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule,
                                              enum vcap_key_field key)
@@ -1434,6 +1458,19 @@ int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key,
 }
 EXPORT_SYMBOL_GPL(vcap_rule_add_key_u128);
 
+/* Find a client action field in a rule */
+static struct vcap_client_actionfield *
+vcap_find_actionfield(struct vcap_rule *rule, enum vcap_action_field act)
+{
+       struct vcap_rule_internal *ri = (struct vcap_rule_internal *)rule;
+       struct vcap_client_actionfield *caf;
+
+       list_for_each_entry(caf, &ri->data.actionfields, ctrl.list)
+               if (caf->ctrl.action == act)
+                       return caf;
+       return NULL;
+}
+
 static void vcap_copy_from_client_actionfield(struct vcap_rule *rule,
                                              struct vcap_client_actionfield *field,
                                              struct vcap_client_actionfield_data *data)
@@ -1772,6 +1809,148 @@ int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr)
 }
 EXPORT_SYMBOL_GPL(vcap_rule_get_counter);
 
+static int vcap_rule_mod_key(struct vcap_rule *rule,
+                            enum vcap_key_field key,
+                            enum vcap_field_type ftype,
+                            struct vcap_client_keyfield_data *data)
+{
+       struct vcap_client_keyfield *field;
+
+       field = vcap_find_keyfield(rule, key);
+       if (!field)
+               return vcap_rule_add_key(rule, key, ftype, data);
+       vcap_copy_from_client_keyfield(rule, field, data);
+       return 0;
+}
+
+/* Modify a 32 bit key field with value and mask in the rule */
+int vcap_rule_mod_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
+                         u32 value, u32 mask)
+{
+       struct vcap_client_keyfield_data data;
+
+       data.u32.value = value;
+       data.u32.mask = mask;
+       return vcap_rule_mod_key(rule, key, VCAP_FIELD_U32, &data);
+}
+EXPORT_SYMBOL_GPL(vcap_rule_mod_key_u32);
+
+static int vcap_rule_mod_action(struct vcap_rule *rule,
+                               enum vcap_action_field action,
+                               enum vcap_field_type ftype,
+                               struct vcap_client_actionfield_data *data)
+{
+       struct vcap_client_actionfield *field;
+
+       field = vcap_find_actionfield(rule, action);
+       if (!field)
+               return vcap_rule_add_action(rule, action, ftype, data);
+       vcap_copy_from_client_actionfield(rule, field, data);
+       return 0;
+}
+
+/* Modify a 32 bit action field with value in the rule */
+int vcap_rule_mod_action_u32(struct vcap_rule *rule,
+                            enum vcap_action_field action,
+                            u32 value)
+{
+       struct vcap_client_actionfield_data data;
+
+       data.u32.value = value;
+       return vcap_rule_mod_action(rule, action, VCAP_FIELD_U32, &data);
+}
+EXPORT_SYMBOL_GPL(vcap_rule_mod_action_u32);
+
+/* Drop keys in a keylist and any keys that are not supported by the keyset */
+int vcap_filter_rule_keys(struct vcap_rule *rule,
+                         enum vcap_key_field keylist[], int length,
+                         bool drop_unsupported)
+{
+       struct vcap_rule_internal *ri = to_intrule(rule);
+       struct vcap_client_keyfield *ckf, *next_ckf;
+       const struct vcap_field *fields;
+       enum vcap_key_field key;
+       int err = 0;
+       int idx;
+
+       if (length > 0) {
+               err = -EEXIST;
+               list_for_each_entry_safe(ckf, next_ckf,
+                                        &ri->data.keyfields, ctrl.list) {
+                       key = ckf->ctrl.key;
+                       for (idx = 0; idx < length; ++idx)
+                               if (key == keylist[idx]) {
+                                       list_del(&ckf->ctrl.list);
+                                       kfree(ckf);
+                                       idx++;
+                                       err = 0;
+                               }
+               }
+       }
+       if (drop_unsupported) {
+               err = -EEXIST;
+               fields = vcap_keyfields(ri->vctrl, ri->admin->vtype,
+                                       rule->keyset);
+               if (!fields)
+                       return err;
+               list_for_each_entry_safe(ckf, next_ckf,
+                                        &ri->data.keyfields, ctrl.list) {
+                       key = ckf->ctrl.key;
+                       if (fields[key].width == 0) {
+                               list_del(&ckf->ctrl.list);
+                               kfree(ckf);
+                               err = 0;
+                       }
+               }
+       }
+       return err;
+}
+EXPORT_SYMBOL_GPL(vcap_filter_rule_keys);
+
+/* Make a full copy of an existing rule with a new rule id */
+struct vcap_rule *vcap_copy_rule(struct vcap_rule *erule)
+{
+       struct vcap_rule_internal *ri = to_intrule(erule);
+       struct vcap_client_actionfield *caf;
+       struct vcap_client_keyfield *ckf;
+       struct vcap_rule *rule;
+       int err;
+
+       err = vcap_api_check(ri->vctrl);
+       if (err)
+               return ERR_PTR(err);
+
+       rule = vcap_alloc_rule(ri->vctrl, ri->ndev, ri->data.vcap_chain_id,
+                              ri->data.user, ri->data.priority, 0);
+       if (IS_ERR(rule))
+               return rule;
+
+       list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
+               /* Add a key duplicate in the new rule */
+               err = vcap_rule_add_key(rule,
+                                       ckf->ctrl.key,
+                                       ckf->ctrl.type,
+                                       &ckf->data);
+               if (err)
+                       goto err;
+       }
+
+       list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
+               /* Add a action duplicate in the new rule */
+               err = vcap_rule_add_action(rule,
+                                          caf->ctrl.action,
+                                          caf->ctrl.type,
+                                          &caf->data);
+               if (err)
+                       goto err;
+       }
+       return rule;
+err:
+       vcap_free_rule(rule);
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(vcap_copy_rule);
+
 #ifdef CONFIG_VCAP_KUNIT_TEST
 #include "vcap_api_kunit.c"
 #endif
index 654ef8f..93a0fcb 100644 (file)
@@ -168,6 +168,8 @@ int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto);
 int vcap_add_rule(struct vcap_rule *rule);
 /* Delete rule in a VCAP instance */
 int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id);
+/* Make a full copy of an existing rule with a new rule id */
+struct vcap_rule *vcap_copy_rule(struct vcap_rule *rule);
 
 /* Update the keyset for the rule */
 int vcap_set_rule_set_keyset(struct vcap_rule *rule,
@@ -213,7 +215,13 @@ bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid);
 /* Provide all rules via a callback interface */
 int vcap_rule_iter(struct vcap_control *vctrl,
                   int (*callback)(void *, struct vcap_rule *), void *arg);
-
+/* Match a list of keys against the keysets available in a vcap type */
+bool vcap_rule_find_keysets(struct vcap_rule *rule,
+                           struct vcap_keyset_list *matches);
+/* Return the keyset information for the keyset */
+const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl,
+                                       enum vcap_type vt,
+                                       enum vcap_keyfield_set keyset);
 /* Copy to host byte order */
 void vcap_netbytes_copy(u8 *dst, u8 *src, int count);
 
@@ -226,6 +234,10 @@ int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin);
 /* Add a keyset to a keyset list */
 bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist,
                          enum vcap_keyfield_set keyset);
+/* Drop keys in a keylist and any keys that are not supported by the keyset */
+int vcap_filter_rule_keys(struct vcap_rule *rule,
+                         enum vcap_key_field keylist[], int length,
+                         bool drop_unsupported);
 
 /* map keyset id to a string with the keyset name */
 const char *vcap_keyset_name(struct vcap_control *vctrl,
@@ -234,4 +246,12 @@ const char *vcap_keyset_name(struct vcap_control *vctrl,
 const char *vcap_keyfield_name(struct vcap_control *vctrl,
                               enum vcap_key_field key);
 
+/* Modify a 32 bit key field with value and mask in the rule */
+int vcap_rule_mod_key_u32(struct vcap_rule *rule, enum vcap_key_field key,
+                         u32 value, u32 mask);
+/* Modify a 32 bit action field with value in the rule */
+int vcap_rule_mod_action_u32(struct vcap_rule *rule,
+                            enum vcap_action_field action,
+                            u32 value);
+
 #endif /* __VCAP_API_CLIENT__ */
index f48d93f..875068e 100644 (file)
@@ -1197,7 +1197,7 @@ static void vcap_api_rule_find_keyset_basic_test(struct kunit *test)
        for (idx = 0; idx < ARRAY_SIZE(ckf); idx++)
                list_add_tail(&ckf[idx].ctrl.list, &ri.data.keyfields);
 
-       ret = vcap_rule_find_keysets(&ri, &matches);
+       ret = vcap_rule_find_keysets(&ri.data, &matches);
 
        KUNIT_EXPECT_EQ(test, true, ret);
        KUNIT_EXPECT_EQ(test, 1, matches.cnt);
@@ -1244,7 +1244,7 @@ static void vcap_api_rule_find_keyset_failed_test(struct kunit *test)
        for (idx = 0; idx < ARRAY_SIZE(ckf); idx++)
                list_add_tail(&ckf[idx].ctrl.list, &ri.data.keyfields);
 
-       ret = vcap_rule_find_keysets(&ri, &matches);
+       ret = vcap_rule_find_keysets(&ri.data, &matches);
 
        KUNIT_EXPECT_EQ(test, false, ret);
        KUNIT_EXPECT_EQ(test, 0, matches.cnt);
@@ -1291,7 +1291,7 @@ static void vcap_api_rule_find_keyset_many_test(struct kunit *test)
        for (idx = 0; idx < ARRAY_SIZE(ckf); idx++)
                list_add_tail(&ckf[idx].ctrl.list, &ri.data.keyfields);
 
-       ret = vcap_rule_find_keysets(&ri, &matches);
+       ret = vcap_rule_find_keysets(&ri.data, &matches);
 
        KUNIT_EXPECT_EQ(test, true, ret);
        KUNIT_EXPECT_EQ(test, 6, matches.cnt);
index 18a9a0c..9ac1b1d 100644 (file)
@@ -59,10 +59,6 @@ void vcap_iter_update(struct vcap_stream_iter *itr);
 
 /* Keyset and keyfield functionality */
 
-/* Return the keyset information for the keyset */
-const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl,
-                                       enum vcap_type vt,
-                                       enum vcap_keyfield_set keyset);
 /* Return the number of keyfields in the keyset */
 int vcap_keyfield_count(struct vcap_control *vctrl,
                        enum vcap_type vt, enum vcap_keyfield_set keyset);