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