1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
22bfe3f2eSlogwang * Copyright 2017 6WIND S.A.
3d30ea906Sjfb8856606 * Copyright 2017 Mellanox Technologies, Ltd
42bfe3f2eSlogwang */
52bfe3f2eSlogwang
6d30ea906Sjfb8856606 #include <fcntl.h>
7d30ea906Sjfb8856606 #include <stdio.h>
8d30ea906Sjfb8856606 #include <stdlib.h>
92bfe3f2eSlogwang #include <string.h>
10d30ea906Sjfb8856606 #include <unistd.h>
112bfe3f2eSlogwang #include <errno.h>
122bfe3f2eSlogwang
132bfe3f2eSlogwang #include <rte_debug.h>
142bfe3f2eSlogwang #include <rte_devargs.h>
152bfe3f2eSlogwang #include <rte_malloc.h>
162bfe3f2eSlogwang #include <rte_kvargs.h>
17d30ea906Sjfb8856606 #include <rte_string_fns.h>
182bfe3f2eSlogwang
192bfe3f2eSlogwang #include "failsafe_private.h"
202bfe3f2eSlogwang
212bfe3f2eSlogwang /* Callback used when a new device is found in devargs */
222bfe3f2eSlogwang typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params,
232bfe3f2eSlogwang uint8_t head);
242bfe3f2eSlogwang
25d30ea906Sjfb8856606 uint64_t failsafe_hotplug_poll = FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS;
26d30ea906Sjfb8856606 int failsafe_mac_from_arg;
272bfe3f2eSlogwang
28d30ea906Sjfb8856606 static const char * const pmd_failsafe_init_parameters[] = {
292bfe3f2eSlogwang PMD_FAILSAFE_HOTPLUG_POLL_KVARG,
302bfe3f2eSlogwang PMD_FAILSAFE_MAC_KVARG,
312bfe3f2eSlogwang NULL,
322bfe3f2eSlogwang };
332bfe3f2eSlogwang
342bfe3f2eSlogwang /*
352bfe3f2eSlogwang * input: text.
362bfe3f2eSlogwang * output: 0: if text[0] != '(',
372bfe3f2eSlogwang * 0: if there are no corresponding ')'
382bfe3f2eSlogwang * n: distance to corresponding ')' otherwise
392bfe3f2eSlogwang */
402bfe3f2eSlogwang static size_t
closing_paren(const char * text)412bfe3f2eSlogwang closing_paren(const char *text)
422bfe3f2eSlogwang {
432bfe3f2eSlogwang int nb_open = 0;
442bfe3f2eSlogwang size_t i = 0;
452bfe3f2eSlogwang
462bfe3f2eSlogwang while (text[i] != '\0') {
472bfe3f2eSlogwang if (text[i] == '(')
482bfe3f2eSlogwang nb_open++;
492bfe3f2eSlogwang if (text[i] == ')')
502bfe3f2eSlogwang nb_open--;
512bfe3f2eSlogwang if (nb_open == 0)
522bfe3f2eSlogwang return i;
532bfe3f2eSlogwang i++;
542bfe3f2eSlogwang }
552bfe3f2eSlogwang return 0;
562bfe3f2eSlogwang }
572bfe3f2eSlogwang
582bfe3f2eSlogwang static int
fs_parse_device(struct sub_device * sdev,char * args)592bfe3f2eSlogwang fs_parse_device(struct sub_device *sdev, char *args)
602bfe3f2eSlogwang {
612bfe3f2eSlogwang struct rte_devargs *d;
622bfe3f2eSlogwang int ret;
632bfe3f2eSlogwang
642bfe3f2eSlogwang d = &sdev->devargs;
652bfe3f2eSlogwang DEBUG("%s", args);
66d30ea906Sjfb8856606 ret = rte_devargs_parse(d, args);
672bfe3f2eSlogwang if (ret) {
682bfe3f2eSlogwang DEBUG("devargs parsing failed with code %d", ret);
692bfe3f2eSlogwang return ret;
702bfe3f2eSlogwang }
712bfe3f2eSlogwang sdev->bus = d->bus;
722bfe3f2eSlogwang sdev->state = DEV_PARSED;
732bfe3f2eSlogwang return 0;
742bfe3f2eSlogwang }
752bfe3f2eSlogwang
762bfe3f2eSlogwang static void
fs_sanitize_cmdline(char * args)772bfe3f2eSlogwang fs_sanitize_cmdline(char *args)
782bfe3f2eSlogwang {
792bfe3f2eSlogwang char *nl;
802bfe3f2eSlogwang
812bfe3f2eSlogwang nl = strrchr(args, '\n');
822bfe3f2eSlogwang if (nl)
832bfe3f2eSlogwang nl[0] = '\0';
842bfe3f2eSlogwang }
852bfe3f2eSlogwang
862bfe3f2eSlogwang static int
fs_execute_cmd(struct sub_device * sdev,char * cmdline)872bfe3f2eSlogwang fs_execute_cmd(struct sub_device *sdev, char *cmdline)
882bfe3f2eSlogwang {
892bfe3f2eSlogwang FILE *fp;
902bfe3f2eSlogwang /* store possible newline as well */
912bfe3f2eSlogwang char output[DEVARGS_MAXLEN + 1];
922bfe3f2eSlogwang size_t len;
932bfe3f2eSlogwang int ret;
942bfe3f2eSlogwang
952bfe3f2eSlogwang RTE_ASSERT(cmdline != NULL || sdev->cmdline != NULL);
962bfe3f2eSlogwang if (sdev->cmdline == NULL) {
972bfe3f2eSlogwang size_t i;
982bfe3f2eSlogwang
992bfe3f2eSlogwang len = strlen(cmdline) + 1;
1002bfe3f2eSlogwang sdev->cmdline = calloc(1, len);
1012bfe3f2eSlogwang if (sdev->cmdline == NULL) {
1022bfe3f2eSlogwang ERROR("Command line allocation failed");
1032bfe3f2eSlogwang return -ENOMEM;
1042bfe3f2eSlogwang }
105*4418919fSjohnjiang strlcpy(sdev->cmdline, cmdline, len);
1062bfe3f2eSlogwang /* Replace all commas in the command line by spaces */
1072bfe3f2eSlogwang for (i = 0; i < len; i++)
1082bfe3f2eSlogwang if (sdev->cmdline[i] == ',')
1092bfe3f2eSlogwang sdev->cmdline[i] = ' ';
1102bfe3f2eSlogwang }
1112bfe3f2eSlogwang DEBUG("'%s'", sdev->cmdline);
1122bfe3f2eSlogwang fp = popen(sdev->cmdline, "r");
1132bfe3f2eSlogwang if (fp == NULL) {
1142bfe3f2eSlogwang ret = -errno;
1152bfe3f2eSlogwang ERROR("popen: %s", strerror(errno));
1162bfe3f2eSlogwang return ret;
1172bfe3f2eSlogwang }
1182bfe3f2eSlogwang /* We only read one line */
1192bfe3f2eSlogwang if (fgets(output, sizeof(output) - 1, fp) == NULL) {
1202bfe3f2eSlogwang DEBUG("Could not read command output");
1212bfe3f2eSlogwang ret = -ENODEV;
1222bfe3f2eSlogwang goto ret_pclose;
1232bfe3f2eSlogwang }
1242bfe3f2eSlogwang fs_sanitize_cmdline(output);
1252bfe3f2eSlogwang if (output[0] == '\0') {
1262bfe3f2eSlogwang ret = -ENODEV;
1272bfe3f2eSlogwang goto ret_pclose;
1282bfe3f2eSlogwang }
1292bfe3f2eSlogwang ret = fs_parse_device(sdev, output);
1302bfe3f2eSlogwang if (ret)
1312bfe3f2eSlogwang ERROR("Parsing device '%s' failed", output);
1322bfe3f2eSlogwang ret_pclose:
1332bfe3f2eSlogwang if (pclose(fp) == -1)
1342bfe3f2eSlogwang ERROR("pclose: %s", strerror(errno));
1352bfe3f2eSlogwang return ret;
1362bfe3f2eSlogwang }
1372bfe3f2eSlogwang
1382bfe3f2eSlogwang static int
fs_read_fd(struct sub_device * sdev,char * fd_str)139d30ea906Sjfb8856606 fs_read_fd(struct sub_device *sdev, char *fd_str)
140d30ea906Sjfb8856606 {
141d30ea906Sjfb8856606 FILE *fp = NULL;
142d30ea906Sjfb8856606 int fd = -1;
143d30ea906Sjfb8856606 /* store possible newline as well */
144d30ea906Sjfb8856606 char output[DEVARGS_MAXLEN + 1];
145d30ea906Sjfb8856606 int err = -ENODEV;
146d30ea906Sjfb8856606 int oflags;
147d30ea906Sjfb8856606 int lcount;
148d30ea906Sjfb8856606
149d30ea906Sjfb8856606 RTE_ASSERT(fd_str != NULL || sdev->fd_str != NULL);
150d30ea906Sjfb8856606 if (sdev->fd_str == NULL) {
151d30ea906Sjfb8856606 sdev->fd_str = strdup(fd_str);
152d30ea906Sjfb8856606 if (sdev->fd_str == NULL) {
153d30ea906Sjfb8856606 ERROR("Command line allocation failed");
154d30ea906Sjfb8856606 return -ENOMEM;
155d30ea906Sjfb8856606 }
156d30ea906Sjfb8856606 }
157d30ea906Sjfb8856606 errno = 0;
158d30ea906Sjfb8856606 fd = strtol(fd_str, &fd_str, 0);
159d30ea906Sjfb8856606 if (errno || *fd_str || fd < 0) {
160d30ea906Sjfb8856606 ERROR("Parsing FD number failed");
161d30ea906Sjfb8856606 goto error;
162d30ea906Sjfb8856606 }
163d30ea906Sjfb8856606 /* Fiddle with copy of file descriptor */
164d30ea906Sjfb8856606 fd = dup(fd);
165d30ea906Sjfb8856606 if (fd == -1)
166d30ea906Sjfb8856606 goto error;
167d30ea906Sjfb8856606 oflags = fcntl(fd, F_GETFL);
168d30ea906Sjfb8856606 if (oflags == -1)
169d30ea906Sjfb8856606 goto error;
170d30ea906Sjfb8856606 if (fcntl(fd, F_SETFL, oflags | O_NONBLOCK) == -1)
171d30ea906Sjfb8856606 goto error;
172d30ea906Sjfb8856606 fp = fdopen(fd, "r");
173d30ea906Sjfb8856606 if (fp == NULL)
174d30ea906Sjfb8856606 goto error;
175d30ea906Sjfb8856606 fd = -1;
176d30ea906Sjfb8856606 /* Only take the last line into account */
177d30ea906Sjfb8856606 lcount = 0;
178d30ea906Sjfb8856606 while (fgets(output, sizeof(output), fp))
179d30ea906Sjfb8856606 ++lcount;
180d30ea906Sjfb8856606 if (lcount == 0)
181d30ea906Sjfb8856606 goto error;
182d30ea906Sjfb8856606 else if (ferror(fp) && errno != EAGAIN)
183d30ea906Sjfb8856606 goto error;
184d30ea906Sjfb8856606 /* Line must end with a newline character */
185d30ea906Sjfb8856606 fs_sanitize_cmdline(output);
186d30ea906Sjfb8856606 if (output[0] == '\0')
187d30ea906Sjfb8856606 goto error;
188d30ea906Sjfb8856606 err = fs_parse_device(sdev, output);
189d30ea906Sjfb8856606 if (err)
190d30ea906Sjfb8856606 ERROR("Parsing device '%s' failed", output);
191d30ea906Sjfb8856606 error:
192d30ea906Sjfb8856606 if (fp)
193d30ea906Sjfb8856606 fclose(fp);
194d30ea906Sjfb8856606 if (fd != -1)
195d30ea906Sjfb8856606 close(fd);
196d30ea906Sjfb8856606 return err;
197d30ea906Sjfb8856606 }
198d30ea906Sjfb8856606
199d30ea906Sjfb8856606 static int
fs_parse_device_param(struct rte_eth_dev * dev,const char * param,uint8_t head)2002bfe3f2eSlogwang fs_parse_device_param(struct rte_eth_dev *dev, const char *param,
2012bfe3f2eSlogwang uint8_t head)
2022bfe3f2eSlogwang {
2032bfe3f2eSlogwang struct fs_priv *priv;
2042bfe3f2eSlogwang struct sub_device *sdev;
2052bfe3f2eSlogwang char *args = NULL;
2062bfe3f2eSlogwang size_t a, b;
2072bfe3f2eSlogwang int ret;
2082bfe3f2eSlogwang
2092bfe3f2eSlogwang priv = PRIV(dev);
2102bfe3f2eSlogwang a = 0;
2112bfe3f2eSlogwang b = 0;
2122bfe3f2eSlogwang ret = 0;
2132bfe3f2eSlogwang while (param[b] != '(' &&
2142bfe3f2eSlogwang param[b] != '\0')
2152bfe3f2eSlogwang b++;
2162bfe3f2eSlogwang a = b;
2172bfe3f2eSlogwang b += closing_paren(¶m[b]);
2182bfe3f2eSlogwang if (a == b) {
2192bfe3f2eSlogwang ERROR("Dangling parenthesis");
2202bfe3f2eSlogwang return -EINVAL;
2212bfe3f2eSlogwang }
2222bfe3f2eSlogwang a += 1;
2232bfe3f2eSlogwang args = strndup(¶m[a], b - a);
2242bfe3f2eSlogwang if (args == NULL) {
2252bfe3f2eSlogwang ERROR("Not enough memory for parameter parsing");
2262bfe3f2eSlogwang return -ENOMEM;
2272bfe3f2eSlogwang }
2282bfe3f2eSlogwang sdev = &priv->subs[head];
2292bfe3f2eSlogwang if (strncmp(param, "dev", 3) == 0) {
2302bfe3f2eSlogwang ret = fs_parse_device(sdev, args);
2312bfe3f2eSlogwang if (ret)
2322bfe3f2eSlogwang goto free_args;
2332bfe3f2eSlogwang } else if (strncmp(param, "exec", 4) == 0) {
2342bfe3f2eSlogwang ret = fs_execute_cmd(sdev, args);
2352bfe3f2eSlogwang if (ret == -ENODEV) {
2362bfe3f2eSlogwang DEBUG("Reading device info from command line failed");
2372bfe3f2eSlogwang ret = 0;
2382bfe3f2eSlogwang }
2392bfe3f2eSlogwang if (ret)
2402bfe3f2eSlogwang goto free_args;
241d30ea906Sjfb8856606 } else if (strncmp(param, "fd(", 3) == 0) {
242d30ea906Sjfb8856606 ret = fs_read_fd(sdev, args);
243d30ea906Sjfb8856606 if (ret == -ENODEV) {
244d30ea906Sjfb8856606 DEBUG("Reading device info from FD failed");
245d30ea906Sjfb8856606 ret = 0;
246d30ea906Sjfb8856606 }
247d30ea906Sjfb8856606 if (ret)
248d30ea906Sjfb8856606 goto free_args;
2492bfe3f2eSlogwang } else {
2502bfe3f2eSlogwang ERROR("Unrecognized device type: %.*s", (int)b, param);
2512bfe3f2eSlogwang return -EINVAL;
2522bfe3f2eSlogwang }
2532bfe3f2eSlogwang free_args:
2542bfe3f2eSlogwang free(args);
2552bfe3f2eSlogwang return ret;
2562bfe3f2eSlogwang }
2572bfe3f2eSlogwang
2582bfe3f2eSlogwang static int
fs_parse_sub_devices(parse_cb * cb,struct rte_eth_dev * dev,const char * params)2592bfe3f2eSlogwang fs_parse_sub_devices(parse_cb *cb,
2602bfe3f2eSlogwang struct rte_eth_dev *dev, const char *params)
2612bfe3f2eSlogwang {
2622bfe3f2eSlogwang size_t a, b;
2632bfe3f2eSlogwang uint8_t head;
2642bfe3f2eSlogwang int ret;
2652bfe3f2eSlogwang
2662bfe3f2eSlogwang a = 0;
2672bfe3f2eSlogwang head = 0;
2682bfe3f2eSlogwang ret = 0;
2692bfe3f2eSlogwang while (params[a] != '\0') {
2702bfe3f2eSlogwang b = a;
2712bfe3f2eSlogwang while (params[b] != '(' &&
2722bfe3f2eSlogwang params[b] != ',' &&
2732bfe3f2eSlogwang params[b] != '\0')
2742bfe3f2eSlogwang b++;
2752bfe3f2eSlogwang if (b == a) {
2762bfe3f2eSlogwang ERROR("Invalid parameter");
2772bfe3f2eSlogwang return -EINVAL;
2782bfe3f2eSlogwang }
2792bfe3f2eSlogwang if (params[b] == ',') {
2802bfe3f2eSlogwang a = b + 1;
2812bfe3f2eSlogwang continue;
2822bfe3f2eSlogwang }
2832bfe3f2eSlogwang if (params[b] == '(') {
2842bfe3f2eSlogwang size_t start = b;
2852bfe3f2eSlogwang
2862bfe3f2eSlogwang b += closing_paren(¶ms[b]);
2872bfe3f2eSlogwang if (b == start) {
2882bfe3f2eSlogwang ERROR("Dangling parenthesis");
2892bfe3f2eSlogwang return -EINVAL;
2902bfe3f2eSlogwang }
2912bfe3f2eSlogwang ret = (*cb)(dev, ¶ms[a], head);
2922bfe3f2eSlogwang if (ret)
2932bfe3f2eSlogwang return ret;
2942bfe3f2eSlogwang head += 1;
2952bfe3f2eSlogwang b += 1;
2962bfe3f2eSlogwang if (params[b] == '\0')
2972bfe3f2eSlogwang return 0;
2982bfe3f2eSlogwang }
2992bfe3f2eSlogwang a = b + 1;
3002bfe3f2eSlogwang }
3012bfe3f2eSlogwang return 0;
3022bfe3f2eSlogwang }
3032bfe3f2eSlogwang
3042bfe3f2eSlogwang static int
fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])3052bfe3f2eSlogwang fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
3062bfe3f2eSlogwang {
3072bfe3f2eSlogwang char buffer[DEVARGS_MAXLEN] = {0};
3082bfe3f2eSlogwang size_t a, b;
3092bfe3f2eSlogwang int i;
3102bfe3f2eSlogwang
3112bfe3f2eSlogwang a = 0;
3122bfe3f2eSlogwang i = 0;
3132bfe3f2eSlogwang while (params[a] != '\0') {
3142bfe3f2eSlogwang b = a;
3152bfe3f2eSlogwang while (params[b] != '(' &&
3162bfe3f2eSlogwang params[b] != ',' &&
3172bfe3f2eSlogwang params[b] != '\0')
3182bfe3f2eSlogwang b++;
3192bfe3f2eSlogwang if (b == a) {
3202bfe3f2eSlogwang ERROR("Invalid parameter");
3212bfe3f2eSlogwang return -EINVAL;
3222bfe3f2eSlogwang }
3232bfe3f2eSlogwang if (params[b] == ',' || params[b] == '\0') {
3242bfe3f2eSlogwang size_t len = b - a;
3252bfe3f2eSlogwang
3262bfe3f2eSlogwang if (i > 0)
3272bfe3f2eSlogwang len += 1;
3282bfe3f2eSlogwang snprintf(&buffer[i], len + 1, "%s%s",
3292bfe3f2eSlogwang i ? "," : "", ¶ms[a]);
3302bfe3f2eSlogwang i += len;
3312bfe3f2eSlogwang } else if (params[b] == '(') {
3322bfe3f2eSlogwang size_t start = b;
3332bfe3f2eSlogwang
3342bfe3f2eSlogwang b += closing_paren(¶ms[b]);
3352bfe3f2eSlogwang if (b == start)
3362bfe3f2eSlogwang return -EINVAL;
3372bfe3f2eSlogwang b += 1;
3382bfe3f2eSlogwang if (params[b] == '\0')
3392bfe3f2eSlogwang goto out;
3402bfe3f2eSlogwang }
3412bfe3f2eSlogwang a = b + 1;
3422bfe3f2eSlogwang }
3432bfe3f2eSlogwang out:
344d30ea906Sjfb8856606 strlcpy(params, buffer, DEVARGS_MAXLEN);
3452bfe3f2eSlogwang return 0;
3462bfe3f2eSlogwang }
3472bfe3f2eSlogwang
3482bfe3f2eSlogwang static int
fs_get_u64_arg(const char * key __rte_unused,const char * value,void * out)3492bfe3f2eSlogwang fs_get_u64_arg(const char *key __rte_unused,
3502bfe3f2eSlogwang const char *value, void *out)
3512bfe3f2eSlogwang {
3522bfe3f2eSlogwang uint64_t *u64 = out;
3532bfe3f2eSlogwang char *endptr = NULL;
3542bfe3f2eSlogwang
3552bfe3f2eSlogwang if ((value == NULL) || (out == NULL))
3562bfe3f2eSlogwang return -EINVAL;
3572bfe3f2eSlogwang errno = 0;
3582bfe3f2eSlogwang *u64 = strtoull(value, &endptr, 0);
3592bfe3f2eSlogwang if (errno != 0)
3602bfe3f2eSlogwang return -errno;
3612bfe3f2eSlogwang if (endptr == value)
3622bfe3f2eSlogwang return -1;
3632bfe3f2eSlogwang return 0;
3642bfe3f2eSlogwang }
3652bfe3f2eSlogwang
3662bfe3f2eSlogwang static int
fs_get_mac_addr_arg(const char * key __rte_unused,const char * value,void * out)3672bfe3f2eSlogwang fs_get_mac_addr_arg(const char *key __rte_unused,
3682bfe3f2eSlogwang const char *value, void *out)
3692bfe3f2eSlogwang {
370*4418919fSjohnjiang struct rte_ether_addr *ea = out;
3712bfe3f2eSlogwang
3722bfe3f2eSlogwang if ((value == NULL) || (out == NULL))
3732bfe3f2eSlogwang return -EINVAL;
374*4418919fSjohnjiang
375*4418919fSjohnjiang return rte_ether_unformat_addr(value, ea);
3762bfe3f2eSlogwang }
3772bfe3f2eSlogwang
3782bfe3f2eSlogwang int
failsafe_args_parse(struct rte_eth_dev * dev,const char * params)3792bfe3f2eSlogwang failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
3802bfe3f2eSlogwang {
3812bfe3f2eSlogwang struct fs_priv *priv;
3822bfe3f2eSlogwang char mut_params[DEVARGS_MAXLEN] = "";
3832bfe3f2eSlogwang struct rte_kvargs *kvlist = NULL;
3842bfe3f2eSlogwang unsigned int arg_count;
3852bfe3f2eSlogwang size_t n;
3862bfe3f2eSlogwang int ret;
3872bfe3f2eSlogwang
3882bfe3f2eSlogwang priv = PRIV(dev);
3892bfe3f2eSlogwang ret = 0;
3902bfe3f2eSlogwang priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
3912bfe3f2eSlogwang /* default parameters */
392d30ea906Sjfb8856606 n = strlcpy(mut_params, params, sizeof(mut_params));
3932bfe3f2eSlogwang if (n >= sizeof(mut_params)) {
3942bfe3f2eSlogwang ERROR("Parameter string too long (>=%zu)",
3952bfe3f2eSlogwang sizeof(mut_params));
3962bfe3f2eSlogwang return -ENOMEM;
3972bfe3f2eSlogwang }
3982bfe3f2eSlogwang ret = fs_parse_sub_devices(fs_parse_device_param,
3992bfe3f2eSlogwang dev, params);
4002bfe3f2eSlogwang if (ret < 0)
4012bfe3f2eSlogwang return ret;
4022bfe3f2eSlogwang ret = fs_remove_sub_devices_definition(mut_params);
4032bfe3f2eSlogwang if (ret < 0)
4042bfe3f2eSlogwang return ret;
4052bfe3f2eSlogwang if (strnlen(mut_params, sizeof(mut_params)) > 0) {
4062bfe3f2eSlogwang kvlist = rte_kvargs_parse(mut_params,
4072bfe3f2eSlogwang pmd_failsafe_init_parameters);
4082bfe3f2eSlogwang if (kvlist == NULL) {
4092bfe3f2eSlogwang ERROR("Error parsing parameters, usage:\n"
4102bfe3f2eSlogwang PMD_FAILSAFE_PARAM_STRING);
4112bfe3f2eSlogwang return -1;
4122bfe3f2eSlogwang }
4132bfe3f2eSlogwang /* PLUG_IN event poll timer */
4142bfe3f2eSlogwang arg_count = rte_kvargs_count(kvlist,
4152bfe3f2eSlogwang PMD_FAILSAFE_HOTPLUG_POLL_KVARG);
4162bfe3f2eSlogwang if (arg_count == 1) {
4172bfe3f2eSlogwang ret = rte_kvargs_process(kvlist,
4182bfe3f2eSlogwang PMD_FAILSAFE_HOTPLUG_POLL_KVARG,
419d30ea906Sjfb8856606 &fs_get_u64_arg, &failsafe_hotplug_poll);
4202bfe3f2eSlogwang if (ret < 0)
4212bfe3f2eSlogwang goto free_kvlist;
4222bfe3f2eSlogwang }
4232bfe3f2eSlogwang /* MAC addr */
4242bfe3f2eSlogwang arg_count = rte_kvargs_count(kvlist,
4252bfe3f2eSlogwang PMD_FAILSAFE_MAC_KVARG);
4262bfe3f2eSlogwang if (arg_count > 0) {
4272bfe3f2eSlogwang ret = rte_kvargs_process(kvlist,
4282bfe3f2eSlogwang PMD_FAILSAFE_MAC_KVARG,
4292bfe3f2eSlogwang &fs_get_mac_addr_arg,
4302bfe3f2eSlogwang &dev->data->mac_addrs[0]);
4312bfe3f2eSlogwang if (ret < 0)
4322bfe3f2eSlogwang goto free_kvlist;
4332bfe3f2eSlogwang
434d30ea906Sjfb8856606 failsafe_mac_from_arg = 1;
4352bfe3f2eSlogwang }
4362bfe3f2eSlogwang }
4372bfe3f2eSlogwang PRIV(dev)->state = DEV_PARSED;
4382bfe3f2eSlogwang free_kvlist:
4392bfe3f2eSlogwang rte_kvargs_free(kvlist);
4402bfe3f2eSlogwang return ret;
4412bfe3f2eSlogwang }
4422bfe3f2eSlogwang
4432bfe3f2eSlogwang void
failsafe_args_free(struct rte_eth_dev * dev)4442bfe3f2eSlogwang failsafe_args_free(struct rte_eth_dev *dev)
4452bfe3f2eSlogwang {
4462bfe3f2eSlogwang struct sub_device *sdev;
4472bfe3f2eSlogwang uint8_t i;
4482bfe3f2eSlogwang
4492bfe3f2eSlogwang FOREACH_SUBDEV(sdev, i, dev) {
4502bfe3f2eSlogwang free(sdev->cmdline);
4512bfe3f2eSlogwang sdev->cmdline = NULL;
452d30ea906Sjfb8856606 free(sdev->fd_str);
453d30ea906Sjfb8856606 sdev->fd_str = NULL;
4542bfe3f2eSlogwang free(sdev->devargs.args);
4552bfe3f2eSlogwang sdev->devargs.args = NULL;
4562bfe3f2eSlogwang }
4572bfe3f2eSlogwang }
4582bfe3f2eSlogwang
4592bfe3f2eSlogwang static int
fs_count_device(struct rte_eth_dev * dev,const char * param,uint8_t head __rte_unused)4602bfe3f2eSlogwang fs_count_device(struct rte_eth_dev *dev, const char *param,
4612bfe3f2eSlogwang uint8_t head __rte_unused)
4622bfe3f2eSlogwang {
4632bfe3f2eSlogwang size_t b = 0;
4642bfe3f2eSlogwang
4652bfe3f2eSlogwang while (param[b] != '(' &&
4662bfe3f2eSlogwang param[b] != '\0')
4672bfe3f2eSlogwang b++;
4682bfe3f2eSlogwang if (strncmp(param, "dev", b) != 0 &&
469d30ea906Sjfb8856606 strncmp(param, "exec", b) != 0 &&
470d30ea906Sjfb8856606 strncmp(param, "fd(", b) != 0) {
4712bfe3f2eSlogwang ERROR("Unrecognized device type: %.*s", (int)b, param);
4722bfe3f2eSlogwang return -EINVAL;
4732bfe3f2eSlogwang }
4742bfe3f2eSlogwang PRIV(dev)->subs_tail += 1;
4752bfe3f2eSlogwang return 0;
4762bfe3f2eSlogwang }
4772bfe3f2eSlogwang
4782bfe3f2eSlogwang int
failsafe_args_count_subdevice(struct rte_eth_dev * dev,const char * params)4792bfe3f2eSlogwang failsafe_args_count_subdevice(struct rte_eth_dev *dev,
4802bfe3f2eSlogwang const char *params)
4812bfe3f2eSlogwang {
4822bfe3f2eSlogwang return fs_parse_sub_devices(fs_count_device,
4832bfe3f2eSlogwang dev, params);
4842bfe3f2eSlogwang }
4852bfe3f2eSlogwang
4862bfe3f2eSlogwang static int
fs_parse_sub_device(struct sub_device * sdev)4872bfe3f2eSlogwang fs_parse_sub_device(struct sub_device *sdev)
4882bfe3f2eSlogwang {
4892bfe3f2eSlogwang struct rte_devargs *da;
4902bfe3f2eSlogwang char devstr[DEVARGS_MAXLEN] = "";
4912bfe3f2eSlogwang
4922bfe3f2eSlogwang da = &sdev->devargs;
4932bfe3f2eSlogwang snprintf(devstr, sizeof(devstr), "%s,%s", da->name, da->args);
4942bfe3f2eSlogwang return fs_parse_device(sdev, devstr);
4952bfe3f2eSlogwang }
4962bfe3f2eSlogwang
4972bfe3f2eSlogwang int
failsafe_args_parse_subs(struct rte_eth_dev * dev)4982bfe3f2eSlogwang failsafe_args_parse_subs(struct rte_eth_dev *dev)
4992bfe3f2eSlogwang {
5002bfe3f2eSlogwang struct sub_device *sdev;
5012bfe3f2eSlogwang uint8_t i;
5022bfe3f2eSlogwang int ret = 0;
5032bfe3f2eSlogwang
5042bfe3f2eSlogwang FOREACH_SUBDEV(sdev, i, dev) {
5052bfe3f2eSlogwang if (sdev->state >= DEV_PARSED)
5062bfe3f2eSlogwang continue;
5072bfe3f2eSlogwang if (sdev->cmdline)
5082bfe3f2eSlogwang ret = fs_execute_cmd(sdev, sdev->cmdline);
509d30ea906Sjfb8856606 else if (sdev->fd_str)
510d30ea906Sjfb8856606 ret = fs_read_fd(sdev, sdev->fd_str);
5112bfe3f2eSlogwang else
5122bfe3f2eSlogwang ret = fs_parse_sub_device(sdev);
5132bfe3f2eSlogwang if (ret == 0)
5142bfe3f2eSlogwang sdev->state = DEV_PARSED;
5152bfe3f2eSlogwang }
5162bfe3f2eSlogwang return 0;
5172bfe3f2eSlogwang }
518