1c9da1ac1SSteen Hegelund // SPDX-License-Identifier: GPL-2.0+ 2c9da1ac1SSteen Hegelund /* Microchip VCAP API 3c9da1ac1SSteen Hegelund * 4c9da1ac1SSteen Hegelund * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. 5c9da1ac1SSteen Hegelund */ 6c9da1ac1SSteen Hegelund 7c9da1ac1SSteen Hegelund #include <linux/types.h> 8c9da1ac1SSteen Hegelund 9c9da1ac1SSteen Hegelund #include "vcap_api.h" 10c9da1ac1SSteen Hegelund #include "vcap_api_client.h" 11c9da1ac1SSteen Hegelund 12c9da1ac1SSteen Hegelund #define to_intrule(rule) container_of((rule), struct vcap_rule_internal, data) 13c9da1ac1SSteen Hegelund 14c9da1ac1SSteen Hegelund /* Private VCAP API rule data */ 15c9da1ac1SSteen Hegelund struct vcap_rule_internal { 16c9da1ac1SSteen Hegelund struct vcap_rule data; /* provided by the client */ 17c9da1ac1SSteen Hegelund struct list_head list; /* for insertion in the vcap admin list of rules */ 18c9da1ac1SSteen Hegelund struct vcap_admin *admin; /* vcap hw instance */ 19c9da1ac1SSteen Hegelund struct net_device *ndev; /* the interface that the rule applies to */ 20c9da1ac1SSteen Hegelund struct vcap_control *vctrl; /* the client control */ 218e10490bSSteen Hegelund u32 sort_key; /* defines the position in the VCAP */ 228e10490bSSteen Hegelund int keyset_sw; /* subwords in a keyset */ 238e10490bSSteen Hegelund int actionset_sw; /* subwords in an actionset */ 248e10490bSSteen Hegelund int keyset_sw_regs; /* registers in a subword in an keyset */ 258e10490bSSteen Hegelund int actionset_sw_regs; /* registers in a subword in an actionset */ 268e10490bSSteen Hegelund int size; /* the size of the rule: max(entry, action) */ 27c9da1ac1SSteen Hegelund u32 addr; /* address in the VCAP at insertion */ 28*f13230a4SSteen Hegelund u32 counter_id; /* counter id (if a dedicated counter is available) */ 29*f13230a4SSteen Hegelund struct vcap_counter counter; /* last read counter value */ 30c9da1ac1SSteen Hegelund }; 31c9da1ac1SSteen Hegelund 328e10490bSSteen Hegelund /* Moving a rule in the VCAP address space */ 338e10490bSSteen Hegelund struct vcap_rule_move { 348e10490bSSteen Hegelund int addr; /* address to move */ 358e10490bSSteen Hegelund int offset; /* change in address */ 368e10490bSSteen Hegelund int count; /* blocksize of addresses to move */ 378e10490bSSteen Hegelund }; 388e10490bSSteen Hegelund 39683e05c0SSteen Hegelund /* Bit iterator for the VCAP cache streams */ 40683e05c0SSteen Hegelund struct vcap_stream_iter { 41683e05c0SSteen Hegelund u32 offset; /* bit offset from the stream start */ 42683e05c0SSteen Hegelund u32 sw_width; /* subword width in bits */ 43683e05c0SSteen Hegelund u32 regs_per_sw; /* registers per subword */ 44683e05c0SSteen Hegelund u32 reg_idx; /* current register index */ 45683e05c0SSteen Hegelund u32 reg_bitpos; /* bit offset in current register */ 46683e05c0SSteen Hegelund const struct vcap_typegroup *tg; /* current typegroup */ 47683e05c0SSteen Hegelund }; 48683e05c0SSteen Hegelund 4967456717SSteen Hegelund /* Stores the filter cookie that enabled the port */ 5067456717SSteen Hegelund struct vcap_enabled_port { 5167456717SSteen Hegelund struct list_head list; /* for insertion in enabled ports list */ 5267456717SSteen Hegelund struct net_device *ndev; /* the enabled port */ 5367456717SSteen Hegelund unsigned long cookie; /* filter that enabled the port */ 5467456717SSteen Hegelund }; 5567456717SSteen Hegelund 56683e05c0SSteen Hegelund static void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width, 57683e05c0SSteen Hegelund const struct vcap_typegroup *tg, u32 offset) 58683e05c0SSteen Hegelund { 59683e05c0SSteen Hegelund memset(itr, 0, sizeof(*itr)); 60683e05c0SSteen Hegelund itr->offset = offset; 61683e05c0SSteen Hegelund itr->sw_width = sw_width; 62683e05c0SSteen Hegelund itr->regs_per_sw = DIV_ROUND_UP(sw_width, 32); 63683e05c0SSteen Hegelund itr->tg = tg; 64683e05c0SSteen Hegelund } 65683e05c0SSteen Hegelund 66683e05c0SSteen Hegelund static void vcap_iter_skip_tg(struct vcap_stream_iter *itr) 67683e05c0SSteen Hegelund { 68683e05c0SSteen Hegelund /* Compensate the field offset for preceding typegroups. 69683e05c0SSteen Hegelund * A typegroup table ends with an all-zero terminator. 70683e05c0SSteen Hegelund */ 71683e05c0SSteen Hegelund while (itr->tg->width && itr->offset >= itr->tg->offset) { 72683e05c0SSteen Hegelund itr->offset += itr->tg->width; 73683e05c0SSteen Hegelund itr->tg++; /* next typegroup */ 74683e05c0SSteen Hegelund } 75683e05c0SSteen Hegelund } 76683e05c0SSteen Hegelund 77683e05c0SSteen Hegelund static void vcap_iter_update(struct vcap_stream_iter *itr) 78683e05c0SSteen Hegelund { 79683e05c0SSteen Hegelund int sw_idx, sw_bitpos; 80683e05c0SSteen Hegelund 81683e05c0SSteen Hegelund /* Calculate the subword index and bitposition for current bit */ 82683e05c0SSteen Hegelund sw_idx = itr->offset / itr->sw_width; 83683e05c0SSteen Hegelund sw_bitpos = itr->offset % itr->sw_width; 84683e05c0SSteen Hegelund /* Calculate the register index and bitposition for current bit */ 85683e05c0SSteen Hegelund itr->reg_idx = (sw_idx * itr->regs_per_sw) + (sw_bitpos / 32); 86683e05c0SSteen Hegelund itr->reg_bitpos = sw_bitpos % 32; 87683e05c0SSteen Hegelund } 88683e05c0SSteen Hegelund 89683e05c0SSteen Hegelund static void vcap_iter_init(struct vcap_stream_iter *itr, int sw_width, 90683e05c0SSteen Hegelund const struct vcap_typegroup *tg, u32 offset) 91683e05c0SSteen Hegelund { 92683e05c0SSteen Hegelund vcap_iter_set(itr, sw_width, tg, offset); 93683e05c0SSteen Hegelund vcap_iter_skip_tg(itr); 94683e05c0SSteen Hegelund vcap_iter_update(itr); 95683e05c0SSteen Hegelund } 96683e05c0SSteen Hegelund 97683e05c0SSteen Hegelund static void vcap_iter_next(struct vcap_stream_iter *itr) 98683e05c0SSteen Hegelund { 99683e05c0SSteen Hegelund itr->offset++; 100683e05c0SSteen Hegelund vcap_iter_skip_tg(itr); 101683e05c0SSteen Hegelund vcap_iter_update(itr); 102683e05c0SSteen Hegelund } 103683e05c0SSteen Hegelund 104683e05c0SSteen Hegelund static void vcap_set_bit(u32 *stream, struct vcap_stream_iter *itr, bool value) 105683e05c0SSteen Hegelund { 106683e05c0SSteen Hegelund u32 mask = BIT(itr->reg_bitpos); 107683e05c0SSteen Hegelund u32 *p = &stream[itr->reg_idx]; 108683e05c0SSteen Hegelund 109683e05c0SSteen Hegelund if (value) 110683e05c0SSteen Hegelund *p |= mask; 111683e05c0SSteen Hegelund else 112683e05c0SSteen Hegelund *p &= ~mask; 113683e05c0SSteen Hegelund } 114683e05c0SSteen Hegelund 115683e05c0SSteen Hegelund static void vcap_encode_bit(u32 *stream, struct vcap_stream_iter *itr, bool val) 116683e05c0SSteen Hegelund { 117683e05c0SSteen Hegelund /* When intersected by a type group field, stream the type group bits 118683e05c0SSteen Hegelund * before continuing with the value bit 119683e05c0SSteen Hegelund */ 120683e05c0SSteen Hegelund while (itr->tg->width && 121683e05c0SSteen Hegelund itr->offset >= itr->tg->offset && 122683e05c0SSteen Hegelund itr->offset < itr->tg->offset + itr->tg->width) { 123683e05c0SSteen Hegelund int tg_bitpos = itr->tg->offset - itr->offset; 124683e05c0SSteen Hegelund 125683e05c0SSteen Hegelund vcap_set_bit(stream, itr, (itr->tg->value >> tg_bitpos) & 0x1); 126683e05c0SSteen Hegelund itr->offset++; 127683e05c0SSteen Hegelund vcap_iter_update(itr); 128683e05c0SSteen Hegelund } 129683e05c0SSteen Hegelund vcap_set_bit(stream, itr, val); 130683e05c0SSteen Hegelund } 131683e05c0SSteen Hegelund 132683e05c0SSteen Hegelund static void vcap_encode_field(u32 *stream, struct vcap_stream_iter *itr, 133683e05c0SSteen Hegelund int width, const u8 *value) 134683e05c0SSteen Hegelund { 135683e05c0SSteen Hegelund int idx; 136683e05c0SSteen Hegelund 137683e05c0SSteen Hegelund /* Loop over the field value bits and add the value bits one by one to 138683e05c0SSteen Hegelund * the output stream. 139683e05c0SSteen Hegelund */ 140683e05c0SSteen Hegelund for (idx = 0; idx < width; idx++) { 141683e05c0SSteen Hegelund u8 bidx = idx & GENMASK(2, 0); 142683e05c0SSteen Hegelund 143683e05c0SSteen Hegelund /* Encode one field value bit */ 144683e05c0SSteen Hegelund vcap_encode_bit(stream, itr, (value[idx / 8] >> bidx) & 0x1); 145683e05c0SSteen Hegelund vcap_iter_next(itr); 146683e05c0SSteen Hegelund } 147683e05c0SSteen Hegelund } 148683e05c0SSteen Hegelund 149683e05c0SSteen Hegelund static void vcap_encode_typegroups(u32 *stream, int sw_width, 150683e05c0SSteen Hegelund const struct vcap_typegroup *tg, 151683e05c0SSteen Hegelund bool mask) 152683e05c0SSteen Hegelund { 153683e05c0SSteen Hegelund struct vcap_stream_iter iter; 154683e05c0SSteen Hegelund int idx; 155683e05c0SSteen Hegelund 156683e05c0SSteen Hegelund /* Mask bits must be set to zeros (inverted later when writing to the 157683e05c0SSteen Hegelund * mask cache register), so that the mask typegroup bits consist of 158683e05c0SSteen Hegelund * match-1 or match-0, or both 159683e05c0SSteen Hegelund */ 160683e05c0SSteen Hegelund vcap_iter_set(&iter, sw_width, tg, 0); 161683e05c0SSteen Hegelund while (iter.tg->width) { 162683e05c0SSteen Hegelund /* Set position to current typegroup bit */ 163683e05c0SSteen Hegelund iter.offset = iter.tg->offset; 164683e05c0SSteen Hegelund vcap_iter_update(&iter); 165683e05c0SSteen Hegelund for (idx = 0; idx < iter.tg->width; idx++) { 166683e05c0SSteen Hegelund /* Iterate over current typegroup bits. Mask typegroup 167683e05c0SSteen Hegelund * bits are always set 168683e05c0SSteen Hegelund */ 169683e05c0SSteen Hegelund if (mask) 170683e05c0SSteen Hegelund vcap_set_bit(stream, &iter, 0x1); 171683e05c0SSteen Hegelund else 172683e05c0SSteen Hegelund vcap_set_bit(stream, &iter, 173683e05c0SSteen Hegelund (iter.tg->value >> idx) & 0x1); 174683e05c0SSteen Hegelund iter.offset++; 175683e05c0SSteen Hegelund vcap_iter_update(&iter); 176683e05c0SSteen Hegelund } 177683e05c0SSteen Hegelund iter.tg++; /* next typegroup */ 178683e05c0SSteen Hegelund } 179683e05c0SSteen Hegelund } 180683e05c0SSteen Hegelund 18146be056eSSteen Hegelund /* Return the list of keyfields for the keyset */ 18246be056eSSteen Hegelund static const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl, 18346be056eSSteen Hegelund enum vcap_type vt, 18446be056eSSteen Hegelund enum vcap_keyfield_set keyset) 18546be056eSSteen Hegelund { 18646be056eSSteen Hegelund /* Check that the keyset exists in the vcap keyset list */ 18746be056eSSteen Hegelund if (keyset >= vctrl->vcaps[vt].keyfield_set_size) 18846be056eSSteen Hegelund return NULL; 18946be056eSSteen Hegelund return vctrl->vcaps[vt].keyfield_set_map[keyset]; 19046be056eSSteen Hegelund } 19146be056eSSteen Hegelund 1928e10490bSSteen Hegelund /* Return the keyset information for the keyset */ 1938e10490bSSteen Hegelund static const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl, 1948e10490bSSteen Hegelund enum vcap_type vt, 1958e10490bSSteen Hegelund enum vcap_keyfield_set keyset) 1968e10490bSSteen Hegelund { 1978e10490bSSteen Hegelund const struct vcap_set *kset; 1988e10490bSSteen Hegelund 1998e10490bSSteen Hegelund /* Check that the keyset exists in the vcap keyset list */ 2008e10490bSSteen Hegelund if (keyset >= vctrl->vcaps[vt].keyfield_set_size) 2018e10490bSSteen Hegelund return NULL; 2028e10490bSSteen Hegelund kset = &vctrl->vcaps[vt].keyfield_set[keyset]; 2038e10490bSSteen Hegelund if (kset->sw_per_item == 0 || kset->sw_per_item > vctrl->vcaps[vt].sw_count) 2048e10490bSSteen Hegelund return NULL; 2058e10490bSSteen Hegelund return kset; 2068e10490bSSteen Hegelund } 2078e10490bSSteen Hegelund 208683e05c0SSteen Hegelund /* Return the typegroup table for the matching keyset (using subword size) */ 209683e05c0SSteen Hegelund static const struct vcap_typegroup * 210683e05c0SSteen Hegelund vcap_keyfield_typegroup(struct vcap_control *vctrl, 211683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_keyfield_set keyset) 212683e05c0SSteen Hegelund { 213683e05c0SSteen Hegelund const struct vcap_set *kset = vcap_keyfieldset(vctrl, vt, keyset); 214683e05c0SSteen Hegelund 215683e05c0SSteen Hegelund /* Check that the keyset is valid */ 216683e05c0SSteen Hegelund if (!kset) 217683e05c0SSteen Hegelund return NULL; 218683e05c0SSteen Hegelund return vctrl->vcaps[vt].keyfield_set_typegroups[kset->sw_per_item]; 219683e05c0SSteen Hegelund } 220683e05c0SSteen Hegelund 221683e05c0SSteen Hegelund /* Return the number of keyfields in the keyset */ 222683e05c0SSteen Hegelund static int vcap_keyfield_count(struct vcap_control *vctrl, 223683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_keyfield_set keyset) 224683e05c0SSteen Hegelund { 225683e05c0SSteen Hegelund /* Check that the keyset exists in the vcap keyset list */ 226683e05c0SSteen Hegelund if (keyset >= vctrl->vcaps[vt].keyfield_set_size) 227683e05c0SSteen Hegelund return 0; 228683e05c0SSteen Hegelund return vctrl->vcaps[vt].keyfield_set_map_size[keyset]; 229683e05c0SSteen Hegelund } 230683e05c0SSteen Hegelund 231683e05c0SSteen Hegelund static void vcap_encode_keyfield(struct vcap_rule_internal *ri, 232683e05c0SSteen Hegelund const struct vcap_client_keyfield *kf, 233683e05c0SSteen Hegelund const struct vcap_field *rf, 234683e05c0SSteen Hegelund const struct vcap_typegroup *tgt) 235683e05c0SSteen Hegelund { 236683e05c0SSteen Hegelund int sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width; 237683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache; 238683e05c0SSteen Hegelund struct vcap_stream_iter iter; 239683e05c0SSteen Hegelund const u8 *value, *mask; 240683e05c0SSteen Hegelund 241683e05c0SSteen Hegelund /* Encode the fields for the key and the mask in their respective 242683e05c0SSteen Hegelund * streams, respecting the subword width. 243683e05c0SSteen Hegelund */ 244683e05c0SSteen Hegelund switch (kf->ctrl.type) { 245683e05c0SSteen Hegelund case VCAP_FIELD_BIT: 246683e05c0SSteen Hegelund value = &kf->data.u1.value; 247683e05c0SSteen Hegelund mask = &kf->data.u1.mask; 248683e05c0SSteen Hegelund break; 249683e05c0SSteen Hegelund case VCAP_FIELD_U32: 250683e05c0SSteen Hegelund value = (const u8 *)&kf->data.u32.value; 251683e05c0SSteen Hegelund mask = (const u8 *)&kf->data.u32.mask; 252683e05c0SSteen Hegelund break; 253683e05c0SSteen Hegelund case VCAP_FIELD_U48: 254683e05c0SSteen Hegelund value = kf->data.u48.value; 255683e05c0SSteen Hegelund mask = kf->data.u48.mask; 256683e05c0SSteen Hegelund break; 257683e05c0SSteen Hegelund case VCAP_FIELD_U56: 258683e05c0SSteen Hegelund value = kf->data.u56.value; 259683e05c0SSteen Hegelund mask = kf->data.u56.mask; 260683e05c0SSteen Hegelund break; 261683e05c0SSteen Hegelund case VCAP_FIELD_U64: 262683e05c0SSteen Hegelund value = kf->data.u64.value; 263683e05c0SSteen Hegelund mask = kf->data.u64.mask; 264683e05c0SSteen Hegelund break; 265683e05c0SSteen Hegelund case VCAP_FIELD_U72: 266683e05c0SSteen Hegelund value = kf->data.u72.value; 267683e05c0SSteen Hegelund mask = kf->data.u72.mask; 268683e05c0SSteen Hegelund break; 269683e05c0SSteen Hegelund case VCAP_FIELD_U112: 270683e05c0SSteen Hegelund value = kf->data.u112.value; 271683e05c0SSteen Hegelund mask = kf->data.u112.mask; 272683e05c0SSteen Hegelund break; 273683e05c0SSteen Hegelund case VCAP_FIELD_U128: 274683e05c0SSteen Hegelund value = kf->data.u128.value; 275683e05c0SSteen Hegelund mask = kf->data.u128.mask; 276683e05c0SSteen Hegelund break; 277683e05c0SSteen Hegelund } 278683e05c0SSteen Hegelund vcap_iter_init(&iter, sw_width, tgt, rf->offset); 279683e05c0SSteen Hegelund vcap_encode_field(cache->keystream, &iter, rf->width, value); 280683e05c0SSteen Hegelund vcap_iter_init(&iter, sw_width, tgt, rf->offset); 281683e05c0SSteen Hegelund vcap_encode_field(cache->maskstream, &iter, rf->width, mask); 282683e05c0SSteen Hegelund } 283683e05c0SSteen Hegelund 284683e05c0SSteen Hegelund static void vcap_encode_keyfield_typegroups(struct vcap_control *vctrl, 285683e05c0SSteen Hegelund struct vcap_rule_internal *ri, 286683e05c0SSteen Hegelund const struct vcap_typegroup *tgt) 287683e05c0SSteen Hegelund { 288683e05c0SSteen Hegelund int sw_width = vctrl->vcaps[ri->admin->vtype].sw_width; 289683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache; 290683e05c0SSteen Hegelund 291683e05c0SSteen Hegelund /* Encode the typegroup bits for the key and the mask in their streams, 292683e05c0SSteen Hegelund * respecting the subword width. 293683e05c0SSteen Hegelund */ 294683e05c0SSteen Hegelund vcap_encode_typegroups(cache->keystream, sw_width, tgt, false); 295683e05c0SSteen Hegelund vcap_encode_typegroups(cache->maskstream, sw_width, tgt, true); 296683e05c0SSteen Hegelund } 297683e05c0SSteen Hegelund 298683e05c0SSteen Hegelund static int vcap_encode_rule_keyset(struct vcap_rule_internal *ri) 299683e05c0SSteen Hegelund { 300683e05c0SSteen Hegelund const struct vcap_client_keyfield *ckf; 301683e05c0SSteen Hegelund const struct vcap_typegroup *tg_table; 302683e05c0SSteen Hegelund const struct vcap_field *kf_table; 303683e05c0SSteen Hegelund int keyset_size; 304683e05c0SSteen Hegelund 305683e05c0SSteen Hegelund /* Get a valid set of fields for the specific keyset */ 306683e05c0SSteen Hegelund kf_table = vcap_keyfields(ri->vctrl, ri->admin->vtype, ri->data.keyset); 307683e05c0SSteen Hegelund if (!kf_table) { 308683e05c0SSteen Hegelund pr_err("%s:%d: no fields available for this keyset: %d\n", 309683e05c0SSteen Hegelund __func__, __LINE__, ri->data.keyset); 310683e05c0SSteen Hegelund return -EINVAL; 311683e05c0SSteen Hegelund } 312683e05c0SSteen Hegelund /* Get a valid typegroup for the specific keyset */ 313683e05c0SSteen Hegelund tg_table = vcap_keyfield_typegroup(ri->vctrl, ri->admin->vtype, 314683e05c0SSteen Hegelund ri->data.keyset); 315683e05c0SSteen Hegelund if (!tg_table) { 316683e05c0SSteen Hegelund pr_err("%s:%d: no typegroups available for this keyset: %d\n", 317683e05c0SSteen Hegelund __func__, __LINE__, ri->data.keyset); 318683e05c0SSteen Hegelund return -EINVAL; 319683e05c0SSteen Hegelund } 320683e05c0SSteen Hegelund /* Get a valid size for the specific keyset */ 321683e05c0SSteen Hegelund keyset_size = vcap_keyfield_count(ri->vctrl, ri->admin->vtype, 322683e05c0SSteen Hegelund ri->data.keyset); 323683e05c0SSteen Hegelund if (keyset_size == 0) { 324683e05c0SSteen Hegelund pr_err("%s:%d: zero field count for this keyset: %d\n", 325683e05c0SSteen Hegelund __func__, __LINE__, ri->data.keyset); 326683e05c0SSteen Hegelund return -EINVAL; 327683e05c0SSteen Hegelund } 328683e05c0SSteen Hegelund /* Iterate over the keyfields (key, mask) in the rule 329683e05c0SSteen Hegelund * and encode these bits 330683e05c0SSteen Hegelund */ 331683e05c0SSteen Hegelund if (list_empty(&ri->data.keyfields)) { 332683e05c0SSteen Hegelund pr_err("%s:%d: no keyfields in the rule\n", __func__, __LINE__); 333683e05c0SSteen Hegelund return -EINVAL; 334683e05c0SSteen Hegelund } 335683e05c0SSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) { 336683e05c0SSteen Hegelund /* Check that the client entry exists in the keyset */ 337683e05c0SSteen Hegelund if (ckf->ctrl.key >= keyset_size) { 338683e05c0SSteen Hegelund pr_err("%s:%d: key %d is not in vcap\n", 339683e05c0SSteen Hegelund __func__, __LINE__, ckf->ctrl.key); 340683e05c0SSteen Hegelund return -EINVAL; 341683e05c0SSteen Hegelund } 342683e05c0SSteen Hegelund vcap_encode_keyfield(ri, ckf, &kf_table[ckf->ctrl.key], tg_table); 343683e05c0SSteen Hegelund } 344683e05c0SSteen Hegelund /* Add typegroup bits to the key/mask bitstreams */ 345683e05c0SSteen Hegelund vcap_encode_keyfield_typegroups(ri->vctrl, ri, tg_table); 346683e05c0SSteen Hegelund return 0; 347683e05c0SSteen Hegelund } 348683e05c0SSteen Hegelund 349683e05c0SSteen Hegelund /* Return the list of actionfields for the actionset */ 350683e05c0SSteen Hegelund static const struct vcap_field * 351683e05c0SSteen Hegelund vcap_actionfields(struct vcap_control *vctrl, 352683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_actionfield_set actionset) 353683e05c0SSteen Hegelund { 354683e05c0SSteen Hegelund /* Check that the actionset exists in the vcap actionset list */ 355683e05c0SSteen Hegelund if (actionset >= vctrl->vcaps[vt].actionfield_set_size) 356683e05c0SSteen Hegelund return NULL; 357683e05c0SSteen Hegelund return vctrl->vcaps[vt].actionfield_set_map[actionset]; 358683e05c0SSteen Hegelund } 359683e05c0SSteen Hegelund 3608e10490bSSteen Hegelund static const struct vcap_set * 3618e10490bSSteen Hegelund vcap_actionfieldset(struct vcap_control *vctrl, 3628e10490bSSteen Hegelund enum vcap_type vt, enum vcap_actionfield_set actionset) 3638e10490bSSteen Hegelund { 3648e10490bSSteen Hegelund const struct vcap_set *aset; 3658e10490bSSteen Hegelund 3668e10490bSSteen Hegelund /* Check that the actionset exists in the vcap actionset list */ 3678e10490bSSteen Hegelund if (actionset >= vctrl->vcaps[vt].actionfield_set_size) 3688e10490bSSteen Hegelund return NULL; 3698e10490bSSteen Hegelund aset = &vctrl->vcaps[vt].actionfield_set[actionset]; 3708e10490bSSteen Hegelund if (aset->sw_per_item == 0 || aset->sw_per_item > vctrl->vcaps[vt].sw_count) 3718e10490bSSteen Hegelund return NULL; 3728e10490bSSteen Hegelund return aset; 3738e10490bSSteen Hegelund } 3748e10490bSSteen Hegelund 375683e05c0SSteen Hegelund /* Return the typegroup table for the matching actionset (using subword size) */ 376683e05c0SSteen Hegelund static const struct vcap_typegroup * 377683e05c0SSteen Hegelund vcap_actionfield_typegroup(struct vcap_control *vctrl, 378683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_actionfield_set actionset) 379683e05c0SSteen Hegelund { 380683e05c0SSteen Hegelund const struct vcap_set *aset = vcap_actionfieldset(vctrl, vt, actionset); 381683e05c0SSteen Hegelund 382683e05c0SSteen Hegelund /* Check that the actionset is valid */ 383683e05c0SSteen Hegelund if (!aset) 384683e05c0SSteen Hegelund return NULL; 385683e05c0SSteen Hegelund return vctrl->vcaps[vt].actionfield_set_typegroups[aset->sw_per_item]; 386683e05c0SSteen Hegelund } 387683e05c0SSteen Hegelund 388683e05c0SSteen Hegelund /* Return the number of actionfields in the actionset */ 389683e05c0SSteen Hegelund static int vcap_actionfield_count(struct vcap_control *vctrl, 390683e05c0SSteen Hegelund enum vcap_type vt, 391683e05c0SSteen Hegelund enum vcap_actionfield_set actionset) 392683e05c0SSteen Hegelund { 393683e05c0SSteen Hegelund /* Check that the actionset exists in the vcap actionset list */ 394683e05c0SSteen Hegelund if (actionset >= vctrl->vcaps[vt].actionfield_set_size) 395683e05c0SSteen Hegelund return 0; 396683e05c0SSteen Hegelund return vctrl->vcaps[vt].actionfield_set_map_size[actionset]; 397683e05c0SSteen Hegelund } 398683e05c0SSteen Hegelund 399683e05c0SSteen Hegelund static void vcap_encode_actionfield(struct vcap_rule_internal *ri, 400683e05c0SSteen Hegelund const struct vcap_client_actionfield *af, 401683e05c0SSteen Hegelund const struct vcap_field *rf, 402683e05c0SSteen Hegelund const struct vcap_typegroup *tgt) 403683e05c0SSteen Hegelund { 404683e05c0SSteen Hegelund int act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width; 405683e05c0SSteen Hegelund 406683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache; 407683e05c0SSteen Hegelund struct vcap_stream_iter iter; 408683e05c0SSteen Hegelund const u8 *value; 409683e05c0SSteen Hegelund 410683e05c0SSteen Hegelund /* Encode the action field in the stream, respecting the subword width */ 411683e05c0SSteen Hegelund switch (af->ctrl.type) { 412683e05c0SSteen Hegelund case VCAP_FIELD_BIT: 413683e05c0SSteen Hegelund value = &af->data.u1.value; 414683e05c0SSteen Hegelund break; 415683e05c0SSteen Hegelund case VCAP_FIELD_U32: 416683e05c0SSteen Hegelund value = (const u8 *)&af->data.u32.value; 417683e05c0SSteen Hegelund break; 418683e05c0SSteen Hegelund case VCAP_FIELD_U48: 419683e05c0SSteen Hegelund value = af->data.u48.value; 420683e05c0SSteen Hegelund break; 421683e05c0SSteen Hegelund case VCAP_FIELD_U56: 422683e05c0SSteen Hegelund value = af->data.u56.value; 423683e05c0SSteen Hegelund break; 424683e05c0SSteen Hegelund case VCAP_FIELD_U64: 425683e05c0SSteen Hegelund value = af->data.u64.value; 426683e05c0SSteen Hegelund break; 427683e05c0SSteen Hegelund case VCAP_FIELD_U72: 428683e05c0SSteen Hegelund value = af->data.u72.value; 429683e05c0SSteen Hegelund break; 430683e05c0SSteen Hegelund case VCAP_FIELD_U112: 431683e05c0SSteen Hegelund value = af->data.u112.value; 432683e05c0SSteen Hegelund break; 433683e05c0SSteen Hegelund case VCAP_FIELD_U128: 434683e05c0SSteen Hegelund value = af->data.u128.value; 435683e05c0SSteen Hegelund break; 436683e05c0SSteen Hegelund } 437683e05c0SSteen Hegelund vcap_iter_init(&iter, act_width, tgt, rf->offset); 438683e05c0SSteen Hegelund vcap_encode_field(cache->actionstream, &iter, rf->width, value); 439683e05c0SSteen Hegelund } 440683e05c0SSteen Hegelund 441683e05c0SSteen Hegelund static void vcap_encode_actionfield_typegroups(struct vcap_rule_internal *ri, 442683e05c0SSteen Hegelund const struct vcap_typegroup *tgt) 443683e05c0SSteen Hegelund { 444683e05c0SSteen Hegelund int sw_width = ri->vctrl->vcaps[ri->admin->vtype].act_width; 445683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache; 446683e05c0SSteen Hegelund 447683e05c0SSteen Hegelund /* Encode the typegroup bits for the actionstream respecting the subword 448683e05c0SSteen Hegelund * width. 449683e05c0SSteen Hegelund */ 450683e05c0SSteen Hegelund vcap_encode_typegroups(cache->actionstream, sw_width, tgt, false); 451683e05c0SSteen Hegelund } 452683e05c0SSteen Hegelund 453683e05c0SSteen Hegelund static int vcap_encode_rule_actionset(struct vcap_rule_internal *ri) 454683e05c0SSteen Hegelund { 455683e05c0SSteen Hegelund const struct vcap_client_actionfield *caf; 456683e05c0SSteen Hegelund const struct vcap_typegroup *tg_table; 457683e05c0SSteen Hegelund const struct vcap_field *af_table; 458683e05c0SSteen Hegelund int actionset_size; 459683e05c0SSteen Hegelund 460683e05c0SSteen Hegelund /* Get a valid set of actionset fields for the specific actionset */ 461683e05c0SSteen Hegelund af_table = vcap_actionfields(ri->vctrl, ri->admin->vtype, 462683e05c0SSteen Hegelund ri->data.actionset); 463683e05c0SSteen Hegelund if (!af_table) { 464683e05c0SSteen Hegelund pr_err("%s:%d: no fields available for this actionset: %d\n", 465683e05c0SSteen Hegelund __func__, __LINE__, ri->data.actionset); 466683e05c0SSteen Hegelund return -EINVAL; 467683e05c0SSteen Hegelund } 468683e05c0SSteen Hegelund /* Get a valid typegroup for the specific actionset */ 469683e05c0SSteen Hegelund tg_table = vcap_actionfield_typegroup(ri->vctrl, ri->admin->vtype, 470683e05c0SSteen Hegelund ri->data.actionset); 471683e05c0SSteen Hegelund if (!tg_table) { 472683e05c0SSteen Hegelund pr_err("%s:%d: no typegroups available for this actionset: %d\n", 473683e05c0SSteen Hegelund __func__, __LINE__, ri->data.actionset); 474683e05c0SSteen Hegelund return -EINVAL; 475683e05c0SSteen Hegelund } 476683e05c0SSteen Hegelund /* Get a valid actionset size for the specific actionset */ 477683e05c0SSteen Hegelund actionset_size = vcap_actionfield_count(ri->vctrl, ri->admin->vtype, 478683e05c0SSteen Hegelund ri->data.actionset); 479683e05c0SSteen Hegelund if (actionset_size == 0) { 480683e05c0SSteen Hegelund pr_err("%s:%d: zero field count for this actionset: %d\n", 481683e05c0SSteen Hegelund __func__, __LINE__, ri->data.actionset); 482683e05c0SSteen Hegelund return -EINVAL; 483683e05c0SSteen Hegelund } 484683e05c0SSteen Hegelund /* Iterate over the actionfields in the rule 485683e05c0SSteen Hegelund * and encode these bits 486683e05c0SSteen Hegelund */ 487683e05c0SSteen Hegelund if (list_empty(&ri->data.actionfields)) 488683e05c0SSteen Hegelund pr_warn("%s:%d: no actionfields in the rule\n", 489683e05c0SSteen Hegelund __func__, __LINE__); 490683e05c0SSteen Hegelund list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) { 491683e05c0SSteen Hegelund /* Check that the client action exists in the actionset */ 492683e05c0SSteen Hegelund if (caf->ctrl.action >= actionset_size) { 493683e05c0SSteen Hegelund pr_err("%s:%d: action %d is not in vcap\n", 494683e05c0SSteen Hegelund __func__, __LINE__, caf->ctrl.action); 495683e05c0SSteen Hegelund return -EINVAL; 496683e05c0SSteen Hegelund } 497683e05c0SSteen Hegelund vcap_encode_actionfield(ri, caf, &af_table[caf->ctrl.action], 498683e05c0SSteen Hegelund tg_table); 499683e05c0SSteen Hegelund } 500683e05c0SSteen Hegelund /* Add typegroup bits to the entry bitstreams */ 501683e05c0SSteen Hegelund vcap_encode_actionfield_typegroups(ri, tg_table); 502683e05c0SSteen Hegelund return 0; 503683e05c0SSteen Hegelund } 504683e05c0SSteen Hegelund 5058e10490bSSteen Hegelund static int vcap_encode_rule(struct vcap_rule_internal *ri) 5068e10490bSSteen Hegelund { 507683e05c0SSteen Hegelund int err; 508683e05c0SSteen Hegelund 509683e05c0SSteen Hegelund err = vcap_encode_rule_keyset(ri); 510683e05c0SSteen Hegelund if (err) 511683e05c0SSteen Hegelund return err; 512683e05c0SSteen Hegelund err = vcap_encode_rule_actionset(ri); 513683e05c0SSteen Hegelund if (err) 514683e05c0SSteen Hegelund return err; 5158e10490bSSteen Hegelund return 0; 5168e10490bSSteen Hegelund } 5178e10490bSSteen Hegelund 5188e10490bSSteen Hegelund static int vcap_api_check(struct vcap_control *ctrl) 5198e10490bSSteen Hegelund { 5208e10490bSSteen Hegelund if (!ctrl) { 5218e10490bSSteen Hegelund pr_err("%s:%d: vcap control is missing\n", __func__, __LINE__); 5228e10490bSSteen Hegelund return -EINVAL; 5238e10490bSSteen Hegelund } 5248e10490bSSteen Hegelund if (!ctrl->ops || !ctrl->ops->validate_keyset || 5258e10490bSSteen Hegelund !ctrl->ops->add_default_fields || !ctrl->ops->cache_erase || 5268e10490bSSteen Hegelund !ctrl->ops->cache_write || !ctrl->ops->cache_read || 5278e10490bSSteen Hegelund !ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move || 52867456717SSteen Hegelund !ctrl->ops->port_info || !ctrl->ops->enable) { 5298e10490bSSteen Hegelund pr_err("%s:%d: client operations are missing\n", 5308e10490bSSteen Hegelund __func__, __LINE__); 5318e10490bSSteen Hegelund return -ENOENT; 5328e10490bSSteen Hegelund } 5338e10490bSSteen Hegelund return 0; 5348e10490bSSteen Hegelund } 5358e10490bSSteen Hegelund 5368e10490bSSteen Hegelund static void vcap_erase_cache(struct vcap_rule_internal *ri) 5378e10490bSSteen Hegelund { 5388e10490bSSteen Hegelund ri->vctrl->ops->cache_erase(ri->admin); 5398e10490bSSteen Hegelund } 5408e10490bSSteen Hegelund 541c9da1ac1SSteen Hegelund /* Update the keyset for the rule */ 542c9da1ac1SSteen Hegelund int vcap_set_rule_set_keyset(struct vcap_rule *rule, 543c9da1ac1SSteen Hegelund enum vcap_keyfield_set keyset) 544c9da1ac1SSteen Hegelund { 5458e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 5468e10490bSSteen Hegelund const struct vcap_set *kset; 5478e10490bSSteen Hegelund int sw_width; 5488e10490bSSteen Hegelund 5498e10490bSSteen Hegelund kset = vcap_keyfieldset(ri->vctrl, ri->admin->vtype, keyset); 5508e10490bSSteen Hegelund /* Check that the keyset is valid */ 5518e10490bSSteen Hegelund if (!kset) 5528e10490bSSteen Hegelund return -EINVAL; 5538e10490bSSteen Hegelund ri->keyset_sw = kset->sw_per_item; 5548e10490bSSteen Hegelund sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width; 5558e10490bSSteen Hegelund ri->keyset_sw_regs = DIV_ROUND_UP(sw_width, 32); 5568e10490bSSteen Hegelund ri->data.keyset = keyset; 557c9da1ac1SSteen Hegelund return 0; 558c9da1ac1SSteen Hegelund } 559c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_keyset); 560c9da1ac1SSteen Hegelund 561c9da1ac1SSteen Hegelund /* Update the actionset for the rule */ 562c9da1ac1SSteen Hegelund int vcap_set_rule_set_actionset(struct vcap_rule *rule, 563c9da1ac1SSteen Hegelund enum vcap_actionfield_set actionset) 564c9da1ac1SSteen Hegelund { 5658e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 5668e10490bSSteen Hegelund const struct vcap_set *aset; 5678e10490bSSteen Hegelund int act_width; 5688e10490bSSteen Hegelund 5698e10490bSSteen Hegelund aset = vcap_actionfieldset(ri->vctrl, ri->admin->vtype, actionset); 5708e10490bSSteen Hegelund /* Check that the actionset is valid */ 5718e10490bSSteen Hegelund if (!aset) 5728e10490bSSteen Hegelund return -EINVAL; 5738e10490bSSteen Hegelund ri->actionset_sw = aset->sw_per_item; 5748e10490bSSteen Hegelund act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width; 5758e10490bSSteen Hegelund ri->actionset_sw_regs = DIV_ROUND_UP(act_width, 32); 5768e10490bSSteen Hegelund ri->data.actionset = actionset; 577c9da1ac1SSteen Hegelund return 0; 578c9da1ac1SSteen Hegelund } 579c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_actionset); 580c9da1ac1SSteen Hegelund 581c9da1ac1SSteen Hegelund /* Find a rule with a provided rule id */ 582c9da1ac1SSteen Hegelund static struct vcap_rule_internal *vcap_lookup_rule(struct vcap_control *vctrl, 583c9da1ac1SSteen Hegelund u32 id) 584c9da1ac1SSteen Hegelund { 585c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri; 586c9da1ac1SSteen Hegelund struct vcap_admin *admin; 587c9da1ac1SSteen Hegelund 588c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */ 589c9da1ac1SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) 590c9da1ac1SSteen Hegelund list_for_each_entry(ri, &admin->rules, list) 591c9da1ac1SSteen Hegelund if (ri->data.id == id) 592c9da1ac1SSteen Hegelund return ri; 593c9da1ac1SSteen Hegelund return NULL; 594c9da1ac1SSteen Hegelund } 595c9da1ac1SSteen Hegelund 596c9da1ac1SSteen Hegelund /* Find a rule id with a provided cookie */ 597c9da1ac1SSteen Hegelund int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie) 598c9da1ac1SSteen Hegelund { 599c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri; 600c9da1ac1SSteen Hegelund struct vcap_admin *admin; 601c9da1ac1SSteen Hegelund 602c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */ 603c9da1ac1SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) 604c9da1ac1SSteen Hegelund list_for_each_entry(ri, &admin->rules, list) 605c9da1ac1SSteen Hegelund if (ri->data.cookie == cookie) 606c9da1ac1SSteen Hegelund return ri->data.id; 607c9da1ac1SSteen Hegelund return -ENOENT; 608c9da1ac1SSteen Hegelund } 609c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie); 610c9da1ac1SSteen Hegelund 6118e10490bSSteen Hegelund /* Make a shallow copy of the rule without the fields */ 6128e10490bSSteen Hegelund static struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri) 6138e10490bSSteen Hegelund { 6148e10490bSSteen Hegelund struct vcap_rule_internal *duprule; 6158e10490bSSteen Hegelund 6168e10490bSSteen Hegelund /* Allocate the client part */ 6178e10490bSSteen Hegelund duprule = kzalloc(sizeof(*duprule), GFP_KERNEL); 6188e10490bSSteen Hegelund if (!duprule) 6198e10490bSSteen Hegelund return ERR_PTR(-ENOMEM); 6208e10490bSSteen Hegelund *duprule = *ri; 6218e10490bSSteen Hegelund /* Not inserted in the VCAP */ 6228e10490bSSteen Hegelund INIT_LIST_HEAD(&duprule->list); 6238e10490bSSteen Hegelund /* No elements in these lists */ 6248e10490bSSteen Hegelund INIT_LIST_HEAD(&duprule->data.keyfields); 6258e10490bSSteen Hegelund INIT_LIST_HEAD(&duprule->data.actionfields); 6268e10490bSSteen Hegelund return duprule; 6278e10490bSSteen Hegelund } 6288e10490bSSteen Hegelund 6298e10490bSSteen Hegelund /* Write VCAP cache content to the VCAP HW instance */ 6308e10490bSSteen Hegelund static int vcap_write_rule(struct vcap_rule_internal *ri) 6318e10490bSSteen Hegelund { 6328e10490bSSteen Hegelund struct vcap_admin *admin = ri->admin; 6338e10490bSSteen Hegelund int sw_idx, ent_idx = 0, act_idx = 0; 6348e10490bSSteen Hegelund u32 addr = ri->addr; 6358e10490bSSteen Hegelund 6368e10490bSSteen Hegelund if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) { 6378e10490bSSteen Hegelund pr_err("%s:%d: rule is empty\n", __func__, __LINE__); 6388e10490bSSteen Hegelund return -EINVAL; 6398e10490bSSteen Hegelund } 6408e10490bSSteen Hegelund /* Use the values in the streams to write the VCAP cache */ 6418e10490bSSteen Hegelund for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) { 6428e10490bSSteen Hegelund ri->vctrl->ops->cache_write(ri->ndev, admin, 6438e10490bSSteen Hegelund VCAP_SEL_ENTRY, ent_idx, 6448e10490bSSteen Hegelund ri->keyset_sw_regs); 6458e10490bSSteen Hegelund ri->vctrl->ops->cache_write(ri->ndev, admin, 6468e10490bSSteen Hegelund VCAP_SEL_ACTION, act_idx, 6478e10490bSSteen Hegelund ri->actionset_sw_regs); 6488e10490bSSteen Hegelund ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE, 6498e10490bSSteen Hegelund VCAP_SEL_ALL, addr); 6508e10490bSSteen Hegelund ent_idx += ri->keyset_sw_regs; 6518e10490bSSteen Hegelund act_idx += ri->actionset_sw_regs; 6528e10490bSSteen Hegelund } 6538e10490bSSteen Hegelund return 0; 6548e10490bSSteen Hegelund } 6558e10490bSSteen Hegelund 656*f13230a4SSteen Hegelund static int vcap_write_counter(struct vcap_rule_internal *ri, 657*f13230a4SSteen Hegelund struct vcap_counter *ctr) 658*f13230a4SSteen Hegelund { 659*f13230a4SSteen Hegelund struct vcap_admin *admin = ri->admin; 660*f13230a4SSteen Hegelund 661*f13230a4SSteen Hegelund admin->cache.counter = ctr->value; 662*f13230a4SSteen Hegelund admin->cache.sticky = ctr->sticky; 663*f13230a4SSteen Hegelund ri->vctrl->ops->cache_write(ri->ndev, admin, VCAP_SEL_COUNTER, 664*f13230a4SSteen Hegelund ri->counter_id, 0); 665*f13230a4SSteen Hegelund ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE, 666*f13230a4SSteen Hegelund VCAP_SEL_COUNTER, ri->addr); 667*f13230a4SSteen Hegelund return 0; 668*f13230a4SSteen Hegelund } 669*f13230a4SSteen Hegelund 6707de1dcadSSteen Hegelund /* Convert a chain id to a VCAP lookup index */ 6717de1dcadSSteen Hegelund int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid) 6727de1dcadSSteen Hegelund { 6737de1dcadSSteen Hegelund int lookup_first = admin->vinst * admin->lookups_per_instance; 6747de1dcadSSteen Hegelund int lookup_last = lookup_first + admin->lookups_per_instance; 6757de1dcadSSteen Hegelund int cid_next = admin->first_cid + VCAP_CID_LOOKUP_SIZE; 6767de1dcadSSteen Hegelund int cid = admin->first_cid; 6777de1dcadSSteen Hegelund int lookup; 6787de1dcadSSteen Hegelund 6797de1dcadSSteen Hegelund for (lookup = lookup_first; lookup < lookup_last; ++lookup, 6807de1dcadSSteen Hegelund cid += VCAP_CID_LOOKUP_SIZE, cid_next += VCAP_CID_LOOKUP_SIZE) 6817de1dcadSSteen Hegelund if (cur_cid >= cid && cur_cid < cid_next) 6827de1dcadSSteen Hegelund return lookup; 6837de1dcadSSteen Hegelund return 0; 6847de1dcadSSteen Hegelund } 6857de1dcadSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_chain_id_to_lookup); 6867de1dcadSSteen Hegelund 687c9da1ac1SSteen Hegelund /* Lookup a vcap instance using chain id */ 688c9da1ac1SSteen Hegelund struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid) 689c9da1ac1SSteen Hegelund { 690c9da1ac1SSteen Hegelund struct vcap_admin *admin; 691c9da1ac1SSteen Hegelund 6928e10490bSSteen Hegelund if (vcap_api_check(vctrl)) 6938e10490bSSteen Hegelund return NULL; 6948e10490bSSteen Hegelund 695c9da1ac1SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) { 696c9da1ac1SSteen Hegelund if (cid >= admin->first_cid && cid <= admin->last_cid) 697c9da1ac1SSteen Hegelund return admin; 698c9da1ac1SSteen Hegelund } 699c9da1ac1SSteen Hegelund return NULL; 700c9da1ac1SSteen Hegelund } 701c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_find_admin); 702c9da1ac1SSteen Hegelund 703392d0ab0SSteen Hegelund /* Is the next chain id in the following lookup, possible in another VCAP */ 704392d0ab0SSteen Hegelund bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid) 705392d0ab0SSteen Hegelund { 706392d0ab0SSteen Hegelund struct vcap_admin *admin, *next_admin; 707392d0ab0SSteen Hegelund int lookup, next_lookup; 708392d0ab0SSteen Hegelund 709392d0ab0SSteen Hegelund /* The offset must be at least one lookup */ 710392d0ab0SSteen Hegelund if (next_cid < cur_cid + VCAP_CID_LOOKUP_SIZE) 711392d0ab0SSteen Hegelund return false; 712392d0ab0SSteen Hegelund 713392d0ab0SSteen Hegelund if (vcap_api_check(vctrl)) 714392d0ab0SSteen Hegelund return false; 715392d0ab0SSteen Hegelund 716392d0ab0SSteen Hegelund admin = vcap_find_admin(vctrl, cur_cid); 717392d0ab0SSteen Hegelund if (!admin) 718392d0ab0SSteen Hegelund return false; 719392d0ab0SSteen Hegelund 720392d0ab0SSteen Hegelund /* If no VCAP contains the next chain, the next chain must be beyond 721392d0ab0SSteen Hegelund * the last chain in the current VCAP 722392d0ab0SSteen Hegelund */ 723392d0ab0SSteen Hegelund next_admin = vcap_find_admin(vctrl, next_cid); 724392d0ab0SSteen Hegelund if (!next_admin) 725392d0ab0SSteen Hegelund return next_cid > admin->last_cid; 726392d0ab0SSteen Hegelund 727392d0ab0SSteen Hegelund lookup = vcap_chain_id_to_lookup(admin, cur_cid); 728392d0ab0SSteen Hegelund next_lookup = vcap_chain_id_to_lookup(next_admin, next_cid); 729392d0ab0SSteen Hegelund 730392d0ab0SSteen Hegelund /* Next lookup must be the following lookup */ 731392d0ab0SSteen Hegelund if (admin == next_admin || admin->vtype == next_admin->vtype) 732392d0ab0SSteen Hegelund return next_lookup == lookup + 1; 733392d0ab0SSteen Hegelund 734392d0ab0SSteen Hegelund /* Must be the first lookup in the next VCAP instance */ 735392d0ab0SSteen Hegelund return next_lookup == 0; 736392d0ab0SSteen Hegelund } 737392d0ab0SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_is_next_lookup); 738392d0ab0SSteen Hegelund 7398e10490bSSteen Hegelund /* Check if there is room for a new rule */ 7408e10490bSSteen Hegelund static int vcap_rule_space(struct vcap_admin *admin, int size) 7418e10490bSSteen Hegelund { 7428e10490bSSteen Hegelund if (admin->last_used_addr - size < admin->first_valid_addr) { 7438e10490bSSteen Hegelund pr_err("%s:%d: No room for rule size: %u, %u\n", 7448e10490bSSteen Hegelund __func__, __LINE__, size, admin->first_valid_addr); 7458e10490bSSteen Hegelund return -ENOSPC; 7468e10490bSSteen Hegelund } 7478e10490bSSteen Hegelund return 0; 7488e10490bSSteen Hegelund } 7498e10490bSSteen Hegelund 7508e10490bSSteen Hegelund /* Add the keyset typefield to the list of rule keyfields */ 7518e10490bSSteen Hegelund static int vcap_add_type_keyfield(struct vcap_rule *rule) 7528e10490bSSteen Hegelund { 7538e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 7548e10490bSSteen Hegelund enum vcap_keyfield_set keyset = rule->keyset; 7558e10490bSSteen Hegelund enum vcap_type vt = ri->admin->vtype; 7568e10490bSSteen Hegelund const struct vcap_field *fields; 7578e10490bSSteen Hegelund const struct vcap_set *kset; 7588e10490bSSteen Hegelund int ret = -EINVAL; 7598e10490bSSteen Hegelund 7608e10490bSSteen Hegelund kset = vcap_keyfieldset(ri->vctrl, vt, keyset); 7618e10490bSSteen Hegelund if (!kset) 7628e10490bSSteen Hegelund return ret; 7638e10490bSSteen Hegelund if (kset->type_id == (u8)-1) /* No type field is needed */ 7648e10490bSSteen Hegelund return 0; 7658e10490bSSteen Hegelund 7668e10490bSSteen Hegelund fields = vcap_keyfields(ri->vctrl, vt, keyset); 7678e10490bSSteen Hegelund if (!fields) 7688e10490bSSteen Hegelund return -EINVAL; 7698e10490bSSteen Hegelund if (fields[VCAP_KF_TYPE].width > 1) { 7708e10490bSSteen Hegelund ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE, 7718e10490bSSteen Hegelund kset->type_id, 0xff); 7728e10490bSSteen Hegelund } else { 7738e10490bSSteen Hegelund if (kset->type_id) 7748e10490bSSteen Hegelund ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE, 7758e10490bSSteen Hegelund VCAP_BIT_1); 7768e10490bSSteen Hegelund else 7778e10490bSSteen Hegelund ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE, 7788e10490bSSteen Hegelund VCAP_BIT_0); 7798e10490bSSteen Hegelund } 7808e10490bSSteen Hegelund return 0; 7818e10490bSSteen Hegelund } 7828e10490bSSteen Hegelund 783abc4010dSSteen Hegelund /* Add a keyset to a keyset list */ 784abc4010dSSteen Hegelund bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist, 785abc4010dSSteen Hegelund enum vcap_keyfield_set keyset) 786abc4010dSSteen Hegelund { 787abc4010dSSteen Hegelund int idx; 788abc4010dSSteen Hegelund 789abc4010dSSteen Hegelund if (keysetlist->cnt < keysetlist->max) { 790abc4010dSSteen Hegelund /* Avoid duplicates */ 791abc4010dSSteen Hegelund for (idx = 0; idx < keysetlist->cnt; ++idx) 792abc4010dSSteen Hegelund if (keysetlist->keysets[idx] == keyset) 793abc4010dSSteen Hegelund return keysetlist->cnt < keysetlist->max; 794abc4010dSSteen Hegelund keysetlist->keysets[keysetlist->cnt++] = keyset; 795abc4010dSSteen Hegelund } 796abc4010dSSteen Hegelund return keysetlist->cnt < keysetlist->max; 797abc4010dSSteen Hegelund } 798abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_list_add); 799abc4010dSSteen Hegelund 800abc4010dSSteen Hegelund /* map keyset id to a string with the keyset name */ 801abc4010dSSteen Hegelund const char *vcap_keyset_name(struct vcap_control *vctrl, 802abc4010dSSteen Hegelund enum vcap_keyfield_set keyset) 803abc4010dSSteen Hegelund { 804abc4010dSSteen Hegelund return vctrl->stats->keyfield_set_names[keyset]; 805abc4010dSSteen Hegelund } 806abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_name); 807abc4010dSSteen Hegelund 808abc4010dSSteen Hegelund /* map key field id to a string with the key name */ 809abc4010dSSteen Hegelund const char *vcap_keyfield_name(struct vcap_control *vctrl, 810abc4010dSSteen Hegelund enum vcap_key_field key) 811abc4010dSSteen Hegelund { 812abc4010dSSteen Hegelund return vctrl->stats->keyfield_names[key]; 813abc4010dSSteen Hegelund } 814abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfield_name); 815abc4010dSSteen Hegelund 816242df4f7SSteen Hegelund /* map action field id to a string with the action name */ 817242df4f7SSteen Hegelund static const char *vcap_actionfield_name(struct vcap_control *vctrl, 818242df4f7SSteen Hegelund enum vcap_action_field action) 819242df4f7SSteen Hegelund { 820242df4f7SSteen Hegelund return vctrl->stats->actionfield_names[action]; 821242df4f7SSteen Hegelund } 822242df4f7SSteen Hegelund 823abc4010dSSteen Hegelund /* Return the keyfield that matches a key in a keyset */ 824abc4010dSSteen Hegelund static const struct vcap_field * 825abc4010dSSteen Hegelund vcap_find_keyset_keyfield(struct vcap_control *vctrl, 826abc4010dSSteen Hegelund enum vcap_type vtype, 827abc4010dSSteen Hegelund enum vcap_keyfield_set keyset, 828abc4010dSSteen Hegelund enum vcap_key_field key) 829abc4010dSSteen Hegelund { 830abc4010dSSteen Hegelund const struct vcap_field *fields; 831abc4010dSSteen Hegelund int idx, count; 832abc4010dSSteen Hegelund 833abc4010dSSteen Hegelund fields = vcap_keyfields(vctrl, vtype, keyset); 834abc4010dSSteen Hegelund if (!fields) 835abc4010dSSteen Hegelund return NULL; 836abc4010dSSteen Hegelund 837abc4010dSSteen Hegelund /* Iterate the keyfields of the keyset */ 838abc4010dSSteen Hegelund count = vcap_keyfield_count(vctrl, vtype, keyset); 839abc4010dSSteen Hegelund for (idx = 0; idx < count; ++idx) { 840abc4010dSSteen Hegelund if (fields[idx].width == 0) 841abc4010dSSteen Hegelund continue; 842abc4010dSSteen Hegelund 843abc4010dSSteen Hegelund if (key == idx) 844abc4010dSSteen Hegelund return &fields[idx]; 845abc4010dSSteen Hegelund } 846abc4010dSSteen Hegelund 847abc4010dSSteen Hegelund return NULL; 848abc4010dSSteen Hegelund } 849abc4010dSSteen Hegelund 850abc4010dSSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */ 851abc4010dSSteen Hegelund static bool vcap_rule_find_keysets(struct vcap_rule_internal *ri, 852abc4010dSSteen Hegelund struct vcap_keyset_list *matches) 853abc4010dSSteen Hegelund { 854abc4010dSSteen Hegelund const struct vcap_client_keyfield *ckf; 855abc4010dSSteen Hegelund int keyset, found, keycount, map_size; 856abc4010dSSteen Hegelund const struct vcap_field **map; 857abc4010dSSteen Hegelund enum vcap_type vtype; 858abc4010dSSteen Hegelund 859abc4010dSSteen Hegelund vtype = ri->admin->vtype; 860abc4010dSSteen Hegelund map = ri->vctrl->vcaps[vtype].keyfield_set_map; 861abc4010dSSteen Hegelund map_size = ri->vctrl->vcaps[vtype].keyfield_set_size; 862abc4010dSSteen Hegelund 863abc4010dSSteen Hegelund /* Get a count of the keyfields we want to match */ 864abc4010dSSteen Hegelund keycount = 0; 865abc4010dSSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) 866abc4010dSSteen Hegelund ++keycount; 867abc4010dSSteen Hegelund 868abc4010dSSteen Hegelund matches->cnt = 0; 869abc4010dSSteen Hegelund /* Iterate the keysets of the VCAP */ 870abc4010dSSteen Hegelund for (keyset = 0; keyset < map_size; ++keyset) { 871abc4010dSSteen Hegelund if (!map[keyset]) 872abc4010dSSteen Hegelund continue; 873abc4010dSSteen Hegelund 874abc4010dSSteen Hegelund /* Iterate the keys in the rule */ 875abc4010dSSteen Hegelund found = 0; 876abc4010dSSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) 877abc4010dSSteen Hegelund if (vcap_find_keyset_keyfield(ri->vctrl, vtype, 878abc4010dSSteen Hegelund keyset, ckf->ctrl.key)) 879abc4010dSSteen Hegelund ++found; 880abc4010dSSteen Hegelund 881abc4010dSSteen Hegelund /* Save the keyset if all keyfields were found */ 882abc4010dSSteen Hegelund if (found == keycount) 883abc4010dSSteen Hegelund if (!vcap_keyset_list_add(matches, keyset)) 884abc4010dSSteen Hegelund /* bail out when the quota is filled */ 885abc4010dSSteen Hegelund break; 886abc4010dSSteen Hegelund } 887abc4010dSSteen Hegelund 888abc4010dSSteen Hegelund return matches->cnt > 0; 889abc4010dSSteen Hegelund } 890abc4010dSSteen Hegelund 891c9da1ac1SSteen Hegelund /* Validate a rule with respect to available port keys */ 892c9da1ac1SSteen Hegelund int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto) 893c9da1ac1SSteen Hegelund { 894c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 895abc4010dSSteen Hegelund struct vcap_keyset_list matches = {}; 8968e10490bSSteen Hegelund enum vcap_keyfield_set keysets[10]; 8978e10490bSSteen Hegelund int ret; 898c9da1ac1SSteen Hegelund 8998e10490bSSteen Hegelund ret = vcap_api_check(ri->vctrl); 9008e10490bSSteen Hegelund if (ret) 9018e10490bSSteen Hegelund return ret; 902c9da1ac1SSteen Hegelund if (!ri->admin) { 903c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_ADMIN; 904c9da1ac1SSteen Hegelund return -EINVAL; 905c9da1ac1SSteen Hegelund } 906c9da1ac1SSteen Hegelund if (!ri->ndev) { 907c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_NETDEV; 908c9da1ac1SSteen Hegelund return -EINVAL; 909c9da1ac1SSteen Hegelund } 910abc4010dSSteen Hegelund 911abc4010dSSteen Hegelund matches.keysets = keysets; 912abc4010dSSteen Hegelund matches.max = ARRAY_SIZE(keysets); 913c9da1ac1SSteen Hegelund if (ri->data.keyset == VCAP_KFS_NO_VALUE) { 914abc4010dSSteen Hegelund /* Iterate over rule keyfields and select keysets that fits */ 915abc4010dSSteen Hegelund if (!vcap_rule_find_keysets(ri, &matches)) { 916c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH; 917c9da1ac1SSteen Hegelund return -EINVAL; 918c9da1ac1SSteen Hegelund } 919abc4010dSSteen Hegelund } else { 9208e10490bSSteen Hegelund /* prepare for keyset validation */ 9218e10490bSSteen Hegelund keysets[0] = ri->data.keyset; 922abc4010dSSteen Hegelund matches.cnt = 1; 923abc4010dSSteen Hegelund } 924abc4010dSSteen Hegelund 9258e10490bSSteen Hegelund /* Pick a keyset that is supported in the port lookups */ 926abc4010dSSteen Hegelund ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule, 927abc4010dSSteen Hegelund &matches, l3_proto); 9288e10490bSSteen Hegelund if (ret < 0) { 9298e10490bSSteen Hegelund pr_err("%s:%d: keyset validation failed: %d\n", 9308e10490bSSteen Hegelund __func__, __LINE__, ret); 9318e10490bSSteen Hegelund ri->data.exterr = VCAP_ERR_NO_PORT_KEYSET_MATCH; 9328e10490bSSteen Hegelund return ret; 9338e10490bSSteen Hegelund } 934abc4010dSSteen Hegelund /* use the keyset that is supported in the port lookups */ 935abc4010dSSteen Hegelund ret = vcap_set_rule_set_keyset(rule, ret); 936abc4010dSSteen Hegelund if (ret < 0) { 937abc4010dSSteen Hegelund pr_err("%s:%d: keyset was not updated: %d\n", 938abc4010dSSteen Hegelund __func__, __LINE__, ret); 939abc4010dSSteen Hegelund return ret; 940abc4010dSSteen Hegelund } 941c9da1ac1SSteen Hegelund if (ri->data.actionset == VCAP_AFS_NO_VALUE) { 942abc4010dSSteen Hegelund /* Later also actionsets will be matched against actions in 943abc4010dSSteen Hegelund * the rule, and the type will be set accordingly 944abc4010dSSteen Hegelund */ 945c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH; 946c9da1ac1SSteen Hegelund return -EINVAL; 947c9da1ac1SSteen Hegelund } 9488e10490bSSteen Hegelund vcap_add_type_keyfield(rule); 9498e10490bSSteen Hegelund /* Add default fields to this rule */ 9508e10490bSSteen Hegelund ri->vctrl->ops->add_default_fields(ri->ndev, ri->admin, rule); 9518e10490bSSteen Hegelund 9528e10490bSSteen Hegelund /* Rule size is the maximum of the entry and action subword count */ 9538e10490bSSteen Hegelund ri->size = max(ri->keyset_sw, ri->actionset_sw); 9548e10490bSSteen Hegelund 9558e10490bSSteen Hegelund /* Finally check if there is room for the rule in the VCAP */ 9568e10490bSSteen Hegelund return vcap_rule_space(ri->admin, ri->size); 957c9da1ac1SSteen Hegelund } 958c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_val_rule); 959c9da1ac1SSteen Hegelund 960990e4839SSteen Hegelund /* Entries are sorted with increasing values of sort_key. 961990e4839SSteen Hegelund * I.e. Lowest numerical sort_key is first in list. 962990e4839SSteen Hegelund * In order to locate largest keys first in list we negate the key size with 963990e4839SSteen Hegelund * (max_size - size). 964990e4839SSteen Hegelund */ 965990e4839SSteen Hegelund static u32 vcap_sort_key(u32 max_size, u32 size, u8 user, u16 prio) 966990e4839SSteen Hegelund { 967990e4839SSteen Hegelund return ((max_size - size) << 24) | (user << 16) | prio; 968990e4839SSteen Hegelund } 969990e4839SSteen Hegelund 9708e10490bSSteen Hegelund /* calculate the address of the next rule after this (lower address and prio) */ 9718e10490bSSteen Hegelund static u32 vcap_next_rule_addr(u32 addr, struct vcap_rule_internal *ri) 9728e10490bSSteen Hegelund { 9738e10490bSSteen Hegelund return ((addr - ri->size) / ri->size) * ri->size; 9748e10490bSSteen Hegelund } 9758e10490bSSteen Hegelund 976c9da1ac1SSteen Hegelund /* Assign a unique rule id and autogenerate one if id == 0 */ 977c9da1ac1SSteen Hegelund static u32 vcap_set_rule_id(struct vcap_rule_internal *ri) 978c9da1ac1SSteen Hegelund { 979c9da1ac1SSteen Hegelund u32 next_id; 980c9da1ac1SSteen Hegelund 981c9da1ac1SSteen Hegelund if (ri->data.id != 0) 982c9da1ac1SSteen Hegelund return ri->data.id; 983c9da1ac1SSteen Hegelund 984c9da1ac1SSteen Hegelund next_id = ri->vctrl->rule_id + 1; 985c9da1ac1SSteen Hegelund 986c9da1ac1SSteen Hegelund for (next_id = ri->vctrl->rule_id + 1; next_id < ~0; ++next_id) { 987c9da1ac1SSteen Hegelund if (!vcap_lookup_rule(ri->vctrl, next_id)) { 988c9da1ac1SSteen Hegelund ri->data.id = next_id; 989c9da1ac1SSteen Hegelund ri->vctrl->rule_id = next_id; 990c9da1ac1SSteen Hegelund break; 991c9da1ac1SSteen Hegelund } 992c9da1ac1SSteen Hegelund } 993c9da1ac1SSteen Hegelund return ri->data.id; 994c9da1ac1SSteen Hegelund } 995c9da1ac1SSteen Hegelund 9968e10490bSSteen Hegelund static int vcap_insert_rule(struct vcap_rule_internal *ri, 9978e10490bSSteen Hegelund struct vcap_rule_move *move) 9988e10490bSSteen Hegelund { 999990e4839SSteen Hegelund int sw_count = ri->vctrl->vcaps[ri->admin->vtype].sw_count; 1000990e4839SSteen Hegelund struct vcap_rule_internal *duprule, *iter, *elem = NULL; 10018e10490bSSteen Hegelund struct vcap_admin *admin = ri->admin; 1002990e4839SSteen Hegelund u32 addr; 10038e10490bSSteen Hegelund 1004990e4839SSteen Hegelund ri->sort_key = vcap_sort_key(sw_count, ri->size, ri->data.user, 1005990e4839SSteen Hegelund ri->data.priority); 1006990e4839SSteen Hegelund 1007990e4839SSteen Hegelund /* Insert the new rule in the list of rule based on the sort key 1008990e4839SSteen Hegelund * If the rule needs to be inserted between existing rules then move 1009990e4839SSteen Hegelund * these rules to make room for the new rule and update their start 1010990e4839SSteen Hegelund * address. 1011990e4839SSteen Hegelund */ 1012990e4839SSteen Hegelund list_for_each_entry(iter, &admin->rules, list) { 1013990e4839SSteen Hegelund if (ri->sort_key < iter->sort_key) { 1014990e4839SSteen Hegelund elem = iter; 1015990e4839SSteen Hegelund break; 1016990e4839SSteen Hegelund } 1017990e4839SSteen Hegelund } 1018990e4839SSteen Hegelund 1019990e4839SSteen Hegelund if (!elem) { 10208e10490bSSteen Hegelund ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri); 10218e10490bSSteen Hegelund admin->last_used_addr = ri->addr; 1022990e4839SSteen Hegelund 10238e10490bSSteen Hegelund /* Add a shallow copy of the rule to the VCAP list */ 10248e10490bSSteen Hegelund duprule = vcap_dup_rule(ri); 10258e10490bSSteen Hegelund if (IS_ERR(duprule)) 10268e10490bSSteen Hegelund return PTR_ERR(duprule); 1027990e4839SSteen Hegelund 10288e10490bSSteen Hegelund list_add_tail(&duprule->list, &admin->rules); 10298e10490bSSteen Hegelund return 0; 10308e10490bSSteen Hegelund } 10318e10490bSSteen Hegelund 1032990e4839SSteen Hegelund /* Reuse the space of the current rule */ 1033990e4839SSteen Hegelund addr = elem->addr + elem->size; 1034990e4839SSteen Hegelund ri->addr = vcap_next_rule_addr(addr, ri); 1035990e4839SSteen Hegelund addr = ri->addr; 1036990e4839SSteen Hegelund 1037990e4839SSteen Hegelund /* Add a shallow copy of the rule to the VCAP list */ 1038990e4839SSteen Hegelund duprule = vcap_dup_rule(ri); 1039990e4839SSteen Hegelund if (IS_ERR(duprule)) 1040990e4839SSteen Hegelund return PTR_ERR(duprule); 1041990e4839SSteen Hegelund 1042990e4839SSteen Hegelund /* Add before the current entry */ 1043990e4839SSteen Hegelund list_add_tail(&duprule->list, &elem->list); 1044990e4839SSteen Hegelund 1045990e4839SSteen Hegelund /* Update the current rule */ 1046990e4839SSteen Hegelund elem->addr = vcap_next_rule_addr(addr, elem); 1047990e4839SSteen Hegelund addr = elem->addr; 1048990e4839SSteen Hegelund 1049990e4839SSteen Hegelund /* Update the address in the remaining rules in the list */ 1050990e4839SSteen Hegelund list_for_each_entry_continue(elem, &admin->rules, list) { 1051990e4839SSteen Hegelund elem->addr = vcap_next_rule_addr(addr, elem); 1052990e4839SSteen Hegelund addr = elem->addr; 1053990e4839SSteen Hegelund } 1054990e4839SSteen Hegelund 1055990e4839SSteen Hegelund /* Update the move info */ 1056990e4839SSteen Hegelund move->addr = admin->last_used_addr; 1057990e4839SSteen Hegelund move->count = ri->addr - addr; 1058990e4839SSteen Hegelund move->offset = admin->last_used_addr - addr; 1059990e4839SSteen Hegelund admin->last_used_addr = addr; 1060990e4839SSteen Hegelund return 0; 1061990e4839SSteen Hegelund } 1062990e4839SSteen Hegelund 10638e10490bSSteen Hegelund static void vcap_move_rules(struct vcap_rule_internal *ri, 10648e10490bSSteen Hegelund struct vcap_rule_move *move) 10658e10490bSSteen Hegelund { 10668e10490bSSteen Hegelund ri->vctrl->ops->move(ri->ndev, ri->admin, move->addr, 10678e10490bSSteen Hegelund move->offset, move->count); 10688e10490bSSteen Hegelund } 10698e10490bSSteen Hegelund 1070c9da1ac1SSteen Hegelund /* Encode and write a validated rule to the VCAP */ 1071c9da1ac1SSteen Hegelund int vcap_add_rule(struct vcap_rule *rule) 1072c9da1ac1SSteen Hegelund { 10738e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 10748e10490bSSteen Hegelund struct vcap_rule_move move = {0}; 10758e10490bSSteen Hegelund int ret; 10768e10490bSSteen Hegelund 10778e10490bSSteen Hegelund ret = vcap_api_check(ri->vctrl); 10788e10490bSSteen Hegelund if (ret) 10798e10490bSSteen Hegelund return ret; 10808e10490bSSteen Hegelund /* Insert the new rule in the list of vcap rules */ 10818e10490bSSteen Hegelund ret = vcap_insert_rule(ri, &move); 10828e10490bSSteen Hegelund if (ret < 0) { 10838e10490bSSteen Hegelund pr_err("%s:%d: could not insert rule in vcap list: %d\n", 10848e10490bSSteen Hegelund __func__, __LINE__, ret); 10858e10490bSSteen Hegelund goto out; 10868e10490bSSteen Hegelund } 10878e10490bSSteen Hegelund if (move.count > 0) 10888e10490bSSteen Hegelund vcap_move_rules(ri, &move); 10898e10490bSSteen Hegelund ret = vcap_encode_rule(ri); 10908e10490bSSteen Hegelund if (ret) { 10918e10490bSSteen Hegelund pr_err("%s:%d: rule encoding error: %d\n", __func__, __LINE__, ret); 10928e10490bSSteen Hegelund goto out; 10938e10490bSSteen Hegelund } 10948e10490bSSteen Hegelund 10958e10490bSSteen Hegelund ret = vcap_write_rule(ri); 10968e10490bSSteen Hegelund if (ret) 10978e10490bSSteen Hegelund pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret); 10988e10490bSSteen Hegelund out: 10998e10490bSSteen Hegelund return ret; 1100c9da1ac1SSteen Hegelund } 1101c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_add_rule); 1102c9da1ac1SSteen Hegelund 1103c9da1ac1SSteen Hegelund /* Allocate a new rule with the provided arguments */ 1104c9da1ac1SSteen Hegelund struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl, 1105c9da1ac1SSteen Hegelund struct net_device *ndev, int vcap_chain_id, 1106c9da1ac1SSteen Hegelund enum vcap_user user, u16 priority, 1107c9da1ac1SSteen Hegelund u32 id) 1108c9da1ac1SSteen Hegelund { 1109c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri; 1110c9da1ac1SSteen Hegelund struct vcap_admin *admin; 1111990e4839SSteen Hegelund int err, maxsize; 1112c9da1ac1SSteen Hegelund 1113990e4839SSteen Hegelund err = vcap_api_check(vctrl); 1114990e4839SSteen Hegelund if (err) 1115990e4839SSteen Hegelund return ERR_PTR(err); 1116c9da1ac1SSteen Hegelund if (!ndev) 1117c9da1ac1SSteen Hegelund return ERR_PTR(-ENODEV); 1118c9da1ac1SSteen Hegelund /* Get the VCAP instance */ 1119c9da1ac1SSteen Hegelund admin = vcap_find_admin(vctrl, vcap_chain_id); 1120c9da1ac1SSteen Hegelund if (!admin) 1121c9da1ac1SSteen Hegelund return ERR_PTR(-ENOENT); 11228e10490bSSteen Hegelund /* Sanity check that this VCAP is supported on this platform */ 11238e10490bSSteen Hegelund if (vctrl->vcaps[admin->vtype].rows == 0) 11248e10490bSSteen Hegelund return ERR_PTR(-EINVAL); 11258e10490bSSteen Hegelund /* Check if a rule with this id already exists */ 11268e10490bSSteen Hegelund if (vcap_lookup_rule(vctrl, id)) 11278e10490bSSteen Hegelund return ERR_PTR(-EEXIST); 11288e10490bSSteen Hegelund /* Check if there is room for the rule in the block(s) of the VCAP */ 11298e10490bSSteen Hegelund maxsize = vctrl->vcaps[admin->vtype].sw_count; /* worst case rule size */ 11308e10490bSSteen Hegelund if (vcap_rule_space(admin, maxsize)) 11318e10490bSSteen Hegelund return ERR_PTR(-ENOSPC); 1132c9da1ac1SSteen Hegelund /* Create a container for the rule and return it */ 1133c9da1ac1SSteen Hegelund ri = kzalloc(sizeof(*ri), GFP_KERNEL); 1134c9da1ac1SSteen Hegelund if (!ri) 1135c9da1ac1SSteen Hegelund return ERR_PTR(-ENOMEM); 1136c9da1ac1SSteen Hegelund ri->data.vcap_chain_id = vcap_chain_id; 1137c9da1ac1SSteen Hegelund ri->data.user = user; 1138c9da1ac1SSteen Hegelund ri->data.priority = priority; 1139c9da1ac1SSteen Hegelund ri->data.id = id; 1140c9da1ac1SSteen Hegelund ri->data.keyset = VCAP_KFS_NO_VALUE; 1141c9da1ac1SSteen Hegelund ri->data.actionset = VCAP_AFS_NO_VALUE; 1142c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->list); 1143c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->data.keyfields); 1144c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->data.actionfields); 1145c9da1ac1SSteen Hegelund ri->ndev = ndev; 1146c9da1ac1SSteen Hegelund ri->admin = admin; /* refer to the vcap instance */ 1147c9da1ac1SSteen Hegelund ri->vctrl = vctrl; /* refer to the client */ 1148c9da1ac1SSteen Hegelund if (vcap_set_rule_id(ri) == 0) 1149c9da1ac1SSteen Hegelund goto out_free; 11508e10490bSSteen Hegelund vcap_erase_cache(ri); 1151c9da1ac1SSteen Hegelund return (struct vcap_rule *)ri; 1152c9da1ac1SSteen Hegelund 1153c9da1ac1SSteen Hegelund out_free: 1154c9da1ac1SSteen Hegelund kfree(ri); 1155c9da1ac1SSteen Hegelund return ERR_PTR(-EINVAL); 1156c9da1ac1SSteen Hegelund } 1157c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_alloc_rule); 1158c9da1ac1SSteen Hegelund 1159c9da1ac1SSteen Hegelund /* Free mem of a rule owned by client after the rule as been added to the VCAP */ 1160c9da1ac1SSteen Hegelund void vcap_free_rule(struct vcap_rule *rule) 1161c9da1ac1SSteen Hegelund { 1162c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1163c9da1ac1SSteen Hegelund struct vcap_client_actionfield *caf, *next_caf; 1164c9da1ac1SSteen Hegelund struct vcap_client_keyfield *ckf, *next_ckf; 1165c9da1ac1SSteen Hegelund 1166c9da1ac1SSteen Hegelund /* Deallocate the list of keys and actions */ 1167c9da1ac1SSteen Hegelund list_for_each_entry_safe(ckf, next_ckf, &ri->data.keyfields, ctrl.list) { 1168c9da1ac1SSteen Hegelund list_del(&ckf->ctrl.list); 1169c9da1ac1SSteen Hegelund kfree(ckf); 1170c9da1ac1SSteen Hegelund } 1171c9da1ac1SSteen Hegelund list_for_each_entry_safe(caf, next_caf, &ri->data.actionfields, ctrl.list) { 1172c9da1ac1SSteen Hegelund list_del(&caf->ctrl.list); 1173c9da1ac1SSteen Hegelund kfree(caf); 1174c9da1ac1SSteen Hegelund } 1175c9da1ac1SSteen Hegelund /* Deallocate the rule */ 1176c9da1ac1SSteen Hegelund kfree(rule); 1177c9da1ac1SSteen Hegelund } 1178c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_free_rule); 1179c9da1ac1SSteen Hegelund 1180990e4839SSteen Hegelund /* Return the alignment offset for a new rule address */ 1181990e4839SSteen Hegelund static int vcap_valid_rule_move(struct vcap_rule_internal *el, int offset) 1182990e4839SSteen Hegelund { 1183990e4839SSteen Hegelund return (el->addr + offset) % el->size; 1184990e4839SSteen Hegelund } 1185990e4839SSteen Hegelund 1186990e4839SSteen Hegelund /* Update the rule address with an offset */ 1187990e4839SSteen Hegelund static void vcap_adjust_rule_addr(struct vcap_rule_internal *el, int offset) 1188990e4839SSteen Hegelund { 1189990e4839SSteen Hegelund el->addr += offset; 1190990e4839SSteen Hegelund } 1191990e4839SSteen Hegelund 1192990e4839SSteen Hegelund /* Rules needs to be moved to fill the gap of the deleted rule */ 1193990e4839SSteen Hegelund static int vcap_fill_rule_gap(struct vcap_rule_internal *ri) 1194990e4839SSteen Hegelund { 1195990e4839SSteen Hegelund struct vcap_admin *admin = ri->admin; 1196990e4839SSteen Hegelund struct vcap_rule_internal *elem; 1197990e4839SSteen Hegelund struct vcap_rule_move move; 1198990e4839SSteen Hegelund int gap = 0, offset = 0; 1199990e4839SSteen Hegelund 1200990e4839SSteen Hegelund /* If the first rule is deleted: Move other rules to the top */ 1201990e4839SSteen Hegelund if (list_is_first(&ri->list, &admin->rules)) 1202990e4839SSteen Hegelund offset = admin->last_valid_addr + 1 - ri->addr - ri->size; 1203990e4839SSteen Hegelund 1204990e4839SSteen Hegelund /* Locate gaps between odd size rules and adjust the move */ 1205990e4839SSteen Hegelund elem = ri; 1206990e4839SSteen Hegelund list_for_each_entry_continue(elem, &admin->rules, list) 1207990e4839SSteen Hegelund gap += vcap_valid_rule_move(elem, ri->size); 1208990e4839SSteen Hegelund 1209990e4839SSteen Hegelund /* Update the address in the remaining rules in the list */ 1210990e4839SSteen Hegelund elem = ri; 1211990e4839SSteen Hegelund list_for_each_entry_continue(elem, &admin->rules, list) 1212990e4839SSteen Hegelund vcap_adjust_rule_addr(elem, ri->size + gap + offset); 1213990e4839SSteen Hegelund 1214990e4839SSteen Hegelund /* Update the move info */ 1215990e4839SSteen Hegelund move.addr = admin->last_used_addr; 1216990e4839SSteen Hegelund move.count = ri->addr - admin->last_used_addr - gap; 1217990e4839SSteen Hegelund move.offset = -(ri->size + gap + offset); 1218990e4839SSteen Hegelund 1219990e4839SSteen Hegelund /* Do the actual move operation */ 1220990e4839SSteen Hegelund vcap_move_rules(ri, &move); 1221990e4839SSteen Hegelund 1222990e4839SSteen Hegelund return gap + offset; 1223990e4839SSteen Hegelund } 1224990e4839SSteen Hegelund 1225c9da1ac1SSteen Hegelund /* Delete rule in a VCAP instance */ 1226c9da1ac1SSteen Hegelund int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id) 1227c9da1ac1SSteen Hegelund { 1228c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri, *elem; 1229c9da1ac1SSteen Hegelund struct vcap_admin *admin; 1230990e4839SSteen Hegelund int gap = 0, err; 1231c9da1ac1SSteen Hegelund 1232c9da1ac1SSteen Hegelund /* This will later also handle rule moving */ 1233c9da1ac1SSteen Hegelund if (!ndev) 1234c9da1ac1SSteen Hegelund return -ENODEV; 12358e10490bSSteen Hegelund err = vcap_api_check(vctrl); 12368e10490bSSteen Hegelund if (err) 12378e10490bSSteen Hegelund return err; 1238c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */ 1239c9da1ac1SSteen Hegelund ri = vcap_lookup_rule(vctrl, id); 1240c9da1ac1SSteen Hegelund if (!ri) 1241c9da1ac1SSteen Hegelund return -EINVAL; 1242c9da1ac1SSteen Hegelund admin = ri->admin; 12438e10490bSSteen Hegelund 1244990e4839SSteen Hegelund if (ri->addr > admin->last_used_addr) 1245990e4839SSteen Hegelund gap = vcap_fill_rule_gap(ri); 1246990e4839SSteen Hegelund 1247990e4839SSteen Hegelund /* Delete the rule from the list of rules and the cache */ 1248990e4839SSteen Hegelund list_del(&ri->list); 1249990e4839SSteen Hegelund vctrl->ops->init(ndev, admin, admin->last_used_addr, ri->size + gap); 1250990e4839SSteen Hegelund kfree(ri); 1251990e4839SSteen Hegelund 1252990e4839SSteen Hegelund /* Update the last used address */ 1253c9da1ac1SSteen Hegelund if (list_empty(&admin->rules)) { 1254c9da1ac1SSteen Hegelund admin->last_used_addr = admin->last_valid_addr; 1255c9da1ac1SSteen Hegelund } else { 1256990e4839SSteen Hegelund elem = list_last_entry(&admin->rules, struct vcap_rule_internal, 1257990e4839SSteen Hegelund list); 1258c9da1ac1SSteen Hegelund admin->last_used_addr = elem->addr; 1259c9da1ac1SSteen Hegelund } 1260c9da1ac1SSteen Hegelund return 0; 1261c9da1ac1SSteen Hegelund } 1262c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rule); 1263c9da1ac1SSteen Hegelund 12648e10490bSSteen Hegelund /* Delete all rules in the VCAP instance */ 12658e10490bSSteen Hegelund int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin) 12668e10490bSSteen Hegelund { 126767456717SSteen Hegelund struct vcap_enabled_port *eport, *next_eport; 12688e10490bSSteen Hegelund struct vcap_rule_internal *ri, *next_ri; 12698e10490bSSteen Hegelund int ret = vcap_api_check(vctrl); 12708e10490bSSteen Hegelund 12718e10490bSSteen Hegelund if (ret) 12728e10490bSSteen Hegelund return ret; 12738e10490bSSteen Hegelund list_for_each_entry_safe(ri, next_ri, &admin->rules, list) { 12748e10490bSSteen Hegelund vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size); 12758e10490bSSteen Hegelund list_del(&ri->list); 12768e10490bSSteen Hegelund kfree(ri); 12778e10490bSSteen Hegelund } 12788e10490bSSteen Hegelund admin->last_used_addr = admin->last_valid_addr; 127967456717SSteen Hegelund 128067456717SSteen Hegelund /* Remove list of enabled ports */ 128167456717SSteen Hegelund list_for_each_entry_safe(eport, next_eport, &admin->enabled, list) { 128267456717SSteen Hegelund list_del(&eport->list); 128367456717SSteen Hegelund kfree(eport); 128467456717SSteen Hegelund } 128567456717SSteen Hegelund 12868e10490bSSteen Hegelund return 0; 12878e10490bSSteen Hegelund } 12888e10490bSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rules); 12898e10490bSSteen Hegelund 129046be056eSSteen Hegelund /* Find information on a key field in a rule */ 129146be056eSSteen Hegelund const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule, 129246be056eSSteen Hegelund enum vcap_key_field key) 129346be056eSSteen Hegelund { 12948e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 129546be056eSSteen Hegelund enum vcap_keyfield_set keyset = rule->keyset; 129646be056eSSteen Hegelund enum vcap_type vt = ri->admin->vtype; 129746be056eSSteen Hegelund const struct vcap_field *fields; 129846be056eSSteen Hegelund 129946be056eSSteen Hegelund if (keyset == VCAP_KFS_NO_VALUE) 130046be056eSSteen Hegelund return NULL; 130146be056eSSteen Hegelund fields = vcap_keyfields(ri->vctrl, vt, keyset); 130246be056eSSteen Hegelund if (!fields) 130346be056eSSteen Hegelund return NULL; 130446be056eSSteen Hegelund return &fields[key]; 130546be056eSSteen Hegelund } 130646be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_keyfield); 130746be056eSSteen Hegelund 1308c9da1ac1SSteen Hegelund static void vcap_copy_from_client_keyfield(struct vcap_rule *rule, 1309c9da1ac1SSteen Hegelund struct vcap_client_keyfield *field, 1310c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data *data) 1311c9da1ac1SSteen Hegelund { 1312c9da1ac1SSteen Hegelund /* This will be expanded later to handle different vcap memory layouts */ 1313c9da1ac1SSteen Hegelund memcpy(&field->data, data, sizeof(field->data)); 1314c9da1ac1SSteen Hegelund } 1315c9da1ac1SSteen Hegelund 1316242df4f7SSteen Hegelund /* Check if the keyfield is already in the rule */ 1317242df4f7SSteen Hegelund static bool vcap_keyfield_unique(struct vcap_rule *rule, 1318242df4f7SSteen Hegelund enum vcap_key_field key) 1319242df4f7SSteen Hegelund { 1320242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1321242df4f7SSteen Hegelund const struct vcap_client_keyfield *ckf; 1322242df4f7SSteen Hegelund 1323242df4f7SSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) 1324242df4f7SSteen Hegelund if (ckf->ctrl.key == key) 1325242df4f7SSteen Hegelund return false; 1326242df4f7SSteen Hegelund return true; 1327242df4f7SSteen Hegelund } 1328242df4f7SSteen Hegelund 1329242df4f7SSteen Hegelund /* Check if the keyfield is in the keyset */ 1330242df4f7SSteen Hegelund static bool vcap_keyfield_match_keyset(struct vcap_rule *rule, 1331242df4f7SSteen Hegelund enum vcap_key_field key) 1332242df4f7SSteen Hegelund { 1333242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1334242df4f7SSteen Hegelund enum vcap_keyfield_set keyset = rule->keyset; 1335242df4f7SSteen Hegelund enum vcap_type vt = ri->admin->vtype; 1336242df4f7SSteen Hegelund const struct vcap_field *fields; 1337242df4f7SSteen Hegelund 1338242df4f7SSteen Hegelund /* the field is accepted if the rule has no keyset yet */ 1339242df4f7SSteen Hegelund if (keyset == VCAP_KFS_NO_VALUE) 1340242df4f7SSteen Hegelund return true; 1341242df4f7SSteen Hegelund fields = vcap_keyfields(ri->vctrl, vt, keyset); 1342242df4f7SSteen Hegelund if (!fields) 1343242df4f7SSteen Hegelund return false; 1344242df4f7SSteen Hegelund /* if there is a width there is a way */ 1345242df4f7SSteen Hegelund return fields[key].width > 0; 1346242df4f7SSteen Hegelund } 1347242df4f7SSteen Hegelund 1348c9da1ac1SSteen Hegelund static int vcap_rule_add_key(struct vcap_rule *rule, 1349c9da1ac1SSteen Hegelund enum vcap_key_field key, 1350c9da1ac1SSteen Hegelund enum vcap_field_type ftype, 1351c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data *data) 1352c9da1ac1SSteen Hegelund { 1353242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1354c9da1ac1SSteen Hegelund struct vcap_client_keyfield *field; 1355c9da1ac1SSteen Hegelund 1356242df4f7SSteen Hegelund if (!vcap_keyfield_unique(rule, key)) { 1357242df4f7SSteen Hegelund pr_warn("%s:%d: keyfield %s is already in the rule\n", 1358242df4f7SSteen Hegelund __func__, __LINE__, 1359242df4f7SSteen Hegelund vcap_keyfield_name(ri->vctrl, key)); 1360242df4f7SSteen Hegelund return -EINVAL; 1361242df4f7SSteen Hegelund } 1362242df4f7SSteen Hegelund 1363242df4f7SSteen Hegelund if (!vcap_keyfield_match_keyset(rule, key)) { 1364242df4f7SSteen Hegelund pr_err("%s:%d: keyfield %s does not belong in the rule keyset\n", 1365242df4f7SSteen Hegelund __func__, __LINE__, 1366242df4f7SSteen Hegelund vcap_keyfield_name(ri->vctrl, key)); 1367242df4f7SSteen Hegelund return -EINVAL; 1368242df4f7SSteen Hegelund } 1369242df4f7SSteen Hegelund 1370c9da1ac1SSteen Hegelund field = kzalloc(sizeof(*field), GFP_KERNEL); 1371c9da1ac1SSteen Hegelund if (!field) 1372c9da1ac1SSteen Hegelund return -ENOMEM; 1373c9da1ac1SSteen Hegelund field->ctrl.key = key; 1374c9da1ac1SSteen Hegelund field->ctrl.type = ftype; 1375c9da1ac1SSteen Hegelund vcap_copy_from_client_keyfield(rule, field, data); 1376c9da1ac1SSteen Hegelund list_add_tail(&field->ctrl.list, &rule->keyfields); 1377c9da1ac1SSteen Hegelund return 0; 1378c9da1ac1SSteen Hegelund } 1379c9da1ac1SSteen Hegelund 138046be056eSSteen Hegelund static void vcap_rule_set_key_bitsize(struct vcap_u1_key *u1, enum vcap_bit val) 138146be056eSSteen Hegelund { 138246be056eSSteen Hegelund switch (val) { 138346be056eSSteen Hegelund case VCAP_BIT_0: 138446be056eSSteen Hegelund u1->value = 0; 138546be056eSSteen Hegelund u1->mask = 1; 138646be056eSSteen Hegelund break; 138746be056eSSteen Hegelund case VCAP_BIT_1: 138846be056eSSteen Hegelund u1->value = 1; 138946be056eSSteen Hegelund u1->mask = 1; 139046be056eSSteen Hegelund break; 139146be056eSSteen Hegelund case VCAP_BIT_ANY: 139246be056eSSteen Hegelund u1->value = 0; 139346be056eSSteen Hegelund u1->mask = 0; 139446be056eSSteen Hegelund break; 139546be056eSSteen Hegelund } 139646be056eSSteen Hegelund } 139746be056eSSteen Hegelund 139846be056eSSteen Hegelund /* Add a bit key with value and mask to the rule */ 139946be056eSSteen Hegelund int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key, 140046be056eSSteen Hegelund enum vcap_bit val) 140146be056eSSteen Hegelund { 140246be056eSSteen Hegelund struct vcap_client_keyfield_data data; 140346be056eSSteen Hegelund 140446be056eSSteen Hegelund vcap_rule_set_key_bitsize(&data.u1, val); 140546be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_BIT, &data); 140646be056eSSteen Hegelund } 140746be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_bit); 140846be056eSSteen Hegelund 140946be056eSSteen Hegelund /* Add a 32 bit key field with value and mask to the rule */ 141046be056eSSteen Hegelund int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key, 141146be056eSSteen Hegelund u32 value, u32 mask) 141246be056eSSteen Hegelund { 141346be056eSSteen Hegelund struct vcap_client_keyfield_data data; 141446be056eSSteen Hegelund 141546be056eSSteen Hegelund data.u32.value = value; 141646be056eSSteen Hegelund data.u32.mask = mask; 141746be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U32, &data); 141846be056eSSteen Hegelund } 141946be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u32); 142046be056eSSteen Hegelund 1421c9da1ac1SSteen Hegelund /* Add a 48 bit key with value and mask to the rule */ 1422c9da1ac1SSteen Hegelund int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key, 1423c9da1ac1SSteen Hegelund struct vcap_u48_key *fieldval) 1424c9da1ac1SSteen Hegelund { 1425c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data data; 1426c9da1ac1SSteen Hegelund 1427c9da1ac1SSteen Hegelund memcpy(&data.u48, fieldval, sizeof(data.u48)); 1428c9da1ac1SSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U48, &data); 1429c9da1ac1SSteen Hegelund } 1430c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u48); 1431c9da1ac1SSteen Hegelund 143246be056eSSteen Hegelund /* Add a 72 bit key with value and mask to the rule */ 143346be056eSSteen Hegelund int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key, 143446be056eSSteen Hegelund struct vcap_u72_key *fieldval) 143546be056eSSteen Hegelund { 143646be056eSSteen Hegelund struct vcap_client_keyfield_data data; 143746be056eSSteen Hegelund 143846be056eSSteen Hegelund memcpy(&data.u72, fieldval, sizeof(data.u72)); 143946be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U72, &data); 144046be056eSSteen Hegelund } 144146be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72); 144246be056eSSteen Hegelund 1443d6c2964dSSteen Hegelund /* Add a 128 bit key with value and mask to the rule */ 1444d6c2964dSSteen Hegelund int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key, 1445d6c2964dSSteen Hegelund struct vcap_u128_key *fieldval) 1446d6c2964dSSteen Hegelund { 1447d6c2964dSSteen Hegelund struct vcap_client_keyfield_data data; 1448d6c2964dSSteen Hegelund 1449d6c2964dSSteen Hegelund memcpy(&data.u128, fieldval, sizeof(data.u128)); 1450d6c2964dSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U128, &data); 1451d6c2964dSSteen Hegelund } 1452d6c2964dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u128); 1453d6c2964dSSteen Hegelund 1454c9da1ac1SSteen Hegelund static void vcap_copy_from_client_actionfield(struct vcap_rule *rule, 1455c9da1ac1SSteen Hegelund struct vcap_client_actionfield *field, 1456c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data *data) 1457c9da1ac1SSteen Hegelund { 1458c9da1ac1SSteen Hegelund /* This will be expanded later to handle different vcap memory layouts */ 1459c9da1ac1SSteen Hegelund memcpy(&field->data, data, sizeof(field->data)); 1460c9da1ac1SSteen Hegelund } 1461c9da1ac1SSteen Hegelund 1462242df4f7SSteen Hegelund /* Check if the actionfield is already in the rule */ 1463242df4f7SSteen Hegelund static bool vcap_actionfield_unique(struct vcap_rule *rule, 1464242df4f7SSteen Hegelund enum vcap_action_field act) 1465242df4f7SSteen Hegelund { 1466242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1467242df4f7SSteen Hegelund const struct vcap_client_actionfield *caf; 1468242df4f7SSteen Hegelund 1469242df4f7SSteen Hegelund list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) 1470242df4f7SSteen Hegelund if (caf->ctrl.action == act) 1471242df4f7SSteen Hegelund return false; 1472242df4f7SSteen Hegelund return true; 1473242df4f7SSteen Hegelund } 1474242df4f7SSteen Hegelund 1475242df4f7SSteen Hegelund /* Check if the actionfield is in the actionset */ 1476242df4f7SSteen Hegelund static bool vcap_actionfield_match_actionset(struct vcap_rule *rule, 1477242df4f7SSteen Hegelund enum vcap_action_field action) 1478242df4f7SSteen Hegelund { 1479242df4f7SSteen Hegelund enum vcap_actionfield_set actionset = rule->actionset; 1480242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1481242df4f7SSteen Hegelund enum vcap_type vt = ri->admin->vtype; 1482242df4f7SSteen Hegelund const struct vcap_field *fields; 1483242df4f7SSteen Hegelund 1484242df4f7SSteen Hegelund /* the field is accepted if the rule has no actionset yet */ 1485242df4f7SSteen Hegelund if (actionset == VCAP_AFS_NO_VALUE) 1486242df4f7SSteen Hegelund return true; 1487242df4f7SSteen Hegelund fields = vcap_actionfields(ri->vctrl, vt, actionset); 1488242df4f7SSteen Hegelund if (!fields) 1489242df4f7SSteen Hegelund return false; 1490242df4f7SSteen Hegelund /* if there is a width there is a way */ 1491242df4f7SSteen Hegelund return fields[action].width > 0; 1492242df4f7SSteen Hegelund } 1493242df4f7SSteen Hegelund 1494c9da1ac1SSteen Hegelund static int vcap_rule_add_action(struct vcap_rule *rule, 1495c9da1ac1SSteen Hegelund enum vcap_action_field action, 1496c9da1ac1SSteen Hegelund enum vcap_field_type ftype, 1497c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data *data) 1498c9da1ac1SSteen Hegelund { 1499242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1500c9da1ac1SSteen Hegelund struct vcap_client_actionfield *field; 1501c9da1ac1SSteen Hegelund 1502242df4f7SSteen Hegelund if (!vcap_actionfield_unique(rule, action)) { 1503242df4f7SSteen Hegelund pr_warn("%s:%d: actionfield %s is already in the rule\n", 1504242df4f7SSteen Hegelund __func__, __LINE__, 1505242df4f7SSteen Hegelund vcap_actionfield_name(ri->vctrl, action)); 1506242df4f7SSteen Hegelund return -EINVAL; 1507242df4f7SSteen Hegelund } 1508242df4f7SSteen Hegelund 1509242df4f7SSteen Hegelund if (!vcap_actionfield_match_actionset(rule, action)) { 1510242df4f7SSteen Hegelund pr_err("%s:%d: actionfield %s does not belong in the rule actionset\n", 1511242df4f7SSteen Hegelund __func__, __LINE__, 1512242df4f7SSteen Hegelund vcap_actionfield_name(ri->vctrl, action)); 1513242df4f7SSteen Hegelund return -EINVAL; 1514242df4f7SSteen Hegelund } 1515242df4f7SSteen Hegelund 1516c9da1ac1SSteen Hegelund field = kzalloc(sizeof(*field), GFP_KERNEL); 1517c9da1ac1SSteen Hegelund if (!field) 1518c9da1ac1SSteen Hegelund return -ENOMEM; 1519c9da1ac1SSteen Hegelund field->ctrl.action = action; 1520c9da1ac1SSteen Hegelund field->ctrl.type = ftype; 1521c9da1ac1SSteen Hegelund vcap_copy_from_client_actionfield(rule, field, data); 1522c9da1ac1SSteen Hegelund list_add_tail(&field->ctrl.list, &rule->actionfields); 1523c9da1ac1SSteen Hegelund return 0; 1524c9da1ac1SSteen Hegelund } 1525c9da1ac1SSteen Hegelund 1526c9da1ac1SSteen Hegelund static void vcap_rule_set_action_bitsize(struct vcap_u1_action *u1, 1527c9da1ac1SSteen Hegelund enum vcap_bit val) 1528c9da1ac1SSteen Hegelund { 1529c9da1ac1SSteen Hegelund switch (val) { 1530c9da1ac1SSteen Hegelund case VCAP_BIT_0: 1531c9da1ac1SSteen Hegelund u1->value = 0; 1532c9da1ac1SSteen Hegelund break; 1533c9da1ac1SSteen Hegelund case VCAP_BIT_1: 1534c9da1ac1SSteen Hegelund u1->value = 1; 1535c9da1ac1SSteen Hegelund break; 1536c9da1ac1SSteen Hegelund case VCAP_BIT_ANY: 1537c9da1ac1SSteen Hegelund u1->value = 0; 1538c9da1ac1SSteen Hegelund break; 1539c9da1ac1SSteen Hegelund } 1540c9da1ac1SSteen Hegelund } 1541c9da1ac1SSteen Hegelund 1542c9da1ac1SSteen Hegelund /* Add a bit action with value to the rule */ 1543c9da1ac1SSteen Hegelund int vcap_rule_add_action_bit(struct vcap_rule *rule, 1544c9da1ac1SSteen Hegelund enum vcap_action_field action, 1545c9da1ac1SSteen Hegelund enum vcap_bit val) 1546c9da1ac1SSteen Hegelund { 1547c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data data; 1548c9da1ac1SSteen Hegelund 1549c9da1ac1SSteen Hegelund vcap_rule_set_action_bitsize(&data.u1, val); 1550c9da1ac1SSteen Hegelund return vcap_rule_add_action(rule, action, VCAP_FIELD_BIT, &data); 1551c9da1ac1SSteen Hegelund } 1552c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_bit); 1553c9da1ac1SSteen Hegelund 1554c9da1ac1SSteen Hegelund /* Add a 32 bit action field with value to the rule */ 1555c9da1ac1SSteen Hegelund int vcap_rule_add_action_u32(struct vcap_rule *rule, 1556c9da1ac1SSteen Hegelund enum vcap_action_field action, 1557c9da1ac1SSteen Hegelund u32 value) 1558c9da1ac1SSteen Hegelund { 1559c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data data; 1560c9da1ac1SSteen Hegelund 1561c9da1ac1SSteen Hegelund data.u32.value = value; 1562c9da1ac1SSteen Hegelund return vcap_rule_add_action(rule, action, VCAP_FIELD_U32, &data); 1563c9da1ac1SSteen Hegelund } 1564c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32); 1565c9da1ac1SSteen Hegelund 1566*f13230a4SSteen Hegelund static int vcap_read_counter(struct vcap_rule_internal *ri, 1567*f13230a4SSteen Hegelund struct vcap_counter *ctr) 1568*f13230a4SSteen Hegelund { 1569*f13230a4SSteen Hegelund struct vcap_admin *admin = ri->admin; 1570*f13230a4SSteen Hegelund 1571*f13230a4SSteen Hegelund ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ, VCAP_SEL_COUNTER, 1572*f13230a4SSteen Hegelund ri->addr); 1573*f13230a4SSteen Hegelund ri->vctrl->ops->cache_read(ri->ndev, admin, VCAP_SEL_COUNTER, 1574*f13230a4SSteen Hegelund ri->counter_id, 0); 1575*f13230a4SSteen Hegelund ctr->value = admin->cache.counter; 1576*f13230a4SSteen Hegelund ctr->sticky = admin->cache.sticky; 1577*f13230a4SSteen Hegelund return 0; 1578*f13230a4SSteen Hegelund } 1579*f13230a4SSteen Hegelund 1580c9da1ac1SSteen Hegelund /* Copy to host byte order */ 1581c9da1ac1SSteen Hegelund void vcap_netbytes_copy(u8 *dst, u8 *src, int count) 1582c9da1ac1SSteen Hegelund { 1583c9da1ac1SSteen Hegelund int idx; 1584c9da1ac1SSteen Hegelund 1585c9da1ac1SSteen Hegelund for (idx = 0; idx < count; ++idx, ++dst) 1586c9da1ac1SSteen Hegelund *dst = src[count - idx - 1]; 1587c9da1ac1SSteen Hegelund } 1588c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_netbytes_copy); 1589c9da1ac1SSteen Hegelund 1590c9da1ac1SSteen Hegelund /* Convert validation error code into tc extact error message */ 1591c9da1ac1SSteen Hegelund void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule) 1592c9da1ac1SSteen Hegelund { 1593c9da1ac1SSteen Hegelund switch (vrule->exterr) { 1594c9da1ac1SSteen Hegelund case VCAP_ERR_NONE: 1595c9da1ac1SSteen Hegelund break; 1596c9da1ac1SSteen Hegelund case VCAP_ERR_NO_ADMIN: 1597c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1598c9da1ac1SSteen Hegelund "Missing VCAP instance"); 1599c9da1ac1SSteen Hegelund break; 1600c9da1ac1SSteen Hegelund case VCAP_ERR_NO_NETDEV: 1601c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1602c9da1ac1SSteen Hegelund "Missing network interface"); 1603c9da1ac1SSteen Hegelund break; 1604c9da1ac1SSteen Hegelund case VCAP_ERR_NO_KEYSET_MATCH: 1605c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1606c9da1ac1SSteen Hegelund "No keyset matched the filter keys"); 1607c9da1ac1SSteen Hegelund break; 1608c9da1ac1SSteen Hegelund case VCAP_ERR_NO_ACTIONSET_MATCH: 1609c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1610c9da1ac1SSteen Hegelund "No actionset matched the filter actions"); 1611c9da1ac1SSteen Hegelund break; 1612c9da1ac1SSteen Hegelund case VCAP_ERR_NO_PORT_KEYSET_MATCH: 1613c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1614c9da1ac1SSteen Hegelund "No port keyset matched the filter keys"); 1615c9da1ac1SSteen Hegelund break; 1616c9da1ac1SSteen Hegelund } 1617c9da1ac1SSteen Hegelund } 1618c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_tc_exterr); 161967d63751SSteen Hegelund 162067456717SSteen Hegelund /* Check if this port is already enabled for this VCAP instance */ 162167456717SSteen Hegelund static bool vcap_is_enabled(struct vcap_admin *admin, struct net_device *ndev, 162267456717SSteen Hegelund unsigned long cookie) 162367456717SSteen Hegelund { 162467456717SSteen Hegelund struct vcap_enabled_port *eport; 162567456717SSteen Hegelund 162667456717SSteen Hegelund list_for_each_entry(eport, &admin->enabled, list) 162767456717SSteen Hegelund if (eport->cookie == cookie || eport->ndev == ndev) 162867456717SSteen Hegelund return true; 162967456717SSteen Hegelund 163067456717SSteen Hegelund return false; 163167456717SSteen Hegelund } 163267456717SSteen Hegelund 163367456717SSteen Hegelund /* Enable this port for this VCAP instance */ 163467456717SSteen Hegelund static int vcap_enable(struct vcap_admin *admin, struct net_device *ndev, 163567456717SSteen Hegelund unsigned long cookie) 163667456717SSteen Hegelund { 163767456717SSteen Hegelund struct vcap_enabled_port *eport; 163867456717SSteen Hegelund 163967456717SSteen Hegelund eport = kzalloc(sizeof(*eport), GFP_KERNEL); 164067456717SSteen Hegelund if (!eport) 164167456717SSteen Hegelund return -ENOMEM; 164267456717SSteen Hegelund 164367456717SSteen Hegelund eport->ndev = ndev; 164467456717SSteen Hegelund eport->cookie = cookie; 164567456717SSteen Hegelund list_add_tail(&eport->list, &admin->enabled); 164667456717SSteen Hegelund 164767456717SSteen Hegelund return 0; 164867456717SSteen Hegelund } 164967456717SSteen Hegelund 165067456717SSteen Hegelund /* Disable this port for this VCAP instance */ 165167456717SSteen Hegelund static int vcap_disable(struct vcap_admin *admin, struct net_device *ndev, 165267456717SSteen Hegelund unsigned long cookie) 165367456717SSteen Hegelund { 165467456717SSteen Hegelund struct vcap_enabled_port *eport; 165567456717SSteen Hegelund 165667456717SSteen Hegelund list_for_each_entry(eport, &admin->enabled, list) { 165767456717SSteen Hegelund if (eport->cookie == cookie && eport->ndev == ndev) { 165867456717SSteen Hegelund list_del(&eport->list); 165967456717SSteen Hegelund kfree(eport); 166067456717SSteen Hegelund return 0; 166167456717SSteen Hegelund } 166267456717SSteen Hegelund } 166367456717SSteen Hegelund 166467456717SSteen Hegelund return -ENOENT; 166567456717SSteen Hegelund } 166667456717SSteen Hegelund 166767456717SSteen Hegelund /* Find the VCAP instance that enabled the port using a specific filter */ 166867456717SSteen Hegelund static struct vcap_admin *vcap_find_admin_by_cookie(struct vcap_control *vctrl, 166967456717SSteen Hegelund unsigned long cookie) 167067456717SSteen Hegelund { 167167456717SSteen Hegelund struct vcap_enabled_port *eport; 167267456717SSteen Hegelund struct vcap_admin *admin; 167367456717SSteen Hegelund 167467456717SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) 167567456717SSteen Hegelund list_for_each_entry(eport, &admin->enabled, list) 167667456717SSteen Hegelund if (eport->cookie == cookie) 167767456717SSteen Hegelund return admin; 167867456717SSteen Hegelund 167967456717SSteen Hegelund return NULL; 168067456717SSteen Hegelund } 168167456717SSteen Hegelund 168267456717SSteen Hegelund /* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */ 168367456717SSteen Hegelund int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev, 168467456717SSteen Hegelund int chain_id, unsigned long cookie, bool enable) 168567456717SSteen Hegelund { 168667456717SSteen Hegelund struct vcap_admin *admin; 168767456717SSteen Hegelund int err; 168867456717SSteen Hegelund 168967456717SSteen Hegelund err = vcap_api_check(vctrl); 169067456717SSteen Hegelund if (err) 169167456717SSteen Hegelund return err; 169267456717SSteen Hegelund 169367456717SSteen Hegelund if (!ndev) 169467456717SSteen Hegelund return -ENODEV; 169567456717SSteen Hegelund 169667456717SSteen Hegelund if (chain_id) 169767456717SSteen Hegelund admin = vcap_find_admin(vctrl, chain_id); 169867456717SSteen Hegelund else 169967456717SSteen Hegelund admin = vcap_find_admin_by_cookie(vctrl, cookie); 170067456717SSteen Hegelund if (!admin) 170167456717SSteen Hegelund return -ENOENT; 170267456717SSteen Hegelund 170367456717SSteen Hegelund /* first instance and first chain */ 170467456717SSteen Hegelund if (admin->vinst || chain_id > admin->first_cid) 170567456717SSteen Hegelund return -EFAULT; 170667456717SSteen Hegelund 170767456717SSteen Hegelund err = vctrl->ops->enable(ndev, admin, enable); 170867456717SSteen Hegelund if (err) 170967456717SSteen Hegelund return err; 171067456717SSteen Hegelund 171167456717SSteen Hegelund if (chain_id) { 171267456717SSteen Hegelund if (vcap_is_enabled(admin, ndev, cookie)) 171367456717SSteen Hegelund return -EADDRINUSE; 171467456717SSteen Hegelund vcap_enable(admin, ndev, cookie); 171567456717SSteen Hegelund } else { 171667456717SSteen Hegelund vcap_disable(admin, ndev, cookie); 171767456717SSteen Hegelund } 171867456717SSteen Hegelund 171967456717SSteen Hegelund return 0; 172067456717SSteen Hegelund } 172167456717SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_enable_lookups); 172267456717SSteen Hegelund 1723*f13230a4SSteen Hegelund /* Set a rule counter id (for certain vcaps only) */ 1724*f13230a4SSteen Hegelund void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id) 1725*f13230a4SSteen Hegelund { 1726*f13230a4SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1727*f13230a4SSteen Hegelund 1728*f13230a4SSteen Hegelund ri->counter_id = counter_id; 1729*f13230a4SSteen Hegelund } 1730*f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter_id); 1731*f13230a4SSteen Hegelund 1732*f13230a4SSteen Hegelund int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr) 1733*f13230a4SSteen Hegelund { 1734*f13230a4SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1735*f13230a4SSteen Hegelund int err; 1736*f13230a4SSteen Hegelund 1737*f13230a4SSteen Hegelund err = vcap_api_check(ri->vctrl); 1738*f13230a4SSteen Hegelund if (err) 1739*f13230a4SSteen Hegelund return err; 1740*f13230a4SSteen Hegelund if (!ctr) { 1741*f13230a4SSteen Hegelund pr_err("%s:%d: counter is missing\n", __func__, __LINE__); 1742*f13230a4SSteen Hegelund return -EINVAL; 1743*f13230a4SSteen Hegelund } 1744*f13230a4SSteen Hegelund return vcap_write_counter(ri, ctr); 1745*f13230a4SSteen Hegelund } 1746*f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter); 1747*f13230a4SSteen Hegelund 1748*f13230a4SSteen Hegelund int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr) 1749*f13230a4SSteen Hegelund { 1750*f13230a4SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1751*f13230a4SSteen Hegelund int err; 1752*f13230a4SSteen Hegelund 1753*f13230a4SSteen Hegelund err = vcap_api_check(ri->vctrl); 1754*f13230a4SSteen Hegelund if (err) 1755*f13230a4SSteen Hegelund return err; 1756*f13230a4SSteen Hegelund if (!ctr) { 1757*f13230a4SSteen Hegelund pr_err("%s:%d: counter is missing\n", __func__, __LINE__); 1758*f13230a4SSteen Hegelund return -EINVAL; 1759*f13230a4SSteen Hegelund } 1760*f13230a4SSteen Hegelund return vcap_read_counter(ri, ctr); 1761*f13230a4SSteen Hegelund } 1762*f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_get_counter); 1763*f13230a4SSteen Hegelund 176467d63751SSteen Hegelund #ifdef CONFIG_VCAP_KUNIT_TEST 176567d63751SSteen Hegelund #include "vcap_api_kunit.c" 176667d63751SSteen Hegelund #endif 1767