net/failsafe: add plug-in support
[dpdk.git] / drivers / net / failsafe / failsafe_args.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2017 6WIND S.A.
5  *   Copyright 2017 Mellanox.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of 6WIND S.A. nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <string.h>
35 #include <errno.h>
36
37 #include <rte_devargs.h>
38 #include <rte_malloc.h>
39 #include <rte_kvargs.h>
40
41 #include "failsafe_private.h"
42
43 #define DEVARGS_MAXLEN 4096
44
45 /* Callback used when a new device is found in devargs */
46 typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params,
47                 uint8_t head);
48
49 uint64_t hotplug_poll = FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS;
50 int mac_from_arg = 0;
51
52 const char *pmd_failsafe_init_parameters[] = {
53         PMD_FAILSAFE_HOTPLUG_POLL_KVARG,
54         PMD_FAILSAFE_MAC_KVARG,
55         NULL,
56 };
57
58 /*
59  * input: text.
60  * output: 0: if text[0] != '(',
61  *         0: if there are no corresponding ')'
62  *         n: distance to corresponding ')' otherwise
63  */
64 static size_t
65 closing_paren(const char *text)
66 {
67         int nb_open = 0;
68         size_t i = 0;
69
70         while (text[i] != '\0') {
71                 if (text[i] == '(')
72                         nb_open++;
73                 if (text[i] == ')')
74                         nb_open--;
75                 if (nb_open == 0)
76                         return i;
77                 i++;
78         }
79         return 0;
80 }
81
82 static int
83 fs_parse_device(struct sub_device *sdev, char *args)
84 {
85         struct rte_devargs *d;
86         int ret;
87
88         d = &sdev->devargs;
89         DEBUG("%s", args);
90         ret = rte_eal_devargs_parse(args, d);
91         if (ret) {
92                 DEBUG("devargs parsing failed with code %d", ret);
93                 return ret;
94         }
95         sdev->bus = d->bus;
96         sdev->state = DEV_PARSED;
97         return 0;
98 }
99
100 static int
101 fs_parse_device_param(struct rte_eth_dev *dev, const char *param,
102                 uint8_t head)
103 {
104         struct fs_priv *priv;
105         struct sub_device *sdev;
106         char *args = NULL;
107         size_t a, b;
108         int ret;
109
110         priv = PRIV(dev);
111         a = 0;
112         b = 0;
113         ret = 0;
114         while  (param[b] != '(' &&
115                 param[b] != '\0')
116                 b++;
117         a = b;
118         b += closing_paren(&param[b]);
119         if (a == b) {
120                 ERROR("Dangling parenthesis");
121                 return -EINVAL;
122         }
123         a += 1;
124         args = strndup(&param[a], b - a);
125         if (args == NULL) {
126                 ERROR("Not enough memory for parameter parsing");
127                 return -ENOMEM;
128         }
129         sdev = &priv->subs[head];
130         if (strncmp(param, "dev", 3) == 0) {
131                 ret = fs_parse_device(sdev, args);
132                 if (ret)
133                         goto free_args;
134         } else {
135                 ERROR("Unrecognized device type: %.*s", (int)b, param);
136                 return -EINVAL;
137         }
138 free_args:
139         free(args);
140         return ret;
141 }
142
143 static int
144 fs_parse_sub_devices(parse_cb *cb,
145                 struct rte_eth_dev *dev, const char *params)
146 {
147         size_t a, b;
148         uint8_t head;
149         int ret;
150
151         a = 0;
152         head = 0;
153         ret = 0;
154         while (params[a] != '\0') {
155                 b = a;
156                 while (params[b] != '(' &&
157                        params[b] != ',' &&
158                        params[b] != '\0')
159                         b++;
160                 if (b == a) {
161                         ERROR("Invalid parameter");
162                         return -EINVAL;
163                 }
164                 if (params[b] == ',') {
165                         a = b + 1;
166                         continue;
167                 }
168                 if (params[b] == '(') {
169                         size_t start = b;
170
171                         b += closing_paren(&params[b]);
172                         if (b == start) {
173                                 ERROR("Dangling parenthesis");
174                                 return -EINVAL;
175                         }
176                         ret = (*cb)(dev, &params[a], head);
177                         if (ret)
178                                 return ret;
179                         head += 1;
180                         b += 1;
181                         if (params[b] == '\0')
182                                 return 0;
183                 }
184                 a = b + 1;
185         }
186         return 0;
187 }
188
189 static int
190 fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
191 {
192         char buffer[DEVARGS_MAXLEN] = {0};
193         size_t a, b;
194         int i;
195
196         a = 0;
197         i = 0;
198         while (params[a] != '\0') {
199                 b = a;
200                 while (params[b] != '(' &&
201                        params[b] != ',' &&
202                        params[b] != '\0')
203                         b++;
204                 if (b == a) {
205                         ERROR("Invalid parameter");
206                         return -EINVAL;
207                 }
208                 if (params[b] == ',' || params[b] == '\0')
209                         i += snprintf(&buffer[i], b - a + 1, "%s", &params[a]);
210                 if (params[b] == '(') {
211                         size_t start = b;
212                         b += closing_paren(&params[b]);
213                         if (b == start)
214                                 return -EINVAL;
215                         b += 1;
216                         if (params[b] == '\0')
217                                 goto out;
218                 }
219                 a = b + 1;
220         }
221 out:
222         snprintf(params, DEVARGS_MAXLEN, "%s", buffer);
223         return 0;
224 }
225
226 static int
227 fs_get_u64_arg(const char *key __rte_unused,
228                 const char *value, void *out)
229 {
230         uint64_t *u64 = out;
231         char *endptr = NULL;
232
233         if ((value == NULL) || (out == NULL))
234                 return -EINVAL;
235         errno = 0;
236         *u64 = strtoull(value, &endptr, 0);
237         if (errno != 0)
238                 return -errno;
239         if (endptr == value)
240                 return -1;
241         return 0;
242 }
243
244 static int
245 fs_get_mac_addr_arg(const char *key __rte_unused,
246                 const char *value, void *out)
247 {
248         struct ether_addr *ea = out;
249         int ret;
250
251         if ((value == NULL) || (out == NULL))
252                 return -EINVAL;
253         ret = sscanf(value, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
254                 &ea->addr_bytes[0], &ea->addr_bytes[1],
255                 &ea->addr_bytes[2], &ea->addr_bytes[3],
256                 &ea->addr_bytes[4], &ea->addr_bytes[5]);
257         return ret != ETHER_ADDR_LEN;
258 }
259
260 int
261 failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
262 {
263         struct fs_priv *priv;
264         char mut_params[DEVARGS_MAXLEN] = "";
265         struct rte_kvargs *kvlist = NULL;
266         unsigned int arg_count;
267         size_t n;
268         int ret;
269
270         priv = PRIV(dev);
271         ret = 0;
272         priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
273         /* default parameters */
274         n = snprintf(mut_params, sizeof(mut_params), "%s", params);
275         if (n >= sizeof(mut_params)) {
276                 ERROR("Parameter string too long (>=%zu)",
277                                 sizeof(mut_params));
278                 return -ENOMEM;
279         }
280         ret = fs_parse_sub_devices(fs_parse_device_param,
281                                    dev, params);
282         if (ret < 0)
283                 return ret;
284         ret = fs_remove_sub_devices_definition(mut_params);
285         if (ret < 0)
286                 return ret;
287         if (strnlen(mut_params, sizeof(mut_params)) > 0) {
288                 kvlist = rte_kvargs_parse(mut_params,
289                                 pmd_failsafe_init_parameters);
290                 if (kvlist == NULL) {
291                         ERROR("Error parsing parameters, usage:\n"
292                                 PMD_FAILSAFE_PARAM_STRING);
293                         return -1;
294                 }
295                 /* PLUG_IN event poll timer */
296                 arg_count = rte_kvargs_count(kvlist,
297                                 PMD_FAILSAFE_HOTPLUG_POLL_KVARG);
298                 if (arg_count == 1) {
299                         ret = rte_kvargs_process(kvlist,
300                                         PMD_FAILSAFE_HOTPLUG_POLL_KVARG,
301                                         &fs_get_u64_arg, &hotplug_poll);
302                         if (ret < 0)
303                                 goto free_kvlist;
304                 }
305                 /* MAC addr */
306                 arg_count = rte_kvargs_count(kvlist,
307                                 PMD_FAILSAFE_MAC_KVARG);
308                 if (arg_count > 0) {
309                         ret = rte_kvargs_process(kvlist,
310                                         PMD_FAILSAFE_MAC_KVARG,
311                                         &fs_get_mac_addr_arg,
312                                         &dev->data->mac_addrs[0]);
313                         if (ret < 0)
314                                 goto free_kvlist;
315                         mac_from_arg = 1;
316                 }
317         }
318         PRIV(dev)->state = DEV_PARSED;
319 free_kvlist:
320         rte_kvargs_free(kvlist);
321         return ret;
322 }
323
324 void
325 failsafe_args_free(struct rte_eth_dev *dev)
326 {
327         struct sub_device *sdev;
328         uint8_t i;
329
330         FOREACH_SUBDEV(sdev, i, dev) {
331                 free(sdev->devargs.args);
332                 sdev->devargs.args = NULL;
333         }
334 }
335
336 static int
337 fs_count_device(struct rte_eth_dev *dev, const char *param,
338                 uint8_t head __rte_unused)
339 {
340         size_t b = 0;
341
342         while  (param[b] != '(' &&
343                 param[b] != '\0')
344                 b++;
345         if (strncmp(param, "dev", b) != 0) {
346                 ERROR("Unrecognized device type: %.*s", (int)b, param);
347                 return -EINVAL;
348         }
349         PRIV(dev)->subs_tail += 1;
350         return 0;
351 }
352
353 int
354 failsafe_args_count_subdevice(struct rte_eth_dev *dev,
355                         const char *params)
356 {
357         return fs_parse_sub_devices(fs_count_device,
358                                     dev, params);
359 }