net: microchip: vcap: Add vcap_get_rule
authorHoratiu Vultur <horatiu.vultur@microchip.com>
Sat, 3 Dec 2022 10:43:45 +0000 (11:43 +0100)
committerPaolo Abeni <pabeni@redhat.com>
Tue, 6 Dec 2022 12:26:43 +0000 (13:26 +0100)
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: Horatiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/microchip/vcap/vcap_api.c
drivers/net/ethernet/microchip/vcap/vcap_api_client.h
drivers/net/ethernet/microchip/vcap/vcap_api_debugfs.c
drivers/net/ethernet/microchip/vcap/vcap_api_private.h

index f2435d7ab515fc966a634a67d4819c75cfc9c909..27128313f15f16aa8f5383be3b04360b48a372d0 100644 (file)
@@ -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)
 {
index 93a0fcb12a81919fcd698908bebe2c43e0a645fe..a354dcd741e2205b22942b9294ef9abaef4c5d03 100644 (file)
@@ -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,
index 3b8d165dc83229ab6f763163297c9efd574a0ab4..895bfff550d23d2e1092e631258bf497b3e8755f 100644 (file)
@@ -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;
 }
 
index 9ac1b1d55f22e8532a042246191a39b5956d707f..4fd21da976799781f6da9a7ef3175ee6eb93dc26 100644 (file)
@@ -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__ */