Commit 610c32b2 authored by Horatiu Vultur's avatar Horatiu Vultur Committed by Paolo Abeni

net: microchip: vcap: Add vcap_get_rule

Add function vcap_get_rule which returns a rule based on the internal
rule id.
The entire functionality of reading and decoding the rule from the VCAP
was inside vcap_api_debugfs file. So move the entire implementation in
vcap_api as this is used also by vcap_get_rule.
Signed-off-by: default avatarHoratiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent c9f8d736
......@@ -169,6 +169,227 @@ static void vcap_encode_typegroups(u32 *stream, int sw_width,
}
}
static bool vcap_bitarray_zero(int width, u8 *value)
{
int bytes = DIV_ROUND_UP(width, BITS_PER_BYTE);
u8 total = 0, bmask = 0xff;
int rwidth = width;
int idx;
for (idx = 0; idx < bytes; ++idx, rwidth -= BITS_PER_BYTE) {
if (rwidth && rwidth < BITS_PER_BYTE)
bmask = (1 << rwidth) - 1;
total += value[idx] & bmask;
}
return total == 0;
}
static bool vcap_get_bit(u32 *stream, struct vcap_stream_iter *itr)
{
u32 mask = BIT(itr->reg_bitpos);
u32 *p = &stream[itr->reg_idx];
return !!(*p & mask);
}
static void vcap_decode_field(u32 *stream, struct vcap_stream_iter *itr,
int width, u8 *value)
{
int idx;
/* Loop over the field value bits and get the field bits and
* set them in the output value byte array
*/
for (idx = 0; idx < width; idx++) {
u8 bidx = idx & 0x7;
/* Decode one field value bit */
if (vcap_get_bit(stream, itr))
*value |= 1 << bidx;
vcap_iter_next(itr);
if (bidx == 7)
value++;
}
}
/* Verify that the type id in the stream matches the type id of the keyset */
static bool vcap_verify_keystream_keyset(struct vcap_control *vctrl,
enum vcap_type vt,
u32 *keystream,
u32 *mskstream,
enum vcap_keyfield_set keyset)
{
const struct vcap_info *vcap = &vctrl->vcaps[vt];
const struct vcap_field *typefld;
const struct vcap_typegroup *tgt;
const struct vcap_field *fields;
struct vcap_stream_iter iter;
const struct vcap_set *info;
u32 value = 0;
u32 mask = 0;
if (vcap_keyfield_count(vctrl, vt, keyset) == 0)
return false;
info = vcap_keyfieldset(vctrl, vt, keyset);
/* Check that the keyset is valid */
if (!info)
return false;
/* a type_id of value -1 means that there is no type field */
if (info->type_id == (u8)-1)
return true;
/* Get a valid typegroup for the specific keyset */
tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
if (!tgt)
return false;
fields = vcap_keyfields(vctrl, vt, keyset);
if (!fields)
return false;
typefld = &fields[VCAP_KF_TYPE];
vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
vcap_decode_field(mskstream, &iter, typefld->width, (u8 *)&mask);
/* no type info if there are no mask bits */
if (vcap_bitarray_zero(typefld->width, (u8 *)&mask))
return false;
/* Get the value of the type field in the stream and compare to the
* one define in the vcap keyset
*/
vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
vcap_decode_field(keystream, &iter, typefld->width, (u8 *)&value);
return (value & mask) == (info->type_id & mask);
}
/* Verify that the typegroup bits have the correct values */
static int vcap_verify_typegroups(u32 *stream, int sw_width,
const struct vcap_typegroup *tgt, bool mask,
int sw_max)
{
struct vcap_stream_iter iter;
int sw_cnt, idx;
vcap_iter_set(&iter, sw_width, tgt, 0);
sw_cnt = 0;
while (iter.tg->width) {
u32 value = 0;
u32 tg_value = iter.tg->value;
if (mask)
tg_value = (1 << iter.tg->width) - 1;
/* Set position to current typegroup bit */
iter.offset = iter.tg->offset;
vcap_iter_update(&iter);
for (idx = 0; idx < iter.tg->width; idx++) {
/* Decode one typegroup bit */
if (vcap_get_bit(stream, &iter))
value |= 1 << idx;
iter.offset++;
vcap_iter_update(&iter);
}
if (value != tg_value)
return -EINVAL;
iter.tg++; /* next typegroup */
sw_cnt++;
/* Stop checking more typegroups */
if (sw_max && sw_cnt >= sw_max)
break;
}
return 0;
}
/* Find the subword width of the key typegroup that matches the stream data */
static int vcap_find_keystream_typegroup_sw(struct vcap_control *vctrl,
enum vcap_type vt, u32 *stream,
bool mask, int sw_max)
{
const struct vcap_typegroup **tgt;
int sw_idx, res;
tgt = vctrl->vcaps[vt].keyfield_set_typegroups;
/* Try the longest subword match first */
for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
if (!tgt[sw_idx])
continue;
res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].sw_width,
tgt[sw_idx], mask, sw_max);
if (res == 0)
return sw_idx;
}
return -EINVAL;
}
/* Verify that the typegroup information, subword count, keyset and type id
* are in sync and correct, return the list of matchin keysets
*/
int
vcap_find_keystream_keysets(struct vcap_control *vctrl,
enum vcap_type vt,
u32 *keystream,
u32 *mskstream,
bool mask, int sw_max,
struct vcap_keyset_list *kslist)
{
const struct vcap_set *keyfield_set;
int sw_count, idx;
sw_count = vcap_find_keystream_typegroup_sw(vctrl, vt, keystream, mask,
sw_max);
if (sw_count < 0)
return sw_count;
keyfield_set = vctrl->vcaps[vt].keyfield_set;
for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
if (keyfield_set[idx].sw_per_item != sw_count)
continue;
if (vcap_verify_keystream_keyset(vctrl, vt, keystream,
mskstream, idx))
vcap_keyset_list_add(kslist, idx);
}
if (kslist->cnt > 0)
return 0;
return -EINVAL;
}
EXPORT_SYMBOL_GPL(vcap_find_keystream_keysets);
/* Read key data from a VCAP address and discover if there are any rule keysets
* here
*/
int vcap_addr_keysets(struct vcap_control *vctrl,
struct net_device *ndev,
struct vcap_admin *admin,
int addr,
struct vcap_keyset_list *kslist)
{
enum vcap_type vt = admin->vtype;
int keyset_sw_regs, idx;
u32 key = 0, mask = 0;
/* Read the cache at the specified address */
keyset_sw_regs = DIV_ROUND_UP(vctrl->vcaps[vt].sw_width, 32);
vctrl->ops->update(ndev, admin, VCAP_CMD_READ, VCAP_SEL_ALL, addr);
vctrl->ops->cache_read(ndev, admin, VCAP_SEL_ENTRY, 0,
keyset_sw_regs);
/* Skip uninitialized key/mask entries */
for (idx = 0; idx < keyset_sw_regs; ++idx) {
key |= ~admin->cache.keystream[idx];
mask |= admin->cache.maskstream[idx];
}
if (key == 0 && mask == 0)
return -EINVAL;
/* Decode and locate the keysets */
return vcap_find_keystream_keysets(vctrl, vt, admin->cache.keystream,
admin->cache.maskstream, false, 0,
kslist);
}
EXPORT_SYMBOL_GPL(vcap_addr_keysets);
/* Return the list of keyfields for the keyset */
const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl,
enum vcap_type vt,
......@@ -618,6 +839,517 @@ struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri)
return duprule;
}
static void vcap_apply_width(u8 *dst, int width, int bytes)
{
u8 bmask;
int idx;
for (idx = 0; idx < bytes; idx++) {
if (width > 0)
if (width < 8)
bmask = (1 << width) - 1;
else
bmask = ~0;
else
bmask = 0;
dst[idx] &= bmask;
width -= 8;
}
}
static void vcap_copy_from_w32be(u8 *dst, u8 *src, int size, int width)
{
int idx, ridx, wstart, nidx;
int tail_bytes = (((size + 4) >> 2) << 2) - size;
for (idx = 0, ridx = size - 1; idx < size; ++idx, --ridx) {
wstart = (idx >> 2) << 2;
nidx = wstart + 3 - (idx & 0x3);
if (nidx >= size)
nidx -= tail_bytes;
dst[nidx] = src[ridx];
}
vcap_apply_width(dst, width, size);
}
static void vcap_copy_action_bit_field(struct vcap_u1_action *field, u8 *value)
{
field->value = (*value) & 0x1;
}
static void vcap_copy_limited_actionfield(u8 *dstvalue, u8 *srcvalue,
int width, int bytes)
{
memcpy(dstvalue, srcvalue, bytes);
vcap_apply_width(dstvalue, width, bytes);
}
static void vcap_copy_to_client_actionfield(struct vcap_rule_internal *ri,
struct vcap_client_actionfield *field,
u8 *value, u16 width)
{
int field_size = actionfield_size_table[field->ctrl.type];
if (ri->admin->w32be) {
switch (field->ctrl.type) {
case VCAP_FIELD_BIT:
vcap_copy_action_bit_field(&field->data.u1, value);
break;
case VCAP_FIELD_U32:
vcap_copy_limited_actionfield((u8 *)&field->data.u32.value,
value,
width, field_size);
break;
case VCAP_FIELD_U48:
vcap_copy_from_w32be(field->data.u48.value, value,
field_size, width);
break;
case VCAP_FIELD_U56:
vcap_copy_from_w32be(field->data.u56.value, value,
field_size, width);
break;
case VCAP_FIELD_U64:
vcap_copy_from_w32be(field->data.u64.value, value,
field_size, width);
break;
case VCAP_FIELD_U72:
vcap_copy_from_w32be(field->data.u72.value, value,
field_size, width);
break;
case VCAP_FIELD_U112:
vcap_copy_from_w32be(field->data.u112.value, value,
field_size, width);
break;
case VCAP_FIELD_U128:
vcap_copy_from_w32be(field->data.u128.value, value,
field_size, width);
break;
};
} else {
switch (field->ctrl.type) {
case VCAP_FIELD_BIT:
vcap_copy_action_bit_field(&field->data.u1, value);
break;
case VCAP_FIELD_U32:
vcap_copy_limited_actionfield((u8 *)&field->data.u32.value,
value,
width, field_size);
break;
case VCAP_FIELD_U48:
vcap_copy_limited_actionfield(field->data.u48.value,
value,
width, field_size);
break;
case VCAP_FIELD_U56:
vcap_copy_limited_actionfield(field->data.u56.value,
value,
width, field_size);
break;
case VCAP_FIELD_U64:
vcap_copy_limited_actionfield(field->data.u64.value,
value,
width, field_size);
break;
case VCAP_FIELD_U72:
vcap_copy_limited_actionfield(field->data.u72.value,
value,
width, field_size);
break;
case VCAP_FIELD_U112:
vcap_copy_limited_actionfield(field->data.u112.value,
value,
width, field_size);
break;
case VCAP_FIELD_U128:
vcap_copy_limited_actionfield(field->data.u128.value,
value,
width, field_size);
break;
};
}
}
static void vcap_copy_key_bit_field(struct vcap_u1_key *field,
u8 *value, u8 *mask)
{
field->value = (*value) & 0x1;
field->mask = (*mask) & 0x1;
}
static void vcap_copy_limited_keyfield(u8 *dstvalue, u8 *dstmask,
u8 *srcvalue, u8 *srcmask,
int width, int bytes)
{
memcpy(dstvalue, srcvalue, bytes);
vcap_apply_width(dstvalue, width, bytes);
memcpy(dstmask, srcmask, bytes);
vcap_apply_width(dstmask, width, bytes);
}
static void vcap_copy_to_client_keyfield(struct vcap_rule_internal *ri,
struct vcap_client_keyfield *field,
u8 *value, u8 *mask, u16 width)
{
int field_size = keyfield_size_table[field->ctrl.type] / 2;
if (ri->admin->w32be) {
switch (field->ctrl.type) {
case VCAP_FIELD_BIT:
vcap_copy_key_bit_field(&field->data.u1, value, mask);
break;
case VCAP_FIELD_U32:
vcap_copy_limited_keyfield((u8 *)&field->data.u32.value,
(u8 *)&field->data.u32.mask,
value, mask,
width, field_size);
break;
case VCAP_FIELD_U48:
vcap_copy_from_w32be(field->data.u48.value, value,
field_size, width);
vcap_copy_from_w32be(field->data.u48.mask, mask,
field_size, width);
break;
case VCAP_FIELD_U56:
vcap_copy_from_w32be(field->data.u56.value, value,
field_size, width);
vcap_copy_from_w32be(field->data.u56.mask, mask,
field_size, width);
break;
case VCAP_FIELD_U64:
vcap_copy_from_w32be(field->data.u64.value, value,
field_size, width);
vcap_copy_from_w32be(field->data.u64.mask, mask,
field_size, width);
break;
case VCAP_FIELD_U72:
vcap_copy_from_w32be(field->data.u72.value, value,
field_size, width);
vcap_copy_from_w32be(field->data.u72.mask, mask,
field_size, width);
break;
case VCAP_FIELD_U112:
vcap_copy_from_w32be(field->data.u112.value, value,
field_size, width);
vcap_copy_from_w32be(field->data.u112.mask, mask,
field_size, width);
break;
case VCAP_FIELD_U128:
vcap_copy_from_w32be(field->data.u128.value, value,
field_size, width);
vcap_copy_from_w32be(field->data.u128.mask, mask,
field_size, width);
break;
};
} else {
switch (field->ctrl.type) {
case VCAP_FIELD_BIT:
vcap_copy_key_bit_field(&field->data.u1, value, mask);
break;
case VCAP_FIELD_U32:
vcap_copy_limited_keyfield((u8 *)&field->data.u32.value,
(u8 *)&field->data.u32.mask,
value, mask,
width, field_size);
break;
case VCAP_FIELD_U48:
vcap_copy_limited_keyfield(field->data.u48.value,
field->data.u48.mask,
value, mask,
width, field_size);
break;
case VCAP_FIELD_U56:
vcap_copy_limited_keyfield(field->data.u56.value,
field->data.u56.mask,
value, mask,
width, field_size);
break;
case VCAP_FIELD_U64:
vcap_copy_limited_keyfield(field->data.u64.value,
field->data.u64.mask,
value, mask,
width, field_size);
break;
case VCAP_FIELD_U72:
vcap_copy_limited_keyfield(field->data.u72.value,
field->data.u72.mask,
value, mask,
width, field_size);
break;
case VCAP_FIELD_U112:
vcap_copy_limited_keyfield(field->data.u112.value,
field->data.u112.mask,
value, mask,
width, field_size);
break;
case VCAP_FIELD_U128:
vcap_copy_limited_keyfield(field->data.u128.value,
field->data.u128.mask,
value, mask,
width, field_size);
break;
};
}
}
static void vcap_rule_alloc_keyfield(struct vcap_rule_internal *ri,
const struct vcap_field *keyfield,
enum vcap_key_field key,
u8 *value, u8 *mask)
{
struct vcap_client_keyfield *field;
field = kzalloc(sizeof(*field), GFP_KERNEL);
if (!field)
return;
INIT_LIST_HEAD(&field->ctrl.list);
field->ctrl.key = key;
field->ctrl.type = keyfield->type;
vcap_copy_to_client_keyfield(ri, field, value, mask, keyfield->width);
list_add_tail(&field->ctrl.list, &ri->data.keyfields);
}
/* Read key data from a VCAP address and discover if there is a rule keyset
* here
*/
static bool
vcap_verify_actionstream_actionset(struct vcap_control *vctrl,
enum vcap_type vt,
u32 *actionstream,
enum vcap_actionfield_set actionset)
{
const struct vcap_typegroup *tgt;
const struct vcap_field *fields;
const struct vcap_set *info;
if (vcap_actionfield_count(vctrl, vt, actionset) == 0)
return false;
info = vcap_actionfieldset(vctrl, vt, actionset);
/* Check that the actionset is valid */
if (!info)
return false;
/* a type_id of value -1 means that there is no type field */
if (info->type_id == (u8)-1)
return true;
/* Get a valid typegroup for the specific actionset */
tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
if (!tgt)
return false;
fields = vcap_actionfields(vctrl, vt, actionset);
if (!fields)
return false;
/* Later this will be expanded with a check of the type id */
return true;
}
/* Find the subword width of the action typegroup that matches the stream data
*/
static int vcap_find_actionstream_typegroup_sw(struct vcap_control *vctrl,
enum vcap_type vt, u32 *stream,
int sw_max)
{
const struct vcap_typegroup **tgt;
int sw_idx, res;
tgt = vctrl->vcaps[vt].actionfield_set_typegroups;
/* Try the longest subword match first */
for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
if (!tgt[sw_idx])
continue;
res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].act_width,
tgt[sw_idx], false, sw_max);
if (res == 0)
return sw_idx;
}
return -EINVAL;
}
/* Verify that the typegroup information, subword count, actionset and type id
* are in sync and correct, return the actionset
*/
static enum vcap_actionfield_set
vcap_find_actionstream_actionset(struct vcap_control *vctrl,
enum vcap_type vt,
u32 *stream,
int sw_max)
{
const struct vcap_set *actionfield_set;
int sw_count, idx;
bool res;
sw_count = vcap_find_actionstream_typegroup_sw(vctrl, vt, stream,
sw_max);
if (sw_count < 0)
return sw_count;
actionfield_set = vctrl->vcaps[vt].actionfield_set;
for (idx = 0; idx < vctrl->vcaps[vt].actionfield_set_size; ++idx) {
if (actionfield_set[idx].sw_per_item != sw_count)
continue;
res = vcap_verify_actionstream_actionset(vctrl, vt,
stream, idx);
if (res)
return idx;
}
return -EINVAL;
}
/* Store action value in an element in a list for the client */
static void vcap_rule_alloc_actionfield(struct vcap_rule_internal *ri,
const struct vcap_field *actionfield,
enum vcap_action_field action,
u8 *value)
{
struct vcap_client_actionfield *field;
field = kzalloc(sizeof(*field), GFP_KERNEL);
if (!field)
return;
INIT_LIST_HEAD(&field->ctrl.list);
field->ctrl.action = action;
field->ctrl.type = actionfield->type;
vcap_copy_to_client_actionfield(ri, field, value, actionfield->width);
list_add_tail(&field->ctrl.list, &ri->data.actionfields);
}
static int vcap_decode_actionset(struct vcap_rule_internal *ri)
{
struct vcap_control *vctrl = ri->vctrl;
struct vcap_admin *admin = ri->admin;
const struct vcap_field *actionfield;
enum vcap_actionfield_set actionset;
enum vcap_type vt = admin->vtype;
const struct vcap_typegroup *tgt;
struct vcap_stream_iter iter;
int idx, res, actfield_count;
u32 *actstream;
u8 value[16];
actstream = admin->cache.actionstream;
res = vcap_find_actionstream_actionset(vctrl, vt, actstream, 0);
if (res < 0) {
pr_err("%s:%d: could not find valid actionset: %d\n",
__func__, __LINE__, res);
return -EINVAL;
}
actionset = res;
actfield_count = vcap_actionfield_count(vctrl, vt, actionset);
actionfield = vcap_actionfields(vctrl, vt, actionset);
tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
/* Start decoding the stream */
for (idx = 0; idx < actfield_count; ++idx) {
if (actionfield[idx].width <= 0)
continue;
/* Get the action */
memset(value, 0, DIV_ROUND_UP(actionfield[idx].width, 8));
vcap_iter_init(&iter, vctrl->vcaps[vt].act_width, tgt,
actionfield[idx].offset);
vcap_decode_field(actstream, &iter, actionfield[idx].width,
value);
/* Skip if no bits are set */
if (vcap_bitarray_zero(actionfield[idx].width, value))
continue;
vcap_rule_alloc_actionfield(ri, &actionfield[idx], idx, value);
/* Later the action id will also be checked */
}
return vcap_set_rule_set_actionset((struct vcap_rule *)ri, actionset);
}
static int vcap_decode_keyset(struct vcap_rule_internal *ri)
{
struct vcap_control *vctrl = ri->vctrl;
struct vcap_stream_iter kiter, miter;
struct vcap_admin *admin = ri->admin;
enum vcap_keyfield_set keysets[10];
const struct vcap_field *keyfield;
enum vcap_type vt = admin->vtype;
const struct vcap_typegroup *tgt;
struct vcap_keyset_list matches;
enum vcap_keyfield_set keyset;
int idx, res, keyfield_count;
u32 *maskstream;
u32 *keystream;
u8 value[16];
u8 mask[16];
keystream = admin->cache.keystream;
maskstream = admin->cache.maskstream;
matches.keysets = keysets;
matches.cnt = 0;
matches.max = ARRAY_SIZE(keysets);
res = vcap_find_keystream_keysets(vctrl, vt, keystream, maskstream,
false, 0, &matches);
if (res < 0) {
pr_err("%s:%d: could not find valid keysets: %d\n",
__func__, __LINE__, res);
return -EINVAL;
}
keyset = matches.keysets[0];
keyfield_count = vcap_keyfield_count(vctrl, vt, keyset);
keyfield = vcap_keyfields(vctrl, vt, keyset);
tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
/* Start decoding the streams */
for (idx = 0; idx < keyfield_count; ++idx) {
if (keyfield[idx].width <= 0)
continue;
/* First get the mask */
memset(mask, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
vcap_iter_init(&miter, vctrl->vcaps[vt].sw_width, tgt,
keyfield[idx].offset);
vcap_decode_field(maskstream, &miter, keyfield[idx].width,
mask);
/* Skip if no mask bits are set */
if (vcap_bitarray_zero(keyfield[idx].width, mask))
continue;
/* Get the key */
memset(value, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
vcap_iter_init(&kiter, vctrl->vcaps[vt].sw_width, tgt,
keyfield[idx].offset);
vcap_decode_field(keystream, &kiter, keyfield[idx].width,
value);
vcap_rule_alloc_keyfield(ri, &keyfield[idx], idx, value, mask);
}
return vcap_set_rule_set_keyset((struct vcap_rule *)ri, keyset);
}
/* Read VCAP content into the VCAP cache */
static int vcap_read_rule(struct vcap_rule_internal *ri)
{
struct vcap_admin *admin = ri->admin;
int sw_idx, ent_idx = 0, act_idx = 0;
u32 addr = ri->addr;
if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
return -EINVAL;
}
vcap_erase_cache(ri);
/* Use the values in the streams to read the VCAP cache */
for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ,
VCAP_SEL_ALL, addr);
ri->vctrl->ops->cache_read(ri->ndev, admin,
VCAP_SEL_ENTRY, ent_idx,
ri->keyset_sw_regs);
ri->vctrl->ops->cache_read(ri->ndev, admin,
VCAP_SEL_ACTION, act_idx,
ri->actionset_sw_regs);
if (sw_idx == 0)
ri->vctrl->ops->cache_read(ri->ndev, admin,
VCAP_SEL_COUNTER,
ri->counter_id, 0);
ent_idx += ri->keyset_sw_regs;
act_idx += ri->actionset_sw_regs;
}
return 0;
}
/* Write VCAP cache content to the VCAP HW instance */
static int vcap_write_rule(struct vcap_rule_internal *ri)
{
......@@ -1183,6 +1915,46 @@ void vcap_free_rule(struct vcap_rule *rule)
}
EXPORT_SYMBOL_GPL(vcap_free_rule);
struct vcap_rule *vcap_get_rule(struct vcap_control *vctrl, u32 id)
{
struct vcap_rule_internal *elem;
struct vcap_rule_internal *ri;
int err;
ri = NULL;
err = vcap_api_check(vctrl);
if (err)
return ERR_PTR(err);
elem = vcap_lookup_rule(vctrl, id);
if (!elem)
return NULL;
mutex_lock(&elem->admin->lock);
ri = vcap_dup_rule(elem);
if (IS_ERR(ri))
goto unlock;
err = vcap_read_rule(ri);
if (err) {
ri = ERR_PTR(err);
goto unlock;
}
err = vcap_decode_keyset(ri);
if (err) {
ri = ERR_PTR(err);
goto unlock;
}
err = vcap_decode_actionset(ri);
if (err) {
ri = ERR_PTR(err);
goto unlock;
}
unlock:
mutex_unlock(&elem->admin->lock);
return (struct vcap_rule *)ri;
}
EXPORT_SYMBOL_GPL(vcap_get_rule);
/* Return the alignment offset for a new rule address */
static int vcap_valid_rule_move(struct vcap_rule_internal *el, int offset)
{
......
......@@ -170,6 +170,8 @@ int vcap_add_rule(struct vcap_rule *rule);
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);
/* Get rule from a VCAP instance */
struct vcap_rule *vcap_get_rule(struct vcap_control *vctrl, u32 id);
/* Update the keyset for the rule */
int vcap_set_rule_set_keyset(struct vcap_rule *rule,
......
......@@ -18,355 +18,15 @@ struct vcap_port_debugfs_info {
struct net_device *ndev;
};
static bool vcap_bitarray_zero(int width, u8 *value)
{
int bytes = DIV_ROUND_UP(width, BITS_PER_BYTE);
u8 total = 0, bmask = 0xff;
int rwidth = width;
int idx;
for (idx = 0; idx < bytes; ++idx, rwidth -= BITS_PER_BYTE) {
if (rwidth && rwidth < BITS_PER_BYTE)
bmask = (1 << rwidth) - 1;
total += value[idx] & bmask;
}
return total == 0;
}
static bool vcap_get_bit(u32 *stream, struct vcap_stream_iter *itr)
{
u32 mask = BIT(itr->reg_bitpos);
u32 *p = &stream[itr->reg_idx];
return !!(*p & mask);
}
static void vcap_decode_field(u32 *stream, struct vcap_stream_iter *itr,
int width, u8 *value)
{
int idx;
/* Loop over the field value bits and get the field bits and
* set them in the output value byte array
*/
for (idx = 0; idx < width; idx++) {
u8 bidx = idx & 0x7;
/* Decode one field value bit */
if (vcap_get_bit(stream, itr))
*value |= 1 << bidx;
vcap_iter_next(itr);
if (bidx == 7)
value++;
}
}
/* Verify that the typegroup bits have the correct values */
static int vcap_verify_typegroups(u32 *stream, int sw_width,
const struct vcap_typegroup *tgt, bool mask,
int sw_max)
{
struct vcap_stream_iter iter;
int sw_cnt, idx;
vcap_iter_set(&iter, sw_width, tgt, 0);
sw_cnt = 0;
while (iter.tg->width) {
u32 value = 0;
u32 tg_value = iter.tg->value;
if (mask)
tg_value = (1 << iter.tg->width) - 1;
/* Set position to current typegroup bit */
iter.offset = iter.tg->offset;
vcap_iter_update(&iter);
for (idx = 0; idx < iter.tg->width; idx++) {
/* Decode one typegroup bit */
if (vcap_get_bit(stream, &iter))
value |= 1 << idx;
iter.offset++;
vcap_iter_update(&iter);
}
if (value != tg_value)
return -EINVAL;
iter.tg++; /* next typegroup */
sw_cnt++;
/* Stop checking more typegroups */
if (sw_max && sw_cnt >= sw_max)
break;
}
return 0;
}
/* Find the subword width of the key typegroup that matches the stream data */
static int vcap_find_keystream_typegroup_sw(struct vcap_control *vctrl,
enum vcap_type vt, u32 *stream,
bool mask, int sw_max)
{
const struct vcap_typegroup **tgt;
int sw_idx, res;
tgt = vctrl->vcaps[vt].keyfield_set_typegroups;
/* Try the longest subword match first */
for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
if (!tgt[sw_idx])
continue;
res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].sw_width,
tgt[sw_idx], mask, sw_max);
if (res == 0)
return sw_idx;
}
return -EINVAL;
}
/* Find the subword width of the action typegroup that matches the stream data
*/
static int vcap_find_actionstream_typegroup_sw(struct vcap_control *vctrl,
enum vcap_type vt, u32 *stream,
int sw_max)
{
const struct vcap_typegroup **tgt;
int sw_idx, res;
tgt = vctrl->vcaps[vt].actionfield_set_typegroups;
/* Try the longest subword match first */
for (sw_idx = vctrl->vcaps[vt].sw_count; sw_idx >= 0; sw_idx--) {
if (!tgt[sw_idx])
continue;
res = vcap_verify_typegroups(stream, vctrl->vcaps[vt].act_width,
tgt[sw_idx], false, sw_max);
if (res == 0)
return sw_idx;
}
return -EINVAL;
}
/* Verify that the type id in the stream matches the type id of the keyset */
static bool vcap_verify_keystream_keyset(struct vcap_control *vctrl,
enum vcap_type vt,
u32 *keystream,
u32 *mskstream,
enum vcap_keyfield_set keyset)
{
const struct vcap_info *vcap = &vctrl->vcaps[vt];
const struct vcap_field *typefld;
const struct vcap_typegroup *tgt;
const struct vcap_field *fields;
struct vcap_stream_iter iter;
const struct vcap_set *info;
u32 value = 0;
u32 mask = 0;
if (vcap_keyfield_count(vctrl, vt, keyset) == 0)
return false;
info = vcap_keyfieldset(vctrl, vt, keyset);
/* Check that the keyset is valid */
if (!info)
return false;
/* a type_id of value -1 means that there is no type field */
if (info->type_id == (u8)-1)
return true;
/* Get a valid typegroup for the specific keyset */
tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
if (!tgt)
return false;
fields = vcap_keyfields(vctrl, vt, keyset);
if (!fields)
return false;
typefld = &fields[VCAP_KF_TYPE];
vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
vcap_decode_field(mskstream, &iter, typefld->width, (u8 *)&mask);
/* no type info if there are no mask bits */
if (vcap_bitarray_zero(typefld->width, (u8 *)&mask))
return false;
/* Get the value of the type field in the stream and compare to the
* one define in the vcap keyset
*/
vcap_iter_init(&iter, vcap->sw_width, tgt, typefld->offset);
vcap_decode_field(keystream, &iter, typefld->width, (u8 *)&value);
return (value & mask) == (info->type_id & mask);
}
/* Verify that the typegroup information, subword count, keyset and type id
* are in sync and correct, return the list of matching keysets
*/
static int
vcap_find_keystream_keysets(struct vcap_control *vctrl,
enum vcap_type vt,
u32 *keystream,
u32 *mskstream,
bool mask, int sw_max,
struct vcap_keyset_list *kslist)
{
const struct vcap_set *keyfield_set;
int sw_count, idx;
sw_count = vcap_find_keystream_typegroup_sw(vctrl, vt, keystream, mask,
sw_max);
if (sw_count < 0)
return sw_count;
keyfield_set = vctrl->vcaps[vt].keyfield_set;
for (idx = 0; idx < vctrl->vcaps[vt].keyfield_set_size; ++idx) {
if (keyfield_set[idx].sw_per_item != sw_count)
continue;
if (vcap_verify_keystream_keyset(vctrl, vt, keystream,
mskstream, idx))
vcap_keyset_list_add(kslist, idx);
}
if (kslist->cnt > 0)
return 0;
return -EINVAL;
}
/* Read key data from a VCAP address and discover if there is a rule keyset
* here
*/
static bool
vcap_verify_actionstream_actionset(struct vcap_control *vctrl,
enum vcap_type vt,
u32 *actionstream,
enum vcap_actionfield_set actionset)
{
const struct vcap_typegroup *tgt;
const struct vcap_field *fields;
const struct vcap_set *info;
if (vcap_actionfield_count(vctrl, vt, actionset) == 0)
return false;
info = vcap_actionfieldset(vctrl, vt, actionset);
/* Check that the actionset is valid */
if (!info)
return false;
/* a type_id of value -1 means that there is no type field */
if (info->type_id == (u8)-1)
return true;
/* Get a valid typegroup for the specific actionset */
tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
if (!tgt)
return false;
fields = vcap_actionfields(vctrl, vt, actionset);
if (!fields)
return false;
/* Later this will be expanded with a check of the type id */
return true;
}
/* Verify that the typegroup information, subword count, actionset and type id
* are in sync and correct, return the actionset
*/
static enum vcap_actionfield_set
vcap_find_actionstream_actionset(struct vcap_control *vctrl,
enum vcap_type vt,
u32 *stream,
int sw_max)
{
const struct vcap_set *actionfield_set;
int sw_count, idx;
bool res;
sw_count = vcap_find_actionstream_typegroup_sw(vctrl, vt, stream,
sw_max);
if (sw_count < 0)
return sw_count;
actionfield_set = vctrl->vcaps[vt].actionfield_set;
for (idx = 0; idx < vctrl->vcaps[vt].actionfield_set_size; ++idx) {
if (actionfield_set[idx].sw_per_item != sw_count)
continue;
res = vcap_verify_actionstream_actionset(vctrl, vt,
stream, idx);
if (res)
return idx;
}
return -EINVAL;
}
/* Read key data from a VCAP address and discover if there are any rule keysets
* here
*/
static int vcap_addr_keysets(struct vcap_control *vctrl,
struct net_device *ndev,
struct vcap_admin *admin,
int addr,
struct vcap_keyset_list *kslist)
{
enum vcap_type vt = admin->vtype;
int keyset_sw_regs, idx;
u32 key = 0, mask = 0;
/* Read the cache at the specified address */
keyset_sw_regs = DIV_ROUND_UP(vctrl->vcaps[vt].sw_width, 32);
vctrl->ops->update(ndev, admin, VCAP_CMD_READ, VCAP_SEL_ALL, addr);
vctrl->ops->cache_read(ndev, admin, VCAP_SEL_ENTRY, 0,
keyset_sw_regs);
/* Skip uninitialized key/mask entries */
for (idx = 0; idx < keyset_sw_regs; ++idx) {
key |= ~admin->cache.keystream[idx];
mask |= admin->cache.maskstream[idx];
}
if (key == 0 && mask == 0)
return -EINVAL;
/* Decode and locate the keysets */
return vcap_find_keystream_keysets(vctrl, vt, admin->cache.keystream,
admin->cache.maskstream, false, 0,
kslist);
}
static int vcap_read_rule(struct vcap_rule_internal *ri)
{
struct vcap_admin *admin = ri->admin;
int sw_idx, ent_idx = 0, act_idx = 0;
u32 addr = ri->addr;
if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) {
pr_err("%s:%d: rule is empty\n", __func__, __LINE__);
return -EINVAL;
}
vcap_erase_cache(ri);
/* Use the values in the streams to read the VCAP cache */
for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) {
ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ,
VCAP_SEL_ALL, addr);
ri->vctrl->ops->cache_read(ri->ndev, admin,
VCAP_SEL_ENTRY, ent_idx,
ri->keyset_sw_regs);
ri->vctrl->ops->cache_read(ri->ndev, admin,
VCAP_SEL_ACTION, act_idx,
ri->actionset_sw_regs);
if (sw_idx == 0)
ri->vctrl->ops->cache_read(ri->ndev, admin,
VCAP_SEL_COUNTER,
ri->counter_id, 0);
ent_idx += ri->keyset_sw_regs;
act_idx += ri->actionset_sw_regs;
}
return 0;
}
/* Dump the keyfields value and mask values */
static void vcap_debugfs_show_rule_keyfield(struct vcap_control *vctrl,
struct vcap_output_print *out,
enum vcap_key_field key,
const struct vcap_field *keyfield,
u8 *value, u8 *mask)
struct vcap_client_keyfield_data *data)
{
bool hex = false;
u8 *value, *mask;
int idx, bytes;
out->prf(out->dst, " %s: W%d: ", vcap_keyfield_name(vctrl, key),
......@@ -374,40 +34,62 @@ static void vcap_debugfs_show_rule_keyfield(struct vcap_control *vctrl,
switch (keyfield[key].type) {
case VCAP_FIELD_BIT:
out->prf(out->dst, "%d/%d", value[0], mask[0]);
out->prf(out->dst, "%d/%d", data->u1.value, data->u1.mask);
break;
case VCAP_FIELD_U32:
value = (u8 *)(&data->u32.value);
mask = (u8 *)(&data->u32.mask);
if (key == VCAP_KF_L3_IP4_SIP || key == VCAP_KF_L3_IP4_DIP) {
out->prf(out->dst, "%pI4h/%pI4h", value, mask);
out->prf(out->dst, "%pI4h/%pI4h", &data->u32.value,
&data->u32.mask);
} else if (key == VCAP_KF_ETYPE ||
key == VCAP_KF_IF_IGR_PORT_MASK) {
hex = true;
} else {
u32 fmsk = (1 << keyfield[key].width) - 1;
u32 val = *(u32 *)value;
u32 msk = *(u32 *)mask;
out->prf(out->dst, "%u/%u", val & fmsk, msk & fmsk);
out->prf(out->dst, "%u/%u", data->u32.value & fmsk,
data->u32.mask & fmsk);
}
break;
case VCAP_FIELD_U48:
value = data->u48.value;
mask = data->u48.mask;
if (key == VCAP_KF_L2_SMAC || key == VCAP_KF_L2_DMAC)
out->prf(out->dst, "%pMR/%pMR", value, mask);
out->prf(out->dst, "%pMR/%pMR", data->u48.value,
data->u48.mask);
else
hex = true;
break;
case VCAP_FIELD_U56:
value = data->u56.value;
mask = data->u56.mask;
hex = true;
break;
case VCAP_FIELD_U64:
value = data->u64.value;
mask = data->u64.mask;
hex = true;
break;
case VCAP_FIELD_U72:
value = data->u72.value;
mask = data->u72.mask;
hex = true;
break;
case VCAP_FIELD_U112:
value = data->u112.value;
mask = data->u112.mask;
hex = true;
break;
case VCAP_FIELD_U128:
if (key == VCAP_KF_L3_IP6_SIP || key == VCAP_KF_L3_IP6_DIP) {
u8 nvalue[16], nmask[16];
vcap_netbytes_copy(nvalue, value, sizeof(nvalue));
vcap_netbytes_copy(nmask, mask, sizeof(nmask));
vcap_netbytes_copy(nvalue, data->u128.value,
sizeof(nvalue));
vcap_netbytes_copy(nmask, data->u128.mask,
sizeof(nmask));
out->prf(out->dst, "%pI6/%pI6", nvalue, nmask);
} else {
hex = true;
......@@ -472,19 +154,15 @@ static int vcap_debugfs_show_rule_keyset(struct vcap_rule_internal *ri,
struct vcap_output_print *out)
{
struct vcap_control *vctrl = ri->vctrl;
struct vcap_stream_iter kiter, miter;
struct vcap_admin *admin = ri->admin;
enum vcap_keyfield_set keysets[10];
const struct vcap_field *keyfield;
enum vcap_type vt = admin->vtype;
const struct vcap_typegroup *tgt;
struct vcap_client_keyfield *ckf;
struct vcap_keyset_list matches;
enum vcap_keyfield_set keyset;
int idx, res, keyfield_count;
u32 *maskstream;
u32 *keystream;
u8 value[16];
u8 mask[16];
int res;
keystream = admin->cache.keystream;
maskstream = admin->cache.maskstream;
......@@ -498,39 +176,20 @@ static int vcap_debugfs_show_rule_keyset(struct vcap_rule_internal *ri,
__func__, __LINE__, res);
return -EINVAL;
}
keyset = matches.keysets[0];
out->prf(out->dst, " keysets:");
for (idx = 0; idx < matches.cnt; ++idx)
for (int idx = 0; idx < matches.cnt; ++idx)
out->prf(out->dst, " %s",
vcap_keyset_name(vctrl, matches.keysets[idx]));
out->prf(out->dst, "\n");
out->prf(out->dst, " keyset_sw: %d\n", ri->keyset_sw);
out->prf(out->dst, " keyset_sw_regs: %d\n", ri->keyset_sw_regs);
keyfield_count = vcap_keyfield_count(vctrl, vt, keyset);
keyfield = vcap_keyfields(vctrl, vt, keyset);
tgt = vcap_keyfield_typegroup(vctrl, vt, keyset);
/* Start decoding the streams */
for (idx = 0; idx < keyfield_count; ++idx) {
if (keyfield[idx].width <= 0)
continue;
/* First get the mask */
memset(mask, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
vcap_iter_init(&miter, vctrl->vcaps[vt].sw_width, tgt,
keyfield[idx].offset);
vcap_decode_field(maskstream, &miter, keyfield[idx].width,
mask);
/* Skip if no mask bits are set */
if (vcap_bitarray_zero(keyfield[idx].width, mask))
continue;
/* Get the key */
memset(value, 0, DIV_ROUND_UP(keyfield[idx].width, 8));
vcap_iter_init(&kiter, vctrl->vcaps[vt].sw_width, tgt,
keyfield[idx].offset);
vcap_decode_field(keystream, &kiter, keyfield[idx].width,
value);
vcap_debugfs_show_rule_keyfield(vctrl, out, idx, keyfield,
value, mask);
list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) {
keyfield = vcap_keyfields(vctrl, admin->vtype, ri->data.keyset);
vcap_debugfs_show_rule_keyfield(vctrl, out, ckf->ctrl.key,
keyfield, &ckf->data);
}
return 0;
}
......@@ -540,48 +199,21 @@ static int vcap_debugfs_show_rule_actionset(struct vcap_rule_internal *ri,
struct vcap_control *vctrl = ri->vctrl;
struct vcap_admin *admin = ri->admin;
const struct vcap_field *actionfield;
enum vcap_actionfield_set actionset;
enum vcap_type vt = admin->vtype;
const struct vcap_typegroup *tgt;
struct vcap_stream_iter iter;
int idx, res, actfield_count;
u32 *actstream;
u8 value[16];
bool no_bits;
actstream = admin->cache.actionstream;
res = vcap_find_actionstream_actionset(vctrl, vt, actstream, 0);
if (res < 0) {
pr_err("%s:%d: could not find valid actionset: %d\n",
__func__, __LINE__, res);
return -EINVAL;
}
actionset = res;
struct vcap_client_actionfield *caf;
out->prf(out->dst, " actionset: %s\n",
vcap_actionset_name(vctrl, ri->data.actionset));
out->prf(out->dst, " actionset_sw: %d\n", ri->actionset_sw);
out->prf(out->dst, " actionset_sw_regs: %d\n", ri->actionset_sw_regs);
actfield_count = vcap_actionfield_count(vctrl, vt, actionset);
actionfield = vcap_actionfields(vctrl, vt, actionset);
tgt = vcap_actionfield_typegroup(vctrl, vt, actionset);
/* Start decoding the stream */
for (idx = 0; idx < actfield_count; ++idx) {
if (actionfield[idx].width <= 0)
continue;
/* Get the action */
memset(value, 0, DIV_ROUND_UP(actionfield[idx].width, 8));
vcap_iter_init(&iter, vctrl->vcaps[vt].act_width, tgt,
actionfield[idx].offset);
vcap_decode_field(actstream, &iter, actionfield[idx].width,
value);
/* Skip if no bits are set */
no_bits = vcap_bitarray_zero(actionfield[idx].width, value);
if (no_bits)
continue;
/* Later the action id will also be checked */
vcap_debugfs_show_rule_actionfield(vctrl, out, idx, actionfield,
value);
list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) {
actionfield = vcap_actionfields(vctrl, admin->vtype,
ri->data.actionset);
vcap_debugfs_show_rule_actionfield(vctrl, out, caf->ctrl.action,
actionfield,
&caf->data.u1.value);
}
return 0;
}
......@@ -632,32 +264,22 @@ static int vcap_show_admin(struct vcap_control *vctrl,
struct vcap_admin *admin,
struct vcap_output_print *out)
{
struct vcap_rule_internal *elem, *ri;
struct vcap_rule_internal *elem;
struct vcap_rule *vrule;
int ret = 0;
vcap_show_admin_info(vctrl, admin, out);
mutex_lock(&admin->lock);
list_for_each_entry(elem, &admin->rules, list) {
ri = vcap_dup_rule(elem);
if (IS_ERR(ri)) {
ret = PTR_ERR(ri);
goto err_unlock;
vrule = vcap_get_rule(vctrl, elem->data.id);
if (IS_ERR_OR_NULL(vrule)) {
ret = PTR_ERR(vrule);
break;
}
/* Read data from VCAP */
ret = vcap_read_rule(ri);
if (ret)
goto err_free_rule;
out->prf(out->dst, "\n");
vcap_show_admin_rule(vctrl, admin, out, ri);
vcap_free_rule((struct vcap_rule *)ri);
vcap_show_admin_rule(vctrl, admin, out, to_intrule(vrule));
vcap_free_rule(vrule);
}
mutex_unlock(&admin->lock);
return 0;
err_free_rule:
vcap_free_rule((struct vcap_rule *)ri);
err_unlock:
mutex_unlock(&admin->lock);
return ret;
}
......
......@@ -96,4 +96,18 @@ const char *vcap_actionset_name(struct vcap_control *vctrl,
const char *vcap_actionfield_name(struct vcap_control *vctrl,
enum vcap_action_field action);
/* Read key data from a VCAP address and discover if there are any rule keysets
* here
*/
int vcap_addr_keysets(struct vcap_control *vctrl, struct net_device *ndev,
struct vcap_admin *admin, int addr,
struct vcap_keyset_list *kslist);
/* Verify that the typegroup information, subword count, keyset and type id
* are in sync and correct, return the list of matchin keysets
*/
int vcap_find_keystream_keysets(struct vcap_control *vctrl, enum vcap_type vt,
u32 *keystream, u32 *mskstream, bool mask,
int sw_max, struct vcap_keyset_list *kslist);
#endif /* __VCAP_API_PRIVATE__ */
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