xref: /linux-6.15/net/devlink/dpipe.c (revision a788acf1)
1a9fd44b1SJiri Pirko // SPDX-License-Identifier: GPL-2.0-or-later
2a9fd44b1SJiri Pirko /*
3a9fd44b1SJiri Pirko  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4a9fd44b1SJiri Pirko  * Copyright (c) 2016 Jiri Pirko <[email protected]>
5a9fd44b1SJiri Pirko  */
6a9fd44b1SJiri Pirko 
7a9fd44b1SJiri Pirko #include "devl_internal.h"
8a9fd44b1SJiri Pirko 
9a9fd44b1SJiri Pirko static struct devlink_dpipe_field devlink_dpipe_fields_ethernet[] = {
10a9fd44b1SJiri Pirko 	{
11a9fd44b1SJiri Pirko 		.name = "destination mac",
12a9fd44b1SJiri Pirko 		.id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
13a9fd44b1SJiri Pirko 		.bitwidth = 48,
14a9fd44b1SJiri Pirko 	},
15a9fd44b1SJiri Pirko };
16a9fd44b1SJiri Pirko 
17a9fd44b1SJiri Pirko struct devlink_dpipe_header devlink_dpipe_header_ethernet = {
18a9fd44b1SJiri Pirko 	.name = "ethernet",
19a9fd44b1SJiri Pirko 	.id = DEVLINK_DPIPE_HEADER_ETHERNET,
20a9fd44b1SJiri Pirko 	.fields = devlink_dpipe_fields_ethernet,
21a9fd44b1SJiri Pirko 	.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ethernet),
22a9fd44b1SJiri Pirko 	.global = true,
23a9fd44b1SJiri Pirko };
24a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devlink_dpipe_header_ethernet);
25a9fd44b1SJiri Pirko 
26a9fd44b1SJiri Pirko static struct devlink_dpipe_field devlink_dpipe_fields_ipv4[] = {
27a9fd44b1SJiri Pirko 	{
28a9fd44b1SJiri Pirko 		.name = "destination ip",
29a9fd44b1SJiri Pirko 		.id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
30a9fd44b1SJiri Pirko 		.bitwidth = 32,
31a9fd44b1SJiri Pirko 	},
32a9fd44b1SJiri Pirko };
33a9fd44b1SJiri Pirko 
34a9fd44b1SJiri Pirko struct devlink_dpipe_header devlink_dpipe_header_ipv4 = {
35a9fd44b1SJiri Pirko 	.name = "ipv4",
36a9fd44b1SJiri Pirko 	.id = DEVLINK_DPIPE_HEADER_IPV4,
37a9fd44b1SJiri Pirko 	.fields = devlink_dpipe_fields_ipv4,
38a9fd44b1SJiri Pirko 	.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv4),
39a9fd44b1SJiri Pirko 	.global = true,
40a9fd44b1SJiri Pirko };
41a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv4);
42a9fd44b1SJiri Pirko 
43a9fd44b1SJiri Pirko static struct devlink_dpipe_field devlink_dpipe_fields_ipv6[] = {
44a9fd44b1SJiri Pirko 	{
45a9fd44b1SJiri Pirko 		.name = "destination ip",
46a9fd44b1SJiri Pirko 		.id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
47a9fd44b1SJiri Pirko 		.bitwidth = 128,
48a9fd44b1SJiri Pirko 	},
49a9fd44b1SJiri Pirko };
50a9fd44b1SJiri Pirko 
51a9fd44b1SJiri Pirko struct devlink_dpipe_header devlink_dpipe_header_ipv6 = {
52a9fd44b1SJiri Pirko 	.name = "ipv6",
53a9fd44b1SJiri Pirko 	.id = DEVLINK_DPIPE_HEADER_IPV6,
54a9fd44b1SJiri Pirko 	.fields = devlink_dpipe_fields_ipv6,
55a9fd44b1SJiri Pirko 	.fields_count = ARRAY_SIZE(devlink_dpipe_fields_ipv6),
56a9fd44b1SJiri Pirko 	.global = true,
57a9fd44b1SJiri Pirko };
58a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devlink_dpipe_header_ipv6);
59a9fd44b1SJiri Pirko 
devlink_dpipe_match_put(struct sk_buff * skb,struct devlink_dpipe_match * match)60a9fd44b1SJiri Pirko int devlink_dpipe_match_put(struct sk_buff *skb,
61a9fd44b1SJiri Pirko 			    struct devlink_dpipe_match *match)
62a9fd44b1SJiri Pirko {
63a9fd44b1SJiri Pirko 	struct devlink_dpipe_header *header = match->header;
64a9fd44b1SJiri Pirko 	struct devlink_dpipe_field *field = &header->fields[match->field_id];
65a9fd44b1SJiri Pirko 	struct nlattr *match_attr;
66a9fd44b1SJiri Pirko 
67a9fd44b1SJiri Pirko 	match_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_MATCH);
68a9fd44b1SJiri Pirko 	if (!match_attr)
69a9fd44b1SJiri Pirko 		return -EMSGSIZE;
70a9fd44b1SJiri Pirko 
71a9fd44b1SJiri Pirko 	if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_MATCH_TYPE, match->type) ||
72a9fd44b1SJiri Pirko 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, match->header_index) ||
73a9fd44b1SJiri Pirko 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
74a9fd44b1SJiri Pirko 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
75a9fd44b1SJiri Pirko 	    nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
76a9fd44b1SJiri Pirko 		goto nla_put_failure;
77a9fd44b1SJiri Pirko 
78a9fd44b1SJiri Pirko 	nla_nest_end(skb, match_attr);
79a9fd44b1SJiri Pirko 	return 0;
80a9fd44b1SJiri Pirko 
81a9fd44b1SJiri Pirko nla_put_failure:
82a9fd44b1SJiri Pirko 	nla_nest_cancel(skb, match_attr);
83a9fd44b1SJiri Pirko 	return -EMSGSIZE;
84a9fd44b1SJiri Pirko }
85a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devlink_dpipe_match_put);
86a9fd44b1SJiri Pirko 
devlink_dpipe_matches_put(struct devlink_dpipe_table * table,struct sk_buff * skb)87a9fd44b1SJiri Pirko static int devlink_dpipe_matches_put(struct devlink_dpipe_table *table,
88a9fd44b1SJiri Pirko 				     struct sk_buff *skb)
89a9fd44b1SJiri Pirko {
90a9fd44b1SJiri Pirko 	struct nlattr *matches_attr;
91a9fd44b1SJiri Pirko 
92a9fd44b1SJiri Pirko 	matches_attr = nla_nest_start_noflag(skb,
93a9fd44b1SJiri Pirko 					     DEVLINK_ATTR_DPIPE_TABLE_MATCHES);
94a9fd44b1SJiri Pirko 	if (!matches_attr)
95a9fd44b1SJiri Pirko 		return -EMSGSIZE;
96a9fd44b1SJiri Pirko 
97a9fd44b1SJiri Pirko 	if (table->table_ops->matches_dump(table->priv, skb))
98a9fd44b1SJiri Pirko 		goto nla_put_failure;
99a9fd44b1SJiri Pirko 
100a9fd44b1SJiri Pirko 	nla_nest_end(skb, matches_attr);
101a9fd44b1SJiri Pirko 	return 0;
102a9fd44b1SJiri Pirko 
103a9fd44b1SJiri Pirko nla_put_failure:
104a9fd44b1SJiri Pirko 	nla_nest_cancel(skb, matches_attr);
105a9fd44b1SJiri Pirko 	return -EMSGSIZE;
106a9fd44b1SJiri Pirko }
107a9fd44b1SJiri Pirko 
devlink_dpipe_action_put(struct sk_buff * skb,struct devlink_dpipe_action * action)108a9fd44b1SJiri Pirko int devlink_dpipe_action_put(struct sk_buff *skb,
109a9fd44b1SJiri Pirko 			     struct devlink_dpipe_action *action)
110a9fd44b1SJiri Pirko {
111a9fd44b1SJiri Pirko 	struct devlink_dpipe_header *header = action->header;
112a9fd44b1SJiri Pirko 	struct devlink_dpipe_field *field = &header->fields[action->field_id];
113a9fd44b1SJiri Pirko 	struct nlattr *action_attr;
114a9fd44b1SJiri Pirko 
115a9fd44b1SJiri Pirko 	action_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ACTION);
116a9fd44b1SJiri Pirko 	if (!action_attr)
117a9fd44b1SJiri Pirko 		return -EMSGSIZE;
118a9fd44b1SJiri Pirko 
119a9fd44b1SJiri Pirko 	if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_ACTION_TYPE, action->type) ||
120a9fd44b1SJiri Pirko 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_INDEX, action->header_index) ||
121a9fd44b1SJiri Pirko 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
122a9fd44b1SJiri Pirko 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
123a9fd44b1SJiri Pirko 	    nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
124a9fd44b1SJiri Pirko 		goto nla_put_failure;
125a9fd44b1SJiri Pirko 
126a9fd44b1SJiri Pirko 	nla_nest_end(skb, action_attr);
127a9fd44b1SJiri Pirko 	return 0;
128a9fd44b1SJiri Pirko 
129a9fd44b1SJiri Pirko nla_put_failure:
130a9fd44b1SJiri Pirko 	nla_nest_cancel(skb, action_attr);
131a9fd44b1SJiri Pirko 	return -EMSGSIZE;
132a9fd44b1SJiri Pirko }
133a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devlink_dpipe_action_put);
134a9fd44b1SJiri Pirko 
devlink_dpipe_actions_put(struct devlink_dpipe_table * table,struct sk_buff * skb)135a9fd44b1SJiri Pirko static int devlink_dpipe_actions_put(struct devlink_dpipe_table *table,
136a9fd44b1SJiri Pirko 				     struct sk_buff *skb)
137a9fd44b1SJiri Pirko {
138a9fd44b1SJiri Pirko 	struct nlattr *actions_attr;
139a9fd44b1SJiri Pirko 
140a9fd44b1SJiri Pirko 	actions_attr = nla_nest_start_noflag(skb,
141a9fd44b1SJiri Pirko 					     DEVLINK_ATTR_DPIPE_TABLE_ACTIONS);
142a9fd44b1SJiri Pirko 	if (!actions_attr)
143a9fd44b1SJiri Pirko 		return -EMSGSIZE;
144a9fd44b1SJiri Pirko 
145a9fd44b1SJiri Pirko 	if (table->table_ops->actions_dump(table->priv, skb))
146a9fd44b1SJiri Pirko 		goto nla_put_failure;
147a9fd44b1SJiri Pirko 
148a9fd44b1SJiri Pirko 	nla_nest_end(skb, actions_attr);
149a9fd44b1SJiri Pirko 	return 0;
150a9fd44b1SJiri Pirko 
151a9fd44b1SJiri Pirko nla_put_failure:
152a9fd44b1SJiri Pirko 	nla_nest_cancel(skb, actions_attr);
153a9fd44b1SJiri Pirko 	return -EMSGSIZE;
154a9fd44b1SJiri Pirko }
155a9fd44b1SJiri Pirko 
devlink_dpipe_table_put(struct sk_buff * skb,struct devlink_dpipe_table * table)156a9fd44b1SJiri Pirko static int devlink_dpipe_table_put(struct sk_buff *skb,
157a9fd44b1SJiri Pirko 				   struct devlink_dpipe_table *table)
158a9fd44b1SJiri Pirko {
159a9fd44b1SJiri Pirko 	struct nlattr *table_attr;
160a9fd44b1SJiri Pirko 	u64 table_size;
161a9fd44b1SJiri Pirko 
162a9fd44b1SJiri Pirko 	table_size = table->table_ops->size_get(table->priv);
163a9fd44b1SJiri Pirko 	table_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLE);
164a9fd44b1SJiri Pirko 	if (!table_attr)
165a9fd44b1SJiri Pirko 		return -EMSGSIZE;
166a9fd44b1SJiri Pirko 
167a9fd44b1SJiri Pirko 	if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_TABLE_NAME, table->name) ||
168*a788acf1SPrzemek Kitszel 	    devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_SIZE, table_size))
169a9fd44b1SJiri Pirko 		goto nla_put_failure;
170a9fd44b1SJiri Pirko 	if (nla_put_u8(skb, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
171a9fd44b1SJiri Pirko 		       table->counters_enabled))
172a9fd44b1SJiri Pirko 		goto nla_put_failure;
173a9fd44b1SJiri Pirko 
174a9fd44b1SJiri Pirko 	if (table->resource_valid) {
175*a788acf1SPrzemek Kitszel 		if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID,
176*a788acf1SPrzemek Kitszel 				       table->resource_id) ||
177*a788acf1SPrzemek Kitszel 		    devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS,
178*a788acf1SPrzemek Kitszel 				       table->resource_units))
179a9fd44b1SJiri Pirko 			goto nla_put_failure;
180a9fd44b1SJiri Pirko 	}
181a9fd44b1SJiri Pirko 	if (devlink_dpipe_matches_put(table, skb))
182a9fd44b1SJiri Pirko 		goto nla_put_failure;
183a9fd44b1SJiri Pirko 
184a9fd44b1SJiri Pirko 	if (devlink_dpipe_actions_put(table, skb))
185a9fd44b1SJiri Pirko 		goto nla_put_failure;
186a9fd44b1SJiri Pirko 
187a9fd44b1SJiri Pirko 	nla_nest_end(skb, table_attr);
188a9fd44b1SJiri Pirko 	return 0;
189a9fd44b1SJiri Pirko 
190a9fd44b1SJiri Pirko nla_put_failure:
191a9fd44b1SJiri Pirko 	nla_nest_cancel(skb, table_attr);
192a9fd44b1SJiri Pirko 	return -EMSGSIZE;
193a9fd44b1SJiri Pirko }
194a9fd44b1SJiri Pirko 
devlink_dpipe_send_and_alloc_skb(struct sk_buff ** pskb,struct genl_info * info)195a9fd44b1SJiri Pirko static int devlink_dpipe_send_and_alloc_skb(struct sk_buff **pskb,
196a9fd44b1SJiri Pirko 					    struct genl_info *info)
197a9fd44b1SJiri Pirko {
198a9fd44b1SJiri Pirko 	int err;
199a9fd44b1SJiri Pirko 
200a9fd44b1SJiri Pirko 	if (*pskb) {
201a9fd44b1SJiri Pirko 		err = genlmsg_reply(*pskb, info);
202a9fd44b1SJiri Pirko 		if (err)
203a9fd44b1SJiri Pirko 			return err;
204a9fd44b1SJiri Pirko 	}
205a9fd44b1SJiri Pirko 	*pskb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
206a9fd44b1SJiri Pirko 	if (!*pskb)
207a9fd44b1SJiri Pirko 		return -ENOMEM;
208a9fd44b1SJiri Pirko 	return 0;
209a9fd44b1SJiri Pirko }
210a9fd44b1SJiri Pirko 
devlink_dpipe_tables_fill(struct genl_info * info,enum devlink_command cmd,int flags,struct list_head * dpipe_tables,const char * table_name)211a9fd44b1SJiri Pirko static int devlink_dpipe_tables_fill(struct genl_info *info,
212a9fd44b1SJiri Pirko 				     enum devlink_command cmd, int flags,
213a9fd44b1SJiri Pirko 				     struct list_head *dpipe_tables,
214a9fd44b1SJiri Pirko 				     const char *table_name)
215a9fd44b1SJiri Pirko {
216a9fd44b1SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
217a9fd44b1SJiri Pirko 	struct devlink_dpipe_table *table;
218a9fd44b1SJiri Pirko 	struct nlattr *tables_attr;
219a9fd44b1SJiri Pirko 	struct sk_buff *skb = NULL;
220a9fd44b1SJiri Pirko 	struct nlmsghdr *nlh;
221a9fd44b1SJiri Pirko 	bool incomplete;
222a9fd44b1SJiri Pirko 	void *hdr;
223a9fd44b1SJiri Pirko 	int i;
224a9fd44b1SJiri Pirko 	int err;
225a9fd44b1SJiri Pirko 
226a9fd44b1SJiri Pirko 	table = list_first_entry(dpipe_tables,
227a9fd44b1SJiri Pirko 				 struct devlink_dpipe_table, list);
228a9fd44b1SJiri Pirko start_again:
229a9fd44b1SJiri Pirko 	err = devlink_dpipe_send_and_alloc_skb(&skb, info);
230a9fd44b1SJiri Pirko 	if (err)
231a9fd44b1SJiri Pirko 		return err;
232a9fd44b1SJiri Pirko 
233a9fd44b1SJiri Pirko 	hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
234a9fd44b1SJiri Pirko 			  &devlink_nl_family, NLM_F_MULTI, cmd);
235a9fd44b1SJiri Pirko 	if (!hdr) {
236a9fd44b1SJiri Pirko 		nlmsg_free(skb);
237a9fd44b1SJiri Pirko 		return -EMSGSIZE;
238a9fd44b1SJiri Pirko 	}
239a9fd44b1SJiri Pirko 
240a9fd44b1SJiri Pirko 	if (devlink_nl_put_handle(skb, devlink))
241a9fd44b1SJiri Pirko 		goto nla_put_failure;
242a9fd44b1SJiri Pirko 	tables_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_TABLES);
243a9fd44b1SJiri Pirko 	if (!tables_attr)
244a9fd44b1SJiri Pirko 		goto nla_put_failure;
245a9fd44b1SJiri Pirko 
246a9fd44b1SJiri Pirko 	i = 0;
247a9fd44b1SJiri Pirko 	incomplete = false;
248a9fd44b1SJiri Pirko 	list_for_each_entry_from(table, dpipe_tables, list) {
249a9fd44b1SJiri Pirko 		if (!table_name) {
250a9fd44b1SJiri Pirko 			err = devlink_dpipe_table_put(skb, table);
251a9fd44b1SJiri Pirko 			if (err) {
252a9fd44b1SJiri Pirko 				if (!i)
253a9fd44b1SJiri Pirko 					goto err_table_put;
254a9fd44b1SJiri Pirko 				incomplete = true;
255a9fd44b1SJiri Pirko 				break;
256a9fd44b1SJiri Pirko 			}
257a9fd44b1SJiri Pirko 		} else {
258a9fd44b1SJiri Pirko 			if (!strcmp(table->name, table_name)) {
259a9fd44b1SJiri Pirko 				err = devlink_dpipe_table_put(skb, table);
260a9fd44b1SJiri Pirko 				if (err)
261a9fd44b1SJiri Pirko 					break;
262a9fd44b1SJiri Pirko 			}
263a9fd44b1SJiri Pirko 		}
264a9fd44b1SJiri Pirko 		i++;
265a9fd44b1SJiri Pirko 	}
266a9fd44b1SJiri Pirko 
267a9fd44b1SJiri Pirko 	nla_nest_end(skb, tables_attr);
268a9fd44b1SJiri Pirko 	genlmsg_end(skb, hdr);
269a9fd44b1SJiri Pirko 	if (incomplete)
270a9fd44b1SJiri Pirko 		goto start_again;
271a9fd44b1SJiri Pirko 
272a9fd44b1SJiri Pirko send_done:
273a9fd44b1SJiri Pirko 	nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
274a9fd44b1SJiri Pirko 			NLMSG_DONE, 0, flags | NLM_F_MULTI);
275a9fd44b1SJiri Pirko 	if (!nlh) {
276a9fd44b1SJiri Pirko 		err = devlink_dpipe_send_and_alloc_skb(&skb, info);
277a9fd44b1SJiri Pirko 		if (err)
278a9fd44b1SJiri Pirko 			return err;
279a9fd44b1SJiri Pirko 		goto send_done;
280a9fd44b1SJiri Pirko 	}
281a9fd44b1SJiri Pirko 
282a9fd44b1SJiri Pirko 	return genlmsg_reply(skb, info);
283a9fd44b1SJiri Pirko 
284a9fd44b1SJiri Pirko nla_put_failure:
285a9fd44b1SJiri Pirko 	err = -EMSGSIZE;
286a9fd44b1SJiri Pirko err_table_put:
287a9fd44b1SJiri Pirko 	nlmsg_free(skb);
288a9fd44b1SJiri Pirko 	return err;
289a9fd44b1SJiri Pirko }
290a9fd44b1SJiri Pirko 
devlink_nl_dpipe_table_get_doit(struct sk_buff * skb,struct genl_info * info)29153590934SJiri Pirko int devlink_nl_dpipe_table_get_doit(struct sk_buff *skb, struct genl_info *info)
292a9fd44b1SJiri Pirko {
293a9fd44b1SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
294a9fd44b1SJiri Pirko 	const char *table_name =  NULL;
295a9fd44b1SJiri Pirko 
296a9fd44b1SJiri Pirko 	if (info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME])
297a9fd44b1SJiri Pirko 		table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
298a9fd44b1SJiri Pirko 
299a9fd44b1SJiri Pirko 	return devlink_dpipe_tables_fill(info, DEVLINK_CMD_DPIPE_TABLE_GET, 0,
300a9fd44b1SJiri Pirko 					 &devlink->dpipe_table_list,
301a9fd44b1SJiri Pirko 					 table_name);
302a9fd44b1SJiri Pirko }
303a9fd44b1SJiri Pirko 
devlink_dpipe_value_put(struct sk_buff * skb,struct devlink_dpipe_value * value)304a9fd44b1SJiri Pirko static int devlink_dpipe_value_put(struct sk_buff *skb,
305a9fd44b1SJiri Pirko 				   struct devlink_dpipe_value *value)
306a9fd44b1SJiri Pirko {
307a9fd44b1SJiri Pirko 	if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE,
308a9fd44b1SJiri Pirko 		    value->value_size, value->value))
309a9fd44b1SJiri Pirko 		return -EMSGSIZE;
310a9fd44b1SJiri Pirko 	if (value->mask)
311a9fd44b1SJiri Pirko 		if (nla_put(skb, DEVLINK_ATTR_DPIPE_VALUE_MASK,
312a9fd44b1SJiri Pirko 			    value->value_size, value->mask))
313a9fd44b1SJiri Pirko 			return -EMSGSIZE;
314a9fd44b1SJiri Pirko 	if (value->mapping_valid)
315a9fd44b1SJiri Pirko 		if (nla_put_u32(skb, DEVLINK_ATTR_DPIPE_VALUE_MAPPING,
316a9fd44b1SJiri Pirko 				value->mapping_value))
317a9fd44b1SJiri Pirko 			return -EMSGSIZE;
318a9fd44b1SJiri Pirko 	return 0;
319a9fd44b1SJiri Pirko }
320a9fd44b1SJiri Pirko 
devlink_dpipe_action_value_put(struct sk_buff * skb,struct devlink_dpipe_value * value)321a9fd44b1SJiri Pirko static int devlink_dpipe_action_value_put(struct sk_buff *skb,
322a9fd44b1SJiri Pirko 					  struct devlink_dpipe_value *value)
323a9fd44b1SJiri Pirko {
324a9fd44b1SJiri Pirko 	if (!value->action)
325a9fd44b1SJiri Pirko 		return -EINVAL;
326a9fd44b1SJiri Pirko 	if (devlink_dpipe_action_put(skb, value->action))
327a9fd44b1SJiri Pirko 		return -EMSGSIZE;
328a9fd44b1SJiri Pirko 	if (devlink_dpipe_value_put(skb, value))
329a9fd44b1SJiri Pirko 		return -EMSGSIZE;
330a9fd44b1SJiri Pirko 	return 0;
331a9fd44b1SJiri Pirko }
332a9fd44b1SJiri Pirko 
devlink_dpipe_action_values_put(struct sk_buff * skb,struct devlink_dpipe_value * values,unsigned int values_count)333a9fd44b1SJiri Pirko static int devlink_dpipe_action_values_put(struct sk_buff *skb,
334a9fd44b1SJiri Pirko 					   struct devlink_dpipe_value *values,
335a9fd44b1SJiri Pirko 					   unsigned int values_count)
336a9fd44b1SJiri Pirko {
337a9fd44b1SJiri Pirko 	struct nlattr *action_attr;
338a9fd44b1SJiri Pirko 	int i;
339a9fd44b1SJiri Pirko 	int err;
340a9fd44b1SJiri Pirko 
341a9fd44b1SJiri Pirko 	for (i = 0; i < values_count; i++) {
342a9fd44b1SJiri Pirko 		action_attr = nla_nest_start_noflag(skb,
343a9fd44b1SJiri Pirko 						    DEVLINK_ATTR_DPIPE_ACTION_VALUE);
344a9fd44b1SJiri Pirko 		if (!action_attr)
345a9fd44b1SJiri Pirko 			return -EMSGSIZE;
346a9fd44b1SJiri Pirko 		err = devlink_dpipe_action_value_put(skb, &values[i]);
347a9fd44b1SJiri Pirko 		if (err)
348a9fd44b1SJiri Pirko 			goto err_action_value_put;
349a9fd44b1SJiri Pirko 		nla_nest_end(skb, action_attr);
350a9fd44b1SJiri Pirko 	}
351a9fd44b1SJiri Pirko 	return 0;
352a9fd44b1SJiri Pirko 
353a9fd44b1SJiri Pirko err_action_value_put:
354a9fd44b1SJiri Pirko 	nla_nest_cancel(skb, action_attr);
355a9fd44b1SJiri Pirko 	return err;
356a9fd44b1SJiri Pirko }
357a9fd44b1SJiri Pirko 
devlink_dpipe_match_value_put(struct sk_buff * skb,struct devlink_dpipe_value * value)358a9fd44b1SJiri Pirko static int devlink_dpipe_match_value_put(struct sk_buff *skb,
359a9fd44b1SJiri Pirko 					 struct devlink_dpipe_value *value)
360a9fd44b1SJiri Pirko {
361a9fd44b1SJiri Pirko 	if (!value->match)
362a9fd44b1SJiri Pirko 		return -EINVAL;
363a9fd44b1SJiri Pirko 	if (devlink_dpipe_match_put(skb, value->match))
364a9fd44b1SJiri Pirko 		return -EMSGSIZE;
365a9fd44b1SJiri Pirko 	if (devlink_dpipe_value_put(skb, value))
366a9fd44b1SJiri Pirko 		return -EMSGSIZE;
367a9fd44b1SJiri Pirko 	return 0;
368a9fd44b1SJiri Pirko }
369a9fd44b1SJiri Pirko 
devlink_dpipe_match_values_put(struct sk_buff * skb,struct devlink_dpipe_value * values,unsigned int values_count)370a9fd44b1SJiri Pirko static int devlink_dpipe_match_values_put(struct sk_buff *skb,
371a9fd44b1SJiri Pirko 					  struct devlink_dpipe_value *values,
372a9fd44b1SJiri Pirko 					  unsigned int values_count)
373a9fd44b1SJiri Pirko {
374a9fd44b1SJiri Pirko 	struct nlattr *match_attr;
375a9fd44b1SJiri Pirko 	int i;
376a9fd44b1SJiri Pirko 	int err;
377a9fd44b1SJiri Pirko 
378a9fd44b1SJiri Pirko 	for (i = 0; i < values_count; i++) {
379a9fd44b1SJiri Pirko 		match_attr = nla_nest_start_noflag(skb,
380a9fd44b1SJiri Pirko 						   DEVLINK_ATTR_DPIPE_MATCH_VALUE);
381a9fd44b1SJiri Pirko 		if (!match_attr)
382a9fd44b1SJiri Pirko 			return -EMSGSIZE;
383a9fd44b1SJiri Pirko 		err = devlink_dpipe_match_value_put(skb, &values[i]);
384a9fd44b1SJiri Pirko 		if (err)
385a9fd44b1SJiri Pirko 			goto err_match_value_put;
386a9fd44b1SJiri Pirko 		nla_nest_end(skb, match_attr);
387a9fd44b1SJiri Pirko 	}
388a9fd44b1SJiri Pirko 	return 0;
389a9fd44b1SJiri Pirko 
390a9fd44b1SJiri Pirko err_match_value_put:
391a9fd44b1SJiri Pirko 	nla_nest_cancel(skb, match_attr);
392a9fd44b1SJiri Pirko 	return err;
393a9fd44b1SJiri Pirko }
394a9fd44b1SJiri Pirko 
devlink_dpipe_entry_put(struct sk_buff * skb,struct devlink_dpipe_entry * entry)395a9fd44b1SJiri Pirko static int devlink_dpipe_entry_put(struct sk_buff *skb,
396a9fd44b1SJiri Pirko 				   struct devlink_dpipe_entry *entry)
397a9fd44b1SJiri Pirko {
398a9fd44b1SJiri Pirko 	struct nlattr *entry_attr, *matches_attr, *actions_attr;
399a9fd44b1SJiri Pirko 	int err;
400a9fd44b1SJiri Pirko 
401a9fd44b1SJiri Pirko 	entry_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_ENTRY);
402a9fd44b1SJiri Pirko 	if (!entry_attr)
403a9fd44b1SJiri Pirko 		return  -EMSGSIZE;
404a9fd44b1SJiri Pirko 
405*a788acf1SPrzemek Kitszel 	if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_ENTRY_INDEX, entry->index))
406a9fd44b1SJiri Pirko 		goto nla_put_failure;
407a9fd44b1SJiri Pirko 	if (entry->counter_valid)
408*a788acf1SPrzemek Kitszel 		if (devlink_nl_put_u64(skb, DEVLINK_ATTR_DPIPE_ENTRY_COUNTER,
409*a788acf1SPrzemek Kitszel 				       entry->counter))
410a9fd44b1SJiri Pirko 			goto nla_put_failure;
411a9fd44b1SJiri Pirko 
412a9fd44b1SJiri Pirko 	matches_attr = nla_nest_start_noflag(skb,
413a9fd44b1SJiri Pirko 					     DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES);
414a9fd44b1SJiri Pirko 	if (!matches_attr)
415a9fd44b1SJiri Pirko 		goto nla_put_failure;
416a9fd44b1SJiri Pirko 
417a9fd44b1SJiri Pirko 	err = devlink_dpipe_match_values_put(skb, entry->match_values,
418a9fd44b1SJiri Pirko 					     entry->match_values_count);
419a9fd44b1SJiri Pirko 	if (err) {
420a9fd44b1SJiri Pirko 		nla_nest_cancel(skb, matches_attr);
421a9fd44b1SJiri Pirko 		goto err_match_values_put;
422a9fd44b1SJiri Pirko 	}
423a9fd44b1SJiri Pirko 	nla_nest_end(skb, matches_attr);
424a9fd44b1SJiri Pirko 
425a9fd44b1SJiri Pirko 	actions_attr = nla_nest_start_noflag(skb,
426a9fd44b1SJiri Pirko 					     DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES);
427a9fd44b1SJiri Pirko 	if (!actions_attr)
428a9fd44b1SJiri Pirko 		goto nla_put_failure;
429a9fd44b1SJiri Pirko 
430a9fd44b1SJiri Pirko 	err = devlink_dpipe_action_values_put(skb, entry->action_values,
431a9fd44b1SJiri Pirko 					      entry->action_values_count);
432a9fd44b1SJiri Pirko 	if (err) {
433a9fd44b1SJiri Pirko 		nla_nest_cancel(skb, actions_attr);
434a9fd44b1SJiri Pirko 		goto err_action_values_put;
435a9fd44b1SJiri Pirko 	}
436a9fd44b1SJiri Pirko 	nla_nest_end(skb, actions_attr);
437a9fd44b1SJiri Pirko 
438a9fd44b1SJiri Pirko 	nla_nest_end(skb, entry_attr);
439a9fd44b1SJiri Pirko 	return 0;
440a9fd44b1SJiri Pirko 
441a9fd44b1SJiri Pirko nla_put_failure:
442a9fd44b1SJiri Pirko 	err = -EMSGSIZE;
443a9fd44b1SJiri Pirko err_match_values_put:
444a9fd44b1SJiri Pirko err_action_values_put:
445a9fd44b1SJiri Pirko 	nla_nest_cancel(skb, entry_attr);
446a9fd44b1SJiri Pirko 	return err;
447a9fd44b1SJiri Pirko }
448a9fd44b1SJiri Pirko 
449a9fd44b1SJiri Pirko static struct devlink_dpipe_table *
devlink_dpipe_table_find(struct list_head * dpipe_tables,const char * table_name,struct devlink * devlink)450a9fd44b1SJiri Pirko devlink_dpipe_table_find(struct list_head *dpipe_tables,
451a9fd44b1SJiri Pirko 			 const char *table_name, struct devlink *devlink)
452a9fd44b1SJiri Pirko {
453a9fd44b1SJiri Pirko 	struct devlink_dpipe_table *table;
454a9fd44b1SJiri Pirko 
455a9fd44b1SJiri Pirko 	list_for_each_entry_rcu(table, dpipe_tables, list,
456a9fd44b1SJiri Pirko 				lockdep_is_held(&devlink->lock)) {
457a9fd44b1SJiri Pirko 		if (!strcmp(table->name, table_name))
458a9fd44b1SJiri Pirko 			return table;
459a9fd44b1SJiri Pirko 	}
460a9fd44b1SJiri Pirko 	return NULL;
461a9fd44b1SJiri Pirko }
462a9fd44b1SJiri Pirko 
devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx * dump_ctx)463a9fd44b1SJiri Pirko int devlink_dpipe_entry_ctx_prepare(struct devlink_dpipe_dump_ctx *dump_ctx)
464a9fd44b1SJiri Pirko {
465a9fd44b1SJiri Pirko 	struct devlink *devlink;
466a9fd44b1SJiri Pirko 	int err;
467a9fd44b1SJiri Pirko 
468a9fd44b1SJiri Pirko 	err = devlink_dpipe_send_and_alloc_skb(&dump_ctx->skb,
469a9fd44b1SJiri Pirko 					       dump_ctx->info);
470a9fd44b1SJiri Pirko 	if (err)
471a9fd44b1SJiri Pirko 		return err;
472a9fd44b1SJiri Pirko 
473a9fd44b1SJiri Pirko 	dump_ctx->hdr = genlmsg_put(dump_ctx->skb,
474a9fd44b1SJiri Pirko 				    dump_ctx->info->snd_portid,
475a9fd44b1SJiri Pirko 				    dump_ctx->info->snd_seq,
476a9fd44b1SJiri Pirko 				    &devlink_nl_family, NLM_F_MULTI,
477a9fd44b1SJiri Pirko 				    dump_ctx->cmd);
478a9fd44b1SJiri Pirko 	if (!dump_ctx->hdr)
479a9fd44b1SJiri Pirko 		goto nla_put_failure;
480a9fd44b1SJiri Pirko 
481a9fd44b1SJiri Pirko 	devlink = dump_ctx->info->user_ptr[0];
482a9fd44b1SJiri Pirko 	if (devlink_nl_put_handle(dump_ctx->skb, devlink))
483a9fd44b1SJiri Pirko 		goto nla_put_failure;
484a9fd44b1SJiri Pirko 	dump_ctx->nest = nla_nest_start_noflag(dump_ctx->skb,
485a9fd44b1SJiri Pirko 					       DEVLINK_ATTR_DPIPE_ENTRIES);
486a9fd44b1SJiri Pirko 	if (!dump_ctx->nest)
487a9fd44b1SJiri Pirko 		goto nla_put_failure;
488a9fd44b1SJiri Pirko 	return 0;
489a9fd44b1SJiri Pirko 
490a9fd44b1SJiri Pirko nla_put_failure:
491a9fd44b1SJiri Pirko 	nlmsg_free(dump_ctx->skb);
492a9fd44b1SJiri Pirko 	return -EMSGSIZE;
493a9fd44b1SJiri Pirko }
494a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_prepare);
495a9fd44b1SJiri Pirko 
devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx * dump_ctx,struct devlink_dpipe_entry * entry)496a9fd44b1SJiri Pirko int devlink_dpipe_entry_ctx_append(struct devlink_dpipe_dump_ctx *dump_ctx,
497a9fd44b1SJiri Pirko 				   struct devlink_dpipe_entry *entry)
498a9fd44b1SJiri Pirko {
499a9fd44b1SJiri Pirko 	return devlink_dpipe_entry_put(dump_ctx->skb, entry);
500a9fd44b1SJiri Pirko }
501a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_append);
502a9fd44b1SJiri Pirko 
devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx * dump_ctx)503a9fd44b1SJiri Pirko int devlink_dpipe_entry_ctx_close(struct devlink_dpipe_dump_ctx *dump_ctx)
504a9fd44b1SJiri Pirko {
505a9fd44b1SJiri Pirko 	nla_nest_end(dump_ctx->skb, dump_ctx->nest);
506a9fd44b1SJiri Pirko 	genlmsg_end(dump_ctx->skb, dump_ctx->hdr);
507a9fd44b1SJiri Pirko 	return 0;
508a9fd44b1SJiri Pirko }
509a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devlink_dpipe_entry_ctx_close);
510a9fd44b1SJiri Pirko 
devlink_dpipe_entry_clear(struct devlink_dpipe_entry * entry)511a9fd44b1SJiri Pirko void devlink_dpipe_entry_clear(struct devlink_dpipe_entry *entry)
512a9fd44b1SJiri Pirko 
513a9fd44b1SJiri Pirko {
514a9fd44b1SJiri Pirko 	unsigned int value_count, value_index;
515a9fd44b1SJiri Pirko 	struct devlink_dpipe_value *value;
516a9fd44b1SJiri Pirko 
517a9fd44b1SJiri Pirko 	value = entry->action_values;
518a9fd44b1SJiri Pirko 	value_count = entry->action_values_count;
519a9fd44b1SJiri Pirko 	for (value_index = 0; value_index < value_count; value_index++) {
520a9fd44b1SJiri Pirko 		kfree(value[value_index].value);
521a9fd44b1SJiri Pirko 		kfree(value[value_index].mask);
522a9fd44b1SJiri Pirko 	}
523a9fd44b1SJiri Pirko 
524a9fd44b1SJiri Pirko 	value = entry->match_values;
525a9fd44b1SJiri Pirko 	value_count = entry->match_values_count;
526a9fd44b1SJiri Pirko 	for (value_index = 0; value_index < value_count; value_index++) {
527a9fd44b1SJiri Pirko 		kfree(value[value_index].value);
528a9fd44b1SJiri Pirko 		kfree(value[value_index].mask);
529a9fd44b1SJiri Pirko 	}
530a9fd44b1SJiri Pirko }
531a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devlink_dpipe_entry_clear);
532a9fd44b1SJiri Pirko 
devlink_dpipe_entries_fill(struct genl_info * info,enum devlink_command cmd,int flags,struct devlink_dpipe_table * table)533a9fd44b1SJiri Pirko static int devlink_dpipe_entries_fill(struct genl_info *info,
534a9fd44b1SJiri Pirko 				      enum devlink_command cmd, int flags,
535a9fd44b1SJiri Pirko 				      struct devlink_dpipe_table *table)
536a9fd44b1SJiri Pirko {
537a9fd44b1SJiri Pirko 	struct devlink_dpipe_dump_ctx dump_ctx;
538a9fd44b1SJiri Pirko 	struct nlmsghdr *nlh;
539a9fd44b1SJiri Pirko 	int err;
540a9fd44b1SJiri Pirko 
541a9fd44b1SJiri Pirko 	dump_ctx.skb = NULL;
542a9fd44b1SJiri Pirko 	dump_ctx.cmd = cmd;
543a9fd44b1SJiri Pirko 	dump_ctx.info = info;
544a9fd44b1SJiri Pirko 
545a9fd44b1SJiri Pirko 	err = table->table_ops->entries_dump(table->priv,
546a9fd44b1SJiri Pirko 					     table->counters_enabled,
547a9fd44b1SJiri Pirko 					     &dump_ctx);
548a9fd44b1SJiri Pirko 	if (err)
549a9fd44b1SJiri Pirko 		return err;
550a9fd44b1SJiri Pirko 
551a9fd44b1SJiri Pirko send_done:
552a9fd44b1SJiri Pirko 	nlh = nlmsg_put(dump_ctx.skb, info->snd_portid, info->snd_seq,
553a9fd44b1SJiri Pirko 			NLMSG_DONE, 0, flags | NLM_F_MULTI);
554a9fd44b1SJiri Pirko 	if (!nlh) {
555a9fd44b1SJiri Pirko 		err = devlink_dpipe_send_and_alloc_skb(&dump_ctx.skb, info);
556a9fd44b1SJiri Pirko 		if (err)
557a9fd44b1SJiri Pirko 			return err;
558a9fd44b1SJiri Pirko 		goto send_done;
559a9fd44b1SJiri Pirko 	}
560a9fd44b1SJiri Pirko 	return genlmsg_reply(dump_ctx.skb, info);
561a9fd44b1SJiri Pirko }
562a9fd44b1SJiri Pirko 
devlink_nl_dpipe_entries_get_doit(struct sk_buff * skb,struct genl_info * info)56353590934SJiri Pirko int devlink_nl_dpipe_entries_get_doit(struct sk_buff *skb,
564a9fd44b1SJiri Pirko 				      struct genl_info *info)
565a9fd44b1SJiri Pirko {
566a9fd44b1SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
567a9fd44b1SJiri Pirko 	struct devlink_dpipe_table *table;
568a9fd44b1SJiri Pirko 	const char *table_name;
569a9fd44b1SJiri Pirko 
570a9fd44b1SJiri Pirko 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_DPIPE_TABLE_NAME))
571a9fd44b1SJiri Pirko 		return -EINVAL;
572a9fd44b1SJiri Pirko 
573a9fd44b1SJiri Pirko 	table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
574a9fd44b1SJiri Pirko 	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
575a9fd44b1SJiri Pirko 					 table_name, devlink);
576a9fd44b1SJiri Pirko 	if (!table)
577a9fd44b1SJiri Pirko 		return -EINVAL;
578a9fd44b1SJiri Pirko 
579a9fd44b1SJiri Pirko 	if (!table->table_ops->entries_dump)
580a9fd44b1SJiri Pirko 		return -EINVAL;
581a9fd44b1SJiri Pirko 
582a9fd44b1SJiri Pirko 	return devlink_dpipe_entries_fill(info, DEVLINK_CMD_DPIPE_ENTRIES_GET,
583a9fd44b1SJiri Pirko 					  0, table);
584a9fd44b1SJiri Pirko }
585a9fd44b1SJiri Pirko 
devlink_dpipe_fields_put(struct sk_buff * skb,const struct devlink_dpipe_header * header)586a9fd44b1SJiri Pirko static int devlink_dpipe_fields_put(struct sk_buff *skb,
587a9fd44b1SJiri Pirko 				    const struct devlink_dpipe_header *header)
588a9fd44b1SJiri Pirko {
589a9fd44b1SJiri Pirko 	struct devlink_dpipe_field *field;
590a9fd44b1SJiri Pirko 	struct nlattr *field_attr;
591a9fd44b1SJiri Pirko 	int i;
592a9fd44b1SJiri Pirko 
593a9fd44b1SJiri Pirko 	for (i = 0; i < header->fields_count; i++) {
594a9fd44b1SJiri Pirko 		field = &header->fields[i];
595a9fd44b1SJiri Pirko 		field_attr = nla_nest_start_noflag(skb,
596a9fd44b1SJiri Pirko 						   DEVLINK_ATTR_DPIPE_FIELD);
597a9fd44b1SJiri Pirko 		if (!field_attr)
598a9fd44b1SJiri Pirko 			return -EMSGSIZE;
599a9fd44b1SJiri Pirko 		if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_FIELD_NAME, field->name) ||
600a9fd44b1SJiri Pirko 		    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_ID, field->id) ||
601a9fd44b1SJiri Pirko 		    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH, field->bitwidth) ||
602a9fd44b1SJiri Pirko 		    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE, field->mapping_type))
603a9fd44b1SJiri Pirko 			goto nla_put_failure;
604a9fd44b1SJiri Pirko 		nla_nest_end(skb, field_attr);
605a9fd44b1SJiri Pirko 	}
606a9fd44b1SJiri Pirko 	return 0;
607a9fd44b1SJiri Pirko 
608a9fd44b1SJiri Pirko nla_put_failure:
609a9fd44b1SJiri Pirko 	nla_nest_cancel(skb, field_attr);
610a9fd44b1SJiri Pirko 	return -EMSGSIZE;
611a9fd44b1SJiri Pirko }
612a9fd44b1SJiri Pirko 
devlink_dpipe_header_put(struct sk_buff * skb,struct devlink_dpipe_header * header)613a9fd44b1SJiri Pirko static int devlink_dpipe_header_put(struct sk_buff *skb,
614a9fd44b1SJiri Pirko 				    struct devlink_dpipe_header *header)
615a9fd44b1SJiri Pirko {
616a9fd44b1SJiri Pirko 	struct nlattr *fields_attr, *header_attr;
617a9fd44b1SJiri Pirko 	int err;
618a9fd44b1SJiri Pirko 
619a9fd44b1SJiri Pirko 	header_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADER);
620a9fd44b1SJiri Pirko 	if (!header_attr)
621a9fd44b1SJiri Pirko 		return -EMSGSIZE;
622a9fd44b1SJiri Pirko 
623a9fd44b1SJiri Pirko 	if (nla_put_string(skb, DEVLINK_ATTR_DPIPE_HEADER_NAME, header->name) ||
624a9fd44b1SJiri Pirko 	    nla_put_u32(skb, DEVLINK_ATTR_DPIPE_HEADER_ID, header->id) ||
625a9fd44b1SJiri Pirko 	    nla_put_u8(skb, DEVLINK_ATTR_DPIPE_HEADER_GLOBAL, header->global))
626a9fd44b1SJiri Pirko 		goto nla_put_failure;
627a9fd44b1SJiri Pirko 
628a9fd44b1SJiri Pirko 	fields_attr = nla_nest_start_noflag(skb,
629a9fd44b1SJiri Pirko 					    DEVLINK_ATTR_DPIPE_HEADER_FIELDS);
630a9fd44b1SJiri Pirko 	if (!fields_attr)
631a9fd44b1SJiri Pirko 		goto nla_put_failure;
632a9fd44b1SJiri Pirko 
633a9fd44b1SJiri Pirko 	err = devlink_dpipe_fields_put(skb, header);
634a9fd44b1SJiri Pirko 	if (err) {
635a9fd44b1SJiri Pirko 		nla_nest_cancel(skb, fields_attr);
636a9fd44b1SJiri Pirko 		goto nla_put_failure;
637a9fd44b1SJiri Pirko 	}
638a9fd44b1SJiri Pirko 	nla_nest_end(skb, fields_attr);
639a9fd44b1SJiri Pirko 	nla_nest_end(skb, header_attr);
640a9fd44b1SJiri Pirko 	return 0;
641a9fd44b1SJiri Pirko 
642a9fd44b1SJiri Pirko nla_put_failure:
643a9fd44b1SJiri Pirko 	err = -EMSGSIZE;
644a9fd44b1SJiri Pirko 	nla_nest_cancel(skb, header_attr);
645a9fd44b1SJiri Pirko 	return err;
646a9fd44b1SJiri Pirko }
647a9fd44b1SJiri Pirko 
devlink_dpipe_headers_fill(struct genl_info * info,enum devlink_command cmd,int flags,struct devlink_dpipe_headers * dpipe_headers)648a9fd44b1SJiri Pirko static int devlink_dpipe_headers_fill(struct genl_info *info,
649a9fd44b1SJiri Pirko 				      enum devlink_command cmd, int flags,
650a9fd44b1SJiri Pirko 				      struct devlink_dpipe_headers *
651a9fd44b1SJiri Pirko 				      dpipe_headers)
652a9fd44b1SJiri Pirko {
653a9fd44b1SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
654a9fd44b1SJiri Pirko 	struct nlattr *headers_attr;
655a9fd44b1SJiri Pirko 	struct sk_buff *skb = NULL;
656a9fd44b1SJiri Pirko 	struct nlmsghdr *nlh;
657a9fd44b1SJiri Pirko 	void *hdr;
658a9fd44b1SJiri Pirko 	int i, j;
659a9fd44b1SJiri Pirko 	int err;
660a9fd44b1SJiri Pirko 
661a9fd44b1SJiri Pirko 	i = 0;
662a9fd44b1SJiri Pirko start_again:
663a9fd44b1SJiri Pirko 	err = devlink_dpipe_send_and_alloc_skb(&skb, info);
664a9fd44b1SJiri Pirko 	if (err)
665a9fd44b1SJiri Pirko 		return err;
666a9fd44b1SJiri Pirko 
667a9fd44b1SJiri Pirko 	hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq,
668a9fd44b1SJiri Pirko 			  &devlink_nl_family, NLM_F_MULTI, cmd);
669a9fd44b1SJiri Pirko 	if (!hdr) {
670a9fd44b1SJiri Pirko 		nlmsg_free(skb);
671a9fd44b1SJiri Pirko 		return -EMSGSIZE;
672a9fd44b1SJiri Pirko 	}
673a9fd44b1SJiri Pirko 
674a9fd44b1SJiri Pirko 	if (devlink_nl_put_handle(skb, devlink))
675a9fd44b1SJiri Pirko 		goto nla_put_failure;
676a9fd44b1SJiri Pirko 	headers_attr = nla_nest_start_noflag(skb, DEVLINK_ATTR_DPIPE_HEADERS);
677a9fd44b1SJiri Pirko 	if (!headers_attr)
678a9fd44b1SJiri Pirko 		goto nla_put_failure;
679a9fd44b1SJiri Pirko 
680a9fd44b1SJiri Pirko 	j = 0;
681a9fd44b1SJiri Pirko 	for (; i < dpipe_headers->headers_count; i++) {
682a9fd44b1SJiri Pirko 		err = devlink_dpipe_header_put(skb, dpipe_headers->headers[i]);
683a9fd44b1SJiri Pirko 		if (err) {
684a9fd44b1SJiri Pirko 			if (!j)
685a9fd44b1SJiri Pirko 				goto err_table_put;
686a9fd44b1SJiri Pirko 			break;
687a9fd44b1SJiri Pirko 		}
688a9fd44b1SJiri Pirko 		j++;
689a9fd44b1SJiri Pirko 	}
690a9fd44b1SJiri Pirko 	nla_nest_end(skb, headers_attr);
691a9fd44b1SJiri Pirko 	genlmsg_end(skb, hdr);
692a9fd44b1SJiri Pirko 	if (i != dpipe_headers->headers_count)
693a9fd44b1SJiri Pirko 		goto start_again;
694a9fd44b1SJiri Pirko 
695a9fd44b1SJiri Pirko send_done:
696a9fd44b1SJiri Pirko 	nlh = nlmsg_put(skb, info->snd_portid, info->snd_seq,
697a9fd44b1SJiri Pirko 			NLMSG_DONE, 0, flags | NLM_F_MULTI);
698a9fd44b1SJiri Pirko 	if (!nlh) {
699a9fd44b1SJiri Pirko 		err = devlink_dpipe_send_and_alloc_skb(&skb, info);
700a9fd44b1SJiri Pirko 		if (err)
701a9fd44b1SJiri Pirko 			return err;
702a9fd44b1SJiri Pirko 		goto send_done;
703a9fd44b1SJiri Pirko 	}
704a9fd44b1SJiri Pirko 	return genlmsg_reply(skb, info);
705a9fd44b1SJiri Pirko 
706a9fd44b1SJiri Pirko nla_put_failure:
707a9fd44b1SJiri Pirko 	err = -EMSGSIZE;
708a9fd44b1SJiri Pirko err_table_put:
709a9fd44b1SJiri Pirko 	nlmsg_free(skb);
710a9fd44b1SJiri Pirko 	return err;
711a9fd44b1SJiri Pirko }
712a9fd44b1SJiri Pirko 
devlink_nl_dpipe_headers_get_doit(struct sk_buff * skb,struct genl_info * info)71353590934SJiri Pirko int devlink_nl_dpipe_headers_get_doit(struct sk_buff *skb,
714a9fd44b1SJiri Pirko 				      struct genl_info *info)
715a9fd44b1SJiri Pirko {
716a9fd44b1SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
717a9fd44b1SJiri Pirko 
718a9fd44b1SJiri Pirko 	if (!devlink->dpipe_headers)
719a9fd44b1SJiri Pirko 		return -EOPNOTSUPP;
720a9fd44b1SJiri Pirko 	return devlink_dpipe_headers_fill(info, DEVLINK_CMD_DPIPE_HEADERS_GET,
721a9fd44b1SJiri Pirko 					  0, devlink->dpipe_headers);
722a9fd44b1SJiri Pirko }
723a9fd44b1SJiri Pirko 
devlink_dpipe_table_counters_set(struct devlink * devlink,const char * table_name,bool enable)724a9fd44b1SJiri Pirko static int devlink_dpipe_table_counters_set(struct devlink *devlink,
725a9fd44b1SJiri Pirko 					    const char *table_name,
726a9fd44b1SJiri Pirko 					    bool enable)
727a9fd44b1SJiri Pirko {
728a9fd44b1SJiri Pirko 	struct devlink_dpipe_table *table;
729a9fd44b1SJiri Pirko 
730a9fd44b1SJiri Pirko 	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
731a9fd44b1SJiri Pirko 					 table_name, devlink);
732a9fd44b1SJiri Pirko 	if (!table)
733a9fd44b1SJiri Pirko 		return -EINVAL;
734a9fd44b1SJiri Pirko 
735a9fd44b1SJiri Pirko 	if (table->counter_control_extern)
736a9fd44b1SJiri Pirko 		return -EOPNOTSUPP;
737a9fd44b1SJiri Pirko 
738a9fd44b1SJiri Pirko 	if (!(table->counters_enabled ^ enable))
739a9fd44b1SJiri Pirko 		return 0;
740a9fd44b1SJiri Pirko 
741a9fd44b1SJiri Pirko 	table->counters_enabled = enable;
742a9fd44b1SJiri Pirko 	if (table->table_ops->counters_set_update)
743a9fd44b1SJiri Pirko 		table->table_ops->counters_set_update(table->priv, enable);
744a9fd44b1SJiri Pirko 	return 0;
745a9fd44b1SJiri Pirko }
746a9fd44b1SJiri Pirko 
devlink_nl_dpipe_table_counters_set_doit(struct sk_buff * skb,struct genl_info * info)74753590934SJiri Pirko int devlink_nl_dpipe_table_counters_set_doit(struct sk_buff *skb,
748a9fd44b1SJiri Pirko 					     struct genl_info *info)
749a9fd44b1SJiri Pirko {
750a9fd44b1SJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
751a9fd44b1SJiri Pirko 	const char *table_name;
752a9fd44b1SJiri Pirko 	bool counters_enable;
753a9fd44b1SJiri Pirko 
754a9fd44b1SJiri Pirko 	if (GENL_REQ_ATTR_CHECK(info, DEVLINK_ATTR_DPIPE_TABLE_NAME) ||
755a9fd44b1SJiri Pirko 	    GENL_REQ_ATTR_CHECK(info,
756a9fd44b1SJiri Pirko 				DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED))
757a9fd44b1SJiri Pirko 		return -EINVAL;
758a9fd44b1SJiri Pirko 
759a9fd44b1SJiri Pirko 	table_name = nla_data(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
760a9fd44b1SJiri Pirko 	counters_enable = !!nla_get_u8(info->attrs[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
761a9fd44b1SJiri Pirko 
762a9fd44b1SJiri Pirko 	return devlink_dpipe_table_counters_set(devlink, table_name,
763a9fd44b1SJiri Pirko 						counters_enable);
764a9fd44b1SJiri Pirko }
765a9fd44b1SJiri Pirko 
766a9fd44b1SJiri Pirko /**
767a9fd44b1SJiri Pirko  * devl_dpipe_headers_register - register dpipe headers
768a9fd44b1SJiri Pirko  *
769a9fd44b1SJiri Pirko  * @devlink: devlink
770a9fd44b1SJiri Pirko  * @dpipe_headers: dpipe header array
771a9fd44b1SJiri Pirko  *
772a9fd44b1SJiri Pirko  * Register the headers supported by hardware.
773a9fd44b1SJiri Pirko  */
devl_dpipe_headers_register(struct devlink * devlink,struct devlink_dpipe_headers * dpipe_headers)774a9fd44b1SJiri Pirko void devl_dpipe_headers_register(struct devlink *devlink,
775a9fd44b1SJiri Pirko 				 struct devlink_dpipe_headers *dpipe_headers)
776a9fd44b1SJiri Pirko {
777a9fd44b1SJiri Pirko 	lockdep_assert_held(&devlink->lock);
778a9fd44b1SJiri Pirko 
779a9fd44b1SJiri Pirko 	devlink->dpipe_headers = dpipe_headers;
780a9fd44b1SJiri Pirko }
781a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devl_dpipe_headers_register);
782a9fd44b1SJiri Pirko 
783a9fd44b1SJiri Pirko /**
784a9fd44b1SJiri Pirko  * devl_dpipe_headers_unregister - unregister dpipe headers
785a9fd44b1SJiri Pirko  *
786a9fd44b1SJiri Pirko  * @devlink: devlink
787a9fd44b1SJiri Pirko  *
788a9fd44b1SJiri Pirko  * Unregister the headers supported by hardware.
789a9fd44b1SJiri Pirko  */
devl_dpipe_headers_unregister(struct devlink * devlink)790a9fd44b1SJiri Pirko void devl_dpipe_headers_unregister(struct devlink *devlink)
791a9fd44b1SJiri Pirko {
792a9fd44b1SJiri Pirko 	lockdep_assert_held(&devlink->lock);
793a9fd44b1SJiri Pirko 
794a9fd44b1SJiri Pirko 	devlink->dpipe_headers = NULL;
795a9fd44b1SJiri Pirko }
796a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devl_dpipe_headers_unregister);
797a9fd44b1SJiri Pirko 
798a9fd44b1SJiri Pirko /**
799a9fd44b1SJiri Pirko  *	devlink_dpipe_table_counter_enabled - check if counter allocation
800a9fd44b1SJiri Pirko  *					      required
801a9fd44b1SJiri Pirko  *	@devlink: devlink
802a9fd44b1SJiri Pirko  *	@table_name: tables name
803a9fd44b1SJiri Pirko  *
804a9fd44b1SJiri Pirko  *	Used by driver to check if counter allocation is required.
805a9fd44b1SJiri Pirko  *	After counter allocation is turned on the table entries
806a9fd44b1SJiri Pirko  *	are updated to include counter statistics.
807a9fd44b1SJiri Pirko  *
808a9fd44b1SJiri Pirko  *	After that point on the driver must respect the counter
809a9fd44b1SJiri Pirko  *	state so that each entry added to the table is added
810a9fd44b1SJiri Pirko  *	with a counter.
811a9fd44b1SJiri Pirko  */
devlink_dpipe_table_counter_enabled(struct devlink * devlink,const char * table_name)812a9fd44b1SJiri Pirko bool devlink_dpipe_table_counter_enabled(struct devlink *devlink,
813a9fd44b1SJiri Pirko 					 const char *table_name)
814a9fd44b1SJiri Pirko {
815a9fd44b1SJiri Pirko 	struct devlink_dpipe_table *table;
816a9fd44b1SJiri Pirko 	bool enabled;
817a9fd44b1SJiri Pirko 
818a9fd44b1SJiri Pirko 	rcu_read_lock();
819a9fd44b1SJiri Pirko 	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
820a9fd44b1SJiri Pirko 					 table_name, devlink);
821a9fd44b1SJiri Pirko 	enabled = false;
822a9fd44b1SJiri Pirko 	if (table)
823a9fd44b1SJiri Pirko 		enabled = table->counters_enabled;
824a9fd44b1SJiri Pirko 	rcu_read_unlock();
825a9fd44b1SJiri Pirko 	return enabled;
826a9fd44b1SJiri Pirko }
827a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devlink_dpipe_table_counter_enabled);
828a9fd44b1SJiri Pirko 
829a9fd44b1SJiri Pirko /**
830a9fd44b1SJiri Pirko  * devl_dpipe_table_register - register dpipe table
831a9fd44b1SJiri Pirko  *
832a9fd44b1SJiri Pirko  * @devlink: devlink
833a9fd44b1SJiri Pirko  * @table_name: table name
834a9fd44b1SJiri Pirko  * @table_ops: table ops
835a9fd44b1SJiri Pirko  * @priv: priv
836a9fd44b1SJiri Pirko  * @counter_control_extern: external control for counters
837a9fd44b1SJiri Pirko  */
devl_dpipe_table_register(struct devlink * devlink,const char * table_name,const struct devlink_dpipe_table_ops * table_ops,void * priv,bool counter_control_extern)838a9fd44b1SJiri Pirko int devl_dpipe_table_register(struct devlink *devlink,
839a9fd44b1SJiri Pirko 			      const char *table_name,
84082dc29b9SChristophe JAILLET 			      const struct devlink_dpipe_table_ops *table_ops,
841a9fd44b1SJiri Pirko 			      void *priv, bool counter_control_extern)
842a9fd44b1SJiri Pirko {
843a9fd44b1SJiri Pirko 	struct devlink_dpipe_table *table;
844a9fd44b1SJiri Pirko 
845a9fd44b1SJiri Pirko 	lockdep_assert_held(&devlink->lock);
846a9fd44b1SJiri Pirko 
847a9fd44b1SJiri Pirko 	if (WARN_ON(!table_ops->size_get))
848a9fd44b1SJiri Pirko 		return -EINVAL;
849a9fd44b1SJiri Pirko 
850a9fd44b1SJiri Pirko 	if (devlink_dpipe_table_find(&devlink->dpipe_table_list, table_name,
851a9fd44b1SJiri Pirko 				     devlink))
852a9fd44b1SJiri Pirko 		return -EEXIST;
853a9fd44b1SJiri Pirko 
854a9fd44b1SJiri Pirko 	table = kzalloc(sizeof(*table), GFP_KERNEL);
855a9fd44b1SJiri Pirko 	if (!table)
856a9fd44b1SJiri Pirko 		return -ENOMEM;
857a9fd44b1SJiri Pirko 
858a9fd44b1SJiri Pirko 	table->name = table_name;
859a9fd44b1SJiri Pirko 	table->table_ops = table_ops;
860a9fd44b1SJiri Pirko 	table->priv = priv;
861a9fd44b1SJiri Pirko 	table->counter_control_extern = counter_control_extern;
862a9fd44b1SJiri Pirko 
863a9fd44b1SJiri Pirko 	list_add_tail_rcu(&table->list, &devlink->dpipe_table_list);
864a9fd44b1SJiri Pirko 
865a9fd44b1SJiri Pirko 	return 0;
866a9fd44b1SJiri Pirko }
867a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devl_dpipe_table_register);
868a9fd44b1SJiri Pirko 
869a9fd44b1SJiri Pirko /**
870a9fd44b1SJiri Pirko  * devl_dpipe_table_unregister - unregister dpipe table
871a9fd44b1SJiri Pirko  *
872a9fd44b1SJiri Pirko  * @devlink: devlink
873a9fd44b1SJiri Pirko  * @table_name: table name
874a9fd44b1SJiri Pirko  */
devl_dpipe_table_unregister(struct devlink * devlink,const char * table_name)875a9fd44b1SJiri Pirko void devl_dpipe_table_unregister(struct devlink *devlink,
876a9fd44b1SJiri Pirko 				 const char *table_name)
877a9fd44b1SJiri Pirko {
878a9fd44b1SJiri Pirko 	struct devlink_dpipe_table *table;
879a9fd44b1SJiri Pirko 
880a9fd44b1SJiri Pirko 	lockdep_assert_held(&devlink->lock);
881a9fd44b1SJiri Pirko 
882a9fd44b1SJiri Pirko 	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
883a9fd44b1SJiri Pirko 					 table_name, devlink);
884a9fd44b1SJiri Pirko 	if (!table)
885a9fd44b1SJiri Pirko 		return;
886a9fd44b1SJiri Pirko 	list_del_rcu(&table->list);
887a9fd44b1SJiri Pirko 	kfree_rcu(table, rcu);
888a9fd44b1SJiri Pirko }
889a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devl_dpipe_table_unregister);
890a9fd44b1SJiri Pirko 
891a9fd44b1SJiri Pirko /**
892a9fd44b1SJiri Pirko  * devl_dpipe_table_resource_set - set the resource id
893a9fd44b1SJiri Pirko  *
894a9fd44b1SJiri Pirko  * @devlink: devlink
895a9fd44b1SJiri Pirko  * @table_name: table name
896a9fd44b1SJiri Pirko  * @resource_id: resource id
897a9fd44b1SJiri Pirko  * @resource_units: number of resource's units consumed per table's entry
898a9fd44b1SJiri Pirko  */
devl_dpipe_table_resource_set(struct devlink * devlink,const char * table_name,u64 resource_id,u64 resource_units)899a9fd44b1SJiri Pirko int devl_dpipe_table_resource_set(struct devlink *devlink,
900a9fd44b1SJiri Pirko 				  const char *table_name, u64 resource_id,
901a9fd44b1SJiri Pirko 				  u64 resource_units)
902a9fd44b1SJiri Pirko {
903a9fd44b1SJiri Pirko 	struct devlink_dpipe_table *table;
904a9fd44b1SJiri Pirko 
905a9fd44b1SJiri Pirko 	table = devlink_dpipe_table_find(&devlink->dpipe_table_list,
906a9fd44b1SJiri Pirko 					 table_name, devlink);
907a9fd44b1SJiri Pirko 	if (!table)
908a9fd44b1SJiri Pirko 		return -EINVAL;
909a9fd44b1SJiri Pirko 
910a9fd44b1SJiri Pirko 	table->resource_id = resource_id;
911a9fd44b1SJiri Pirko 	table->resource_units = resource_units;
912a9fd44b1SJiri Pirko 	table->resource_valid = true;
913a9fd44b1SJiri Pirko 	return 0;
914a9fd44b1SJiri Pirko }
915a9fd44b1SJiri Pirko EXPORT_SYMBOL_GPL(devl_dpipe_table_resource_set);
916