1c9da1ac1SSteen Hegelund // SPDX-License-Identifier: GPL-2.0+ 2c9da1ac1SSteen Hegelund /* Microchip VCAP API 3c9da1ac1SSteen Hegelund * 4c9da1ac1SSteen Hegelund * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. 5c9da1ac1SSteen Hegelund */ 6c9da1ac1SSteen Hegelund 7c9da1ac1SSteen Hegelund #include <linux/types.h> 8c9da1ac1SSteen Hegelund 9c9da1ac1SSteen Hegelund #include "vcap_api.h" 10c9da1ac1SSteen Hegelund #include "vcap_api_client.h" 11c9da1ac1SSteen Hegelund 12c9da1ac1SSteen Hegelund #define to_intrule(rule) container_of((rule), struct vcap_rule_internal, data) 13c9da1ac1SSteen Hegelund 14c9da1ac1SSteen Hegelund /* Private VCAP API rule data */ 15c9da1ac1SSteen Hegelund struct vcap_rule_internal { 16c9da1ac1SSteen Hegelund struct vcap_rule data; /* provided by the client */ 17c9da1ac1SSteen Hegelund struct list_head list; /* for insertion in the vcap admin list of rules */ 18c9da1ac1SSteen Hegelund struct vcap_admin *admin; /* vcap hw instance */ 19c9da1ac1SSteen Hegelund struct net_device *ndev; /* the interface that the rule applies to */ 20c9da1ac1SSteen Hegelund struct vcap_control *vctrl; /* the client control */ 21c9da1ac1SSteen Hegelund u32 addr; /* address in the VCAP at insertion */ 22c9da1ac1SSteen Hegelund }; 23c9da1ac1SSteen Hegelund 24*46be056eSSteen Hegelund /* Return the list of keyfields for the keyset */ 25*46be056eSSteen Hegelund static const struct vcap_field *vcap_keyfields(struct vcap_control *vctrl, 26*46be056eSSteen Hegelund enum vcap_type vt, 27*46be056eSSteen Hegelund enum vcap_keyfield_set keyset) 28*46be056eSSteen Hegelund { 29*46be056eSSteen Hegelund /* Check that the keyset exists in the vcap keyset list */ 30*46be056eSSteen Hegelund if (keyset >= vctrl->vcaps[vt].keyfield_set_size) 31*46be056eSSteen Hegelund return NULL; 32*46be056eSSteen Hegelund return vctrl->vcaps[vt].keyfield_set_map[keyset]; 33*46be056eSSteen Hegelund } 34*46be056eSSteen Hegelund 35c9da1ac1SSteen Hegelund /* Update the keyset for the rule */ 36c9da1ac1SSteen Hegelund int vcap_set_rule_set_keyset(struct vcap_rule *rule, 37c9da1ac1SSteen Hegelund enum vcap_keyfield_set keyset) 38c9da1ac1SSteen Hegelund { 39c9da1ac1SSteen Hegelund /* This will be expanded with more information later */ 40c9da1ac1SSteen Hegelund rule->keyset = keyset; 41c9da1ac1SSteen Hegelund return 0; 42c9da1ac1SSteen Hegelund } 43c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_keyset); 44c9da1ac1SSteen Hegelund 45c9da1ac1SSteen Hegelund /* Update the actionset for the rule */ 46c9da1ac1SSteen Hegelund int vcap_set_rule_set_actionset(struct vcap_rule *rule, 47c9da1ac1SSteen Hegelund enum vcap_actionfield_set actionset) 48c9da1ac1SSteen Hegelund { 49c9da1ac1SSteen Hegelund /* This will be expanded with more information later */ 50c9da1ac1SSteen Hegelund rule->actionset = actionset; 51c9da1ac1SSteen Hegelund return 0; 52c9da1ac1SSteen Hegelund } 53c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_rule_set_actionset); 54c9da1ac1SSteen Hegelund 55c9da1ac1SSteen Hegelund /* Find a rule with a provided rule id */ 56c9da1ac1SSteen Hegelund static struct vcap_rule_internal *vcap_lookup_rule(struct vcap_control *vctrl, 57c9da1ac1SSteen Hegelund u32 id) 58c9da1ac1SSteen Hegelund { 59c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri; 60c9da1ac1SSteen Hegelund struct vcap_admin *admin; 61c9da1ac1SSteen Hegelund 62c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */ 63c9da1ac1SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) 64c9da1ac1SSteen Hegelund list_for_each_entry(ri, &admin->rules, list) 65c9da1ac1SSteen Hegelund if (ri->data.id == id) 66c9da1ac1SSteen Hegelund return ri; 67c9da1ac1SSteen Hegelund return NULL; 68c9da1ac1SSteen Hegelund } 69c9da1ac1SSteen Hegelund 70c9da1ac1SSteen Hegelund /* Find a rule id with a provided cookie */ 71c9da1ac1SSteen Hegelund int vcap_lookup_rule_by_cookie(struct vcap_control *vctrl, u64 cookie) 72c9da1ac1SSteen Hegelund { 73c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri; 74c9da1ac1SSteen Hegelund struct vcap_admin *admin; 75c9da1ac1SSteen Hegelund 76c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */ 77c9da1ac1SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) 78c9da1ac1SSteen Hegelund list_for_each_entry(ri, &admin->rules, list) 79c9da1ac1SSteen Hegelund if (ri->data.cookie == cookie) 80c9da1ac1SSteen Hegelund return ri->data.id; 81c9da1ac1SSteen Hegelund return -ENOENT; 82c9da1ac1SSteen Hegelund } 83c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_rule_by_cookie); 84c9da1ac1SSteen Hegelund 85c9da1ac1SSteen Hegelund /* Lookup a vcap instance using chain id */ 86c9da1ac1SSteen Hegelund struct vcap_admin *vcap_find_admin(struct vcap_control *vctrl, int cid) 87c9da1ac1SSteen Hegelund { 88c9da1ac1SSteen Hegelund struct vcap_admin *admin; 89c9da1ac1SSteen Hegelund 90c9da1ac1SSteen Hegelund list_for_each_entry(admin, &vctrl->list, list) { 91c9da1ac1SSteen Hegelund if (cid >= admin->first_cid && cid <= admin->last_cid) 92c9da1ac1SSteen Hegelund return admin; 93c9da1ac1SSteen Hegelund } 94c9da1ac1SSteen Hegelund return NULL; 95c9da1ac1SSteen Hegelund } 96c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_find_admin); 97c9da1ac1SSteen Hegelund 98c9da1ac1SSteen Hegelund /* Validate a rule with respect to available port keys */ 99c9da1ac1SSteen Hegelund int vcap_val_rule(struct vcap_rule *rule, u16 l3_proto) 100c9da1ac1SSteen Hegelund { 101c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 102c9da1ac1SSteen Hegelund 103c9da1ac1SSteen Hegelund /* This validation will be much expanded later */ 104c9da1ac1SSteen Hegelund if (!ri->admin) { 105c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_ADMIN; 106c9da1ac1SSteen Hegelund return -EINVAL; 107c9da1ac1SSteen Hegelund } 108c9da1ac1SSteen Hegelund if (!ri->ndev) { 109c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_NETDEV; 110c9da1ac1SSteen Hegelund return -EINVAL; 111c9da1ac1SSteen Hegelund } 112c9da1ac1SSteen Hegelund if (ri->data.keyset == VCAP_KFS_NO_VALUE) { 113c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_KEYSET_MATCH; 114c9da1ac1SSteen Hegelund return -EINVAL; 115c9da1ac1SSteen Hegelund } 116c9da1ac1SSteen Hegelund if (ri->data.actionset == VCAP_AFS_NO_VALUE) { 117c9da1ac1SSteen Hegelund ri->data.exterr = VCAP_ERR_NO_ACTIONSET_MATCH; 118c9da1ac1SSteen Hegelund return -EINVAL; 119c9da1ac1SSteen Hegelund } 120c9da1ac1SSteen Hegelund return 0; 121c9da1ac1SSteen Hegelund } 122c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_val_rule); 123c9da1ac1SSteen Hegelund 124c9da1ac1SSteen Hegelund /* Assign a unique rule id and autogenerate one if id == 0 */ 125c9da1ac1SSteen Hegelund static u32 vcap_set_rule_id(struct vcap_rule_internal *ri) 126c9da1ac1SSteen Hegelund { 127c9da1ac1SSteen Hegelund u32 next_id; 128c9da1ac1SSteen Hegelund 129c9da1ac1SSteen Hegelund if (ri->data.id != 0) 130c9da1ac1SSteen Hegelund return ri->data.id; 131c9da1ac1SSteen Hegelund 132c9da1ac1SSteen Hegelund next_id = ri->vctrl->rule_id + 1; 133c9da1ac1SSteen Hegelund 134c9da1ac1SSteen Hegelund for (next_id = ri->vctrl->rule_id + 1; next_id < ~0; ++next_id) { 135c9da1ac1SSteen Hegelund if (!vcap_lookup_rule(ri->vctrl, next_id)) { 136c9da1ac1SSteen Hegelund ri->data.id = next_id; 137c9da1ac1SSteen Hegelund ri->vctrl->rule_id = next_id; 138c9da1ac1SSteen Hegelund break; 139c9da1ac1SSteen Hegelund } 140c9da1ac1SSteen Hegelund } 141c9da1ac1SSteen Hegelund return ri->data.id; 142c9da1ac1SSteen Hegelund } 143c9da1ac1SSteen Hegelund 144c9da1ac1SSteen Hegelund /* Encode and write a validated rule to the VCAP */ 145c9da1ac1SSteen Hegelund int vcap_add_rule(struct vcap_rule *rule) 146c9da1ac1SSteen Hegelund { 147c9da1ac1SSteen Hegelund /* This will later handling the encode and writing of the rule */ 148c9da1ac1SSteen Hegelund return 0; 149c9da1ac1SSteen Hegelund } 150c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_add_rule); 151c9da1ac1SSteen Hegelund 152c9da1ac1SSteen Hegelund /* Allocate a new rule with the provided arguments */ 153c9da1ac1SSteen Hegelund struct vcap_rule *vcap_alloc_rule(struct vcap_control *vctrl, 154c9da1ac1SSteen Hegelund struct net_device *ndev, int vcap_chain_id, 155c9da1ac1SSteen Hegelund enum vcap_user user, u16 priority, 156c9da1ac1SSteen Hegelund u32 id) 157c9da1ac1SSteen Hegelund { 158c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri; 159c9da1ac1SSteen Hegelund struct vcap_admin *admin; 160c9da1ac1SSteen Hegelund 161c9da1ac1SSteen Hegelund if (!ndev) 162c9da1ac1SSteen Hegelund return ERR_PTR(-ENODEV); 163c9da1ac1SSteen Hegelund /* Get the VCAP instance */ 164c9da1ac1SSteen Hegelund admin = vcap_find_admin(vctrl, vcap_chain_id); 165c9da1ac1SSteen Hegelund if (!admin) 166c9da1ac1SSteen Hegelund return ERR_PTR(-ENOENT); 167c9da1ac1SSteen Hegelund /* Create a container for the rule and return it */ 168c9da1ac1SSteen Hegelund ri = kzalloc(sizeof(*ri), GFP_KERNEL); 169c9da1ac1SSteen Hegelund if (!ri) 170c9da1ac1SSteen Hegelund return ERR_PTR(-ENOMEM); 171c9da1ac1SSteen Hegelund ri->data.vcap_chain_id = vcap_chain_id; 172c9da1ac1SSteen Hegelund ri->data.user = user; 173c9da1ac1SSteen Hegelund ri->data.priority = priority; 174c9da1ac1SSteen Hegelund ri->data.id = id; 175c9da1ac1SSteen Hegelund ri->data.keyset = VCAP_KFS_NO_VALUE; 176c9da1ac1SSteen Hegelund ri->data.actionset = VCAP_AFS_NO_VALUE; 177c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->list); 178c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->data.keyfields); 179c9da1ac1SSteen Hegelund INIT_LIST_HEAD(&ri->data.actionfields); 180c9da1ac1SSteen Hegelund ri->ndev = ndev; 181c9da1ac1SSteen Hegelund ri->admin = admin; /* refer to the vcap instance */ 182c9da1ac1SSteen Hegelund ri->vctrl = vctrl; /* refer to the client */ 183c9da1ac1SSteen Hegelund if (vcap_set_rule_id(ri) == 0) 184c9da1ac1SSteen Hegelund goto out_free; 185c9da1ac1SSteen Hegelund return (struct vcap_rule *)ri; 186c9da1ac1SSteen Hegelund 187c9da1ac1SSteen Hegelund out_free: 188c9da1ac1SSteen Hegelund kfree(ri); 189c9da1ac1SSteen Hegelund return ERR_PTR(-EINVAL); 190c9da1ac1SSteen Hegelund } 191c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_alloc_rule); 192c9da1ac1SSteen Hegelund 193c9da1ac1SSteen Hegelund /* Free mem of a rule owned by client after the rule as been added to the VCAP */ 194c9da1ac1SSteen Hegelund void vcap_free_rule(struct vcap_rule *rule) 195c9da1ac1SSteen Hegelund { 196c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri = to_intrule(rule); 197c9da1ac1SSteen Hegelund struct vcap_client_actionfield *caf, *next_caf; 198c9da1ac1SSteen Hegelund struct vcap_client_keyfield *ckf, *next_ckf; 199c9da1ac1SSteen Hegelund 200c9da1ac1SSteen Hegelund /* Deallocate the list of keys and actions */ 201c9da1ac1SSteen Hegelund list_for_each_entry_safe(ckf, next_ckf, &ri->data.keyfields, ctrl.list) { 202c9da1ac1SSteen Hegelund list_del(&ckf->ctrl.list); 203c9da1ac1SSteen Hegelund kfree(ckf); 204c9da1ac1SSteen Hegelund } 205c9da1ac1SSteen Hegelund list_for_each_entry_safe(caf, next_caf, &ri->data.actionfields, ctrl.list) { 206c9da1ac1SSteen Hegelund list_del(&caf->ctrl.list); 207c9da1ac1SSteen Hegelund kfree(caf); 208c9da1ac1SSteen Hegelund } 209c9da1ac1SSteen Hegelund /* Deallocate the rule */ 210c9da1ac1SSteen Hegelund kfree(rule); 211c9da1ac1SSteen Hegelund } 212c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_free_rule); 213c9da1ac1SSteen Hegelund 214c9da1ac1SSteen Hegelund /* Delete rule in a VCAP instance */ 215c9da1ac1SSteen Hegelund int vcap_del_rule(struct vcap_control *vctrl, struct net_device *ndev, u32 id) 216c9da1ac1SSteen Hegelund { 217c9da1ac1SSteen Hegelund struct vcap_rule_internal *ri, *elem; 218c9da1ac1SSteen Hegelund struct vcap_admin *admin; 219c9da1ac1SSteen Hegelund 220c9da1ac1SSteen Hegelund /* This will later also handle rule moving */ 221c9da1ac1SSteen Hegelund if (!ndev) 222c9da1ac1SSteen Hegelund return -ENODEV; 223c9da1ac1SSteen Hegelund /* Look for the rule id in all vcaps */ 224c9da1ac1SSteen Hegelund ri = vcap_lookup_rule(vctrl, id); 225c9da1ac1SSteen Hegelund if (!ri) 226c9da1ac1SSteen Hegelund return -EINVAL; 227c9da1ac1SSteen Hegelund admin = ri->admin; 228c9da1ac1SSteen Hegelund list_del(&ri->list); 229c9da1ac1SSteen Hegelund if (list_empty(&admin->rules)) { 230c9da1ac1SSteen Hegelund admin->last_used_addr = admin->last_valid_addr; 231c9da1ac1SSteen Hegelund } else { 232c9da1ac1SSteen Hegelund /* update the address range end marker from the last rule in the list */ 233c9da1ac1SSteen Hegelund elem = list_last_entry(&admin->rules, struct vcap_rule_internal, list); 234c9da1ac1SSteen Hegelund admin->last_used_addr = elem->addr; 235c9da1ac1SSteen Hegelund } 236c9da1ac1SSteen Hegelund kfree(ri); 237c9da1ac1SSteen Hegelund return 0; 238c9da1ac1SSteen Hegelund } 239c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_del_rule); 240c9da1ac1SSteen Hegelund 241*46be056eSSteen Hegelund /* Find information on a key field in a rule */ 242*46be056eSSteen Hegelund const struct vcap_field *vcap_lookup_keyfield(struct vcap_rule *rule, 243*46be056eSSteen Hegelund enum vcap_key_field key) 244*46be056eSSteen Hegelund { 245*46be056eSSteen Hegelund struct vcap_rule_internal *ri = (struct vcap_rule_internal *)rule; 246*46be056eSSteen Hegelund enum vcap_keyfield_set keyset = rule->keyset; 247*46be056eSSteen Hegelund enum vcap_type vt = ri->admin->vtype; 248*46be056eSSteen Hegelund const struct vcap_field *fields; 249*46be056eSSteen Hegelund 250*46be056eSSteen Hegelund if (keyset == VCAP_KFS_NO_VALUE) 251*46be056eSSteen Hegelund return NULL; 252*46be056eSSteen Hegelund fields = vcap_keyfields(ri->vctrl, vt, keyset); 253*46be056eSSteen Hegelund if (!fields) 254*46be056eSSteen Hegelund return NULL; 255*46be056eSSteen Hegelund return &fields[key]; 256*46be056eSSteen Hegelund } 257*46be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_lookup_keyfield); 258*46be056eSSteen Hegelund 259c9da1ac1SSteen Hegelund static void vcap_copy_from_client_keyfield(struct vcap_rule *rule, 260c9da1ac1SSteen Hegelund struct vcap_client_keyfield *field, 261c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data *data) 262c9da1ac1SSteen Hegelund { 263c9da1ac1SSteen Hegelund /* This will be expanded later to handle different vcap memory layouts */ 264c9da1ac1SSteen Hegelund memcpy(&field->data, data, sizeof(field->data)); 265c9da1ac1SSteen Hegelund } 266c9da1ac1SSteen Hegelund 267c9da1ac1SSteen Hegelund static int vcap_rule_add_key(struct vcap_rule *rule, 268c9da1ac1SSteen Hegelund enum vcap_key_field key, 269c9da1ac1SSteen Hegelund enum vcap_field_type ftype, 270c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data *data) 271c9da1ac1SSteen Hegelund { 272c9da1ac1SSteen Hegelund struct vcap_client_keyfield *field; 273c9da1ac1SSteen Hegelund 274c9da1ac1SSteen Hegelund /* More validation will be added here later */ 275c9da1ac1SSteen Hegelund field = kzalloc(sizeof(*field), GFP_KERNEL); 276c9da1ac1SSteen Hegelund if (!field) 277c9da1ac1SSteen Hegelund return -ENOMEM; 278c9da1ac1SSteen Hegelund field->ctrl.key = key; 279c9da1ac1SSteen Hegelund field->ctrl.type = ftype; 280c9da1ac1SSteen Hegelund vcap_copy_from_client_keyfield(rule, field, data); 281c9da1ac1SSteen Hegelund list_add_tail(&field->ctrl.list, &rule->keyfields); 282c9da1ac1SSteen Hegelund return 0; 283c9da1ac1SSteen Hegelund } 284c9da1ac1SSteen Hegelund 285*46be056eSSteen Hegelund static void vcap_rule_set_key_bitsize(struct vcap_u1_key *u1, enum vcap_bit val) 286*46be056eSSteen Hegelund { 287*46be056eSSteen Hegelund switch (val) { 288*46be056eSSteen Hegelund case VCAP_BIT_0: 289*46be056eSSteen Hegelund u1->value = 0; 290*46be056eSSteen Hegelund u1->mask = 1; 291*46be056eSSteen Hegelund break; 292*46be056eSSteen Hegelund case VCAP_BIT_1: 293*46be056eSSteen Hegelund u1->value = 1; 294*46be056eSSteen Hegelund u1->mask = 1; 295*46be056eSSteen Hegelund break; 296*46be056eSSteen Hegelund case VCAP_BIT_ANY: 297*46be056eSSteen Hegelund u1->value = 0; 298*46be056eSSteen Hegelund u1->mask = 0; 299*46be056eSSteen Hegelund break; 300*46be056eSSteen Hegelund } 301*46be056eSSteen Hegelund } 302*46be056eSSteen Hegelund 303*46be056eSSteen Hegelund /* Add a bit key with value and mask to the rule */ 304*46be056eSSteen Hegelund int vcap_rule_add_key_bit(struct vcap_rule *rule, enum vcap_key_field key, 305*46be056eSSteen Hegelund enum vcap_bit val) 306*46be056eSSteen Hegelund { 307*46be056eSSteen Hegelund struct vcap_client_keyfield_data data; 308*46be056eSSteen Hegelund 309*46be056eSSteen Hegelund vcap_rule_set_key_bitsize(&data.u1, val); 310*46be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_BIT, &data); 311*46be056eSSteen Hegelund } 312*46be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_bit); 313*46be056eSSteen Hegelund 314*46be056eSSteen Hegelund /* Add a 32 bit key field with value and mask to the rule */ 315*46be056eSSteen Hegelund int vcap_rule_add_key_u32(struct vcap_rule *rule, enum vcap_key_field key, 316*46be056eSSteen Hegelund u32 value, u32 mask) 317*46be056eSSteen Hegelund { 318*46be056eSSteen Hegelund struct vcap_client_keyfield_data data; 319*46be056eSSteen Hegelund 320*46be056eSSteen Hegelund data.u32.value = value; 321*46be056eSSteen Hegelund data.u32.mask = mask; 322*46be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U32, &data); 323*46be056eSSteen Hegelund } 324*46be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u32); 325*46be056eSSteen Hegelund 326c9da1ac1SSteen Hegelund /* Add a 48 bit key with value and mask to the rule */ 327c9da1ac1SSteen Hegelund int vcap_rule_add_key_u48(struct vcap_rule *rule, enum vcap_key_field key, 328c9da1ac1SSteen Hegelund struct vcap_u48_key *fieldval) 329c9da1ac1SSteen Hegelund { 330c9da1ac1SSteen Hegelund struct vcap_client_keyfield_data data; 331c9da1ac1SSteen Hegelund 332c9da1ac1SSteen Hegelund memcpy(&data.u48, fieldval, sizeof(data.u48)); 333c9da1ac1SSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U48, &data); 334c9da1ac1SSteen Hegelund } 335c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u48); 336c9da1ac1SSteen Hegelund 337*46be056eSSteen Hegelund /* Add a 72 bit key with value and mask to the rule */ 338*46be056eSSteen Hegelund int vcap_rule_add_key_u72(struct vcap_rule *rule, enum vcap_key_field key, 339*46be056eSSteen Hegelund struct vcap_u72_key *fieldval) 340*46be056eSSteen Hegelund { 341*46be056eSSteen Hegelund struct vcap_client_keyfield_data data; 342*46be056eSSteen Hegelund 343*46be056eSSteen Hegelund memcpy(&data.u72, fieldval, sizeof(data.u72)); 344*46be056eSSteen Hegelund return vcap_rule_add_key(rule, key, VCAP_FIELD_U72, &data); 345*46be056eSSteen Hegelund } 346*46be056eSSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_key_u72); 347*46be056eSSteen Hegelund 348c9da1ac1SSteen Hegelund static void vcap_copy_from_client_actionfield(struct vcap_rule *rule, 349c9da1ac1SSteen Hegelund struct vcap_client_actionfield *field, 350c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data *data) 351c9da1ac1SSteen Hegelund { 352c9da1ac1SSteen Hegelund /* This will be expanded later to handle different vcap memory layouts */ 353c9da1ac1SSteen Hegelund memcpy(&field->data, data, sizeof(field->data)); 354c9da1ac1SSteen Hegelund } 355c9da1ac1SSteen Hegelund 356c9da1ac1SSteen Hegelund static int vcap_rule_add_action(struct vcap_rule *rule, 357c9da1ac1SSteen Hegelund enum vcap_action_field action, 358c9da1ac1SSteen Hegelund enum vcap_field_type ftype, 359c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data *data) 360c9da1ac1SSteen Hegelund { 361c9da1ac1SSteen Hegelund struct vcap_client_actionfield *field; 362c9da1ac1SSteen Hegelund 363c9da1ac1SSteen Hegelund /* More validation will be added here later */ 364c9da1ac1SSteen Hegelund field = kzalloc(sizeof(*field), GFP_KERNEL); 365c9da1ac1SSteen Hegelund if (!field) 366c9da1ac1SSteen Hegelund return -ENOMEM; 367c9da1ac1SSteen Hegelund field->ctrl.action = action; 368c9da1ac1SSteen Hegelund field->ctrl.type = ftype; 369c9da1ac1SSteen Hegelund vcap_copy_from_client_actionfield(rule, field, data); 370c9da1ac1SSteen Hegelund list_add_tail(&field->ctrl.list, &rule->actionfields); 371c9da1ac1SSteen Hegelund return 0; 372c9da1ac1SSteen Hegelund } 373c9da1ac1SSteen Hegelund 374c9da1ac1SSteen Hegelund static void vcap_rule_set_action_bitsize(struct vcap_u1_action *u1, 375c9da1ac1SSteen Hegelund enum vcap_bit val) 376c9da1ac1SSteen Hegelund { 377c9da1ac1SSteen Hegelund switch (val) { 378c9da1ac1SSteen Hegelund case VCAP_BIT_0: 379c9da1ac1SSteen Hegelund u1->value = 0; 380c9da1ac1SSteen Hegelund break; 381c9da1ac1SSteen Hegelund case VCAP_BIT_1: 382c9da1ac1SSteen Hegelund u1->value = 1; 383c9da1ac1SSteen Hegelund break; 384c9da1ac1SSteen Hegelund case VCAP_BIT_ANY: 385c9da1ac1SSteen Hegelund u1->value = 0; 386c9da1ac1SSteen Hegelund break; 387c9da1ac1SSteen Hegelund } 388c9da1ac1SSteen Hegelund } 389c9da1ac1SSteen Hegelund 390c9da1ac1SSteen Hegelund /* Add a bit action with value to the rule */ 391c9da1ac1SSteen Hegelund int vcap_rule_add_action_bit(struct vcap_rule *rule, 392c9da1ac1SSteen Hegelund enum vcap_action_field action, 393c9da1ac1SSteen Hegelund enum vcap_bit val) 394c9da1ac1SSteen Hegelund { 395c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data data; 396c9da1ac1SSteen Hegelund 397c9da1ac1SSteen Hegelund vcap_rule_set_action_bitsize(&data.u1, val); 398c9da1ac1SSteen Hegelund return vcap_rule_add_action(rule, action, VCAP_FIELD_BIT, &data); 399c9da1ac1SSteen Hegelund } 400c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_bit); 401c9da1ac1SSteen Hegelund 402c9da1ac1SSteen Hegelund /* Add a 32 bit action field with value to the rule */ 403c9da1ac1SSteen Hegelund int vcap_rule_add_action_u32(struct vcap_rule *rule, 404c9da1ac1SSteen Hegelund enum vcap_action_field action, 405c9da1ac1SSteen Hegelund u32 value) 406c9da1ac1SSteen Hegelund { 407c9da1ac1SSteen Hegelund struct vcap_client_actionfield_data data; 408c9da1ac1SSteen Hegelund 409c9da1ac1SSteen Hegelund data.u32.value = value; 410c9da1ac1SSteen Hegelund return vcap_rule_add_action(rule, action, VCAP_FIELD_U32, &data); 411c9da1ac1SSteen Hegelund } 412c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_rule_add_action_u32); 413c9da1ac1SSteen Hegelund 414c9da1ac1SSteen Hegelund /* Copy to host byte order */ 415c9da1ac1SSteen Hegelund void vcap_netbytes_copy(u8 *dst, u8 *src, int count) 416c9da1ac1SSteen Hegelund { 417c9da1ac1SSteen Hegelund int idx; 418c9da1ac1SSteen Hegelund 419c9da1ac1SSteen Hegelund for (idx = 0; idx < count; ++idx, ++dst) 420c9da1ac1SSteen Hegelund *dst = src[count - idx - 1]; 421c9da1ac1SSteen Hegelund } 422c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_netbytes_copy); 423c9da1ac1SSteen Hegelund 424c9da1ac1SSteen Hegelund /* Convert validation error code into tc extact error message */ 425c9da1ac1SSteen Hegelund void vcap_set_tc_exterr(struct flow_cls_offload *fco, struct vcap_rule *vrule) 426c9da1ac1SSteen Hegelund { 427c9da1ac1SSteen Hegelund switch (vrule->exterr) { 428c9da1ac1SSteen Hegelund case VCAP_ERR_NONE: 429c9da1ac1SSteen Hegelund break; 430c9da1ac1SSteen Hegelund case VCAP_ERR_NO_ADMIN: 431c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 432c9da1ac1SSteen Hegelund "Missing VCAP instance"); 433c9da1ac1SSteen Hegelund break; 434c9da1ac1SSteen Hegelund case VCAP_ERR_NO_NETDEV: 435c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 436c9da1ac1SSteen Hegelund "Missing network interface"); 437c9da1ac1SSteen Hegelund break; 438c9da1ac1SSteen Hegelund case VCAP_ERR_NO_KEYSET_MATCH: 439c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 440c9da1ac1SSteen Hegelund "No keyset matched the filter keys"); 441c9da1ac1SSteen Hegelund break; 442c9da1ac1SSteen Hegelund case VCAP_ERR_NO_ACTIONSET_MATCH: 443c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 444c9da1ac1SSteen Hegelund "No actionset matched the filter actions"); 445c9da1ac1SSteen Hegelund break; 446c9da1ac1SSteen Hegelund case VCAP_ERR_NO_PORT_KEYSET_MATCH: 447c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 448c9da1ac1SSteen Hegelund "No port keyset matched the filter keys"); 449c9da1ac1SSteen Hegelund break; 450c9da1ac1SSteen Hegelund } 451c9da1ac1SSteen Hegelund } 452c9da1ac1SSteen Hegelund EXPORT_SYMBOL_GPL(vcap_set_tc_exterr); 453