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 9d4134d41SSteen Hegelund #include "vcap_api_private.h" 10c9da1ac1SSteen Hegelund 11*4f141e36SHoratiu Vultur static int keyfield_size_table[] = { 12*4f141e36SHoratiu Vultur [VCAP_FIELD_BIT] = sizeof(struct vcap_u1_key), 13*4f141e36SHoratiu Vultur [VCAP_FIELD_U32] = sizeof(struct vcap_u32_key), 14*4f141e36SHoratiu Vultur [VCAP_FIELD_U48] = sizeof(struct vcap_u48_key), 15*4f141e36SHoratiu Vultur [VCAP_FIELD_U56] = sizeof(struct vcap_u56_key), 16*4f141e36SHoratiu Vultur [VCAP_FIELD_U64] = sizeof(struct vcap_u64_key), 17*4f141e36SHoratiu Vultur [VCAP_FIELD_U72] = sizeof(struct vcap_u72_key), 18*4f141e36SHoratiu Vultur [VCAP_FIELD_U112] = sizeof(struct vcap_u112_key), 19*4f141e36SHoratiu Vultur [VCAP_FIELD_U128] = sizeof(struct vcap_u128_key), 20*4f141e36SHoratiu Vultur }; 21*4f141e36SHoratiu Vultur 22*4f141e36SHoratiu Vultur static int actionfield_size_table[] = { 23*4f141e36SHoratiu Vultur [VCAP_FIELD_BIT] = sizeof(struct vcap_u1_action), 24*4f141e36SHoratiu Vultur [VCAP_FIELD_U32] = sizeof(struct vcap_u32_action), 25*4f141e36SHoratiu Vultur [VCAP_FIELD_U48] = sizeof(struct vcap_u48_action), 26*4f141e36SHoratiu Vultur [VCAP_FIELD_U56] = sizeof(struct vcap_u56_action), 27*4f141e36SHoratiu Vultur [VCAP_FIELD_U64] = sizeof(struct vcap_u64_action), 28*4f141e36SHoratiu Vultur [VCAP_FIELD_U72] = sizeof(struct vcap_u72_action), 29*4f141e36SHoratiu Vultur [VCAP_FIELD_U112] = sizeof(struct vcap_u112_action), 30*4f141e36SHoratiu Vultur [VCAP_FIELD_U128] = sizeof(struct vcap_u128_action), 31*4f141e36SHoratiu Vultur }; 32*4f141e36SHoratiu Vultur 338e10490bSSteen Hegelund /* Moving a rule in the VCAP address space */ 348e10490bSSteen Hegelund struct vcap_rule_move { 358e10490bSSteen Hegelund int addr; /* address to move */ 368e10490bSSteen Hegelund int offset; /* change in address */ 378e10490bSSteen Hegelund int count; /* blocksize of addresses to move */ 388e10490bSSteen Hegelund }; 398e10490bSSteen Hegelund 4067456717SSteen Hegelund /* Stores the filter cookie that enabled the port */ 4167456717SSteen Hegelund struct vcap_enabled_port { 4267456717SSteen Hegelund struct list_head list; /* for insertion in enabled ports list */ 4367456717SSteen Hegelund struct net_device *ndev; /* the enabled port */ 4467456717SSteen Hegelund unsigned long cookie; /* filter that enabled the port */ 4567456717SSteen Hegelund }; 4667456717SSteen Hegelund 47d4134d41SSteen Hegelund void vcap_iter_set(struct vcap_stream_iter *itr, int sw_width, 48683e05c0SSteen Hegelund const struct vcap_typegroup *tg, u32 offset) 49683e05c0SSteen Hegelund { 50683e05c0SSteen Hegelund memset(itr, 0, sizeof(*itr)); 51683e05c0SSteen Hegelund itr->offset = offset; 52683e05c0SSteen Hegelund itr->sw_width = sw_width; 53683e05c0SSteen Hegelund itr->regs_per_sw = DIV_ROUND_UP(sw_width, 32); 54683e05c0SSteen Hegelund itr->tg = tg; 55683e05c0SSteen Hegelund } 56683e05c0SSteen Hegelund 57683e05c0SSteen Hegelund static void vcap_iter_skip_tg(struct vcap_stream_iter *itr) 58683e05c0SSteen Hegelund { 59683e05c0SSteen Hegelund /* Compensate the field offset for preceding typegroups. 60683e05c0SSteen Hegelund * A typegroup table ends with an all-zero terminator. 61683e05c0SSteen Hegelund */ 62683e05c0SSteen Hegelund while (itr->tg->width && itr->offset >= itr->tg->offset) { 63683e05c0SSteen Hegelund itr->offset += itr->tg->width; 64683e05c0SSteen Hegelund itr->tg++; /* next typegroup */ 65683e05c0SSteen Hegelund } 66683e05c0SSteen Hegelund } 67683e05c0SSteen Hegelund 68d4134d41SSteen Hegelund void vcap_iter_update(struct vcap_stream_iter *itr) 69683e05c0SSteen Hegelund { 70683e05c0SSteen Hegelund int sw_idx, sw_bitpos; 71683e05c0SSteen Hegelund 72683e05c0SSteen Hegelund /* Calculate the subword index and bitposition for current bit */ 73683e05c0SSteen Hegelund sw_idx = itr->offset / itr->sw_width; 74683e05c0SSteen Hegelund sw_bitpos = itr->offset % itr->sw_width; 75683e05c0SSteen Hegelund /* Calculate the register index and bitposition for current bit */ 76683e05c0SSteen Hegelund itr->reg_idx = (sw_idx * itr->regs_per_sw) + (sw_bitpos / 32); 77683e05c0SSteen Hegelund itr->reg_bitpos = sw_bitpos % 32; 78683e05c0SSteen Hegelund } 79683e05c0SSteen Hegelund 80d4134d41SSteen Hegelund void vcap_iter_init(struct vcap_stream_iter *itr, int sw_width, 81683e05c0SSteen Hegelund const struct vcap_typegroup *tg, u32 offset) 82683e05c0SSteen Hegelund { 83683e05c0SSteen Hegelund vcap_iter_set(itr, sw_width, tg, offset); 84683e05c0SSteen Hegelund vcap_iter_skip_tg(itr); 85683e05c0SSteen Hegelund vcap_iter_update(itr); 86683e05c0SSteen Hegelund } 87683e05c0SSteen Hegelund 88d4134d41SSteen Hegelund void vcap_iter_next(struct vcap_stream_iter *itr) 89683e05c0SSteen Hegelund { 90683e05c0SSteen Hegelund itr->offset++; 91683e05c0SSteen Hegelund vcap_iter_skip_tg(itr); 92683e05c0SSteen Hegelund vcap_iter_update(itr); 93683e05c0SSteen Hegelund } 94683e05c0SSteen Hegelund 95683e05c0SSteen Hegelund static void vcap_set_bit(u32 *stream, struct vcap_stream_iter *itr, bool value) 96683e05c0SSteen Hegelund { 97683e05c0SSteen Hegelund u32 mask = BIT(itr->reg_bitpos); 98683e05c0SSteen Hegelund u32 *p = &stream[itr->reg_idx]; 99683e05c0SSteen Hegelund 100683e05c0SSteen Hegelund if (value) 101683e05c0SSteen Hegelund *p |= mask; 102683e05c0SSteen Hegelund else 103683e05c0SSteen Hegelund *p &= ~mask; 104683e05c0SSteen Hegelund } 105683e05c0SSteen Hegelund 106683e05c0SSteen Hegelund static void vcap_encode_bit(u32 *stream, struct vcap_stream_iter *itr, bool val) 107683e05c0SSteen Hegelund { 108683e05c0SSteen Hegelund /* When intersected by a type group field, stream the type group bits 109683e05c0SSteen Hegelund * before continuing with the value bit 110683e05c0SSteen Hegelund */ 111683e05c0SSteen Hegelund while (itr->tg->width && 112683e05c0SSteen Hegelund itr->offset >= itr->tg->offset && 113683e05c0SSteen Hegelund itr->offset < itr->tg->offset + itr->tg->width) { 114683e05c0SSteen Hegelund int tg_bitpos = itr->tg->offset - itr->offset; 115683e05c0SSteen Hegelund 116683e05c0SSteen Hegelund vcap_set_bit(stream, itr, (itr->tg->value >> tg_bitpos) & 0x1); 117683e05c0SSteen Hegelund itr->offset++; 118683e05c0SSteen Hegelund vcap_iter_update(itr); 119683e05c0SSteen Hegelund } 120683e05c0SSteen Hegelund vcap_set_bit(stream, itr, val); 121683e05c0SSteen Hegelund } 122683e05c0SSteen Hegelund 123683e05c0SSteen Hegelund static void vcap_encode_field(u32 *stream, struct vcap_stream_iter *itr, 124683e05c0SSteen Hegelund int width, const u8 *value) 125683e05c0SSteen Hegelund { 126683e05c0SSteen Hegelund int idx; 127683e05c0SSteen Hegelund 128683e05c0SSteen Hegelund /* Loop over the field value bits and add the value bits one by one to 129683e05c0SSteen Hegelund * the output stream. 130683e05c0SSteen Hegelund */ 131683e05c0SSteen Hegelund for (idx = 0; idx < width; idx++) { 132683e05c0SSteen Hegelund u8 bidx = idx & GENMASK(2, 0); 133683e05c0SSteen Hegelund 134683e05c0SSteen Hegelund /* Encode one field value bit */ 135683e05c0SSteen Hegelund vcap_encode_bit(stream, itr, (value[idx / 8] >> bidx) & 0x1); 136683e05c0SSteen Hegelund vcap_iter_next(itr); 137683e05c0SSteen Hegelund } 138683e05c0SSteen Hegelund } 139683e05c0SSteen Hegelund 140683e05c0SSteen Hegelund static void vcap_encode_typegroups(u32 *stream, int sw_width, 141683e05c0SSteen Hegelund const struct vcap_typegroup *tg, 142683e05c0SSteen Hegelund bool mask) 143683e05c0SSteen Hegelund { 144683e05c0SSteen Hegelund struct vcap_stream_iter iter; 145683e05c0SSteen Hegelund int idx; 146683e05c0SSteen Hegelund 147683e05c0SSteen Hegelund /* Mask bits must be set to zeros (inverted later when writing to the 148683e05c0SSteen Hegelund * mask cache register), so that the mask typegroup bits consist of 149683e05c0SSteen Hegelund * match-1 or match-0, or both 150683e05c0SSteen Hegelund */ 151683e05c0SSteen Hegelund vcap_iter_set(&iter, sw_width, tg, 0); 152683e05c0SSteen Hegelund while (iter.tg->width) { 153683e05c0SSteen Hegelund /* Set position to current typegroup bit */ 154683e05c0SSteen Hegelund iter.offset = iter.tg->offset; 155683e05c0SSteen Hegelund vcap_iter_update(&iter); 156683e05c0SSteen Hegelund for (idx = 0; idx < iter.tg->width; idx++) { 157683e05c0SSteen Hegelund /* Iterate over current typegroup bits. Mask typegroup 158683e05c0SSteen Hegelund * bits are always set 159683e05c0SSteen Hegelund */ 160683e05c0SSteen Hegelund if (mask) 161683e05c0SSteen Hegelund vcap_set_bit(stream, &iter, 0x1); 162683e05c0SSteen Hegelund else 163683e05c0SSteen Hegelund vcap_set_bit(stream, &iter, 164683e05c0SSteen Hegelund (iter.tg->value >> idx) & 0x1); 165683e05c0SSteen Hegelund iter.offset++; 166683e05c0SSteen Hegelund vcap_iter_update(&iter); 167683e05c0SSteen Hegelund } 168683e05c0SSteen Hegelund iter.tg++; /* next typegroup */ 169683e05c0SSteen Hegelund } 170683e05c0SSteen Hegelund } 171683e05c0SSteen Hegelund 17246be056eSSteen Hegelund /* Return the list of keyfields for the keyset */ 173d4134d41SSteen Hegelund const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl, 17446be056eSSteen Hegelund enum vcap_type vt, 17546be056eSSteen Hegelund enum vcap_keyfield_set keyset) 17646be056eSSteen Hegelund { 17746be056eSSteen Hegelund /* Check that the keyset exists in the vcap keyset list */ 17846be056eSSteen Hegelund if (keyset >= vctrl->vcaps[vt].keyfield_set_size) 17946be056eSSteen Hegelund return NULL; 18046be056eSSteen Hegelund return vctrl->vcaps[vt].keyfield_set_map[keyset]; 18146be056eSSteen Hegelund } 18246be056eSSteen Hegelund 1838e10490bSSteen Hegelund /* Return the keyset information for the keyset */ 184d4134d41SSteen Hegelund const struct vcap_set *vcap_keyfieldset(struct vcap_control *vctrl, 1858e10490bSSteen Hegelund enum vcap_type vt, 1868e10490bSSteen Hegelund enum vcap_keyfield_set keyset) 1878e10490bSSteen Hegelund { 1888e10490bSSteen Hegelund const struct vcap_set *kset; 1898e10490bSSteen Hegelund 1908e10490bSSteen Hegelund /* Check that the keyset exists in the vcap keyset list */ 1918e10490bSSteen Hegelund if (keyset >= vctrl->vcaps[vt].keyfield_set_size) 1928e10490bSSteen Hegelund return NULL; 1938e10490bSSteen Hegelund kset = &vctrl->vcaps[vt].keyfield_set[keyset]; 1948e10490bSSteen Hegelund if (kset->sw_per_item == 0 || kset->sw_per_item > vctrl->vcaps[vt].sw_count) 1958e10490bSSteen Hegelund return NULL; 1968e10490bSSteen Hegelund return kset; 1978e10490bSSteen Hegelund } 198465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfieldset); 1998e10490bSSteen Hegelund 200683e05c0SSteen Hegelund /* Return the typegroup table for the matching keyset (using subword size) */ 201d4134d41SSteen Hegelund const struct vcap_typegroup * 202683e05c0SSteen Hegelund vcap_keyfield_typegroup(struct vcap_control *vctrl, 203683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_keyfield_set keyset) 204683e05c0SSteen Hegelund { 205683e05c0SSteen Hegelund const struct vcap_set *kset = vcap_keyfieldset(vctrl, vt, keyset); 206683e05c0SSteen Hegelund 207683e05c0SSteen Hegelund /* Check that the keyset is valid */ 208683e05c0SSteen Hegelund if (!kset) 209683e05c0SSteen Hegelund return NULL; 210683e05c0SSteen Hegelund return vctrl->vcaps[vt].keyfield_set_typegroups[kset->sw_per_item]; 211683e05c0SSteen Hegelund } 212683e05c0SSteen Hegelund 213683e05c0SSteen Hegelund /* Return the number of keyfields in the keyset */ 214d4134d41SSteen Hegelund int vcap_keyfield_count(struct vcap_control *vctrl, 215683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_keyfield_set keyset) 216683e05c0SSteen Hegelund { 217683e05c0SSteen Hegelund /* Check that the keyset exists in the vcap keyset list */ 218683e05c0SSteen Hegelund if (keyset >= vctrl->vcaps[vt].keyfield_set_size) 219683e05c0SSteen Hegelund return 0; 220683e05c0SSteen Hegelund return vctrl->vcaps[vt].keyfield_set_map_size[keyset]; 221683e05c0SSteen Hegelund } 222683e05c0SSteen Hegelund 223683e05c0SSteen Hegelund static void vcap_encode_keyfield(struct vcap_rule_internal *ri, 224683e05c0SSteen Hegelund const struct vcap_client_keyfield *kf, 225683e05c0SSteen Hegelund const struct vcap_field *rf, 226683e05c0SSteen Hegelund const struct vcap_typegroup *tgt) 227683e05c0SSteen Hegelund { 228683e05c0SSteen Hegelund int sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width; 229683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache; 230683e05c0SSteen Hegelund struct vcap_stream_iter iter; 231683e05c0SSteen Hegelund const u8 *value, *mask; 232683e05c0SSteen Hegelund 233683e05c0SSteen Hegelund /* Encode the fields for the key and the mask in their respective 234683e05c0SSteen Hegelund * streams, respecting the subword width. 235683e05c0SSteen Hegelund */ 236683e05c0SSteen Hegelund switch (kf->ctrl.type) { 237683e05c0SSteen Hegelund case VCAP_FIELD_BIT: 238683e05c0SSteen Hegelund value = &kf->data.u1.value; 239683e05c0SSteen Hegelund mask = &kf->data.u1.mask; 240683e05c0SSteen Hegelund break; 241683e05c0SSteen Hegelund case VCAP_FIELD_U32: 242683e05c0SSteen Hegelund value = (const u8 *)&kf->data.u32.value; 243683e05c0SSteen Hegelund mask = (const u8 *)&kf->data.u32.mask; 244683e05c0SSteen Hegelund break; 245683e05c0SSteen Hegelund case VCAP_FIELD_U48: 246683e05c0SSteen Hegelund value = kf->data.u48.value; 247683e05c0SSteen Hegelund mask = kf->data.u48.mask; 248683e05c0SSteen Hegelund break; 249683e05c0SSteen Hegelund case VCAP_FIELD_U56: 250683e05c0SSteen Hegelund value = kf->data.u56.value; 251683e05c0SSteen Hegelund mask = kf->data.u56.mask; 252683e05c0SSteen Hegelund break; 253683e05c0SSteen Hegelund case VCAP_FIELD_U64: 254683e05c0SSteen Hegelund value = kf->data.u64.value; 255683e05c0SSteen Hegelund mask = kf->data.u64.mask; 256683e05c0SSteen Hegelund break; 257683e05c0SSteen Hegelund case VCAP_FIELD_U72: 258683e05c0SSteen Hegelund value = kf->data.u72.value; 259683e05c0SSteen Hegelund mask = kf->data.u72.mask; 260683e05c0SSteen Hegelund break; 261683e05c0SSteen Hegelund case VCAP_FIELD_U112: 262683e05c0SSteen Hegelund value = kf->data.u112.value; 263683e05c0SSteen Hegelund mask = kf->data.u112.mask; 264683e05c0SSteen Hegelund break; 265683e05c0SSteen Hegelund case VCAP_FIELD_U128: 266683e05c0SSteen Hegelund value = kf->data.u128.value; 267683e05c0SSteen Hegelund mask = kf->data.u128.mask; 268683e05c0SSteen Hegelund break; 269683e05c0SSteen Hegelund } 270683e05c0SSteen Hegelund vcap_iter_init(&iter, sw_width, tgt, rf->offset); 271683e05c0SSteen Hegelund vcap_encode_field(cache->keystream, &iter, rf->width, value); 272683e05c0SSteen Hegelund vcap_iter_init(&iter, sw_width, tgt, rf->offset); 273683e05c0SSteen Hegelund vcap_encode_field(cache->maskstream, &iter, rf->width, mask); 274683e05c0SSteen Hegelund } 275683e05c0SSteen Hegelund 276683e05c0SSteen Hegelund static void vcap_encode_keyfield_typegroups(struct vcap_control *vctrl, 277683e05c0SSteen Hegelund struct vcap_rule_internal *ri, 278683e05c0SSteen Hegelund const struct vcap_typegroup *tgt) 279683e05c0SSteen Hegelund { 280683e05c0SSteen Hegelund int sw_width = vctrl->vcaps[ri->admin->vtype].sw_width; 281683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache; 282683e05c0SSteen Hegelund 283683e05c0SSteen Hegelund /* Encode the typegroup bits for the key and the mask in their streams, 284683e05c0SSteen Hegelund * respecting the subword width. 285683e05c0SSteen Hegelund */ 286683e05c0SSteen Hegelund vcap_encode_typegroups(cache->keystream, sw_width, tgt, false); 287683e05c0SSteen Hegelund vcap_encode_typegroups(cache->maskstream, sw_width, tgt, true); 288683e05c0SSteen Hegelund } 289683e05c0SSteen Hegelund 290683e05c0SSteen Hegelund static int vcap_encode_rule_keyset(struct vcap_rule_internal *ri) 291683e05c0SSteen Hegelund { 292683e05c0SSteen Hegelund const struct vcap_client_keyfield *ckf; 293683e05c0SSteen Hegelund const struct vcap_typegroup *tg_table; 294683e05c0SSteen Hegelund const struct vcap_field *kf_table; 295683e05c0SSteen Hegelund int keyset_size; 296683e05c0SSteen Hegelund 297683e05c0SSteen Hegelund /* Get a valid set of fields for the specific keyset */ 298683e05c0SSteen Hegelund kf_table = vcap_keyfields(ri->vctrl, ri->admin->vtype, ri->data.keyset); 299683e05c0SSteen Hegelund if (!kf_table) { 300683e05c0SSteen Hegelund pr_err("%s:%d: no fields available for this keyset: %d\n", 301683e05c0SSteen Hegelund __func__, __LINE__, ri->data.keyset); 302683e05c0SSteen Hegelund return -EINVAL; 303683e05c0SSteen Hegelund } 304683e05c0SSteen Hegelund /* Get a valid typegroup for the specific keyset */ 305683e05c0SSteen Hegelund tg_table = vcap_keyfield_typegroup(ri->vctrl, ri->admin->vtype, 306683e05c0SSteen Hegelund ri->data.keyset); 307683e05c0SSteen Hegelund if (!tg_table) { 308683e05c0SSteen Hegelund pr_err("%s:%d: no typegroups available for this keyset: %d\n", 309683e05c0SSteen Hegelund __func__, __LINE__, ri->data.keyset); 310683e05c0SSteen Hegelund return -EINVAL; 311683e05c0SSteen Hegelund } 312683e05c0SSteen Hegelund /* Get a valid size for the specific keyset */ 313683e05c0SSteen Hegelund keyset_size = vcap_keyfield_count(ri->vctrl, ri->admin->vtype, 314683e05c0SSteen Hegelund ri->data.keyset); 315683e05c0SSteen Hegelund if (keyset_size == 0) { 316683e05c0SSteen Hegelund pr_err("%s:%d: zero field count for this keyset: %d\n", 317683e05c0SSteen Hegelund __func__, __LINE__, ri->data.keyset); 318683e05c0SSteen Hegelund return -EINVAL; 319683e05c0SSteen Hegelund } 320683e05c0SSteen Hegelund /* Iterate over the keyfields (key, mask) in the rule 321683e05c0SSteen Hegelund * and encode these bits 322683e05c0SSteen Hegelund */ 323683e05c0SSteen Hegelund if (list_empty(&ri->data.keyfields)) { 324683e05c0SSteen Hegelund pr_err("%s:%d: no keyfields in the rule\n", __func__, __LINE__); 325683e05c0SSteen Hegelund return -EINVAL; 326683e05c0SSteen Hegelund } 327683e05c0SSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) { 328683e05c0SSteen Hegelund /* Check that the client entry exists in the keyset */ 329683e05c0SSteen Hegelund if (ckf->ctrl.key >= keyset_size) { 330683e05c0SSteen Hegelund pr_err("%s:%d: key %d is not in vcap\n", 331683e05c0SSteen Hegelund __func__, __LINE__, ckf->ctrl.key); 332683e05c0SSteen Hegelund return -EINVAL; 333683e05c0SSteen Hegelund } 334683e05c0SSteen Hegelund vcap_encode_keyfield(ri, ckf, &kf_table[ckf->ctrl.key], tg_table); 335683e05c0SSteen Hegelund } 336683e05c0SSteen Hegelund /* Add typegroup bits to the key/mask bitstreams */ 337683e05c0SSteen Hegelund vcap_encode_keyfield_typegroups(ri->vctrl, ri, tg_table); 338683e05c0SSteen Hegelund return 0; 339683e05c0SSteen Hegelund } 340683e05c0SSteen Hegelund 341683e05c0SSteen Hegelund /* Return the list of actionfields for the actionset */ 34272d84dd6SSteen Hegelund const struct vcap_field * 343683e05c0SSteen Hegelund vcap_actionfields(struct vcap_control *vctrl, 344683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_actionfield_set actionset) 345683e05c0SSteen Hegelund { 346683e05c0SSteen Hegelund /* Check that the actionset exists in the vcap actionset list */ 347683e05c0SSteen Hegelund if (actionset >= vctrl->vcaps[vt].actionfield_set_size) 348683e05c0SSteen Hegelund return NULL; 349683e05c0SSteen Hegelund return vctrl->vcaps[vt].actionfield_set_map[actionset]; 350683e05c0SSteen Hegelund } 351683e05c0SSteen Hegelund 35272d84dd6SSteen Hegelund const struct vcap_set * 3538e10490bSSteen Hegelund vcap_actionfieldset(struct vcap_control *vctrl, 3548e10490bSSteen Hegelund enum vcap_type vt, enum vcap_actionfield_set actionset) 3558e10490bSSteen Hegelund { 3568e10490bSSteen Hegelund const struct vcap_set *aset; 3578e10490bSSteen Hegelund 3588e10490bSSteen Hegelund /* Check that the actionset exists in the vcap actionset list */ 3598e10490bSSteen Hegelund if (actionset >= vctrl->vcaps[vt].actionfield_set_size) 3608e10490bSSteen Hegelund return NULL; 3618e10490bSSteen Hegelund aset = &vctrl->vcaps[vt].actionfield_set[actionset]; 3628e10490bSSteen Hegelund if (aset->sw_per_item == 0 || aset->sw_per_item > vctrl->vcaps[vt].sw_count) 3638e10490bSSteen Hegelund return NULL; 3648e10490bSSteen Hegelund return aset; 3658e10490bSSteen Hegelund } 3668e10490bSSteen Hegelund 367683e05c0SSteen Hegelund /* Return the typegroup table for the matching actionset (using subword size) */ 36872d84dd6SSteen Hegelund const struct vcap_typegroup * 369683e05c0SSteen Hegelund vcap_actionfield_typegroup(struct vcap_control *vctrl, 370683e05c0SSteen Hegelund enum vcap_type vt, enum vcap_actionfield_set actionset) 371683e05c0SSteen Hegelund { 372683e05c0SSteen Hegelund const struct vcap_set *aset = vcap_actionfieldset(vctrl, vt, actionset); 373683e05c0SSteen Hegelund 374683e05c0SSteen Hegelund /* Check that the actionset is valid */ 375683e05c0SSteen Hegelund if (!aset) 376683e05c0SSteen Hegelund return NULL; 377683e05c0SSteen Hegelund return vctrl->vcaps[vt].actionfield_set_typegroups[aset->sw_per_item]; 378683e05c0SSteen Hegelund } 379683e05c0SSteen Hegelund 380683e05c0SSteen Hegelund /* Return the number of actionfields in the actionset */ 38172d84dd6SSteen Hegelund int vcap_actionfield_count(struct vcap_control *vctrl, 382683e05c0SSteen Hegelund enum vcap_type vt, 383683e05c0SSteen Hegelund enum vcap_actionfield_set actionset) 384683e05c0SSteen Hegelund { 385683e05c0SSteen Hegelund /* Check that the actionset exists in the vcap actionset list */ 386683e05c0SSteen Hegelund if (actionset >= vctrl->vcaps[vt].actionfield_set_size) 387683e05c0SSteen Hegelund return 0; 388683e05c0SSteen Hegelund return vctrl->vcaps[vt].actionfield_set_map_size[actionset]; 389683e05c0SSteen Hegelund } 390683e05c0SSteen Hegelund 391683e05c0SSteen Hegelund static void vcap_encode_actionfield(struct vcap_rule_internal *ri, 392683e05c0SSteen Hegelund const struct vcap_client_actionfield *af, 393683e05c0SSteen Hegelund const struct vcap_field *rf, 394683e05c0SSteen Hegelund const struct vcap_typegroup *tgt) 395683e05c0SSteen Hegelund { 396683e05c0SSteen Hegelund int act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width; 397683e05c0SSteen Hegelund 398683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache; 399683e05c0SSteen Hegelund struct vcap_stream_iter iter; 400683e05c0SSteen Hegelund const u8 *value; 401683e05c0SSteen Hegelund 402683e05c0SSteen Hegelund /* Encode the action field in the stream, respecting the subword width */ 403683e05c0SSteen Hegelund switch (af->ctrl.type) { 404683e05c0SSteen Hegelund case VCAP_FIELD_BIT: 405683e05c0SSteen Hegelund value = &af->data.u1.value; 406683e05c0SSteen Hegelund break; 407683e05c0SSteen Hegelund case VCAP_FIELD_U32: 408683e05c0SSteen Hegelund value = (const u8 *)&af->data.u32.value; 409683e05c0SSteen Hegelund break; 410683e05c0SSteen Hegelund case VCAP_FIELD_U48: 411683e05c0SSteen Hegelund value = af->data.u48.value; 412683e05c0SSteen Hegelund break; 413683e05c0SSteen Hegelund case VCAP_FIELD_U56: 414683e05c0SSteen Hegelund value = af->data.u56.value; 415683e05c0SSteen Hegelund break; 416683e05c0SSteen Hegelund case VCAP_FIELD_U64: 417683e05c0SSteen Hegelund value = af->data.u64.value; 418683e05c0SSteen Hegelund break; 419683e05c0SSteen Hegelund case VCAP_FIELD_U72: 420683e05c0SSteen Hegelund value = af->data.u72.value; 421683e05c0SSteen Hegelund break; 422683e05c0SSteen Hegelund case VCAP_FIELD_U112: 423683e05c0SSteen Hegelund value = af->data.u112.value; 424683e05c0SSteen Hegelund break; 425683e05c0SSteen Hegelund case VCAP_FIELD_U128: 426683e05c0SSteen Hegelund value = af->data.u128.value; 427683e05c0SSteen Hegelund break; 428683e05c0SSteen Hegelund } 429683e05c0SSteen Hegelund vcap_iter_init(&iter, act_width, tgt, rf->offset); 430683e05c0SSteen Hegelund vcap_encode_field(cache->actionstream, &iter, rf->width, value); 431683e05c0SSteen Hegelund } 432683e05c0SSteen Hegelund 433683e05c0SSteen Hegelund static void vcap_encode_actionfield_typegroups(struct vcap_rule_internal *ri, 434683e05c0SSteen Hegelund const struct vcap_typegroup *tgt) 435683e05c0SSteen Hegelund { 436683e05c0SSteen Hegelund int sw_width = ri->vctrl->vcaps[ri->admin->vtype].act_width; 437683e05c0SSteen Hegelund struct vcap_cache_data *cache = &ri->admin->cache; 438683e05c0SSteen Hegelund 439683e05c0SSteen Hegelund /* Encode the typegroup bits for the actionstream respecting the subword 440683e05c0SSteen Hegelund * width. 441683e05c0SSteen Hegelund */ 442683e05c0SSteen Hegelund vcap_encode_typegroups(cache->actionstream, sw_width, tgt, false); 443683e05c0SSteen Hegelund } 444683e05c0SSteen Hegelund 445683e05c0SSteen Hegelund static int vcap_encode_rule_actionset(struct vcap_rule_internal *ri) 446683e05c0SSteen Hegelund { 447683e05c0SSteen Hegelund const struct vcap_client_actionfield *caf; 448683e05c0SSteen Hegelund const struct vcap_typegroup *tg_table; 449683e05c0SSteen Hegelund const struct vcap_field *af_table; 450683e05c0SSteen Hegelund int actionset_size; 451683e05c0SSteen Hegelund 452683e05c0SSteen Hegelund /* Get a valid set of actionset fields for the specific actionset */ 453683e05c0SSteen Hegelund af_table = vcap_actionfields(ri->vctrl, ri->admin->vtype, 454683e05c0SSteen Hegelund ri->data.actionset); 455683e05c0SSteen Hegelund if (!af_table) { 456683e05c0SSteen Hegelund pr_err("%s:%d: no fields available for this actionset: %d\n", 457683e05c0SSteen Hegelund __func__, __LINE__, ri->data.actionset); 458683e05c0SSteen Hegelund return -EINVAL; 459683e05c0SSteen Hegelund } 460683e05c0SSteen Hegelund /* Get a valid typegroup for the specific actionset */ 461683e05c0SSteen Hegelund tg_table = vcap_actionfield_typegroup(ri->vctrl, ri->admin->vtype, 462683e05c0SSteen Hegelund ri->data.actionset); 463683e05c0SSteen Hegelund if (!tg_table) { 464683e05c0SSteen Hegelund pr_err("%s:%d: no typegroups available for this actionset: %d\n", 465683e05c0SSteen Hegelund __func__, __LINE__, ri->data.actionset); 466683e05c0SSteen Hegelund return -EINVAL; 467683e05c0SSteen Hegelund } 468683e05c0SSteen Hegelund /* Get a valid actionset size for the specific actionset */ 469683e05c0SSteen Hegelund actionset_size = vcap_actionfield_count(ri->vctrl, ri->admin->vtype, 470683e05c0SSteen Hegelund ri->data.actionset); 471683e05c0SSteen Hegelund if (actionset_size == 0) { 472683e05c0SSteen Hegelund pr_err("%s:%d: zero field count for this actionset: %d\n", 473683e05c0SSteen Hegelund __func__, __LINE__, ri->data.actionset); 474683e05c0SSteen Hegelund return -EINVAL; 475683e05c0SSteen Hegelund } 476683e05c0SSteen Hegelund /* Iterate over the actionfields in the rule 477683e05c0SSteen Hegelund * and encode these bits 478683e05c0SSteen Hegelund */ 479683e05c0SSteen Hegelund if (list_empty(&ri->data.actionfields)) 480683e05c0SSteen Hegelund pr_warn("%s:%d: no actionfields in the rule\n", 481683e05c0SSteen Hegelund __func__, __LINE__); 482683e05c0SSteen Hegelund list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) { 483683e05c0SSteen Hegelund /* Check that the client action exists in the actionset */ 484683e05c0SSteen Hegelund if (caf->ctrl.action >= actionset_size) { 485683e05c0SSteen Hegelund pr_err("%s:%d: action %d is not in vcap\n", 486683e05c0SSteen Hegelund __func__, __LINE__, caf->ctrl.action); 487683e05c0SSteen Hegelund return -EINVAL; 488683e05c0SSteen Hegelund } 489683e05c0SSteen Hegelund vcap_encode_actionfield(ri, caf, &af_table[caf->ctrl.action], 490683e05c0SSteen Hegelund tg_table); 491683e05c0SSteen Hegelund } 492683e05c0SSteen Hegelund /* Add typegroup bits to the entry bitstreams */ 493683e05c0SSteen Hegelund vcap_encode_actionfield_typegroups(ri, tg_table); 494683e05c0SSteen Hegelund return 0; 495683e05c0SSteen Hegelund } 496683e05c0SSteen Hegelund 4978e10490bSSteen Hegelund static int vcap_encode_rule(struct vcap_rule_internal *ri) 4988e10490bSSteen Hegelund { 499683e05c0SSteen Hegelund int err; 500683e05c0SSteen Hegelund 501683e05c0SSteen Hegelund err = vcap_encode_rule_keyset(ri); 502683e05c0SSteen Hegelund if (err) 503683e05c0SSteen Hegelund return err; 504683e05c0SSteen Hegelund err = vcap_encode_rule_actionset(ri); 505683e05c0SSteen Hegelund if (err) 506683e05c0SSteen Hegelund return err; 5078e10490bSSteen Hegelund return 0; 5088e10490bSSteen Hegelund } 5098e10490bSSteen Hegelund 510d4134d41SSteen Hegelund int vcap_api_check(struct vcap_control *ctrl) 5118e10490bSSteen Hegelund { 5128e10490bSSteen Hegelund if (!ctrl) { 5138e10490bSSteen Hegelund pr_err("%s:%d: vcap control is missing\n", __func__, __LINE__); 5148e10490bSSteen Hegelund return -EINVAL; 5158e10490bSSteen Hegelund } 5168e10490bSSteen Hegelund if (!ctrl->ops || !ctrl->ops->validate_keyset || 5178e10490bSSteen Hegelund !ctrl->ops->add_default_fields || !ctrl->ops->cache_erase || 5188e10490bSSteen Hegelund !ctrl->ops->cache_write || !ctrl->ops->cache_read || 5198e10490bSSteen Hegelund !ctrl->ops->init || !ctrl->ops->update || !ctrl->ops->move || 52067456717SSteen Hegelund !ctrl->ops->port_info || !ctrl->ops->enable) { 5218e10490bSSteen Hegelund pr_err("%s:%d: client operations are missing\n", 5228e10490bSSteen Hegelund __func__, __LINE__); 5238e10490bSSteen Hegelund return -ENOENT; 5248e10490bSSteen Hegelund } 5258e10490bSSteen Hegelund return 0; 5268e10490bSSteen Hegelund } 5278e10490bSSteen Hegelund 5283a792156SSteen Hegelund void vcap_erase_cache(struct vcap_rule_internal *ri) 5298e10490bSSteen Hegelund { 5308e10490bSSteen Hegelund ri->vctrl->ops->cache_erase(ri->admin); 5318e10490bSSteen Hegelund } 5328e10490bSSteen Hegelund 533c9da1ac1SSteen Hegelund /* Update the keyset for the rule */ 534c9da1ac1SSteen Hegelund int vcap_set_rule_set_keyset(struct vcap_rule *rule, 535c9da1ac1SSteen Hegelund enum vcap_keyfield_set keyset) 536c9da1ac1SSteen Hegelund { 5378e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 5388e10490bSSteen Hegelund const struct vcap_set *kset; 5398e10490bSSteen Hegelund int sw_width; 5408e10490bSSteen Hegelund 5418e10490bSSteen Hegelund kset = vcap_keyfieldset(ri->vctrl, ri->admin->vtype, keyset); 5428e10490bSSteen Hegelund /* Check that the keyset is valid */ 5438e10490bSSteen Hegelund if (!kset) 5448e10490bSSteen Hegelund return -EINVAL; 5458e10490bSSteen Hegelund ri->keyset_sw = kset->sw_per_item; 5468e10490bSSteen Hegelund sw_width = ri->vctrl->vcaps[ri->admin->vtype].sw_width; 5478e10490bSSteen Hegelund ri->keyset_sw_regs = DIV_ROUND_UP(sw_width, 32); 5488e10490bSSteen Hegelund ri->data.keyset = keyset; 549c9da1ac1SSteen Hegelund return 0; 550c9da1ac1SSteen Hegelund } 551c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_keyset); 552c9da1ac1SSteen Hegelund 553c9da1ac1SSteen Hegelund /* Update the actionset for the rule */ 554c9da1ac1SSteen Hegelund int vcap_set_rule_set_actionset(struct vcap_rule *rule, 555c9da1ac1SSteen Hegelund enum vcap_actionfield_set actionset) 556c9da1ac1SSteen Hegelund { 5578e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 5588e10490bSSteen Hegelund const struct vcap_set *aset; 5598e10490bSSteen Hegelund int act_width; 5608e10490bSSteen Hegelund 5618e10490bSSteen Hegelund aset = vcap_actionfieldset(ri->vctrl, ri->admin->vtype, actionset); 5628e10490bSSteen Hegelund /* Check that the actionset is valid */ 5638e10490bSSteen Hegelund if (!aset) 5648e10490bSSteen Hegelund return -EINVAL; 5658e10490bSSteen Hegelund ri->actionset_sw = aset->sw_per_item; 5668e10490bSSteen Hegelund act_width = ri->vctrl->vcaps[ri->admin->vtype].act_width; 5678e10490bSSteen Hegelund ri->actionset_sw_regs = DIV_ROUND_UP(act_width, 32); 5688e10490bSSteen Hegelund ri->data.actionset = actionset; 569c9da1ac1SSteen Hegelund return 0; 570c9da1ac1SSteen Hegelund } 571c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_actionset); 572c9da1ac1SSteen Hegelund 573c9da1ac1SSteen Hegelund /* Find a rule with a provided rule id */ 574c9da1ac1SSteen Hegelund static struct vcap_rule_internal *vcap_lookup_rule(struct vcap_control *vctrl, 575c9da1ac1SSteen Hegelund u32 id) 576c9da1ac1SSteen Hegelund { 577c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri; 578c9da1ac1SSteen Hegelund struct vcap_admin *admin; 579c9da1ac1SSteen Hegelund 580c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */ 581c9da1ac1SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) 582c9da1ac1SSteen Hegelund list_for_each_entry(ri, &admin->rules, list) 583c9da1ac1SSteen Hegelund if (ri->data.id == id) 584c9da1ac1SSteen Hegelund return ri; 585c9da1ac1SSteen Hegelund return NULL; 586c9da1ac1SSteen Hegelund } 587c9da1ac1SSteen Hegelund 588c9da1ac1SSteen Hegelund /* Find a rule id with a provided cookie */ 589c9da1ac1SSteen Hegelund int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie) 590c9da1ac1SSteen Hegelund { 591c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri; 592c9da1ac1SSteen Hegelund struct vcap_admin *admin; 593c9da1ac1SSteen Hegelund 594c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */ 595c9da1ac1SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) 596c9da1ac1SSteen Hegelund list_for_each_entry(ri, &admin->rules, list) 597c9da1ac1SSteen Hegelund if (ri->data.cookie == cookie) 598c9da1ac1SSteen Hegelund return ri->data.id; 599c9da1ac1SSteen Hegelund return -ENOENT; 600c9da1ac1SSteen Hegelund } 601c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie); 602c9da1ac1SSteen Hegelund 6038e10490bSSteen Hegelund /* Make a shallow copy of the rule without the fields */ 6043a792156SSteen Hegelund struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri) 6058e10490bSSteen Hegelund { 6068e10490bSSteen Hegelund struct vcap_rule_internal *duprule; 6078e10490bSSteen Hegelund 6088e10490bSSteen Hegelund /* Allocate the client part */ 6098e10490bSSteen Hegelund duprule = kzalloc(sizeof(*duprule), GFP_KERNEL); 6108e10490bSSteen Hegelund if (!duprule) 6118e10490bSSteen Hegelund return ERR_PTR(-ENOMEM); 6128e10490bSSteen Hegelund *duprule = *ri; 6138e10490bSSteen Hegelund /* Not inserted in the VCAP */ 6148e10490bSSteen Hegelund INIT_LIST_HEAD(&duprule->list); 6158e10490bSSteen Hegelund /* No elements in these lists */ 6168e10490bSSteen Hegelund INIT_LIST_HEAD(&duprule->data.keyfields); 6178e10490bSSteen Hegelund INIT_LIST_HEAD(&duprule->data.actionfields); 6188e10490bSSteen Hegelund return duprule; 6198e10490bSSteen Hegelund } 6208e10490bSSteen Hegelund 6218e10490bSSteen Hegelund /* Write VCAP cache content to the VCAP HW instance */ 6228e10490bSSteen Hegelund static int vcap_write_rule(struct vcap_rule_internal *ri) 6238e10490bSSteen Hegelund { 6248e10490bSSteen Hegelund struct vcap_admin *admin = ri->admin; 6258e10490bSSteen Hegelund int sw_idx, ent_idx = 0, act_idx = 0; 6268e10490bSSteen Hegelund u32 addr = ri->addr; 6278e10490bSSteen Hegelund 6288e10490bSSteen Hegelund if (!ri->size || !ri->keyset_sw_regs || !ri->actionset_sw_regs) { 6298e10490bSSteen Hegelund pr_err("%s:%d: rule is empty\n", __func__, __LINE__); 6308e10490bSSteen Hegelund return -EINVAL; 6318e10490bSSteen Hegelund } 6328e10490bSSteen Hegelund /* Use the values in the streams to write the VCAP cache */ 6338e10490bSSteen Hegelund for (sw_idx = 0; sw_idx < ri->size; sw_idx++, addr++) { 6348e10490bSSteen Hegelund ri->vctrl->ops->cache_write(ri->ndev, admin, 6358e10490bSSteen Hegelund VCAP_SEL_ENTRY, ent_idx, 6368e10490bSSteen Hegelund ri->keyset_sw_regs); 6378e10490bSSteen Hegelund ri->vctrl->ops->cache_write(ri->ndev, admin, 6388e10490bSSteen Hegelund VCAP_SEL_ACTION, act_idx, 6398e10490bSSteen Hegelund ri->actionset_sw_regs); 6408e10490bSSteen Hegelund ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE, 6418e10490bSSteen Hegelund VCAP_SEL_ALL, addr); 6428e10490bSSteen Hegelund ent_idx += ri->keyset_sw_regs; 6438e10490bSSteen Hegelund act_idx += ri->actionset_sw_regs; 6448e10490bSSteen Hegelund } 6458e10490bSSteen Hegelund return 0; 6468e10490bSSteen Hegelund } 6478e10490bSSteen Hegelund 648f13230a4SSteen Hegelund static int vcap_write_counter(struct vcap_rule_internal *ri, 649f13230a4SSteen Hegelund struct vcap_counter *ctr) 650f13230a4SSteen Hegelund { 651f13230a4SSteen Hegelund struct vcap_admin *admin = ri->admin; 652f13230a4SSteen Hegelund 653f13230a4SSteen Hegelund admin->cache.counter = ctr->value; 654f13230a4SSteen Hegelund admin->cache.sticky = ctr->sticky; 655f13230a4SSteen Hegelund ri->vctrl->ops->cache_write(ri->ndev, admin, VCAP_SEL_COUNTER, 656f13230a4SSteen Hegelund ri->counter_id, 0); 657f13230a4SSteen Hegelund ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_WRITE, 658f13230a4SSteen Hegelund VCAP_SEL_COUNTER, ri->addr); 659f13230a4SSteen Hegelund return 0; 660f13230a4SSteen Hegelund } 661f13230a4SSteen Hegelund 6627de1dcadSSteen Hegelund /* Convert a chain id to a VCAP lookup index */ 6637de1dcadSSteen Hegelund int vcap_chain_id_to_lookup(struct vcap_admin *admin, int cur_cid) 6647de1dcadSSteen Hegelund { 6657de1dcadSSteen Hegelund int lookup_first = admin->vinst * admin->lookups_per_instance; 6667de1dcadSSteen Hegelund int lookup_last = lookup_first + admin->lookups_per_instance; 6677de1dcadSSteen Hegelund int cid_next = admin->first_cid + VCAP_CID_LOOKUP_SIZE; 6687de1dcadSSteen Hegelund int cid = admin->first_cid; 6697de1dcadSSteen Hegelund int lookup; 6707de1dcadSSteen Hegelund 6717de1dcadSSteen Hegelund for (lookup = lookup_first; lookup < lookup_last; ++lookup, 6727de1dcadSSteen Hegelund cid += VCAP_CID_LOOKUP_SIZE, cid_next += VCAP_CID_LOOKUP_SIZE) 6737de1dcadSSteen Hegelund if (cur_cid >= cid && cur_cid < cid_next) 6747de1dcadSSteen Hegelund return lookup; 6757de1dcadSSteen Hegelund return 0; 6767de1dcadSSteen Hegelund } 6777de1dcadSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_chain_id_to_lookup); 6787de1dcadSSteen Hegelund 679c9da1ac1SSteen Hegelund /* Lookup a vcap instance using chain id */ 680c9da1ac1SSteen Hegelund struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid) 681c9da1ac1SSteen Hegelund { 682c9da1ac1SSteen Hegelund struct vcap_admin *admin; 683c9da1ac1SSteen Hegelund 6848e10490bSSteen Hegelund if (vcap_api_check(vctrl)) 6858e10490bSSteen Hegelund return NULL; 6868e10490bSSteen Hegelund 687c9da1ac1SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) { 688c9da1ac1SSteen Hegelund if (cid >= admin->first_cid && cid <= admin->last_cid) 689c9da1ac1SSteen Hegelund return admin; 690c9da1ac1SSteen Hegelund } 691c9da1ac1SSteen Hegelund return NULL; 692c9da1ac1SSteen Hegelund } 693c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_find_admin); 694c9da1ac1SSteen Hegelund 695392d0ab0SSteen Hegelund /* Is the next chain id in the following lookup, possible in another VCAP */ 696392d0ab0SSteen Hegelund bool vcap_is_next_lookup(struct vcap_control *vctrl, int cur_cid, int next_cid) 697392d0ab0SSteen Hegelund { 698392d0ab0SSteen Hegelund struct vcap_admin *admin, *next_admin; 699392d0ab0SSteen Hegelund int lookup, next_lookup; 700392d0ab0SSteen Hegelund 701392d0ab0SSteen Hegelund /* The offset must be at least one lookup */ 702392d0ab0SSteen Hegelund if (next_cid < cur_cid + VCAP_CID_LOOKUP_SIZE) 703392d0ab0SSteen Hegelund return false; 704392d0ab0SSteen Hegelund 705392d0ab0SSteen Hegelund if (vcap_api_check(vctrl)) 706392d0ab0SSteen Hegelund return false; 707392d0ab0SSteen Hegelund 708392d0ab0SSteen Hegelund admin = vcap_find_admin(vctrl, cur_cid); 709392d0ab0SSteen Hegelund if (!admin) 710392d0ab0SSteen Hegelund return false; 711392d0ab0SSteen Hegelund 712392d0ab0SSteen Hegelund /* If no VCAP contains the next chain, the next chain must be beyond 713392d0ab0SSteen Hegelund * the last chain in the current VCAP 714392d0ab0SSteen Hegelund */ 715392d0ab0SSteen Hegelund next_admin = vcap_find_admin(vctrl, next_cid); 716392d0ab0SSteen Hegelund if (!next_admin) 717392d0ab0SSteen Hegelund return next_cid > admin->last_cid; 718392d0ab0SSteen Hegelund 719392d0ab0SSteen Hegelund lookup = vcap_chain_id_to_lookup(admin, cur_cid); 720392d0ab0SSteen Hegelund next_lookup = vcap_chain_id_to_lookup(next_admin, next_cid); 721392d0ab0SSteen Hegelund 722392d0ab0SSteen Hegelund /* Next lookup must be the following lookup */ 723392d0ab0SSteen Hegelund if (admin == next_admin || admin->vtype == next_admin->vtype) 724392d0ab0SSteen Hegelund return next_lookup == lookup + 1; 725392d0ab0SSteen Hegelund 726392d0ab0SSteen Hegelund /* Must be the first lookup in the next VCAP instance */ 727392d0ab0SSteen Hegelund return next_lookup == 0; 728392d0ab0SSteen Hegelund } 729392d0ab0SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_is_next_lookup); 730392d0ab0SSteen Hegelund 7318e10490bSSteen Hegelund /* Check if there is room for a new rule */ 7328e10490bSSteen Hegelund static int vcap_rule_space(struct vcap_admin *admin, int size) 7338e10490bSSteen Hegelund { 7348e10490bSSteen Hegelund if (admin->last_used_addr - size < admin->first_valid_addr) { 7358e10490bSSteen Hegelund pr_err("%s:%d: No room for rule size: %u, %u\n", 7368e10490bSSteen Hegelund __func__, __LINE__, size, admin->first_valid_addr); 7378e10490bSSteen Hegelund return -ENOSPC; 7388e10490bSSteen Hegelund } 7398e10490bSSteen Hegelund return 0; 7408e10490bSSteen Hegelund } 7418e10490bSSteen Hegelund 7428e10490bSSteen Hegelund /* Add the keyset typefield to the list of rule keyfields */ 7438e10490bSSteen Hegelund static int vcap_add_type_keyfield(struct vcap_rule *rule) 7448e10490bSSteen Hegelund { 7458e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 7468e10490bSSteen Hegelund enum vcap_keyfield_set keyset = rule->keyset; 7478e10490bSSteen Hegelund enum vcap_type vt = ri->admin->vtype; 7488e10490bSSteen Hegelund const struct vcap_field *fields; 7498e10490bSSteen Hegelund const struct vcap_set *kset; 7508e10490bSSteen Hegelund int ret = -EINVAL; 7518e10490bSSteen Hegelund 7528e10490bSSteen Hegelund kset = vcap_keyfieldset(ri->vctrl, vt, keyset); 7538e10490bSSteen Hegelund if (!kset) 7548e10490bSSteen Hegelund return ret; 7558e10490bSSteen Hegelund if (kset->type_id == (u8)-1) /* No type field is needed */ 7568e10490bSSteen Hegelund return 0; 7578e10490bSSteen Hegelund 7588e10490bSSteen Hegelund fields = vcap_keyfields(ri->vctrl, vt, keyset); 7598e10490bSSteen Hegelund if (!fields) 7608e10490bSSteen Hegelund return -EINVAL; 7618e10490bSSteen Hegelund if (fields[VCAP_KF_TYPE].width > 1) { 7628e10490bSSteen Hegelund ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE, 7638e10490bSSteen Hegelund kset->type_id, 0xff); 7648e10490bSSteen Hegelund } else { 7658e10490bSSteen Hegelund if (kset->type_id) 7668e10490bSSteen Hegelund ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE, 7678e10490bSSteen Hegelund VCAP_BIT_1); 7688e10490bSSteen Hegelund else 7698e10490bSSteen Hegelund ret = vcap_rule_add_key_bit(rule, VCAP_KF_TYPE, 7708e10490bSSteen Hegelund VCAP_BIT_0); 7718e10490bSSteen Hegelund } 7728e10490bSSteen Hegelund return 0; 7738e10490bSSteen Hegelund } 7748e10490bSSteen Hegelund 775abc4010dSSteen Hegelund /* Add a keyset to a keyset list */ 776abc4010dSSteen Hegelund bool vcap_keyset_list_add(struct vcap_keyset_list *keysetlist, 777abc4010dSSteen Hegelund enum vcap_keyfield_set keyset) 778abc4010dSSteen Hegelund { 779abc4010dSSteen Hegelund int idx; 780abc4010dSSteen Hegelund 781abc4010dSSteen Hegelund if (keysetlist->cnt < keysetlist->max) { 782abc4010dSSteen Hegelund /* Avoid duplicates */ 783abc4010dSSteen Hegelund for (idx = 0; idx < keysetlist->cnt; ++idx) 784abc4010dSSteen Hegelund if (keysetlist->keysets[idx] == keyset) 785abc4010dSSteen Hegelund return keysetlist->cnt < keysetlist->max; 786abc4010dSSteen Hegelund keysetlist->keysets[keysetlist->cnt++] = keyset; 787abc4010dSSteen Hegelund } 788abc4010dSSteen Hegelund return keysetlist->cnt < keysetlist->max; 789abc4010dSSteen Hegelund } 790abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_list_add); 791abc4010dSSteen Hegelund 792abc4010dSSteen Hegelund /* map keyset id to a string with the keyset name */ 793abc4010dSSteen Hegelund const char *vcap_keyset_name(struct vcap_control *vctrl, 794abc4010dSSteen Hegelund enum vcap_keyfield_set keyset) 795abc4010dSSteen Hegelund { 796abc4010dSSteen Hegelund return vctrl->stats->keyfield_set_names[keyset]; 797abc4010dSSteen Hegelund } 798abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyset_name); 799abc4010dSSteen Hegelund 800abc4010dSSteen Hegelund /* map key field id to a string with the key name */ 801abc4010dSSteen Hegelund const char *vcap_keyfield_name(struct vcap_control *vctrl, 802abc4010dSSteen Hegelund enum vcap_key_field key) 803abc4010dSSteen Hegelund { 804abc4010dSSteen Hegelund return vctrl->stats->keyfield_names[key]; 805abc4010dSSteen Hegelund } 806abc4010dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_keyfield_name); 807abc4010dSSteen Hegelund 8083a792156SSteen Hegelund /* map actionset id to a string with the actionset name */ 8093a792156SSteen Hegelund const char *vcap_actionset_name(struct vcap_control *vctrl, 8103a792156SSteen Hegelund enum vcap_actionfield_set actionset) 8113a792156SSteen Hegelund { 8123a792156SSteen Hegelund return vctrl->stats->actionfield_set_names[actionset]; 8133a792156SSteen Hegelund } 8143a792156SSteen Hegelund 815242df4f7SSteen Hegelund /* map action field id to a string with the action name */ 8163a792156SSteen Hegelund const char *vcap_actionfield_name(struct vcap_control *vctrl, 817242df4f7SSteen Hegelund enum vcap_action_field action) 818242df4f7SSteen Hegelund { 819242df4f7SSteen Hegelund return vctrl->stats->actionfield_names[action]; 820242df4f7SSteen Hegelund } 821242df4f7SSteen Hegelund 822abc4010dSSteen Hegelund /* Return the keyfield that matches a key in a keyset */ 823abc4010dSSteen Hegelund static const struct vcap_field * 824abc4010dSSteen Hegelund vcap_find_keyset_keyfield(struct vcap_control *vctrl, 825abc4010dSSteen Hegelund enum vcap_type vtype, 826abc4010dSSteen Hegelund enum vcap_keyfield_set keyset, 827abc4010dSSteen Hegelund enum vcap_key_field key) 828abc4010dSSteen Hegelund { 829abc4010dSSteen Hegelund const struct vcap_field *fields; 830abc4010dSSteen Hegelund int idx, count; 831abc4010dSSteen Hegelund 832abc4010dSSteen Hegelund fields = vcap_keyfields(vctrl, vtype, keyset); 833abc4010dSSteen Hegelund if (!fields) 834abc4010dSSteen Hegelund return NULL; 835abc4010dSSteen Hegelund 836abc4010dSSteen Hegelund /* Iterate the keyfields of the keyset */ 837abc4010dSSteen Hegelund count = vcap_keyfield_count(vctrl, vtype, keyset); 838abc4010dSSteen Hegelund for (idx = 0; idx < count; ++idx) { 839abc4010dSSteen Hegelund if (fields[idx].width == 0) 840abc4010dSSteen Hegelund continue; 841abc4010dSSteen Hegelund 842abc4010dSSteen Hegelund if (key == idx) 843abc4010dSSteen Hegelund return &fields[idx]; 844abc4010dSSteen Hegelund } 845abc4010dSSteen Hegelund 846abc4010dSSteen Hegelund return NULL; 847abc4010dSSteen Hegelund } 848abc4010dSSteen Hegelund 849abc4010dSSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */ 850465a38a2SSteen Hegelund static bool _vcap_rule_find_keysets(struct vcap_rule_internal *ri, 851abc4010dSSteen Hegelund struct vcap_keyset_list *matches) 852abc4010dSSteen Hegelund { 853abc4010dSSteen Hegelund const struct vcap_client_keyfield *ckf; 854abc4010dSSteen Hegelund int keyset, found, keycount, map_size; 855abc4010dSSteen Hegelund const struct vcap_field **map; 856abc4010dSSteen Hegelund enum vcap_type vtype; 857abc4010dSSteen Hegelund 858abc4010dSSteen Hegelund vtype = ri->admin->vtype; 859abc4010dSSteen Hegelund map = ri->vctrl->vcaps[vtype].keyfield_set_map; 860abc4010dSSteen Hegelund map_size = ri->vctrl->vcaps[vtype].keyfield_set_size; 861abc4010dSSteen Hegelund 862abc4010dSSteen Hegelund /* Get a count of the keyfields we want to match */ 863abc4010dSSteen Hegelund keycount = 0; 864abc4010dSSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) 865abc4010dSSteen Hegelund ++keycount; 866abc4010dSSteen Hegelund 867abc4010dSSteen Hegelund matches->cnt = 0; 868abc4010dSSteen Hegelund /* Iterate the keysets of the VCAP */ 869abc4010dSSteen Hegelund for (keyset = 0; keyset < map_size; ++keyset) { 870abc4010dSSteen Hegelund if (!map[keyset]) 871abc4010dSSteen Hegelund continue; 872abc4010dSSteen Hegelund 873abc4010dSSteen Hegelund /* Iterate the keys in the rule */ 874abc4010dSSteen Hegelund found = 0; 875abc4010dSSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) 876abc4010dSSteen Hegelund if (vcap_find_keyset_keyfield(ri->vctrl, vtype, 877abc4010dSSteen Hegelund keyset, ckf->ctrl.key)) 878abc4010dSSteen Hegelund ++found; 879abc4010dSSteen Hegelund 880abc4010dSSteen Hegelund /* Save the keyset if all keyfields were found */ 881abc4010dSSteen Hegelund if (found == keycount) 882abc4010dSSteen Hegelund if (!vcap_keyset_list_add(matches, keyset)) 883abc4010dSSteen Hegelund /* bail out when the quota is filled */ 884abc4010dSSteen Hegelund break; 885abc4010dSSteen Hegelund } 886abc4010dSSteen Hegelund 887abc4010dSSteen Hegelund return matches->cnt > 0; 888abc4010dSSteen Hegelund } 889abc4010dSSteen Hegelund 890465a38a2SSteen Hegelund /* Match a list of keys against the keysets available in a vcap type */ 891465a38a2SSteen Hegelund bool vcap_rule_find_keysets(struct vcap_rule *rule, 892465a38a2SSteen Hegelund struct vcap_keyset_list *matches) 893465a38a2SSteen Hegelund { 894465a38a2SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 895465a38a2SSteen Hegelund 896465a38a2SSteen Hegelund return _vcap_rule_find_keysets(ri, matches); 897465a38a2SSteen Hegelund } 898465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_find_keysets); 899465a38a2SSteen Hegelund 900c9da1ac1SSteen Hegelund /* Validate a rule with respect to available port keys */ 901c9da1ac1SSteen Hegelund int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto) 902c9da1ac1SSteen Hegelund { 903c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 904abc4010dSSteen Hegelund struct vcap_keyset_list matches = {}; 9058e10490bSSteen Hegelund enum vcap_keyfield_set keysets[10]; 9068e10490bSSteen Hegelund int ret; 907c9da1ac1SSteen Hegelund 9088e10490bSSteen Hegelund ret = vcap_api_check(ri->vctrl); 9098e10490bSSteen Hegelund if (ret) 9108e10490bSSteen Hegelund return ret; 911c9da1ac1SSteen Hegelund if (!ri->admin) { 912c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_ADMIN; 913c9da1ac1SSteen Hegelund return -EINVAL; 914c9da1ac1SSteen Hegelund } 915c9da1ac1SSteen Hegelund if (!ri->ndev) { 916c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_NETDEV; 917c9da1ac1SSteen Hegelund return -EINVAL; 918c9da1ac1SSteen Hegelund } 919abc4010dSSteen Hegelund 920abc4010dSSteen Hegelund matches.keysets = keysets; 921abc4010dSSteen Hegelund matches.max = ARRAY_SIZE(keysets); 922c9da1ac1SSteen Hegelund if (ri->data.keyset == VCAP_KFS_NO_VALUE) { 923abc4010dSSteen Hegelund /* Iterate over rule keyfields and select keysets that fits */ 924465a38a2SSteen Hegelund if (!_vcap_rule_find_keysets(ri, &matches)) { 925c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH; 926c9da1ac1SSteen Hegelund return -EINVAL; 927c9da1ac1SSteen Hegelund } 928abc4010dSSteen Hegelund } else { 9298e10490bSSteen Hegelund /* prepare for keyset validation */ 9308e10490bSSteen Hegelund keysets[0] = ri->data.keyset; 931abc4010dSSteen Hegelund matches.cnt = 1; 932abc4010dSSteen Hegelund } 933abc4010dSSteen Hegelund 9348e10490bSSteen Hegelund /* Pick a keyset that is supported in the port lookups */ 935abc4010dSSteen Hegelund ret = ri->vctrl->ops->validate_keyset(ri->ndev, ri->admin, rule, 936abc4010dSSteen Hegelund &matches, l3_proto); 9378e10490bSSteen Hegelund if (ret < 0) { 9388e10490bSSteen Hegelund pr_err("%s:%d: keyset validation failed: %d\n", 9398e10490bSSteen Hegelund __func__, __LINE__, ret); 9408e10490bSSteen Hegelund ri->data.exterr = VCAP_ERR_NO_PORT_KEYSET_MATCH; 9418e10490bSSteen Hegelund return ret; 9428e10490bSSteen Hegelund } 943abc4010dSSteen Hegelund /* use the keyset that is supported in the port lookups */ 944abc4010dSSteen Hegelund ret = vcap_set_rule_set_keyset(rule, ret); 945abc4010dSSteen Hegelund if (ret < 0) { 946abc4010dSSteen Hegelund pr_err("%s:%d: keyset was not updated: %d\n", 947abc4010dSSteen Hegelund __func__, __LINE__, ret); 948abc4010dSSteen Hegelund return ret; 949abc4010dSSteen Hegelund } 950c9da1ac1SSteen Hegelund if (ri->data.actionset == VCAP_AFS_NO_VALUE) { 951abc4010dSSteen Hegelund /* Later also actionsets will be matched against actions in 952abc4010dSSteen Hegelund * the rule, and the type will be set accordingly 953abc4010dSSteen Hegelund */ 954c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH; 955c9da1ac1SSteen Hegelund return -EINVAL; 956c9da1ac1SSteen Hegelund } 9578e10490bSSteen Hegelund vcap_add_type_keyfield(rule); 9588e10490bSSteen Hegelund /* Add default fields to this rule */ 9598e10490bSSteen Hegelund ri->vctrl->ops->add_default_fields(ri->ndev, ri->admin, rule); 9608e10490bSSteen Hegelund 9618e10490bSSteen Hegelund /* Rule size is the maximum of the entry and action subword count */ 9628e10490bSSteen Hegelund ri->size = max(ri->keyset_sw, ri->actionset_sw); 9638e10490bSSteen Hegelund 9648e10490bSSteen Hegelund /* Finally check if there is room for the rule in the VCAP */ 9658e10490bSSteen Hegelund return vcap_rule_space(ri->admin, ri->size); 966c9da1ac1SSteen Hegelund } 967c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_val_rule); 968c9da1ac1SSteen Hegelund 969990e4839SSteen Hegelund /* Entries are sorted with increasing values of sort_key. 970990e4839SSteen Hegelund * I.e. Lowest numerical sort_key is first in list. 971990e4839SSteen Hegelund * In order to locate largest keys first in list we negate the key size with 972990e4839SSteen Hegelund * (max_size - size). 973990e4839SSteen Hegelund */ 974990e4839SSteen Hegelund static u32 vcap_sort_key(u32 max_size, u32 size, u8 user, u16 prio) 975990e4839SSteen Hegelund { 976990e4839SSteen Hegelund return ((max_size - size) << 24) | (user << 16) | prio; 977990e4839SSteen Hegelund } 978990e4839SSteen Hegelund 9798e10490bSSteen Hegelund /* calculate the address of the next rule after this (lower address and prio) */ 9808e10490bSSteen Hegelund static u32 vcap_next_rule_addr(u32 addr, struct vcap_rule_internal *ri) 9818e10490bSSteen Hegelund { 9828e10490bSSteen Hegelund return ((addr - ri->size) / ri->size) * ri->size; 9838e10490bSSteen Hegelund } 9848e10490bSSteen Hegelund 985c9da1ac1SSteen Hegelund /* Assign a unique rule id and autogenerate one if id == 0 */ 986c9da1ac1SSteen Hegelund static u32 vcap_set_rule_id(struct vcap_rule_internal *ri) 987c9da1ac1SSteen Hegelund { 988c9da1ac1SSteen Hegelund u32 next_id; 989c9da1ac1SSteen Hegelund 990c9da1ac1SSteen Hegelund if (ri->data.id != 0) 991c9da1ac1SSteen Hegelund return ri->data.id; 992c9da1ac1SSteen Hegelund 993c9da1ac1SSteen Hegelund next_id = ri->vctrl->rule_id + 1; 994c9da1ac1SSteen Hegelund 995c9da1ac1SSteen Hegelund for (next_id = ri->vctrl->rule_id + 1; next_id < ~0; ++next_id) { 996c9da1ac1SSteen Hegelund if (!vcap_lookup_rule(ri->vctrl, next_id)) { 997c9da1ac1SSteen Hegelund ri->data.id = next_id; 998c9da1ac1SSteen Hegelund ri->vctrl->rule_id = next_id; 999c9da1ac1SSteen Hegelund break; 1000c9da1ac1SSteen Hegelund } 1001c9da1ac1SSteen Hegelund } 1002c9da1ac1SSteen Hegelund return ri->data.id; 1003c9da1ac1SSteen Hegelund } 1004c9da1ac1SSteen Hegelund 10058e10490bSSteen Hegelund static int vcap_insert_rule(struct vcap_rule_internal *ri, 10068e10490bSSteen Hegelund struct vcap_rule_move *move) 10078e10490bSSteen Hegelund { 1008990e4839SSteen Hegelund int sw_count = ri->vctrl->vcaps[ri->admin->vtype].sw_count; 1009990e4839SSteen Hegelund struct vcap_rule_internal *duprule, *iter, *elem = NULL; 10108e10490bSSteen Hegelund struct vcap_admin *admin = ri->admin; 1011990e4839SSteen Hegelund u32 addr; 10128e10490bSSteen Hegelund 1013990e4839SSteen Hegelund ri->sort_key = vcap_sort_key(sw_count, ri->size, ri->data.user, 1014990e4839SSteen Hegelund ri->data.priority); 1015990e4839SSteen Hegelund 1016990e4839SSteen Hegelund /* Insert the new rule in the list of rule based on the sort key 1017990e4839SSteen Hegelund * If the rule needs to be inserted between existing rules then move 1018990e4839SSteen Hegelund * these rules to make room for the new rule and update their start 1019990e4839SSteen Hegelund * address. 1020990e4839SSteen Hegelund */ 1021990e4839SSteen Hegelund list_for_each_entry(iter, &admin->rules, list) { 1022990e4839SSteen Hegelund if (ri->sort_key < iter->sort_key) { 1023990e4839SSteen Hegelund elem = iter; 1024990e4839SSteen Hegelund break; 1025990e4839SSteen Hegelund } 1026990e4839SSteen Hegelund } 1027990e4839SSteen Hegelund 1028990e4839SSteen Hegelund if (!elem) { 10298e10490bSSteen Hegelund ri->addr = vcap_next_rule_addr(admin->last_used_addr, ri); 10308e10490bSSteen Hegelund admin->last_used_addr = ri->addr; 1031990e4839SSteen Hegelund 10328e10490bSSteen Hegelund /* Add a shallow copy of the rule to the VCAP list */ 10338e10490bSSteen Hegelund duprule = vcap_dup_rule(ri); 10348e10490bSSteen Hegelund if (IS_ERR(duprule)) 10358e10490bSSteen Hegelund return PTR_ERR(duprule); 1036990e4839SSteen Hegelund 10378e10490bSSteen Hegelund list_add_tail(&duprule->list, &admin->rules); 10388e10490bSSteen Hegelund return 0; 10398e10490bSSteen Hegelund } 10408e10490bSSteen Hegelund 1041990e4839SSteen Hegelund /* Reuse the space of the current rule */ 1042990e4839SSteen Hegelund addr = elem->addr + elem->size; 1043990e4839SSteen Hegelund ri->addr = vcap_next_rule_addr(addr, ri); 1044990e4839SSteen Hegelund addr = ri->addr; 1045990e4839SSteen Hegelund 1046990e4839SSteen Hegelund /* Add a shallow copy of the rule to the VCAP list */ 1047990e4839SSteen Hegelund duprule = vcap_dup_rule(ri); 1048990e4839SSteen Hegelund if (IS_ERR(duprule)) 1049990e4839SSteen Hegelund return PTR_ERR(duprule); 1050990e4839SSteen Hegelund 1051990e4839SSteen Hegelund /* Add before the current entry */ 1052990e4839SSteen Hegelund list_add_tail(&duprule->list, &elem->list); 1053990e4839SSteen Hegelund 1054990e4839SSteen Hegelund /* Update the current rule */ 1055990e4839SSteen Hegelund elem->addr = vcap_next_rule_addr(addr, elem); 1056990e4839SSteen Hegelund addr = elem->addr; 1057990e4839SSteen Hegelund 1058990e4839SSteen Hegelund /* Update the address in the remaining rules in the list */ 1059990e4839SSteen Hegelund list_for_each_entry_continue(elem, &admin->rules, list) { 1060990e4839SSteen Hegelund elem->addr = vcap_next_rule_addr(addr, elem); 1061990e4839SSteen Hegelund addr = elem->addr; 1062990e4839SSteen Hegelund } 1063990e4839SSteen Hegelund 1064990e4839SSteen Hegelund /* Update the move info */ 1065990e4839SSteen Hegelund move->addr = admin->last_used_addr; 1066990e4839SSteen Hegelund move->count = ri->addr - addr; 1067990e4839SSteen Hegelund move->offset = admin->last_used_addr - addr; 1068990e4839SSteen Hegelund admin->last_used_addr = addr; 1069990e4839SSteen Hegelund return 0; 1070990e4839SSteen Hegelund } 1071990e4839SSteen Hegelund 10728e10490bSSteen Hegelund static void vcap_move_rules(struct vcap_rule_internal *ri, 10738e10490bSSteen Hegelund struct vcap_rule_move *move) 10748e10490bSSteen Hegelund { 10758e10490bSSteen Hegelund ri->vctrl->ops->move(ri->ndev, ri->admin, move->addr, 10768e10490bSSteen Hegelund move->offset, move->count); 10778e10490bSSteen Hegelund } 10788e10490bSSteen Hegelund 1079c9da1ac1SSteen Hegelund /* Encode and write a validated rule to the VCAP */ 1080c9da1ac1SSteen Hegelund int vcap_add_rule(struct vcap_rule *rule) 1081c9da1ac1SSteen Hegelund { 10828e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 10838e10490bSSteen Hegelund struct vcap_rule_move move = {0}; 10848e10490bSSteen Hegelund int ret; 10858e10490bSSteen Hegelund 10868e10490bSSteen Hegelund ret = vcap_api_check(ri->vctrl); 10878e10490bSSteen Hegelund if (ret) 10888e10490bSSteen Hegelund return ret; 10898e10490bSSteen Hegelund /* Insert the new rule in the list of vcap rules */ 109071c9de99SSteen Hegelund mutex_lock(&ri->admin->lock); 10918e10490bSSteen Hegelund ret = vcap_insert_rule(ri, &move); 10928e10490bSSteen Hegelund if (ret < 0) { 10938e10490bSSteen Hegelund pr_err("%s:%d: could not insert rule in vcap list: %d\n", 10948e10490bSSteen Hegelund __func__, __LINE__, ret); 10958e10490bSSteen Hegelund goto out; 10968e10490bSSteen Hegelund } 10978e10490bSSteen Hegelund if (move.count > 0) 10988e10490bSSteen Hegelund vcap_move_rules(ri, &move); 10998e10490bSSteen Hegelund ret = vcap_encode_rule(ri); 11008e10490bSSteen Hegelund if (ret) { 11018e10490bSSteen Hegelund pr_err("%s:%d: rule encoding error: %d\n", __func__, __LINE__, ret); 11028e10490bSSteen Hegelund goto out; 11038e10490bSSteen Hegelund } 11048e10490bSSteen Hegelund 11058e10490bSSteen Hegelund ret = vcap_write_rule(ri); 11068e10490bSSteen Hegelund if (ret) 11078e10490bSSteen Hegelund pr_err("%s:%d: rule write error: %d\n", __func__, __LINE__, ret); 11088e10490bSSteen Hegelund out: 110971c9de99SSteen Hegelund mutex_unlock(&ri->admin->lock); 11108e10490bSSteen Hegelund return ret; 1111c9da1ac1SSteen Hegelund } 1112c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_add_rule); 1113c9da1ac1SSteen Hegelund 1114c9da1ac1SSteen Hegelund /* Allocate a new rule with the provided arguments */ 1115c9da1ac1SSteen Hegelund struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl, 1116c9da1ac1SSteen Hegelund struct net_device *ndev, int vcap_chain_id, 1117c9da1ac1SSteen Hegelund enum vcap_user user, u16 priority, 1118c9da1ac1SSteen Hegelund u32 id) 1119c9da1ac1SSteen Hegelund { 1120c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri; 1121c9da1ac1SSteen Hegelund struct vcap_admin *admin; 1122990e4839SSteen Hegelund int err, maxsize; 1123c9da1ac1SSteen Hegelund 1124990e4839SSteen Hegelund err = vcap_api_check(vctrl); 1125990e4839SSteen Hegelund if (err) 1126990e4839SSteen Hegelund return ERR_PTR(err); 1127c9da1ac1SSteen Hegelund if (!ndev) 1128c9da1ac1SSteen Hegelund return ERR_PTR(-ENODEV); 1129c9da1ac1SSteen Hegelund /* Get the VCAP instance */ 1130c9da1ac1SSteen Hegelund admin = vcap_find_admin(vctrl, vcap_chain_id); 1131c9da1ac1SSteen Hegelund if (!admin) 1132c9da1ac1SSteen Hegelund return ERR_PTR(-ENOENT); 11338e10490bSSteen Hegelund /* Sanity check that this VCAP is supported on this platform */ 11348e10490bSSteen Hegelund if (vctrl->vcaps[admin->vtype].rows == 0) 11358e10490bSSteen Hegelund return ERR_PTR(-EINVAL); 11368e10490bSSteen Hegelund /* Check if a rule with this id already exists */ 11378e10490bSSteen Hegelund if (vcap_lookup_rule(vctrl, id)) 11388e10490bSSteen Hegelund return ERR_PTR(-EEXIST); 11398e10490bSSteen Hegelund /* Check if there is room for the rule in the block(s) of the VCAP */ 11408e10490bSSteen Hegelund maxsize = vctrl->vcaps[admin->vtype].sw_count; /* worst case rule size */ 11418e10490bSSteen Hegelund if (vcap_rule_space(admin, maxsize)) 11428e10490bSSteen Hegelund return ERR_PTR(-ENOSPC); 1143c9da1ac1SSteen Hegelund /* Create a container for the rule and return it */ 1144c9da1ac1SSteen Hegelund ri = kzalloc(sizeof(*ri), GFP_KERNEL); 1145c9da1ac1SSteen Hegelund if (!ri) 1146c9da1ac1SSteen Hegelund return ERR_PTR(-ENOMEM); 1147c9da1ac1SSteen Hegelund ri->data.vcap_chain_id = vcap_chain_id; 1148c9da1ac1SSteen Hegelund ri->data.user = user; 1149c9da1ac1SSteen Hegelund ri->data.priority = priority; 1150c9da1ac1SSteen Hegelund ri->data.id = id; 1151c9da1ac1SSteen Hegelund ri->data.keyset = VCAP_KFS_NO_VALUE; 1152c9da1ac1SSteen Hegelund ri->data.actionset = VCAP_AFS_NO_VALUE; 1153c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->list); 1154c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->data.keyfields); 1155c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->data.actionfields); 1156c9da1ac1SSteen Hegelund ri->ndev = ndev; 1157c9da1ac1SSteen Hegelund ri->admin = admin; /* refer to the vcap instance */ 1158c9da1ac1SSteen Hegelund ri->vctrl = vctrl; /* refer to the client */ 1159c9da1ac1SSteen Hegelund if (vcap_set_rule_id(ri) == 0) 1160c9da1ac1SSteen Hegelund goto out_free; 11618e10490bSSteen Hegelund vcap_erase_cache(ri); 1162c9da1ac1SSteen Hegelund return (struct vcap_rule *)ri; 1163c9da1ac1SSteen Hegelund 1164c9da1ac1SSteen Hegelund out_free: 1165c9da1ac1SSteen Hegelund kfree(ri); 1166c9da1ac1SSteen Hegelund return ERR_PTR(-EINVAL); 1167c9da1ac1SSteen Hegelund } 1168c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_alloc_rule); 1169c9da1ac1SSteen Hegelund 1170c9da1ac1SSteen Hegelund /* Free mem of a rule owned by client after the rule as been added to the VCAP */ 1171c9da1ac1SSteen Hegelund void vcap_free_rule(struct vcap_rule *rule) 1172c9da1ac1SSteen Hegelund { 1173c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1174c9da1ac1SSteen Hegelund struct vcap_client_actionfield *caf, *next_caf; 1175c9da1ac1SSteen Hegelund struct vcap_client_keyfield *ckf, *next_ckf; 1176c9da1ac1SSteen Hegelund 1177c9da1ac1SSteen Hegelund /* Deallocate the list of keys and actions */ 1178c9da1ac1SSteen Hegelund list_for_each_entry_safe(ckf, next_ckf, &ri->data.keyfields, ctrl.list) { 1179c9da1ac1SSteen Hegelund list_del(&ckf->ctrl.list); 1180c9da1ac1SSteen Hegelund kfree(ckf); 1181c9da1ac1SSteen Hegelund } 1182c9da1ac1SSteen Hegelund list_for_each_entry_safe(caf, next_caf, &ri->data.actionfields, ctrl.list) { 1183c9da1ac1SSteen Hegelund list_del(&caf->ctrl.list); 1184c9da1ac1SSteen Hegelund kfree(caf); 1185c9da1ac1SSteen Hegelund } 1186c9da1ac1SSteen Hegelund /* Deallocate the rule */ 1187c9da1ac1SSteen Hegelund kfree(rule); 1188c9da1ac1SSteen Hegelund } 1189c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_free_rule); 1190c9da1ac1SSteen Hegelund 1191990e4839SSteen Hegelund /* Return the alignment offset for a new rule address */ 1192990e4839SSteen Hegelund static int vcap_valid_rule_move(struct vcap_rule_internal *el, int offset) 1193990e4839SSteen Hegelund { 1194990e4839SSteen Hegelund return (el->addr + offset) % el->size; 1195990e4839SSteen Hegelund } 1196990e4839SSteen Hegelund 1197990e4839SSteen Hegelund /* Update the rule address with an offset */ 1198990e4839SSteen Hegelund static void vcap_adjust_rule_addr(struct vcap_rule_internal *el, int offset) 1199990e4839SSteen Hegelund { 1200990e4839SSteen Hegelund el->addr += offset; 1201990e4839SSteen Hegelund } 1202990e4839SSteen Hegelund 1203990e4839SSteen Hegelund /* Rules needs to be moved to fill the gap of the deleted rule */ 1204990e4839SSteen Hegelund static int vcap_fill_rule_gap(struct vcap_rule_internal *ri) 1205990e4839SSteen Hegelund { 1206990e4839SSteen Hegelund struct vcap_admin *admin = ri->admin; 1207990e4839SSteen Hegelund struct vcap_rule_internal *elem; 1208990e4839SSteen Hegelund struct vcap_rule_move move; 1209990e4839SSteen Hegelund int gap = 0, offset = 0; 1210990e4839SSteen Hegelund 1211990e4839SSteen Hegelund /* If the first rule is deleted: Move other rules to the top */ 1212990e4839SSteen Hegelund if (list_is_first(&ri->list, &admin->rules)) 1213990e4839SSteen Hegelund offset = admin->last_valid_addr + 1 - ri->addr - ri->size; 1214990e4839SSteen Hegelund 1215990e4839SSteen Hegelund /* Locate gaps between odd size rules and adjust the move */ 1216990e4839SSteen Hegelund elem = ri; 1217990e4839SSteen Hegelund list_for_each_entry_continue(elem, &admin->rules, list) 1218990e4839SSteen Hegelund gap += vcap_valid_rule_move(elem, ri->size); 1219990e4839SSteen Hegelund 1220990e4839SSteen Hegelund /* Update the address in the remaining rules in the list */ 1221990e4839SSteen Hegelund elem = ri; 1222990e4839SSteen Hegelund list_for_each_entry_continue(elem, &admin->rules, list) 1223990e4839SSteen Hegelund vcap_adjust_rule_addr(elem, ri->size + gap + offset); 1224990e4839SSteen Hegelund 1225990e4839SSteen Hegelund /* Update the move info */ 1226990e4839SSteen Hegelund move.addr = admin->last_used_addr; 1227990e4839SSteen Hegelund move.count = ri->addr - admin->last_used_addr - gap; 1228990e4839SSteen Hegelund move.offset = -(ri->size + gap + offset); 1229990e4839SSteen Hegelund 1230990e4839SSteen Hegelund /* Do the actual move operation */ 1231990e4839SSteen Hegelund vcap_move_rules(ri, &move); 1232990e4839SSteen Hegelund 1233990e4839SSteen Hegelund return gap + offset; 1234990e4839SSteen Hegelund } 1235990e4839SSteen Hegelund 1236c9da1ac1SSteen Hegelund /* Delete rule in a VCAP instance */ 1237c9da1ac1SSteen Hegelund int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id) 1238c9da1ac1SSteen Hegelund { 1239c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri, *elem; 1240c9da1ac1SSteen Hegelund struct vcap_admin *admin; 1241990e4839SSteen Hegelund int gap = 0, err; 1242c9da1ac1SSteen Hegelund 1243c9da1ac1SSteen Hegelund /* This will later also handle rule moving */ 1244c9da1ac1SSteen Hegelund if (!ndev) 1245c9da1ac1SSteen Hegelund return -ENODEV; 12468e10490bSSteen Hegelund err = vcap_api_check(vctrl); 12478e10490bSSteen Hegelund if (err) 12488e10490bSSteen Hegelund return err; 1249c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */ 1250c9da1ac1SSteen Hegelund ri = vcap_lookup_rule(vctrl, id); 1251c9da1ac1SSteen Hegelund if (!ri) 1252c9da1ac1SSteen Hegelund return -EINVAL; 1253c9da1ac1SSteen Hegelund admin = ri->admin; 12548e10490bSSteen Hegelund 1255990e4839SSteen Hegelund if (ri->addr > admin->last_used_addr) 1256990e4839SSteen Hegelund gap = vcap_fill_rule_gap(ri); 1257990e4839SSteen Hegelund 1258990e4839SSteen Hegelund /* Delete the rule from the list of rules and the cache */ 125971c9de99SSteen Hegelund mutex_lock(&admin->lock); 1260990e4839SSteen Hegelund list_del(&ri->list); 1261990e4839SSteen Hegelund vctrl->ops->init(ndev, admin, admin->last_used_addr, ri->size + gap); 1262990e4839SSteen Hegelund kfree(ri); 126371c9de99SSteen Hegelund mutex_unlock(&admin->lock); 1264990e4839SSteen Hegelund 1265277e9179SSteen Hegelund /* Update the last used address, set to default when no rules */ 1266c9da1ac1SSteen Hegelund if (list_empty(&admin->rules)) { 1267277e9179SSteen Hegelund admin->last_used_addr = admin->last_valid_addr + 1; 1268c9da1ac1SSteen Hegelund } else { 1269990e4839SSteen Hegelund elem = list_last_entry(&admin->rules, struct vcap_rule_internal, 1270990e4839SSteen Hegelund list); 1271c9da1ac1SSteen Hegelund admin->last_used_addr = elem->addr; 1272c9da1ac1SSteen Hegelund } 1273c9da1ac1SSteen Hegelund return 0; 1274c9da1ac1SSteen Hegelund } 1275c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rule); 1276c9da1ac1SSteen Hegelund 12778e10490bSSteen Hegelund /* Delete all rules in the VCAP instance */ 12788e10490bSSteen Hegelund int vcap_del_rules(struct vcap_control *vctrl, struct vcap_admin *admin) 12798e10490bSSteen Hegelund { 128067456717SSteen Hegelund struct vcap_enabled_port *eport, *next_eport; 12818e10490bSSteen Hegelund struct vcap_rule_internal *ri, *next_ri; 12828e10490bSSteen Hegelund int ret = vcap_api_check(vctrl); 12838e10490bSSteen Hegelund 12848e10490bSSteen Hegelund if (ret) 12858e10490bSSteen Hegelund return ret; 128671c9de99SSteen Hegelund 128771c9de99SSteen Hegelund mutex_lock(&admin->lock); 12888e10490bSSteen Hegelund list_for_each_entry_safe(ri, next_ri, &admin->rules, list) { 12898e10490bSSteen Hegelund vctrl->ops->init(ri->ndev, admin, ri->addr, ri->size); 12908e10490bSSteen Hegelund list_del(&ri->list); 12918e10490bSSteen Hegelund kfree(ri); 12928e10490bSSteen Hegelund } 12938e10490bSSteen Hegelund admin->last_used_addr = admin->last_valid_addr; 129467456717SSteen Hegelund 129567456717SSteen Hegelund /* Remove list of enabled ports */ 129667456717SSteen Hegelund list_for_each_entry_safe(eport, next_eport, &admin->enabled, list) { 129767456717SSteen Hegelund list_del(&eport->list); 129867456717SSteen Hegelund kfree(eport); 129967456717SSteen Hegelund } 130071c9de99SSteen Hegelund mutex_unlock(&admin->lock); 130167456717SSteen Hegelund 13028e10490bSSteen Hegelund return 0; 13038e10490bSSteen Hegelund } 13048e10490bSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rules); 13058e10490bSSteen Hegelund 1306465a38a2SSteen Hegelund /* Find a client key field in a rule */ 1307465a38a2SSteen Hegelund static struct vcap_client_keyfield * 1308465a38a2SSteen Hegelund vcap_find_keyfield(struct vcap_rule *rule, enum vcap_key_field key) 1309465a38a2SSteen Hegelund { 1310465a38a2SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1311465a38a2SSteen Hegelund struct vcap_client_keyfield *ckf; 1312465a38a2SSteen Hegelund 1313465a38a2SSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) 1314465a38a2SSteen Hegelund if (ckf->ctrl.key == key) 1315465a38a2SSteen Hegelund return ckf; 1316465a38a2SSteen Hegelund return NULL; 1317465a38a2SSteen Hegelund } 1318465a38a2SSteen Hegelund 131946be056eSSteen Hegelund /* Find information on a key field in a rule */ 132046be056eSSteen Hegelund const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule, 132146be056eSSteen Hegelund enum vcap_key_field key) 132246be056eSSteen Hegelund { 13238e10490bSSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 132446be056eSSteen Hegelund enum vcap_keyfield_set keyset = rule->keyset; 132546be056eSSteen Hegelund enum vcap_type vt = ri->admin->vtype; 132646be056eSSteen Hegelund const struct vcap_field *fields; 132746be056eSSteen Hegelund 132846be056eSSteen Hegelund if (keyset == VCAP_KFS_NO_VALUE) 132946be056eSSteen Hegelund return NULL; 133046be056eSSteen Hegelund fields = vcap_keyfields(ri->vctrl, vt, keyset); 133146be056eSSteen Hegelund if (!fields) 133246be056eSSteen Hegelund return NULL; 133346be056eSSteen Hegelund return &fields[key]; 133446be056eSSteen Hegelund } 133546be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_keyfield); 133646be056eSSteen Hegelund 1337*4f141e36SHoratiu Vultur /* Copy data from src to dst but reverse the data in chunks of 32bits. 1338*4f141e36SHoratiu Vultur * For example if src is 00:11:22:33:44:55 where 55 is LSB the dst will 1339*4f141e36SHoratiu Vultur * have the value 22:33:44:55:00:11. 1340*4f141e36SHoratiu Vultur */ 1341*4f141e36SHoratiu Vultur static void vcap_copy_to_w32be(u8 *dst, u8 *src, int size) 1342*4f141e36SHoratiu Vultur { 1343*4f141e36SHoratiu Vultur for (int idx = 0; idx < size; ++idx) { 1344*4f141e36SHoratiu Vultur int first_byte_index = 0; 1345*4f141e36SHoratiu Vultur int nidx; 1346*4f141e36SHoratiu Vultur 1347*4f141e36SHoratiu Vultur first_byte_index = size - (((idx >> 2) + 1) << 2); 1348*4f141e36SHoratiu Vultur if (first_byte_index < 0) 1349*4f141e36SHoratiu Vultur first_byte_index = 0; 1350*4f141e36SHoratiu Vultur nidx = idx + first_byte_index - (idx & ~0x3); 1351*4f141e36SHoratiu Vultur dst[nidx] = src[idx]; 1352*4f141e36SHoratiu Vultur } 1353*4f141e36SHoratiu Vultur } 1354*4f141e36SHoratiu Vultur 1355c9da1ac1SSteen Hegelund static void vcap_copy_from_client_keyfield(struct vcap_rule *rule, 1356c9da1ac1SSteen Hegelund struct vcap_client_keyfield *field, 1357c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data *data) 1358c9da1ac1SSteen Hegelund { 1359*4f141e36SHoratiu Vultur struct vcap_rule_internal *ri = to_intrule(rule); 1360*4f141e36SHoratiu Vultur int size; 1361*4f141e36SHoratiu Vultur 1362*4f141e36SHoratiu Vultur if (!ri->admin->w32be) { 1363c9da1ac1SSteen Hegelund memcpy(&field->data, data, sizeof(field->data)); 1364*4f141e36SHoratiu Vultur return; 1365*4f141e36SHoratiu Vultur } 1366*4f141e36SHoratiu Vultur 1367*4f141e36SHoratiu Vultur size = keyfield_size_table[field->ctrl.type] / 2; 1368*4f141e36SHoratiu Vultur switch (field->ctrl.type) { 1369*4f141e36SHoratiu Vultur case VCAP_FIELD_BIT: 1370*4f141e36SHoratiu Vultur case VCAP_FIELD_U32: 1371*4f141e36SHoratiu Vultur memcpy(&field->data, data, sizeof(field->data)); 1372*4f141e36SHoratiu Vultur break; 1373*4f141e36SHoratiu Vultur case VCAP_FIELD_U48: 1374*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u48.value, data->u48.value, size); 1375*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u48.mask, data->u48.mask, size); 1376*4f141e36SHoratiu Vultur break; 1377*4f141e36SHoratiu Vultur case VCAP_FIELD_U56: 1378*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u56.value, data->u56.value, size); 1379*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u56.mask, data->u56.mask, size); 1380*4f141e36SHoratiu Vultur break; 1381*4f141e36SHoratiu Vultur case VCAP_FIELD_U64: 1382*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u64.value, data->u64.value, size); 1383*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u64.mask, data->u64.mask, size); 1384*4f141e36SHoratiu Vultur break; 1385*4f141e36SHoratiu Vultur case VCAP_FIELD_U72: 1386*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u72.value, data->u72.value, size); 1387*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u72.mask, data->u72.mask, size); 1388*4f141e36SHoratiu Vultur break; 1389*4f141e36SHoratiu Vultur case VCAP_FIELD_U112: 1390*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u112.value, data->u112.value, size); 1391*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u112.mask, data->u112.mask, size); 1392*4f141e36SHoratiu Vultur break; 1393*4f141e36SHoratiu Vultur case VCAP_FIELD_U128: 1394*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u128.value, data->u128.value, size); 1395*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u128.mask, data->u128.mask, size); 1396*4f141e36SHoratiu Vultur break; 1397*4f141e36SHoratiu Vultur }; 1398c9da1ac1SSteen Hegelund } 1399c9da1ac1SSteen Hegelund 1400242df4f7SSteen Hegelund /* Check if the keyfield is already in the rule */ 1401242df4f7SSteen Hegelund static bool vcap_keyfield_unique(struct vcap_rule *rule, 1402242df4f7SSteen Hegelund enum vcap_key_field key) 1403242df4f7SSteen Hegelund { 1404242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1405242df4f7SSteen Hegelund const struct vcap_client_keyfield *ckf; 1406242df4f7SSteen Hegelund 1407242df4f7SSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) 1408242df4f7SSteen Hegelund if (ckf->ctrl.key == key) 1409242df4f7SSteen Hegelund return false; 1410242df4f7SSteen Hegelund return true; 1411242df4f7SSteen Hegelund } 1412242df4f7SSteen Hegelund 1413242df4f7SSteen Hegelund /* Check if the keyfield is in the keyset */ 1414242df4f7SSteen Hegelund static bool vcap_keyfield_match_keyset(struct vcap_rule *rule, 1415242df4f7SSteen Hegelund enum vcap_key_field key) 1416242df4f7SSteen Hegelund { 1417242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1418242df4f7SSteen Hegelund enum vcap_keyfield_set keyset = rule->keyset; 1419242df4f7SSteen Hegelund enum vcap_type vt = ri->admin->vtype; 1420242df4f7SSteen Hegelund const struct vcap_field *fields; 1421242df4f7SSteen Hegelund 1422242df4f7SSteen Hegelund /* the field is accepted if the rule has no keyset yet */ 1423242df4f7SSteen Hegelund if (keyset == VCAP_KFS_NO_VALUE) 1424242df4f7SSteen Hegelund return true; 1425242df4f7SSteen Hegelund fields = vcap_keyfields(ri->vctrl, vt, keyset); 1426242df4f7SSteen Hegelund if (!fields) 1427242df4f7SSteen Hegelund return false; 1428242df4f7SSteen Hegelund /* if there is a width there is a way */ 1429242df4f7SSteen Hegelund return fields[key].width > 0; 1430242df4f7SSteen Hegelund } 1431242df4f7SSteen Hegelund 1432c9da1ac1SSteen Hegelund static int vcap_rule_add_key(struct vcap_rule *rule, 1433c9da1ac1SSteen Hegelund enum vcap_key_field key, 1434c9da1ac1SSteen Hegelund enum vcap_field_type ftype, 1435c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data *data) 1436c9da1ac1SSteen Hegelund { 1437242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1438c9da1ac1SSteen Hegelund struct vcap_client_keyfield *field; 1439c9da1ac1SSteen Hegelund 1440242df4f7SSteen Hegelund if (!vcap_keyfield_unique(rule, key)) { 1441242df4f7SSteen Hegelund pr_warn("%s:%d: keyfield %s is already in the rule\n", 1442242df4f7SSteen Hegelund __func__, __LINE__, 1443242df4f7SSteen Hegelund vcap_keyfield_name(ri->vctrl, key)); 1444242df4f7SSteen Hegelund return -EINVAL; 1445242df4f7SSteen Hegelund } 1446242df4f7SSteen Hegelund 1447242df4f7SSteen Hegelund if (!vcap_keyfield_match_keyset(rule, key)) { 1448242df4f7SSteen Hegelund pr_err("%s:%d: keyfield %s does not belong in the rule keyset\n", 1449242df4f7SSteen Hegelund __func__, __LINE__, 1450242df4f7SSteen Hegelund vcap_keyfield_name(ri->vctrl, key)); 1451242df4f7SSteen Hegelund return -EINVAL; 1452242df4f7SSteen Hegelund } 1453242df4f7SSteen Hegelund 1454c9da1ac1SSteen Hegelund field = kzalloc(sizeof(*field), GFP_KERNEL); 1455c9da1ac1SSteen Hegelund if (!field) 1456c9da1ac1SSteen Hegelund return -ENOMEM; 1457c9da1ac1SSteen Hegelund field->ctrl.key = key; 1458c9da1ac1SSteen Hegelund field->ctrl.type = ftype; 1459c9da1ac1SSteen Hegelund vcap_copy_from_client_keyfield(rule, field, data); 1460c9da1ac1SSteen Hegelund list_add_tail(&field->ctrl.list, &rule->keyfields); 1461c9da1ac1SSteen Hegelund return 0; 1462c9da1ac1SSteen Hegelund } 1463c9da1ac1SSteen Hegelund 146446be056eSSteen Hegelund static void vcap_rule_set_key_bitsize(struct vcap_u1_key *u1, enum vcap_bit val) 146546be056eSSteen Hegelund { 146646be056eSSteen Hegelund switch (val) { 146746be056eSSteen Hegelund case VCAP_BIT_0: 146846be056eSSteen Hegelund u1->value = 0; 146946be056eSSteen Hegelund u1->mask = 1; 147046be056eSSteen Hegelund break; 147146be056eSSteen Hegelund case VCAP_BIT_1: 147246be056eSSteen Hegelund u1->value = 1; 147346be056eSSteen Hegelund u1->mask = 1; 147446be056eSSteen Hegelund break; 147546be056eSSteen Hegelund case VCAP_BIT_ANY: 147646be056eSSteen Hegelund u1->value = 0; 147746be056eSSteen Hegelund u1->mask = 0; 147846be056eSSteen Hegelund break; 147946be056eSSteen Hegelund } 148046be056eSSteen Hegelund } 148146be056eSSteen Hegelund 148246be056eSSteen Hegelund /* Add a bit key with value and mask to the rule */ 148346be056eSSteen Hegelund int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key, 148446be056eSSteen Hegelund enum vcap_bit val) 148546be056eSSteen Hegelund { 148646be056eSSteen Hegelund struct vcap_client_keyfield_data data; 148746be056eSSteen Hegelund 148846be056eSSteen Hegelund vcap_rule_set_key_bitsize(&data.u1, val); 148946be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_BIT, &data); 149046be056eSSteen Hegelund } 149146be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_bit); 149246be056eSSteen Hegelund 149346be056eSSteen Hegelund /* Add a 32 bit key field with value and mask to the rule */ 149446be056eSSteen Hegelund int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key, 149546be056eSSteen Hegelund u32 value, u32 mask) 149646be056eSSteen Hegelund { 149746be056eSSteen Hegelund struct vcap_client_keyfield_data data; 149846be056eSSteen Hegelund 149946be056eSSteen Hegelund data.u32.value = value; 150046be056eSSteen Hegelund data.u32.mask = mask; 150146be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U32, &data); 150246be056eSSteen Hegelund } 150346be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u32); 150446be056eSSteen Hegelund 1505c9da1ac1SSteen Hegelund /* Add a 48 bit key with value and mask to the rule */ 1506c9da1ac1SSteen Hegelund int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key, 1507c9da1ac1SSteen Hegelund struct vcap_u48_key *fieldval) 1508c9da1ac1SSteen Hegelund { 1509c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data data; 1510c9da1ac1SSteen Hegelund 1511c9da1ac1SSteen Hegelund memcpy(&data.u48, fieldval, sizeof(data.u48)); 1512c9da1ac1SSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U48, &data); 1513c9da1ac1SSteen Hegelund } 1514c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u48); 1515c9da1ac1SSteen Hegelund 151646be056eSSteen Hegelund /* Add a 72 bit key with value and mask to the rule */ 151746be056eSSteen Hegelund int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key, 151846be056eSSteen Hegelund struct vcap_u72_key *fieldval) 151946be056eSSteen Hegelund { 152046be056eSSteen Hegelund struct vcap_client_keyfield_data data; 152146be056eSSteen Hegelund 152246be056eSSteen Hegelund memcpy(&data.u72, fieldval, sizeof(data.u72)); 152346be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U72, &data); 152446be056eSSteen Hegelund } 152546be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72); 152646be056eSSteen Hegelund 1527d6c2964dSSteen Hegelund /* Add a 128 bit key with value and mask to the rule */ 1528d6c2964dSSteen Hegelund int vcap_rule_add_key_u128(struct vcap_rule *rule, enum vcap_key_field key, 1529d6c2964dSSteen Hegelund struct vcap_u128_key *fieldval) 1530d6c2964dSSteen Hegelund { 1531d6c2964dSSteen Hegelund struct vcap_client_keyfield_data data; 1532d6c2964dSSteen Hegelund 1533d6c2964dSSteen Hegelund memcpy(&data.u128, fieldval, sizeof(data.u128)); 1534d6c2964dSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U128, &data); 1535d6c2964dSSteen Hegelund } 1536d6c2964dSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u128); 1537d6c2964dSSteen Hegelund 1538465a38a2SSteen Hegelund /* Find a client action field in a rule */ 1539465a38a2SSteen Hegelund static struct vcap_client_actionfield * 1540465a38a2SSteen Hegelund vcap_find_actionfield(struct vcap_rule *rule, enum vcap_action_field act) 1541465a38a2SSteen Hegelund { 1542465a38a2SSteen Hegelund struct vcap_rule_internal *ri = (struct vcap_rule_internal *)rule; 1543465a38a2SSteen Hegelund struct vcap_client_actionfield *caf; 1544465a38a2SSteen Hegelund 1545465a38a2SSteen Hegelund list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) 1546465a38a2SSteen Hegelund if (caf->ctrl.action == act) 1547465a38a2SSteen Hegelund return caf; 1548465a38a2SSteen Hegelund return NULL; 1549465a38a2SSteen Hegelund } 1550465a38a2SSteen Hegelund 1551c9da1ac1SSteen Hegelund static void vcap_copy_from_client_actionfield(struct vcap_rule *rule, 1552c9da1ac1SSteen Hegelund struct vcap_client_actionfield *field, 1553c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data *data) 1554c9da1ac1SSteen Hegelund { 1555*4f141e36SHoratiu Vultur struct vcap_rule_internal *ri = to_intrule(rule); 1556*4f141e36SHoratiu Vultur int size; 1557*4f141e36SHoratiu Vultur 1558*4f141e36SHoratiu Vultur if (!ri->admin->w32be) { 1559c9da1ac1SSteen Hegelund memcpy(&field->data, data, sizeof(field->data)); 1560*4f141e36SHoratiu Vultur return; 1561*4f141e36SHoratiu Vultur } 1562*4f141e36SHoratiu Vultur 1563*4f141e36SHoratiu Vultur size = actionfield_size_table[field->ctrl.type]; 1564*4f141e36SHoratiu Vultur switch (field->ctrl.type) { 1565*4f141e36SHoratiu Vultur case VCAP_FIELD_BIT: 1566*4f141e36SHoratiu Vultur case VCAP_FIELD_U32: 1567*4f141e36SHoratiu Vultur memcpy(&field->data, data, sizeof(field->data)); 1568*4f141e36SHoratiu Vultur break; 1569*4f141e36SHoratiu Vultur case VCAP_FIELD_U48: 1570*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u48.value, data->u48.value, size); 1571*4f141e36SHoratiu Vultur break; 1572*4f141e36SHoratiu Vultur case VCAP_FIELD_U56: 1573*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u56.value, data->u56.value, size); 1574*4f141e36SHoratiu Vultur break; 1575*4f141e36SHoratiu Vultur case VCAP_FIELD_U64: 1576*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u64.value, data->u64.value, size); 1577*4f141e36SHoratiu Vultur break; 1578*4f141e36SHoratiu Vultur case VCAP_FIELD_U72: 1579*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u72.value, data->u72.value, size); 1580*4f141e36SHoratiu Vultur break; 1581*4f141e36SHoratiu Vultur case VCAP_FIELD_U112: 1582*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u112.value, data->u112.value, size); 1583*4f141e36SHoratiu Vultur break; 1584*4f141e36SHoratiu Vultur case VCAP_FIELD_U128: 1585*4f141e36SHoratiu Vultur vcap_copy_to_w32be(field->data.u128.value, data->u128.value, size); 1586*4f141e36SHoratiu Vultur break; 1587*4f141e36SHoratiu Vultur }; 1588c9da1ac1SSteen Hegelund } 1589c9da1ac1SSteen Hegelund 1590242df4f7SSteen Hegelund /* Check if the actionfield is already in the rule */ 1591242df4f7SSteen Hegelund static bool vcap_actionfield_unique(struct vcap_rule *rule, 1592242df4f7SSteen Hegelund enum vcap_action_field act) 1593242df4f7SSteen Hegelund { 1594242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1595242df4f7SSteen Hegelund const struct vcap_client_actionfield *caf; 1596242df4f7SSteen Hegelund 1597242df4f7SSteen Hegelund list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) 1598242df4f7SSteen Hegelund if (caf->ctrl.action == act) 1599242df4f7SSteen Hegelund return false; 1600242df4f7SSteen Hegelund return true; 1601242df4f7SSteen Hegelund } 1602242df4f7SSteen Hegelund 1603242df4f7SSteen Hegelund /* Check if the actionfield is in the actionset */ 1604242df4f7SSteen Hegelund static bool vcap_actionfield_match_actionset(struct vcap_rule *rule, 1605242df4f7SSteen Hegelund enum vcap_action_field action) 1606242df4f7SSteen Hegelund { 1607242df4f7SSteen Hegelund enum vcap_actionfield_set actionset = rule->actionset; 1608242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1609242df4f7SSteen Hegelund enum vcap_type vt = ri->admin->vtype; 1610242df4f7SSteen Hegelund const struct vcap_field *fields; 1611242df4f7SSteen Hegelund 1612242df4f7SSteen Hegelund /* the field is accepted if the rule has no actionset yet */ 1613242df4f7SSteen Hegelund if (actionset == VCAP_AFS_NO_VALUE) 1614242df4f7SSteen Hegelund return true; 1615242df4f7SSteen Hegelund fields = vcap_actionfields(ri->vctrl, vt, actionset); 1616242df4f7SSteen Hegelund if (!fields) 1617242df4f7SSteen Hegelund return false; 1618242df4f7SSteen Hegelund /* if there is a width there is a way */ 1619242df4f7SSteen Hegelund return fields[action].width > 0; 1620242df4f7SSteen Hegelund } 1621242df4f7SSteen Hegelund 1622c9da1ac1SSteen Hegelund static int vcap_rule_add_action(struct vcap_rule *rule, 1623c9da1ac1SSteen Hegelund enum vcap_action_field action, 1624c9da1ac1SSteen Hegelund enum vcap_field_type ftype, 1625c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data *data) 1626c9da1ac1SSteen Hegelund { 1627242df4f7SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1628c9da1ac1SSteen Hegelund struct vcap_client_actionfield *field; 1629c9da1ac1SSteen Hegelund 1630242df4f7SSteen Hegelund if (!vcap_actionfield_unique(rule, action)) { 1631242df4f7SSteen Hegelund pr_warn("%s:%d: actionfield %s is already in the rule\n", 1632242df4f7SSteen Hegelund __func__, __LINE__, 1633242df4f7SSteen Hegelund vcap_actionfield_name(ri->vctrl, action)); 1634242df4f7SSteen Hegelund return -EINVAL; 1635242df4f7SSteen Hegelund } 1636242df4f7SSteen Hegelund 1637242df4f7SSteen Hegelund if (!vcap_actionfield_match_actionset(rule, action)) { 1638242df4f7SSteen Hegelund pr_err("%s:%d: actionfield %s does not belong in the rule actionset\n", 1639242df4f7SSteen Hegelund __func__, __LINE__, 1640242df4f7SSteen Hegelund vcap_actionfield_name(ri->vctrl, action)); 1641242df4f7SSteen Hegelund return -EINVAL; 1642242df4f7SSteen Hegelund } 1643242df4f7SSteen Hegelund 1644c9da1ac1SSteen Hegelund field = kzalloc(sizeof(*field), GFP_KERNEL); 1645c9da1ac1SSteen Hegelund if (!field) 1646c9da1ac1SSteen Hegelund return -ENOMEM; 1647c9da1ac1SSteen Hegelund field->ctrl.action = action; 1648c9da1ac1SSteen Hegelund field->ctrl.type = ftype; 1649c9da1ac1SSteen Hegelund vcap_copy_from_client_actionfield(rule, field, data); 1650c9da1ac1SSteen Hegelund list_add_tail(&field->ctrl.list, &rule->actionfields); 1651c9da1ac1SSteen Hegelund return 0; 1652c9da1ac1SSteen Hegelund } 1653c9da1ac1SSteen Hegelund 1654c9da1ac1SSteen Hegelund static void vcap_rule_set_action_bitsize(struct vcap_u1_action *u1, 1655c9da1ac1SSteen Hegelund enum vcap_bit val) 1656c9da1ac1SSteen Hegelund { 1657c9da1ac1SSteen Hegelund switch (val) { 1658c9da1ac1SSteen Hegelund case VCAP_BIT_0: 1659c9da1ac1SSteen Hegelund u1->value = 0; 1660c9da1ac1SSteen Hegelund break; 1661c9da1ac1SSteen Hegelund case VCAP_BIT_1: 1662c9da1ac1SSteen Hegelund u1->value = 1; 1663c9da1ac1SSteen Hegelund break; 1664c9da1ac1SSteen Hegelund case VCAP_BIT_ANY: 1665c9da1ac1SSteen Hegelund u1->value = 0; 1666c9da1ac1SSteen Hegelund break; 1667c9da1ac1SSteen Hegelund } 1668c9da1ac1SSteen Hegelund } 1669c9da1ac1SSteen Hegelund 1670c9da1ac1SSteen Hegelund /* Add a bit action with value to the rule */ 1671c9da1ac1SSteen Hegelund int vcap_rule_add_action_bit(struct vcap_rule *rule, 1672c9da1ac1SSteen Hegelund enum vcap_action_field action, 1673c9da1ac1SSteen Hegelund enum vcap_bit val) 1674c9da1ac1SSteen Hegelund { 1675c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data data; 1676c9da1ac1SSteen Hegelund 1677c9da1ac1SSteen Hegelund vcap_rule_set_action_bitsize(&data.u1, val); 1678c9da1ac1SSteen Hegelund return vcap_rule_add_action(rule, action, VCAP_FIELD_BIT, &data); 1679c9da1ac1SSteen Hegelund } 1680c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_bit); 1681c9da1ac1SSteen Hegelund 1682c9da1ac1SSteen Hegelund /* Add a 32 bit action field with value to the rule */ 1683c9da1ac1SSteen Hegelund int vcap_rule_add_action_u32(struct vcap_rule *rule, 1684c9da1ac1SSteen Hegelund enum vcap_action_field action, 1685c9da1ac1SSteen Hegelund u32 value) 1686c9da1ac1SSteen Hegelund { 1687c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data data; 1688c9da1ac1SSteen Hegelund 1689c9da1ac1SSteen Hegelund data.u32.value = value; 1690c9da1ac1SSteen Hegelund return vcap_rule_add_action(rule, action, VCAP_FIELD_U32, &data); 1691c9da1ac1SSteen Hegelund } 1692c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32); 1693c9da1ac1SSteen Hegelund 1694f13230a4SSteen Hegelund static int vcap_read_counter(struct vcap_rule_internal *ri, 1695f13230a4SSteen Hegelund struct vcap_counter *ctr) 1696f13230a4SSteen Hegelund { 1697f13230a4SSteen Hegelund struct vcap_admin *admin = ri->admin; 1698f13230a4SSteen Hegelund 1699f13230a4SSteen Hegelund ri->vctrl->ops->update(ri->ndev, admin, VCAP_CMD_READ, VCAP_SEL_COUNTER, 1700f13230a4SSteen Hegelund ri->addr); 1701f13230a4SSteen Hegelund ri->vctrl->ops->cache_read(ri->ndev, admin, VCAP_SEL_COUNTER, 1702f13230a4SSteen Hegelund ri->counter_id, 0); 1703f13230a4SSteen Hegelund ctr->value = admin->cache.counter; 1704f13230a4SSteen Hegelund ctr->sticky = admin->cache.sticky; 1705f13230a4SSteen Hegelund return 0; 1706f13230a4SSteen Hegelund } 1707f13230a4SSteen Hegelund 1708c9da1ac1SSteen Hegelund /* Copy to host byte order */ 1709c9da1ac1SSteen Hegelund void vcap_netbytes_copy(u8 *dst, u8 *src, int count) 1710c9da1ac1SSteen Hegelund { 1711c9da1ac1SSteen Hegelund int idx; 1712c9da1ac1SSteen Hegelund 1713c9da1ac1SSteen Hegelund for (idx = 0; idx < count; ++idx, ++dst) 1714c9da1ac1SSteen Hegelund *dst = src[count - idx - 1]; 1715c9da1ac1SSteen Hegelund } 1716c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_netbytes_copy); 1717c9da1ac1SSteen Hegelund 1718c9da1ac1SSteen Hegelund /* Convert validation error code into tc extact error message */ 1719c9da1ac1SSteen Hegelund void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule) 1720c9da1ac1SSteen Hegelund { 1721c9da1ac1SSteen Hegelund switch (vrule->exterr) { 1722c9da1ac1SSteen Hegelund case VCAP_ERR_NONE: 1723c9da1ac1SSteen Hegelund break; 1724c9da1ac1SSteen Hegelund case VCAP_ERR_NO_ADMIN: 1725c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1726c9da1ac1SSteen Hegelund "Missing VCAP instance"); 1727c9da1ac1SSteen Hegelund break; 1728c9da1ac1SSteen Hegelund case VCAP_ERR_NO_NETDEV: 1729c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1730c9da1ac1SSteen Hegelund "Missing network interface"); 1731c9da1ac1SSteen Hegelund break; 1732c9da1ac1SSteen Hegelund case VCAP_ERR_NO_KEYSET_MATCH: 1733c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1734c9da1ac1SSteen Hegelund "No keyset matched the filter keys"); 1735c9da1ac1SSteen Hegelund break; 1736c9da1ac1SSteen Hegelund case VCAP_ERR_NO_ACTIONSET_MATCH: 1737c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1738c9da1ac1SSteen Hegelund "No actionset matched the filter actions"); 1739c9da1ac1SSteen Hegelund break; 1740c9da1ac1SSteen Hegelund case VCAP_ERR_NO_PORT_KEYSET_MATCH: 1741c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1742c9da1ac1SSteen Hegelund "No port keyset matched the filter keys"); 1743c9da1ac1SSteen Hegelund break; 1744c9da1ac1SSteen Hegelund } 1745c9da1ac1SSteen Hegelund } 1746c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_tc_exterr); 174767d63751SSteen Hegelund 174867456717SSteen Hegelund /* Check if this port is already enabled for this VCAP instance */ 174967456717SSteen Hegelund static bool vcap_is_enabled(struct vcap_admin *admin, struct net_device *ndev, 175067456717SSteen Hegelund unsigned long cookie) 175167456717SSteen Hegelund { 175267456717SSteen Hegelund struct vcap_enabled_port *eport; 175367456717SSteen Hegelund 175467456717SSteen Hegelund list_for_each_entry(eport, &admin->enabled, list) 175567456717SSteen Hegelund if (eport->cookie == cookie || eport->ndev == ndev) 175667456717SSteen Hegelund return true; 175767456717SSteen Hegelund 175867456717SSteen Hegelund return false; 175967456717SSteen Hegelund } 176067456717SSteen Hegelund 176167456717SSteen Hegelund /* Enable this port for this VCAP instance */ 176267456717SSteen Hegelund static int vcap_enable(struct vcap_admin *admin, struct net_device *ndev, 176367456717SSteen Hegelund unsigned long cookie) 176467456717SSteen Hegelund { 176567456717SSteen Hegelund struct vcap_enabled_port *eport; 176667456717SSteen Hegelund 176767456717SSteen Hegelund eport = kzalloc(sizeof(*eport), GFP_KERNEL); 176867456717SSteen Hegelund if (!eport) 176967456717SSteen Hegelund return -ENOMEM; 177067456717SSteen Hegelund 177167456717SSteen Hegelund eport->ndev = ndev; 177267456717SSteen Hegelund eport->cookie = cookie; 177367456717SSteen Hegelund list_add_tail(&eport->list, &admin->enabled); 177467456717SSteen Hegelund 177567456717SSteen Hegelund return 0; 177667456717SSteen Hegelund } 177767456717SSteen Hegelund 177867456717SSteen Hegelund /* Disable this port for this VCAP instance */ 177967456717SSteen Hegelund static int vcap_disable(struct vcap_admin *admin, struct net_device *ndev, 178067456717SSteen Hegelund unsigned long cookie) 178167456717SSteen Hegelund { 178267456717SSteen Hegelund struct vcap_enabled_port *eport; 178367456717SSteen Hegelund 178467456717SSteen Hegelund list_for_each_entry(eport, &admin->enabled, list) { 178567456717SSteen Hegelund if (eport->cookie == cookie && eport->ndev == ndev) { 178667456717SSteen Hegelund list_del(&eport->list); 178767456717SSteen Hegelund kfree(eport); 178867456717SSteen Hegelund return 0; 178967456717SSteen Hegelund } 179067456717SSteen Hegelund } 179167456717SSteen Hegelund 179267456717SSteen Hegelund return -ENOENT; 179367456717SSteen Hegelund } 179467456717SSteen Hegelund 179567456717SSteen Hegelund /* Find the VCAP instance that enabled the port using a specific filter */ 179667456717SSteen Hegelund static struct vcap_admin *vcap_find_admin_by_cookie(struct vcap_control *vctrl, 179767456717SSteen Hegelund unsigned long cookie) 179867456717SSteen Hegelund { 179967456717SSteen Hegelund struct vcap_enabled_port *eport; 180067456717SSteen Hegelund struct vcap_admin *admin; 180167456717SSteen Hegelund 180267456717SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) 180367456717SSteen Hegelund list_for_each_entry(eport, &admin->enabled, list) 180467456717SSteen Hegelund if (eport->cookie == cookie) 180567456717SSteen Hegelund return admin; 180667456717SSteen Hegelund 180767456717SSteen Hegelund return NULL; 180867456717SSteen Hegelund } 180967456717SSteen Hegelund 181067456717SSteen Hegelund /* Enable/Disable the VCAP instance lookups. Chain id 0 means disable */ 181167456717SSteen Hegelund int vcap_enable_lookups(struct vcap_control *vctrl, struct net_device *ndev, 181267456717SSteen Hegelund int chain_id, unsigned long cookie, bool enable) 181367456717SSteen Hegelund { 181467456717SSteen Hegelund struct vcap_admin *admin; 181567456717SSteen Hegelund int err; 181667456717SSteen Hegelund 181767456717SSteen Hegelund err = vcap_api_check(vctrl); 181867456717SSteen Hegelund if (err) 181967456717SSteen Hegelund return err; 182067456717SSteen Hegelund 182167456717SSteen Hegelund if (!ndev) 182267456717SSteen Hegelund return -ENODEV; 182367456717SSteen Hegelund 182467456717SSteen Hegelund if (chain_id) 182567456717SSteen Hegelund admin = vcap_find_admin(vctrl, chain_id); 182667456717SSteen Hegelund else 182767456717SSteen Hegelund admin = vcap_find_admin_by_cookie(vctrl, cookie); 182867456717SSteen Hegelund if (!admin) 182967456717SSteen Hegelund return -ENOENT; 183067456717SSteen Hegelund 183167456717SSteen Hegelund /* first instance and first chain */ 183267456717SSteen Hegelund if (admin->vinst || chain_id > admin->first_cid) 183367456717SSteen Hegelund return -EFAULT; 183467456717SSteen Hegelund 183567456717SSteen Hegelund err = vctrl->ops->enable(ndev, admin, enable); 183667456717SSteen Hegelund if (err) 183767456717SSteen Hegelund return err; 183867456717SSteen Hegelund 183967456717SSteen Hegelund if (chain_id) { 184067456717SSteen Hegelund if (vcap_is_enabled(admin, ndev, cookie)) 184167456717SSteen Hegelund return -EADDRINUSE; 184271c9de99SSteen Hegelund mutex_lock(&admin->lock); 184367456717SSteen Hegelund vcap_enable(admin, ndev, cookie); 184467456717SSteen Hegelund } else { 184571c9de99SSteen Hegelund mutex_lock(&admin->lock); 184667456717SSteen Hegelund vcap_disable(admin, ndev, cookie); 184767456717SSteen Hegelund } 184871c9de99SSteen Hegelund mutex_unlock(&admin->lock); 184967456717SSteen Hegelund 185067456717SSteen Hegelund return 0; 185167456717SSteen Hegelund } 185267456717SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_enable_lookups); 185367456717SSteen Hegelund 1854f13230a4SSteen Hegelund /* Set a rule counter id (for certain vcaps only) */ 1855f13230a4SSteen Hegelund void vcap_rule_set_counter_id(struct vcap_rule *rule, u32 counter_id) 1856f13230a4SSteen Hegelund { 1857f13230a4SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1858f13230a4SSteen Hegelund 1859f13230a4SSteen Hegelund ri->counter_id = counter_id; 1860f13230a4SSteen Hegelund } 1861f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter_id); 1862f13230a4SSteen Hegelund 186340e7fe18SSteen Hegelund /* Provide all rules via a callback interface */ 186440e7fe18SSteen Hegelund int vcap_rule_iter(struct vcap_control *vctrl, 186540e7fe18SSteen Hegelund int (*callback)(void *, struct vcap_rule *), void *arg) 186640e7fe18SSteen Hegelund { 186740e7fe18SSteen Hegelund struct vcap_rule_internal *ri; 186840e7fe18SSteen Hegelund struct vcap_admin *admin; 186940e7fe18SSteen Hegelund int ret; 187040e7fe18SSteen Hegelund 187140e7fe18SSteen Hegelund ret = vcap_api_check(vctrl); 187240e7fe18SSteen Hegelund if (ret) 187340e7fe18SSteen Hegelund return ret; 187440e7fe18SSteen Hegelund 187540e7fe18SSteen Hegelund /* Iterate all rules in each VCAP instance */ 187640e7fe18SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) { 187740e7fe18SSteen Hegelund list_for_each_entry(ri, &admin->rules, list) { 187840e7fe18SSteen Hegelund ret = callback(arg, &ri->data); 187940e7fe18SSteen Hegelund if (ret) 188040e7fe18SSteen Hegelund return ret; 188140e7fe18SSteen Hegelund } 188240e7fe18SSteen Hegelund } 188340e7fe18SSteen Hegelund 188440e7fe18SSteen Hegelund return 0; 188540e7fe18SSteen Hegelund } 188640e7fe18SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_iter); 188740e7fe18SSteen Hegelund 1888f13230a4SSteen Hegelund int vcap_rule_set_counter(struct vcap_rule *rule, struct vcap_counter *ctr) 1889f13230a4SSteen Hegelund { 1890f13230a4SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1891f13230a4SSteen Hegelund int err; 1892f13230a4SSteen Hegelund 1893f13230a4SSteen Hegelund err = vcap_api_check(ri->vctrl); 1894f13230a4SSteen Hegelund if (err) 1895f13230a4SSteen Hegelund return err; 1896f13230a4SSteen Hegelund if (!ctr) { 1897f13230a4SSteen Hegelund pr_err("%s:%d: counter is missing\n", __func__, __LINE__); 1898f13230a4SSteen Hegelund return -EINVAL; 1899f13230a4SSteen Hegelund } 1900f13230a4SSteen Hegelund return vcap_write_counter(ri, ctr); 1901f13230a4SSteen Hegelund } 1902f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_set_counter); 1903f13230a4SSteen Hegelund 1904f13230a4SSteen Hegelund int vcap_rule_get_counter(struct vcap_rule *rule, struct vcap_counter *ctr) 1905f13230a4SSteen Hegelund { 1906f13230a4SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1907f13230a4SSteen Hegelund int err; 1908f13230a4SSteen Hegelund 1909f13230a4SSteen Hegelund err = vcap_api_check(ri->vctrl); 1910f13230a4SSteen Hegelund if (err) 1911f13230a4SSteen Hegelund return err; 1912f13230a4SSteen Hegelund if (!ctr) { 1913f13230a4SSteen Hegelund pr_err("%s:%d: counter is missing\n", __func__, __LINE__); 1914f13230a4SSteen Hegelund return -EINVAL; 1915f13230a4SSteen Hegelund } 1916f13230a4SSteen Hegelund return vcap_read_counter(ri, ctr); 1917f13230a4SSteen Hegelund } 1918f13230a4SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_get_counter); 1919f13230a4SSteen Hegelund 1920465a38a2SSteen Hegelund static int vcap_rule_mod_key(struct vcap_rule *rule, 1921465a38a2SSteen Hegelund enum vcap_key_field key, 1922465a38a2SSteen Hegelund enum vcap_field_type ftype, 1923465a38a2SSteen Hegelund struct vcap_client_keyfield_data *data) 1924465a38a2SSteen Hegelund { 1925465a38a2SSteen Hegelund struct vcap_client_keyfield *field; 1926465a38a2SSteen Hegelund 1927465a38a2SSteen Hegelund field = vcap_find_keyfield(rule, key); 1928465a38a2SSteen Hegelund if (!field) 1929465a38a2SSteen Hegelund return vcap_rule_add_key(rule, key, ftype, data); 1930465a38a2SSteen Hegelund vcap_copy_from_client_keyfield(rule, field, data); 1931465a38a2SSteen Hegelund return 0; 1932465a38a2SSteen Hegelund } 1933465a38a2SSteen Hegelund 1934465a38a2SSteen Hegelund /* Modify a 32 bit key field with value and mask in the rule */ 1935465a38a2SSteen Hegelund int vcap_rule_mod_key_u32(struct vcap_rule *rule, enum vcap_key_field key, 1936465a38a2SSteen Hegelund u32 value, u32 mask) 1937465a38a2SSteen Hegelund { 1938465a38a2SSteen Hegelund struct vcap_client_keyfield_data data; 1939465a38a2SSteen Hegelund 1940465a38a2SSteen Hegelund data.u32.value = value; 1941465a38a2SSteen Hegelund data.u32.mask = mask; 1942465a38a2SSteen Hegelund return vcap_rule_mod_key(rule, key, VCAP_FIELD_U32, &data); 1943465a38a2SSteen Hegelund } 1944465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_mod_key_u32); 1945465a38a2SSteen Hegelund 1946465a38a2SSteen Hegelund static int vcap_rule_mod_action(struct vcap_rule *rule, 1947465a38a2SSteen Hegelund enum vcap_action_field action, 1948465a38a2SSteen Hegelund enum vcap_field_type ftype, 1949465a38a2SSteen Hegelund struct vcap_client_actionfield_data *data) 1950465a38a2SSteen Hegelund { 1951465a38a2SSteen Hegelund struct vcap_client_actionfield *field; 1952465a38a2SSteen Hegelund 1953465a38a2SSteen Hegelund field = vcap_find_actionfield(rule, action); 1954465a38a2SSteen Hegelund if (!field) 1955465a38a2SSteen Hegelund return vcap_rule_add_action(rule, action, ftype, data); 1956465a38a2SSteen Hegelund vcap_copy_from_client_actionfield(rule, field, data); 1957465a38a2SSteen Hegelund return 0; 1958465a38a2SSteen Hegelund } 1959465a38a2SSteen Hegelund 1960465a38a2SSteen Hegelund /* Modify a 32 bit action field with value in the rule */ 1961465a38a2SSteen Hegelund int vcap_rule_mod_action_u32(struct vcap_rule *rule, 1962465a38a2SSteen Hegelund enum vcap_action_field action, 1963465a38a2SSteen Hegelund u32 value) 1964465a38a2SSteen Hegelund { 1965465a38a2SSteen Hegelund struct vcap_client_actionfield_data data; 1966465a38a2SSteen Hegelund 1967465a38a2SSteen Hegelund data.u32.value = value; 1968465a38a2SSteen Hegelund return vcap_rule_mod_action(rule, action, VCAP_FIELD_U32, &data); 1969465a38a2SSteen Hegelund } 1970465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_mod_action_u32); 1971465a38a2SSteen Hegelund 1972465a38a2SSteen Hegelund /* Drop keys in a keylist and any keys that are not supported by the keyset */ 1973465a38a2SSteen Hegelund int vcap_filter_rule_keys(struct vcap_rule *rule, 1974465a38a2SSteen Hegelund enum vcap_key_field keylist[], int length, 1975465a38a2SSteen Hegelund bool drop_unsupported) 1976465a38a2SSteen Hegelund { 1977465a38a2SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 1978465a38a2SSteen Hegelund struct vcap_client_keyfield *ckf, *next_ckf; 1979465a38a2SSteen Hegelund const struct vcap_field *fields; 1980465a38a2SSteen Hegelund enum vcap_key_field key; 1981465a38a2SSteen Hegelund int err = 0; 1982465a38a2SSteen Hegelund int idx; 1983465a38a2SSteen Hegelund 1984465a38a2SSteen Hegelund if (length > 0) { 1985465a38a2SSteen Hegelund err = -EEXIST; 1986465a38a2SSteen Hegelund list_for_each_entry_safe(ckf, next_ckf, 1987465a38a2SSteen Hegelund &ri->data.keyfields, ctrl.list) { 1988465a38a2SSteen Hegelund key = ckf->ctrl.key; 1989465a38a2SSteen Hegelund for (idx = 0; idx < length; ++idx) 1990465a38a2SSteen Hegelund if (key == keylist[idx]) { 1991465a38a2SSteen Hegelund list_del(&ckf->ctrl.list); 1992465a38a2SSteen Hegelund kfree(ckf); 1993465a38a2SSteen Hegelund idx++; 1994465a38a2SSteen Hegelund err = 0; 1995465a38a2SSteen Hegelund } 1996465a38a2SSteen Hegelund } 1997465a38a2SSteen Hegelund } 1998465a38a2SSteen Hegelund if (drop_unsupported) { 1999465a38a2SSteen Hegelund err = -EEXIST; 2000465a38a2SSteen Hegelund fields = vcap_keyfields(ri->vctrl, ri->admin->vtype, 2001465a38a2SSteen Hegelund rule->keyset); 2002465a38a2SSteen Hegelund if (!fields) 2003465a38a2SSteen Hegelund return err; 2004465a38a2SSteen Hegelund list_for_each_entry_safe(ckf, next_ckf, 2005465a38a2SSteen Hegelund &ri->data.keyfields, ctrl.list) { 2006465a38a2SSteen Hegelund key = ckf->ctrl.key; 2007465a38a2SSteen Hegelund if (fields[key].width == 0) { 2008465a38a2SSteen Hegelund list_del(&ckf->ctrl.list); 2009465a38a2SSteen Hegelund kfree(ckf); 2010465a38a2SSteen Hegelund err = 0; 2011465a38a2SSteen Hegelund } 2012465a38a2SSteen Hegelund } 2013465a38a2SSteen Hegelund } 2014465a38a2SSteen Hegelund return err; 2015465a38a2SSteen Hegelund } 2016465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_filter_rule_keys); 2017465a38a2SSteen Hegelund 2018465a38a2SSteen Hegelund /* Make a full copy of an existing rule with a new rule id */ 2019465a38a2SSteen Hegelund struct vcap_rule *vcap_copy_rule(struct vcap_rule *erule) 2020465a38a2SSteen Hegelund { 2021465a38a2SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(erule); 2022465a38a2SSteen Hegelund struct vcap_client_actionfield *caf; 2023465a38a2SSteen Hegelund struct vcap_client_keyfield *ckf; 2024465a38a2SSteen Hegelund struct vcap_rule *rule; 2025465a38a2SSteen Hegelund int err; 2026465a38a2SSteen Hegelund 2027465a38a2SSteen Hegelund err = vcap_api_check(ri->vctrl); 2028465a38a2SSteen Hegelund if (err) 2029465a38a2SSteen Hegelund return ERR_PTR(err); 2030465a38a2SSteen Hegelund 2031465a38a2SSteen Hegelund rule = vcap_alloc_rule(ri->vctrl, ri->ndev, ri->data.vcap_chain_id, 2032465a38a2SSteen Hegelund ri->data.user, ri->data.priority, 0); 2033465a38a2SSteen Hegelund if (IS_ERR(rule)) 2034465a38a2SSteen Hegelund return rule; 2035465a38a2SSteen Hegelund 2036465a38a2SSteen Hegelund list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) { 2037465a38a2SSteen Hegelund /* Add a key duplicate in the new rule */ 2038465a38a2SSteen Hegelund err = vcap_rule_add_key(rule, 2039465a38a2SSteen Hegelund ckf->ctrl.key, 2040465a38a2SSteen Hegelund ckf->ctrl.type, 2041465a38a2SSteen Hegelund &ckf->data); 2042465a38a2SSteen Hegelund if (err) 2043465a38a2SSteen Hegelund goto err; 2044465a38a2SSteen Hegelund } 2045465a38a2SSteen Hegelund 2046465a38a2SSteen Hegelund list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) { 2047465a38a2SSteen Hegelund /* Add a action duplicate in the new rule */ 2048465a38a2SSteen Hegelund err = vcap_rule_add_action(rule, 2049465a38a2SSteen Hegelund caf->ctrl.action, 2050465a38a2SSteen Hegelund caf->ctrl.type, 2051465a38a2SSteen Hegelund &caf->data); 2052465a38a2SSteen Hegelund if (err) 2053465a38a2SSteen Hegelund goto err; 2054465a38a2SSteen Hegelund } 2055465a38a2SSteen Hegelund return rule; 2056465a38a2SSteen Hegelund err: 2057465a38a2SSteen Hegelund vcap_free_rule(rule); 2058465a38a2SSteen Hegelund return ERR_PTR(err); 2059465a38a2SSteen Hegelund } 2060465a38a2SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_copy_rule); 2061465a38a2SSteen Hegelund 206267d63751SSteen Hegelund #ifdef CONFIG_VCAP_KUNIT_TEST 206367d63751SSteen Hegelund #include "vcap_api_kunit.c" 206467d63751SSteen Hegelund #endif 2065