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