net/failsafe: add fail-safe PMD
[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
36 #include <rte_devargs.h>
37 #include <rte_malloc.h>
38 #include <rte_kvargs.h>
39
40 #include "failsafe_private.h"
41
42 #define DEVARGS_MAXLEN 4096
43
44 /* Callback used when a new device is found in devargs */
45 typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params,
46                 uint8_t head);
47
48 int mac_from_arg = 0;
49
50 const char *pmd_failsafe_init_parameters[] = {
51         PMD_FAILSAFE_MAC_KVARG,
52         NULL,
53 };
54
55 /*
56  * input: text.
57  * output: 0: if text[0] != '(',
58  *         0: if there are no corresponding ')'
59  *         n: distance to corresponding ')' otherwise
60  */
61 static size_t
62 closing_paren(const char *text)
63 {
64         int nb_open = 0;
65         size_t i = 0;
66
67         while (text[i] != '\0') {
68                 if (text[i] == '(')
69                         nb_open++;
70                 if (text[i] == ')')
71                         nb_open--;
72                 if (nb_open == 0)
73                         return i;
74                 i++;
75         }
76         return 0;
77 }
78
79 static int
80 fs_parse_device(struct sub_device *sdev, char *args)
81 {
82         struct rte_devargs *d;
83         int ret;
84
85         d = &sdev->devargs;
86         DEBUG("%s", args);
87         ret = rte_eal_devargs_parse(args, d);
88         if (ret) {
89                 DEBUG("devargs parsing failed with code %d", ret);
90                 return ret;
91         }
92         sdev->bus = d->bus;
93         sdev->state = DEV_PARSED;
94         return 0;
95 }
96
97 static int
98 fs_parse_device_param(struct rte_eth_dev *dev, const char *param,
99                 uint8_t head)
100 {
101         struct fs_priv *priv;
102         struct sub_device *sdev;
103         char *args = NULL;
104         size_t a, b;
105         int ret;
106
107         priv = PRIV(dev);
108         a = 0;
109         b = 0;
110         ret = 0;
111         while  (param[b] != '(' &&
112                 param[b] != '\0')
113                 b++;
114         a = b;
115         b += closing_paren(&param[b]);
116         if (a == b) {
117                 ERROR("Dangling parenthesis");
118                 return -EINVAL;
119         }
120         a += 1;
121         args = strndup(&param[a], b - a);
122         if (args == NULL) {
123                 ERROR("Not enough memory for parameter parsing");
124                 return -ENOMEM;
125         }
126         sdev = &priv->subs[head];
127         if (strncmp(param, "dev", 3) == 0) {
128                 ret = fs_parse_device(sdev, args);
129                 if (ret)
130                         goto free_args;
131         } else {
132                 ERROR("Unrecognized device type: %.*s", (int)b, param);
133                 return -EINVAL;
134         }
135 free_args:
136         free(args);
137         return ret;
138 }
139
140 static int
141 fs_parse_sub_devices(parse_cb *cb,
142                 struct rte_eth_dev *dev, const char *params)
143 {
144         size_t a, b;
145         uint8_t head;
146         int ret;
147
148         a = 0;
149         head = 0;
150         ret = 0;
151         while (params[a] != '\0') {
152                 b = a;
153                 while (params[b] != '(' &&
154                        params[b] != ',' &&
155                        params[b] != '\0')
156                         b++;
157                 if (b == a) {
158                         ERROR("Invalid parameter");
159                         return -EINVAL;
160                 }
161                 if (params[b] == ',') {
162                         a = b + 1;
163                         continue;
164                 }
165                 if (params[b] == '(') {
166                         size_t start = b;
167
168                         b += closing_paren(&params[b]);
169                         if (b == start) {
170                                 ERROR("Dangling parenthesis");
171                                 return -EINVAL;
172                         }
173                         ret = (*cb)(dev, &params[a], head);
174                         if (ret)
175                                 return ret;
176                         head += 1;
177                         b += 1;
178                         if (params[b] == '\0')
179                                 return 0;
180                 }
181                 a = b + 1;
182         }
183         return 0;
184 }
185
186 static int
187 fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
188 {
189         char buffer[DEVARGS_MAXLEN] = {0};
190         size_t a, b;
191         int i;
192
193         a = 0;
194         i = 0;
195         while (params[a] != '\0') {
196                 b = a;
197                 while (params[b] != '(' &&
198                        params[b] != ',' &&
199                        params[b] != '\0')
200                         b++;
201                 if (b == a) {
202                         ERROR("Invalid parameter");
203                         return -EINVAL;
204                 }
205                 if (params[b] == ',' || params[b] == '\0')
206                         i += snprintf(&buffer[i], b - a + 1, "%s", &params[a]);
207                 if (params[b] == '(') {
208                         size_t start = b;
209                         b += closing_paren(&params[b]);
210                         if (b == start)
211                                 return -EINVAL;
212                         b += 1;
213                         if (params[b] == '\0')
214                                 goto out;
215                 }
216                 a = b + 1;
217         }
218 out:
219         snprintf(params, DEVARGS_MAXLEN, "%s", buffer);
220         return 0;
221 }
222
223 static int
224 fs_get_mac_addr_arg(const char *key __rte_unused,
225                 const char *value, void *out)
226 {
227         struct ether_addr *ea = out;
228         int ret;
229
230         if ((value == NULL) || (out == NULL))
231                 return -EINVAL;
232         ret = sscanf(value, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
233                 &ea->addr_bytes[0], &ea->addr_bytes[1],
234                 &ea->addr_bytes[2], &ea->addr_bytes[3],
235                 &ea->addr_bytes[4], &ea->addr_bytes[5]);
236         return ret != ETHER_ADDR_LEN;
237 }
238
239 int
240 failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
241 {
242         struct fs_priv *priv;
243         char mut_params[DEVARGS_MAXLEN] = "";
244         struct rte_kvargs *kvlist = NULL;
245         unsigned int arg_count;
246         size_t n;
247         int ret;
248
249         priv = PRIV(dev);
250         ret = 0;
251         priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
252         /* default parameters */
253         n = snprintf(mut_params, sizeof(mut_params), "%s", params);
254         if (n >= sizeof(mut_params)) {
255                 ERROR("Parameter string too long (>=%zu)",
256                                 sizeof(mut_params));
257                 return -ENOMEM;
258         }
259         ret = fs_parse_sub_devices(fs_parse_device_param,
260                                    dev, params);
261         if (ret < 0)
262                 return ret;
263         ret = fs_remove_sub_devices_definition(mut_params);
264         if (ret < 0)
265                 return ret;
266         if (strnlen(mut_params, sizeof(mut_params)) > 0) {
267                 kvlist = rte_kvargs_parse(mut_params,
268                                 pmd_failsafe_init_parameters);
269                 if (kvlist == NULL) {
270                         ERROR("Error parsing parameters, usage:\n"
271                                 PMD_FAILSAFE_PARAM_STRING);
272                         return -1;
273                 }
274                 /* MAC addr */
275                 arg_count = rte_kvargs_count(kvlist,
276                                 PMD_FAILSAFE_MAC_KVARG);
277                 if (arg_count > 0) {
278                         ret = rte_kvargs_process(kvlist,
279                                         PMD_FAILSAFE_MAC_KVARG,
280                                         &fs_get_mac_addr_arg,
281                                         &dev->data->mac_addrs[0]);
282                         if (ret < 0)
283                                 goto free_kvlist;
284                         mac_from_arg = 1;
285                 }
286         }
287 free_kvlist:
288         rte_kvargs_free(kvlist);
289         return ret;
290 }
291
292 void
293 failsafe_args_free(struct rte_eth_dev *dev)
294 {
295         struct sub_device *sdev;
296         uint8_t i;
297
298         FOREACH_SUBDEV(sdev, i, dev) {
299                 free(sdev->devargs.args);
300                 sdev->devargs.args = NULL;
301         }
302 }
303
304 static int
305 fs_count_device(struct rte_eth_dev *dev, const char *param,
306                 uint8_t head __rte_unused)
307 {
308         size_t b = 0;
309
310         while  (param[b] != '(' &&
311                 param[b] != '\0')
312                 b++;
313         if (strncmp(param, "dev", b) != 0) {
314                 ERROR("Unrecognized device type: %.*s", (int)b, param);
315                 return -EINVAL;
316         }
317         PRIV(dev)->subs_tail += 1;
318         return 0;
319 }
320
321 int
322 failsafe_args_count_subdevice(struct rte_eth_dev *dev,
323                         const char *params)
324 {
325         return fs_parse_sub_devices(fs_count_device,
326                                     dev, params);
327 }