diff options
Diffstat (limited to 'drivers/net/ethernet/microchip/vcap')
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_api.c | 424 | ||||
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_api.h | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_api_client.h | 21 | ||||
-rw-r--r-- | drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c | 592 |
4 files changed, 1030 insertions, 13 deletions
diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c index d255bc7deae7..b6ab6bae28c0 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c @@ -44,6 +44,13 @@ struct vcap_stream_iter { const struct vcap_typegroup *tg; /* current typegroup */ }; +/* Stores the filter cookie that enabled the port */ +struct vcap_enabled_port { + struct list_head list; /* for insertion in enabled ports list */ + struct net_device *ndev; /* the enabled port */ + unsigned long cookie; /* filter that enabled the port */ +}; + static void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width, const struct vcap_typegroup *tg, u32 offset) { @@ -516,7 +523,7 @@ static int vcap_api_check(struct vcap_control *ctrl) !ctrl->ops->add_default_fields || !ctrl->ops->cache_erase || !ctrl->ops->cache_write || !ctrl->ops->cache_read || !ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move || - !ctrl->ops->port_info) { + !ctrl->ops->port_info || !ctrl->ops->enable) { pr_err("%s:%d: client operations are missing\n", __func__, __LINE__); return -ENOENT; @@ -644,6 +651,23 @@ static int vcap_write_rule(struct vcap_rule_internal *ri) return 0; } +/* Convert a chain id to a VCAP lookup index */ +int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid) +{ + int lookup_first = admin->vinst * admin->lookups_per_instance; + int lookup_last = lookup_first + admin->lookups_per_instance; + int cid_next = admin->first_cid + VCAP_CID_LOOKUP_SIZE; + int cid = admin->first_cid; + int lookup; + + for (lookup = lookup_first; lookup < lookup_last; ++lookup, + cid += VCAP_CID_LOOKUP_SIZE, cid_next += VCAP_CID_LOOKUP_SIZE) + if (cur_cid >= cid && cur_cid < cid_next) + return lookup; + return 0; +} +EXPORT_SYMBOL_GPL(vcap_chain_id_to_lookup); + /* Lookup a vcap instance using chain id */ struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid) { @@ -660,6 +684,42 @@ struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid) } EXPORT_SYMBOL_GPL(vcap_find_admin); +/* Is the next chain id in the following lookup, possible in another VCAP */ +bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid) +{ + struct vcap_admin *admin, *next_admin; + int lookup, next_lookup; + + /* The offset must be at least one lookup */ + if (next_cid < cur_cid + VCAP_CID_LOOKUP_SIZE) + return false; + + if (vcap_api_check(vctrl)) + return false; + + admin = vcap_find_admin(vctrl, cur_cid); + if (!admin) + return false; + + /* If no VCAP contains the next chain, the next chain must be beyond + * the last chain in the current VCAP + */ + next_admin = vcap_find_admin(vctrl, next_cid); + if (!next_admin) + return next_cid > admin->last_cid; + + lookup = vcap_chain_id_to_lookup(admin, cur_cid); + next_lookup = vcap_chain_id_to_lookup(next_admin, next_cid); + + /* Next lookup must be the following lookup */ + if (admin == next_admin || admin->vtype == next_admin->vtype) + return next_lookup == lookup + 1; + + /* Must be the first lookup in the next VCAP instance */ + return next_lookup == 0; +} +EXPORT_SYMBOL_GPL(vcap_is_next_lookup); + /* Check if there is room for a new rule */ static int vcap_rule_space(struct vcap_admin *admin, int size) { @@ -704,15 +764,122 @@ static int vcap_add_type_keyfield(struct vcap_rule *rule) return 0; } +/* Add a keyset to a keyset list */ +bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist, + enum vcap_keyfield_set keyset) +{ + int idx; + + if (keysetlist->cnt < keysetlist->max) { + /* Avoid duplicates */ + for (idx = 0; idx < keysetlist->cnt; ++idx) + if (keysetlist->keysets[idx] == keyset) + return keysetlist->cnt < keysetlist->max; + keysetlist->keysets[keysetlist->cnt++] = keyset; + } + return keysetlist->cnt < keysetlist->max; +} +EXPORT_SYMBOL_GPL(vcap_keyset_list_add); + +/* map keyset id to a string with the keyset name */ +const char *vcap_keyset_name(struct vcap_control *vctrl, + enum vcap_keyfield_set keyset) +{ + return vctrl->stats->keyfield_set_names[keyset]; +} +EXPORT_SYMBOL_GPL(vcap_keyset_name); + +/* map key field id to a string with the key name */ +const char *vcap_keyfield_name(struct vcap_control *vctrl, + enum vcap_key_field key) +{ + return vctrl->stats->keyfield_names[key]; +} +EXPORT_SYMBOL_GPL(vcap_keyfield_name); + +/* map action field id to a string with the action name */ +static const char *vcap_actionfield_name(struct vcap_control *vctrl, + enum vcap_action_field action) +{ + return vctrl->stats->actionfield_names[action]; +} + +/* Return the keyfield that matches a key in a keyset */ +static const struct vcap_field * +vcap_find_keyset_keyfield(struct vcap_control *vctrl, + enum vcap_type vtype, + enum vcap_keyfield_set keyset, + enum vcap_key_field key) +{ + const struct vcap_field *fields; + int idx, count; + + fields = vcap_keyfields(vctrl, vtype, keyset); + if (!fields) + return NULL; + + /* Iterate the keyfields of the keyset */ + count = vcap_keyfield_count(vctrl, vtype, keyset); + for (idx = 0; idx < count; ++idx) { + if (fields[idx].width == 0) + continue; + + if (key == idx) + return &fields[idx]; + } + + return NULL; +} + +/* 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) +{ + const struct vcap_client_keyfield *ckf; + int keyset, found, keycount, map_size; + const struct vcap_field **map; + enum vcap_type vtype; + + vtype = ri->admin->vtype; + map = ri->vctrl->vcaps[vtype].keyfield_set_map; + map_size = ri->vctrl->vcaps[vtype].keyfield_set_size; + + /* Get a count of the keyfields we want to match */ + keycount = 0; + list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) + ++keycount; + + matches->cnt = 0; + /* Iterate the keysets of the VCAP */ + for (keyset = 0; keyset < map_size; ++keyset) { + if (!map[keyset]) + continue; + + /* Iterate the keys in the rule */ + found = 0; + list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) + if (vcap_find_keyset_keyfield(ri->vctrl, vtype, + keyset, ckf->ctrl.key)) + ++found; + + /* Save the keyset if all keyfields were found */ + if (found == keycount) + if (!vcap_keyset_list_add(matches, keyset)) + /* bail out when the quota is filled */ + break; + } + + return matches->cnt > 0; +} + /* Validate a rule with respect to available port keys */ int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto) { struct vcap_rule_internal *ri = to_intrule(rule); + struct vcap_keyset_list matches = {}; enum vcap_keyfield_set keysets[10]; - struct vcap_keyset_list kslist; int ret; - /* This validation will be much expanded later */ ret = vcap_api_check(ri->vctrl); if (ret) return ret; @@ -724,24 +891,41 @@ int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto) ri->data.exterr = VCAP_ERR_NO_NETDEV; return -EINVAL; } + + matches.keysets = keysets; + matches.max = ARRAY_SIZE(keysets); if (ri->data.keyset == VCAP_KFS_NO_VALUE) { - ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH; - return -EINVAL; + /* Iterate over rule keyfields and select keysets that fits */ + if (!vcap_rule_find_keysets(ri, &matches)) { + ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH; + return -EINVAL; + } + } else { + /* prepare for keyset validation */ + keysets[0] = ri->data.keyset; + matches.cnt = 1; } - /* prepare for keyset validation */ - keysets[0] = ri->data.keyset; - kslist.keysets = keysets; - kslist.cnt = 1; + /* Pick a keyset that is supported in the port lookups */ - ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule, &kslist, - l3_proto); + ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule, + &matches, l3_proto); if (ret < 0) { pr_err("%s:%d: keyset validation failed: %d\n", __func__, __LINE__, ret); ri->data.exterr = VCAP_ERR_NO_PORT_KEYSET_MATCH; return ret; } + /* use the keyset that is supported in the port lookups */ + ret = vcap_set_rule_set_keyset(rule, ret); + if (ret < 0) { + pr_err("%s:%d: keyset was not updated: %d\n", + __func__, __LINE__, ret); + return ret; + } if (ri->data.actionset == VCAP_AFS_NO_VALUE) { + /* Later also actionsets will be matched against actions in + * the rule, and the type will be set accordingly + */ ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH; return -EINVAL; } @@ -951,6 +1135,7 @@ EXPORT_SYMBOL_GPL(vcap_del_rule); /* Delete all rules in the VCAP instance */ int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin) { + struct vcap_enabled_port *eport, *next_eport; struct vcap_rule_internal *ri, *next_ri; int ret = vcap_api_check(vctrl); @@ -962,6 +1147,13 @@ int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin) kfree(ri); } admin->last_used_addr = admin->last_valid_addr; + + /* Remove list of enabled ports */ + list_for_each_entry_safe(eport, next_eport, &admin->enabled, list) { + list_del(&eport->list); + kfree(eport); + } + return 0; } EXPORT_SYMBOL_GPL(vcap_del_rules); @@ -992,14 +1184,60 @@ static void vcap_copy_from_client_keyfield(struct vcap_rule *rule, memcpy(&field->data, data, sizeof(field->data)); } +/* Check if the keyfield is already in the rule */ +static bool vcap_keyfield_unique(struct vcap_rule *rule, + enum vcap_key_field key) +{ + struct vcap_rule_internal *ri = to_intrule(rule); + const struct vcap_client_keyfield *ckf; + + list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) + if (ckf->ctrl.key == key) + return false; + return true; +} + +/* Check if the keyfield is in the keyset */ +static bool vcap_keyfield_match_keyset(struct vcap_rule *rule, + enum vcap_key_field key) +{ + struct vcap_rule_internal *ri = to_intrule(rule); + enum vcap_keyfield_set keyset = rule->keyset; + enum vcap_type vt = ri->admin->vtype; + const struct vcap_field *fields; + + /* the field is accepted if the rule has no keyset yet */ + if (keyset == VCAP_KFS_NO_VALUE) + return true; + fields = vcap_keyfields(ri->vctrl, vt, keyset); + if (!fields) + return false; + /* if there is a width there is a way */ + return fields[key].width > 0; +} + static int vcap_rule_add_key(struct vcap_rule *rule, enum vcap_key_field key, enum vcap_field_type ftype, struct vcap_client_keyfield_data *data) { + struct vcap_rule_internal *ri = to_intrule(rule); struct vcap_client_keyfield *field; - /* More validation will be added here later */ + if (!vcap_keyfield_unique(rule, key)) { + pr_warn("%s:%d: keyfield %s is already in the rule\n", + __func__, __LINE__, + vcap_keyfield_name(ri->vctrl, key)); + return -EINVAL; + } + + if (!vcap_keyfield_match_keyset(rule, key)) { + pr_err("%s:%d: keyfield %s does not belong in the rule keyset\n", + __func__, __LINE__, + vcap_keyfield_name(ri->vctrl, key)); + return -EINVAL; + } + field = kzalloc(sizeof(*field), GFP_KERNEL); if (!field) return -ENOMEM; @@ -1073,6 +1311,17 @@ int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key, } EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72); +/* Add a 128 bit key with value and mask to the rule */ +int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key, + struct vcap_u128_key *fieldval) +{ + struct vcap_client_keyfield_data data; + + memcpy(&data.u128, fieldval, sizeof(data.u128)); + return vcap_rule_add_key(rule, key, VCAP_FIELD_U128, &data); +} +EXPORT_SYMBOL_GPL(vcap_rule_add_key_u128); + static void vcap_copy_from_client_actionfield(struct vcap_rule *rule, struct vcap_client_actionfield *field, struct vcap_client_actionfield_data *data) @@ -1081,14 +1330,60 @@ static void vcap_copy_from_client_actionfield(struct vcap_rule *rule, memcpy(&field->data, data, sizeof(field->data)); } +/* Check if the actionfield is already in the rule */ +static bool vcap_actionfield_unique(struct vcap_rule *rule, + enum vcap_action_field act) +{ + struct vcap_rule_internal *ri = to_intrule(rule); + const struct vcap_client_actionfield *caf; + + list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) + if (caf->ctrl.action == act) + return false; + return true; +} + +/* Check if the actionfield is in the actionset */ +static bool vcap_actionfield_match_actionset(struct vcap_rule *rule, + enum vcap_action_field action) +{ + enum vcap_actionfield_set actionset = rule->actionset; + struct vcap_rule_internal *ri = to_intrule(rule); + enum vcap_type vt = ri->admin->vtype; + const struct vcap_field *fields; + + /* the field is accepted if the rule has no actionset yet */ + if (actionset == VCAP_AFS_NO_VALUE) + return true; + fields = vcap_actionfields(ri->vctrl, vt, actionset); + if (!fields) + return false; + /* if there is a width there is a way */ + return fields[action].width > 0; +} + static int vcap_rule_add_action(struct vcap_rule *rule, enum vcap_action_field action, enum vcap_field_type ftype, struct vcap_client_actionfield_data *data) { + struct vcap_rule_internal *ri = to_intrule(rule); struct vcap_client_actionfield *field; - /* More validation will be added here later */ + if (!vcap_actionfield_unique(rule, action)) { + pr_warn("%s:%d: actionfield %s is already in the rule\n", + __func__, __LINE__, + vcap_actionfield_name(ri->vctrl, action)); + return -EINVAL; + } + + if (!vcap_actionfield_match_actionset(rule, action)) { + pr_err("%s:%d: actionfield %s does not belong in the rule actionset\n", + __func__, __LINE__, + vcap_actionfield_name(ri->vctrl, action)); + return -EINVAL; + } + field = kzalloc(sizeof(*field), GFP_KERNEL); if (!field) return -ENOMEM; @@ -1179,6 +1474,109 @@ void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule) } EXPORT_SYMBOL_GPL(vcap_set_tc_exterr); +/* Check if this port is already enabled for this VCAP instance */ +static bool vcap_is_enabled(struct vcap_admin *admin, struct net_device *ndev, + unsigned long cookie) +{ + struct vcap_enabled_port *eport; + + list_for_each_entry(eport, &admin->enabled, list) + if (eport->cookie == cookie || eport->ndev == ndev) + return true; + + return false; +} + +/* Enable this port for this VCAP instance */ +static int vcap_enable(struct vcap_admin *admin, struct net_device *ndev, + unsigned long cookie) +{ + struct vcap_enabled_port *eport; + + eport = kzalloc(sizeof(*eport), GFP_KERNEL); + if (!eport) + return -ENOMEM; + + eport->ndev = ndev; + eport->cookie = cookie; + list_add_tail(&eport->list, &admin->enabled); + + return 0; +} + +/* Disable this port for this VCAP instance */ +static int vcap_disable(struct vcap_admin *admin, struct net_device *ndev, + unsigned long cookie) +{ + struct vcap_enabled_port *eport; + + list_for_each_entry(eport, &admin->enabled, list) { + if (eport->cookie == cookie && eport->ndev == ndev) { + list_del(&eport->list); + kfree(eport); + return 0; + } + } + + return -ENOENT; +} + +/* Find the VCAP instance that enabled the port using a specific filter */ +static struct vcap_admin *vcap_find_admin_by_cookie(struct vcap_control *vctrl, + unsigned long cookie) +{ + struct vcap_enabled_port *eport; + struct vcap_admin *admin; + + list_for_each_entry(admin, &vctrl->list, list) + list_for_each_entry(eport, &admin->enabled, list) + if (eport->cookie == cookie) + return admin; + + return NULL; +} + +/* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */ +int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev, + int chain_id, unsigned long cookie, bool enable) +{ + struct vcap_admin *admin; + int err; + + err = vcap_api_check(vctrl); + if (err) + return err; + + if (!ndev) + return -ENODEV; + + if (chain_id) + admin = vcap_find_admin(vctrl, chain_id); + else + admin = vcap_find_admin_by_cookie(vctrl, cookie); + if (!admin) + return -ENOENT; + + /* first instance and first chain */ + if (admin->vinst || chain_id > admin->first_cid) + return -EFAULT; + + err = vctrl->ops->enable(ndev, admin, enable); + if (err) + return err; + + if (chain_id) { + if (vcap_is_enabled(admin, ndev, cookie)) + return -EADDRINUSE; + vcap_enable(admin, ndev, cookie); + } else { + vcap_disable(admin, ndev, cookie); + } + + return 0; +} +EXPORT_SYMBOL_GPL(vcap_enable_lookups); + #ifdef CONFIG_VCAP_KUNIT_TEST #include "vcap_api_kunit.c" #endif diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.h b/drivers/net/ethernet/microchip/vcap/vcap_api.h index eb2eae75c7e8..bfb8ad535074 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.h @@ -166,6 +166,7 @@ enum vcap_rule_error { struct vcap_admin { struct list_head list; /* for insertion in vcap_control */ struct list_head rules; /* list of rules */ + struct list_head enabled; /* list of enabled ports */ enum vcap_type vtype; /* type of vcap */ int vinst; /* instance number within the same type */ int first_cid; /* first chain id in this vcap */ @@ -255,6 +256,11 @@ struct vcap_operations { int (*pf)(void *out, int arg, const char *fmt, ...), void *out, int arg); + /* enable/disable the lookups in a vcap instance */ + int (*enable) + (struct net_device *ndev, + struct vcap_admin *admin, + bool enable); }; /* VCAP API Client control interface */ diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h index 5df6808679ff..0ea5ec96adc8 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_client.h +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_client.h @@ -143,6 +143,10 @@ enum vcap_bit { VCAP_BIT_1 }; +/* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */ +int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev, + int chain_id, unsigned long cookie, bool enable); + /* VCAP rule operations */ /* Allocate a rule and fill in the basic information */ struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl, @@ -176,12 +180,16 @@ int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key, struct vcap_u48_key *fieldval); int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key, struct vcap_u72_key *fieldval); +int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key, + struct vcap_u128_key *fieldval); int vcap_rule_add_action_bit(struct vcap_rule *rule, enum vcap_action_field action, enum vcap_bit val); int vcap_rule_add_action_u32(struct vcap_rule *rule, enum vcap_action_field action, u32 value); /* VCAP lookup operations */ +/* Convert a chain id to a VCAP lookup index */ +int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid); /* Lookup a vcap instance using chain id */ struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid); /* Find information on a key field in a rule */ @@ -189,6 +197,8 @@ const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule, enum vcap_key_field key); /* Find a rule id with a provided cookie */ int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie); +/* Is the next chain id in the following lookup, possible in another VCAP */ +bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid); /* Copy to host byte order */ void vcap_netbytes_copy(u8 *dst, u8 *src, int count); @@ -199,4 +209,15 @@ void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule); /* Cleanup a VCAP instance */ 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); + +/* map keyset id to a string with the keyset name */ +const char *vcap_keyset_name(struct vcap_control *vctrl, + enum vcap_keyfield_set keyset); +/* map key field id to a string with the key name */ +const char *vcap_keyfield_name(struct vcap_control *vctrl, + enum vcap_key_field key); + #endif /* __VCAP_API_CLIENT__ */ diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c index d142ed660338..b0ec51b37683 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c @@ -22,6 +22,7 @@ static u32 test_init_start; static u32 test_init_count; static u32 test_hw_counter_id; static struct vcap_cache_data test_hw_cache; +static struct net_device test_netdev = {}; /* Callback used by the VCAP API */ static enum vcap_keyfield_set test_val_keyset(struct net_device *ndev, @@ -204,6 +205,13 @@ static int vcap_test_port_info(struct net_device *ndev, enum vcap_type vtype, return 0; } +static int vcap_test_enable(struct net_device *ndev, + struct vcap_admin *admin, + bool enable) +{ + return 0; +} + static struct vcap_operations test_callbacks = { .validate_keyset = test_val_keyset, .add_default_fields = test_add_def_fields, @@ -214,6 +222,7 @@ static struct vcap_operations test_callbacks = { .update = test_cache_update, .move = test_cache_move, .port_info = vcap_test_port_info, + .enable = vcap_test_enable, }; static struct vcap_control test_vctrl = { @@ -904,6 +913,586 @@ static void vcap_api_encode_rule_actionset_test(struct kunit *test) KUNIT_EXPECT_EQ(test, (u32)0x00000000, actwords[11]); } +static void vcap_api_rule_add_keyvalue_test(struct kunit *test) +{ + struct vcap_admin admin = { + .vtype = VCAP_TYPE_IS2, + }; + struct vcap_rule_internal ri = { + .admin = &admin, + .data = { + .keyset = VCAP_KFS_NO_VALUE, + }, + .vctrl = &test_vctrl, + }; + struct vcap_rule *rule = (struct vcap_rule *)&ri; + struct vcap_client_keyfield *kf; + int ret; + struct vcap_u128_key dip = { + .value = {0x17, 0x26, 0x35, 0x44, 0x63, 0x62, 0x71}, + .mask = {0xf1, 0xf2, 0xf3, 0xf4, 0x4f, 0x3f, 0x2f, 0x1f}, + }; + int idx; + + INIT_LIST_HEAD(&rule->keyfields); + ret = vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_0); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->keyfields); + KUNIT_EXPECT_EQ(test, false, ret); + kf = list_first_entry(&rule->keyfields, struct vcap_client_keyfield, + ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_KF_LOOKUP_FIRST_IS, kf->ctrl.key); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, kf->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x0, kf->data.u1.value); + KUNIT_EXPECT_EQ(test, 0x1, kf->data.u1.mask); + + INIT_LIST_HEAD(&rule->keyfields); + ret = vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_1); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->keyfields); + KUNIT_EXPECT_EQ(test, false, ret); + kf = list_first_entry(&rule->keyfields, struct vcap_client_keyfield, + ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_KF_LOOKUP_FIRST_IS, kf->ctrl.key); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, kf->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x1, kf->data.u1.value); + KUNIT_EXPECT_EQ(test, 0x1, kf->data.u1.mask); + + INIT_LIST_HEAD(&rule->keyfields); + ret = vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, + VCAP_BIT_ANY); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->keyfields); + KUNIT_EXPECT_EQ(test, false, ret); + kf = list_first_entry(&rule->keyfields, struct vcap_client_keyfield, + ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_KF_LOOKUP_FIRST_IS, kf->ctrl.key); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, kf->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x0, kf->data.u1.value); + KUNIT_EXPECT_EQ(test, 0x0, kf->data.u1.mask); + + INIT_LIST_HEAD(&rule->keyfields); + ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE, 0x98765432, 0xff00ffab); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->keyfields); + KUNIT_EXPECT_EQ(test, false, ret); + kf = list_first_entry(&rule->keyfields, struct vcap_client_keyfield, + ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_KF_TYPE, kf->ctrl.key); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_U32, kf->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x98765432, kf->data.u32.value); + KUNIT_EXPECT_EQ(test, 0xff00ffab, kf->data.u32.mask); + + INIT_LIST_HEAD(&rule->keyfields); + ret = vcap_rule_add_key_u128(rule, VCAP_KF_L3_IP6_SIP, &dip); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->keyfields); + KUNIT_EXPECT_EQ(test, false, ret); + kf = list_first_entry(&rule->keyfields, struct vcap_client_keyfield, + ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_KF_L3_IP6_SIP, kf->ctrl.key); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_U128, kf->ctrl.type); + for (idx = 0; idx < ARRAY_SIZE(dip.value); ++idx) + KUNIT_EXPECT_EQ(test, dip.value[idx], kf->data.u128.value[idx]); + for (idx = 0; idx < ARRAY_SIZE(dip.mask); ++idx) + KUNIT_EXPECT_EQ(test, dip.mask[idx], kf->data.u128.mask[idx]); +} + +static void vcap_api_rule_add_actionvalue_test(struct kunit *test) +{ + struct vcap_admin admin = { + .vtype = VCAP_TYPE_IS2, + }; + struct vcap_rule_internal ri = { + .admin = &admin, + .data = { + .actionset = VCAP_AFS_NO_VALUE, + }, + }; + struct vcap_rule *rule = (struct vcap_rule *)&ri; + struct vcap_client_actionfield *af; + int ret; + + INIT_LIST_HEAD(&rule->actionfields); + ret = vcap_rule_add_action_bit(rule, VCAP_AF_POLICE_ENA, VCAP_BIT_0); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->actionfields); + KUNIT_EXPECT_EQ(test, false, ret); + af = list_first_entry(&rule->actionfields, + struct vcap_client_actionfield, ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_AF_POLICE_ENA, af->ctrl.action); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, af->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x0, af->data.u1.value); + + INIT_LIST_HEAD(&rule->actionfields); + ret = vcap_rule_add_action_bit(rule, VCAP_AF_POLICE_ENA, VCAP_BIT_1); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->actionfields); + KUNIT_EXPECT_EQ(test, false, ret); + af = list_first_entry(&rule->actionfields, + struct vcap_client_actionfield, ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_AF_POLICE_ENA, af->ctrl.action); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, af->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x1, af->data.u1.value); + + INIT_LIST_HEAD(&rule->actionfields); + ret = vcap_rule_add_action_bit(rule, VCAP_AF_POLICE_ENA, VCAP_BIT_ANY); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->actionfields); + KUNIT_EXPECT_EQ(test, false, ret); + af = list_first_entry(&rule->actionfields, + struct vcap_client_actionfield, ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_AF_POLICE_ENA, af->ctrl.action); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, af->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x0, af->data.u1.value); + + INIT_LIST_HEAD(&rule->actionfields); + ret = vcap_rule_add_action_u32(rule, VCAP_AF_TYPE, 0x98765432); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->actionfields); + KUNIT_EXPECT_EQ(test, false, ret); + af = list_first_entry(&rule->actionfields, + struct vcap_client_actionfield, ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_AF_TYPE, af->ctrl.action); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_U32, af->ctrl.type); + KUNIT_EXPECT_EQ(test, 0x98765432, af->data.u32.value); + + INIT_LIST_HEAD(&rule->actionfields); + ret = vcap_rule_add_action_u32(rule, VCAP_AF_MASK_MODE, 0xaabbccdd); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = list_empty(&rule->actionfields); + KUNIT_EXPECT_EQ(test, false, ret); + af = list_first_entry(&rule->actionfields, + struct vcap_client_actionfield, ctrl.list); + KUNIT_EXPECT_EQ(test, VCAP_AF_MASK_MODE, af->ctrl.action); + KUNIT_EXPECT_EQ(test, VCAP_FIELD_U32, af->ctrl.type); + KUNIT_EXPECT_EQ(test, 0xaabbccdd, af->data.u32.value); +} + +static void vcap_api_rule_find_keyset_basic_test(struct kunit *test) +{ + struct vcap_keyset_list matches = {}; + struct vcap_admin admin = { + .vtype = VCAP_TYPE_IS2, + }; + struct vcap_rule_internal ri = { + .admin = &admin, + .vctrl = &test_vctrl, + }; + struct vcap_client_keyfield ckf[] = { + { + .ctrl.key = VCAP_KF_TYPE, + }, { + .ctrl.key = VCAP_KF_LOOKUP_FIRST_IS, + }, { + .ctrl.key = VCAP_KF_IF_IGR_PORT_MASK_L3, + }, { + .ctrl.key = VCAP_KF_IF_IGR_PORT_MASK_RNG, + }, { + .ctrl.key = VCAP_KF_IF_IGR_PORT_MASK, + }, { + .ctrl.key = VCAP_KF_L2_DMAC, + }, { + .ctrl.key = VCAP_KF_ETYPE_LEN_IS, + }, { + .ctrl.key = VCAP_KF_ETYPE, + }, + }; + int idx; + bool ret; + enum vcap_keyfield_set keysets[10] = {}; + + matches.keysets = keysets; + matches.max = ARRAY_SIZE(keysets); + + INIT_LIST_HEAD(&ri.data.keyfields); + 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); + + KUNIT_EXPECT_EQ(test, true, ret); + KUNIT_EXPECT_EQ(test, 1, matches.cnt); + KUNIT_EXPECT_EQ(test, VCAP_KFS_MAC_ETYPE, matches.keysets[0]); +} + +static void vcap_api_rule_find_keyset_failed_test(struct kunit *test) +{ + struct vcap_keyset_list matches = {}; + struct vcap_admin admin = { + .vtype = VCAP_TYPE_IS2, + }; + struct vcap_rule_internal ri = { + .admin = &admin, + .vctrl = &test_vctrl, + }; + struct vcap_client_keyfield ckf[] = { + { + .ctrl.key = VCAP_KF_TYPE, + }, { + .ctrl.key = VCAP_KF_LOOKUP_FIRST_IS, + }, { + .ctrl.key = VCAP_KF_ARP_OPCODE, + }, { + .ctrl.key = VCAP_KF_L3_IP4_SIP, + }, { + .ctrl.key = VCAP_KF_L3_IP4_DIP, + }, { + .ctrl.key = VCAP_KF_8021Q_PCP_CLS, + }, { + .ctrl.key = VCAP_KF_ETYPE_LEN_IS, /* Not with ARP */ + }, { + .ctrl.key = VCAP_KF_ETYPE, /* Not with ARP */ + }, + }; + int idx; + bool ret; + enum vcap_keyfield_set keysets[10] = {}; + + matches.keysets = keysets; + matches.max = ARRAY_SIZE(keysets); + + INIT_LIST_HEAD(&ri.data.keyfields); + 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); + + KUNIT_EXPECT_EQ(test, false, ret); + KUNIT_EXPECT_EQ(test, 0, matches.cnt); + KUNIT_EXPECT_EQ(test, VCAP_KFS_NO_VALUE, matches.keysets[0]); +} + +static void vcap_api_rule_find_keyset_many_test(struct kunit *test) +{ + struct vcap_keyset_list matches = {}; + struct vcap_admin admin = { + .vtype = VCAP_TYPE_IS2, + }; + struct vcap_rule_internal ri = { + .admin = &admin, + .vctrl = &test_vctrl, + }; + struct vcap_client_keyfield ckf[] = { + { + .ctrl.key = VCAP_KF_TYPE, + }, { + .ctrl.key = VCAP_KF_LOOKUP_FIRST_IS, + }, { + .ctrl.key = VCAP_KF_8021Q_DEI_CLS, + }, { + .ctrl.key = VCAP_KF_8021Q_PCP_CLS, + }, { + .ctrl.key = VCAP_KF_8021Q_VID_CLS, + }, { + .ctrl.key = VCAP_KF_ISDX_CLS, + }, { + .ctrl.key = VCAP_KF_L2_MC_IS, + }, { + .ctrl.key = VCAP_KF_L2_BC_IS, + }, + }; + int idx; + bool ret; + enum vcap_keyfield_set keysets[10] = {}; + + matches.keysets = keysets; + matches.max = ARRAY_SIZE(keysets); + + INIT_LIST_HEAD(&ri.data.keyfields); + 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); + + KUNIT_EXPECT_EQ(test, true, ret); + KUNIT_EXPECT_EQ(test, 6, matches.cnt); + KUNIT_EXPECT_EQ(test, VCAP_KFS_ARP, matches.keysets[0]); + KUNIT_EXPECT_EQ(test, VCAP_KFS_IP4_OTHER, matches.keysets[1]); + KUNIT_EXPECT_EQ(test, VCAP_KFS_IP4_TCP_UDP, matches.keysets[2]); + KUNIT_EXPECT_EQ(test, VCAP_KFS_IP6_STD, matches.keysets[3]); + KUNIT_EXPECT_EQ(test, VCAP_KFS_IP_7TUPLE, matches.keysets[4]); + KUNIT_EXPECT_EQ(test, VCAP_KFS_MAC_ETYPE, matches.keysets[5]); +} + +static void vcap_api_encode_rule_test(struct kunit *test) +{ + /* Data used by VCAP Library callback */ + static u32 keydata[32] = {}; + static u32 mskdata[32] = {}; + static u32 actdata[32] = {}; + + struct vcap_admin is2_admin = { + .vtype = VCAP_TYPE_IS2, + .first_cid = 10000, + .last_cid = 19999, + .lookups = 4, + .last_valid_addr = 3071, + .first_valid_addr = 0, + .last_used_addr = 800, + .cache = { + .keystream = keydata, + .maskstream = mskdata, + .actionstream = actdata, + }, + }; + struct vcap_rule *rule = 0; + struct vcap_rule_internal *ri = 0; + int vcap_chain_id = 10005; + enum vcap_user user = VCAP_USER_VCAP_UTIL; + u16 priority = 10; + int id = 100; + int ret; + struct vcap_u48_key smac = { + .value = { 0x88, 0x75, 0x32, 0x34, 0x9e, 0xb1 }, + .mask = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } + }; + struct vcap_u48_key dmac = { + .value = { 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 }, + .mask = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } + }; + u32 port_mask_rng_value = 0x05; + u32 port_mask_rng_mask = 0x0f; + u32 igr_port_mask_value = 0xffabcd01; + u32 igr_port_mask_mask = ~0; + /* counter is not written yet, so it is not in expwriteaddr */ + u32 expwriteaddr[] = {792, 793, 794, 795, 796, 797, 0}; + int idx; + + vcap_test_api_init(&is2_admin); + + /* Allocate the rule */ + rule = vcap_alloc_rule(&test_vctrl, &test_netdev, vcap_chain_id, user, + priority, id); + KUNIT_EXPECT_PTR_NE(test, NULL, rule); + ri = (struct vcap_rule_internal *)rule; + + /* Add rule keys */ + ret = vcap_rule_add_key_u48(rule, VCAP_KF_L2_DMAC, &dmac); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_key_u48(rule, VCAP_KF_L2_SMAC, &smac); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_key_bit(rule, VCAP_KF_ETYPE_LEN_IS, VCAP_BIT_1); + KUNIT_EXPECT_EQ(test, 0, ret); + /* Cannot add the same field twice */ + ret = vcap_rule_add_key_bit(rule, VCAP_KF_ETYPE_LEN_IS, VCAP_BIT_1); + KUNIT_EXPECT_EQ(test, -EINVAL, ret); + ret = vcap_rule_add_key_bit(rule, VCAP_KF_IF_IGR_PORT_MASK_L3, + VCAP_BIT_ANY); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_RNG, + port_mask_rng_value, port_mask_rng_mask); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, + igr_port_mask_value, igr_port_mask_mask); + KUNIT_EXPECT_EQ(test, 0, ret); + + /* Add rule actions */ + ret = vcap_rule_add_action_bit(rule, VCAP_AF_POLICE_ENA, VCAP_BIT_1); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_action_u32(rule, VCAP_AF_CNT_ID, id); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_action_u32(rule, VCAP_AF_MATCH_ID, 1); + KUNIT_EXPECT_EQ(test, 0, ret); + ret = vcap_rule_add_action_u32(rule, VCAP_AF_MATCH_ID_MASK, 1); + KUNIT_EXPECT_EQ(test, 0, ret); + + /* For now the actionset is hardcoded */ + ret = vcap_set_rule_set_actionset(rule, VCAP_AFS_BASE_TYPE); + KUNIT_EXPECT_EQ(test, 0, ret); + + /* Validation with validate keyset callback */ + ret = vcap_val_rule(rule, ETH_P_ALL); + KUNIT_EXPECT_EQ(test, 0, ret); + KUNIT_EXPECT_EQ(test, VCAP_KFS_MAC_ETYPE, rule->keyset); + KUNIT_EXPECT_EQ(test, VCAP_AFS_BASE_TYPE, rule->actionset); + KUNIT_EXPECT_EQ(test, 6, ri->size); + KUNIT_EXPECT_EQ(test, 2, ri->keyset_sw_regs); + KUNIT_EXPECT_EQ(test, 4, ri->actionset_sw_regs); + + /* Add rule with write callback */ + ret = vcap_add_rule(rule); + KUNIT_EXPECT_EQ(test, 0, ret); + KUNIT_EXPECT_EQ(test, 792, is2_admin.last_used_addr); + for (idx = 0; idx < ARRAY_SIZE(expwriteaddr); ++idx) + KUNIT_EXPECT_EQ(test, expwriteaddr[idx], test_updateaddr[idx]); + + /* Check that the rule has been added */ + ret = list_empty(&is2_admin.rules); + KUNIT_EXPECT_EQ(test, false, ret); + KUNIT_EXPECT_EQ(test, 0, ret); + vcap_free_rule(rule); + + /* Check that the rule has been freed: tricky to access since this + * memory should not be accessible anymore + */ + KUNIT_EXPECT_PTR_NE(test, NULL, rule); + ret = list_empty(&rule->keyfields); + KUNIT_EXPECT_EQ(test, true, ret); + ret = list_empty(&rule->actionfields); + KUNIT_EXPECT_EQ(test, true, ret); +} + +static void vcap_api_next_lookup_basic_test(struct kunit *test) +{ + struct vcap_admin admin1 = { + .vtype = VCAP_TYPE_IS2, + .vinst = 0, + .first_cid = 8000000, + .last_cid = 8199999, + .lookups = 4, + .lookups_per_instance = 2, + }; + struct vcap_admin admin2 = { + .vtype = VCAP_TYPE_IS2, + .vinst = 1, + .first_cid = 8200000, + .last_cid = 8399999, + .lookups = 4, + .lookups_per_instance = 2, + }; + bool ret; + + vcap_test_api_init(&admin1); + list_add_tail(&admin2.list, &test_vctrl.list); + + ret = vcap_is_next_lookup(&test_vctrl, 8000000, 1001000); + KUNIT_EXPECT_EQ(test, false, ret); + ret = vcap_is_next_lookup(&test_vctrl, 8000000, 8001000); + KUNIT_EXPECT_EQ(test, false, ret); + ret = vcap_is_next_lookup(&test_vctrl, 8000000, 8101000); + KUNIT_EXPECT_EQ(test, true, ret); + + ret = vcap_is_next_lookup(&test_vctrl, 8100000, 8101000); + KUNIT_EXPECT_EQ(test, false, ret); + ret = vcap_is_next_lookup(&test_vctrl, 8100000, 8201000); + KUNIT_EXPECT_EQ(test, true, ret); + + ret = vcap_is_next_lookup(&test_vctrl, 8200000, 8201000); + KUNIT_EXPECT_EQ(test, false, ret); + ret = vcap_is_next_lookup(&test_vctrl, 8200000, 8301000); + KUNIT_EXPECT_EQ(test, true, ret); + + ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8301000); + KUNIT_EXPECT_EQ(test, false, ret); + ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8401000); + KUNIT_EXPECT_EQ(test, true, ret); +} + +static void vcap_api_next_lookup_advanced_test(struct kunit *test) +{ + struct vcap_admin admin1 = { + .vtype = VCAP_TYPE_IS0, + .vinst = 0, + .first_cid = 1000000, + .last_cid = 1199999, + .lookups = 6, + .lookups_per_instance = 2, + }; + struct vcap_admin admin2 = { + .vtype = VCAP_TYPE_IS0, + .vinst = 1, + .first_cid = 1200000, + .last_cid = 1399999, + .lookups = 6, + .lookups_per_instance = 2, + }; + struct vcap_admin admin3 = { + .vtype = VCAP_TYPE_IS0, + .vinst = 2, + .first_cid = 1400000, + .last_cid = 1599999, + .lookups = 6, + .lookups_per_instance = 2, + }; + struct vcap_admin admin4 = { + .vtype = VCAP_TYPE_IS2, + .vinst = 0, + .first_cid = 8000000, + .last_cid = 8199999, + .lookups = 4, + .lookups_per_instance = 2, + }; + struct vcap_admin admin5 = { + .vtype = VCAP_TYPE_IS2, + .vinst = 1, + .first_cid = 8200000, + .last_cid = 8399999, + .lookups = 4, + .lookups_per_instance = 2, + }; + bool ret; + + vcap_test_api_init(&admin1); + list_add_tail(&admin2.list, &test_vctrl.list); + list_add_tail(&admin3.list, &test_vctrl.list); + list_add_tail(&admin4.list, &test_vctrl.list); + list_add_tail(&admin5.list, &test_vctrl.list); + + ret = vcap_is_next_lookup(&test_vctrl, 1000000, 1001000); + KUNIT_EXPECT_EQ(test, false, ret); + ret = vcap_is_next_lookup(&test_vctrl, 1000000, 1101000); + KUNIT_EXPECT_EQ(test, true, ret); + + ret = vcap_is_next_lookup(&test_vctrl, 1100000, 1201000); + KUNIT_EXPECT_EQ(test, true, ret); + ret = vcap_is_next_lookup(&test_vctrl, 1100000, 1301000); + KUNIT_EXPECT_EQ(test, false, ret); + ret = vcap_is_next_lookup(&test_vctrl, 1100000, 8101000); + KUNIT_EXPECT_EQ(test, false, ret); + ret = vcap_is_next_lookup(&test_vctrl, 1300000, 1401000); + KUNIT_EXPECT_EQ(test, true, ret); + ret = vcap_is_next_lookup(&test_vctrl, 1400000, 1501000); + KUNIT_EXPECT_EQ(test, true, ret); + ret = vcap_is_next_lookup(&test_vctrl, 1500000, 8001000); + KUNIT_EXPECT_EQ(test, true, ret); + + ret = vcap_is_next_lookup(&test_vctrl, 8000000, 8001000); + KUNIT_EXPECT_EQ(test, false, ret); + ret = vcap_is_next_lookup(&test_vctrl, 8000000, 8101000); + KUNIT_EXPECT_EQ(test, true, ret); + + ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8301000); + KUNIT_EXPECT_EQ(test, false, ret); + ret = vcap_is_next_lookup(&test_vctrl, 8300000, 8401000); + KUNIT_EXPECT_EQ(test, true, ret); +} + +static struct kunit_case vcap_api_support_test_cases[] = { + KUNIT_CASE(vcap_api_next_lookup_basic_test), + KUNIT_CASE(vcap_api_next_lookup_advanced_test), + {} +}; + +static struct kunit_suite vcap_api_support_test_suite = { + .name = "VCAP_API_Support_Testsuite", + .test_cases = vcap_api_support_test_cases, +}; + +static struct kunit_case vcap_api_full_rule_test_cases[] = { + KUNIT_CASE(vcap_api_rule_find_keyset_basic_test), + KUNIT_CASE(vcap_api_rule_find_keyset_failed_test), + KUNIT_CASE(vcap_api_rule_find_keyset_many_test), + KUNIT_CASE(vcap_api_encode_rule_test), + {} +}; + +static struct kunit_suite vcap_api_full_rule_test_suite = { + .name = "VCAP_API_Full_Rule_Testsuite", + .test_cases = vcap_api_full_rule_test_cases, +}; + +static struct kunit_case vcap_api_rule_value_test_cases[] = { + KUNIT_CASE(vcap_api_rule_add_keyvalue_test), + KUNIT_CASE(vcap_api_rule_add_actionvalue_test), + {} +}; + +static struct kunit_suite vcap_api_rule_value_test_suite = { + .name = "VCAP_API_Rule_Value_Testsuite", + .test_cases = vcap_api_rule_value_test_cases, +}; + static struct kunit_case vcap_api_encoding_test_cases[] = { KUNIT_CASE(vcap_api_set_bit_1_test), KUNIT_CASE(vcap_api_set_bit_0_test), @@ -930,4 +1519,7 @@ static struct kunit_suite vcap_api_encoding_test_suite = { .test_cases = vcap_api_encoding_test_cases, }; +kunit_test_suite(vcap_api_support_test_suite); +kunit_test_suite(vcap_api_full_rule_test_suite); +kunit_test_suite(vcap_api_rule_value_test_suite); kunit_test_suite(vcap_api_encoding_test_suite); |