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