1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2017 6WIND S.A.
3 * Copyright 2017 Mellanox Technologies, Ltd
13 #include <rte_debug.h>
14 #include <rte_devargs.h>
15 #include <rte_malloc.h>
16 #include <rte_kvargs.h>
17 #include <rte_string_fns.h>
19 #include "failsafe_private.h"
21 /* Callback used when a new device is found in devargs */
22 typedef int (parse_cb
)(struct rte_eth_dev
*dev
, const char *params
,
25 uint64_t failsafe_hotplug_poll
= FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS
;
26 int failsafe_mac_from_arg
;
28 static const char * const pmd_failsafe_init_parameters
[] = {
29 PMD_FAILSAFE_HOTPLUG_POLL_KVARG
,
30 PMD_FAILSAFE_MAC_KVARG
,
36 * output: 0: if text[0] != '(',
37 * 0: if there are no corresponding ')'
38 * n: distance to corresponding ')' otherwise
41 closing_paren(const char *text
)
46 while (text
[i
] != '\0') {
59 fs_parse_device(struct sub_device
*sdev
, char *args
)
61 struct rte_devargs
*d
;
66 ret
= rte_devargs_parse(d
, args
);
68 DEBUG("devargs parsing failed with code %d", ret
);
72 sdev
->state
= DEV_PARSED
;
77 fs_sanitize_cmdline(char *args
)
81 nl
= strrchr(args
, '\n');
87 fs_execute_cmd(struct sub_device
*sdev
, char *cmdline
)
90 /* store possible newline as well */
91 char output
[DEVARGS_MAXLEN
+ 1];
95 RTE_ASSERT(cmdline
!= NULL
|| sdev
->cmdline
!= NULL
);
96 if (sdev
->cmdline
== NULL
) {
99 len
= strlen(cmdline
) + 1;
100 sdev
->cmdline
= calloc(1, len
);
101 if (sdev
->cmdline
== NULL
) {
102 ERROR("Command line allocation failed");
105 strlcpy(sdev
->cmdline
, cmdline
, len
);
106 /* Replace all commas in the command line by spaces */
107 for (i
= 0; i
< len
; i
++)
108 if (sdev
->cmdline
[i
] == ',')
109 sdev
->cmdline
[i
] = ' ';
111 DEBUG("'%s'", sdev
->cmdline
);
112 fp
= popen(sdev
->cmdline
, "r");
115 ERROR("popen: %s", strerror(errno
));
118 /* We only read one line */
119 if (fgets(output
, sizeof(output
) - 1, fp
) == NULL
) {
120 DEBUG("Could not read command output");
124 fs_sanitize_cmdline(output
);
125 if (output
[0] == '\0') {
129 ret
= fs_parse_device(sdev
, output
);
131 ERROR("Parsing device '%s' failed", output
);
133 if (pclose(fp
) == -1)
134 ERROR("pclose: %s", strerror(errno
));
139 fs_read_fd(struct sub_device
*sdev
, char *fd_str
)
143 /* store possible newline as well */
144 char output
[DEVARGS_MAXLEN
+ 1];
149 RTE_ASSERT(fd_str
!= NULL
|| sdev
->fd_str
!= NULL
);
150 if (sdev
->fd_str
== NULL
) {
151 sdev
->fd_str
= strdup(fd_str
);
152 if (sdev
->fd_str
== NULL
) {
153 ERROR("Command line allocation failed");
158 fd
= strtol(fd_str
, &fd_str
, 0);
159 if (errno
|| *fd_str
|| fd
< 0) {
160 ERROR("Parsing FD number failed");
163 /* Fiddle with copy of file descriptor */
167 oflags
= fcntl(fd
, F_GETFL
);
170 if (fcntl(fd
, F_SETFL
, oflags
| O_NONBLOCK
) == -1)
172 fp
= fdopen(fd
, "r");
176 /* Only take the last line into account */
178 while (fgets(output
, sizeof(output
), fp
))
182 else if (ferror(fp
) && errno
!= EAGAIN
)
184 /* Line must end with a newline character */
185 fs_sanitize_cmdline(output
);
186 if (output
[0] == '\0')
188 err
= fs_parse_device(sdev
, output
);
190 ERROR("Parsing device '%s' failed", output
);
200 fs_parse_device_param(struct rte_eth_dev
*dev
, const char *param
,
203 struct fs_priv
*priv
;
204 struct sub_device
*sdev
;
213 while (param
[b
] != '(' &&
217 b
+= closing_paren(¶m
[b
]);
219 ERROR("Dangling parenthesis");
223 args
= strndup(¶m
[a
], b
- a
);
225 ERROR("Not enough memory for parameter parsing");
228 sdev
= &priv
->subs
[head
];
229 if (strncmp(param
, "dev", 3) == 0) {
230 ret
= fs_parse_device(sdev
, args
);
233 } else if (strncmp(param
, "exec", 4) == 0) {
234 ret
= fs_execute_cmd(sdev
, args
);
235 if (ret
== -ENODEV
) {
236 DEBUG("Reading device info from command line failed");
241 } else if (strncmp(param
, "fd(", 3) == 0) {
242 ret
= fs_read_fd(sdev
, args
);
243 if (ret
== -ENODEV
) {
244 DEBUG("Reading device info from FD failed");
250 ERROR("Unrecognized device type: %.*s", (int)b
, param
);
259 fs_parse_sub_devices(parse_cb
*cb
,
260 struct rte_eth_dev
*dev
, const char *params
)
269 while (params
[a
] != '\0') {
271 while (params
[b
] != '(' &&
276 ERROR("Invalid parameter");
279 if (params
[b
] == ',') {
283 if (params
[b
] == '(') {
286 b
+= closing_paren(¶ms
[b
]);
288 ERROR("Dangling parenthesis");
291 ret
= (*cb
)(dev
, ¶ms
[a
], head
);
296 if (params
[b
] == '\0')
305 fs_remove_sub_devices_definition(char params
[DEVARGS_MAXLEN
])
307 char buffer
[DEVARGS_MAXLEN
] = {0};
313 while (params
[a
] != '\0') {
315 while (params
[b
] != '(' &&
320 ERROR("Invalid parameter");
323 if (params
[b
] == ',' || params
[b
] == '\0') {
328 snprintf(&buffer
[i
], len
+ 1, "%s%s",
329 i
? "," : "", ¶ms
[a
]);
331 } else if (params
[b
] == '(') {
334 b
+= closing_paren(¶ms
[b
]);
338 if (params
[b
] == '\0')
344 strlcpy(params
, buffer
, DEVARGS_MAXLEN
);
349 fs_get_u64_arg(const char *key __rte_unused
,
350 const char *value
, void *out
)
355 if ((value
== NULL
) || (out
== NULL
))
358 *u64
= strtoull(value
, &endptr
, 0);
367 fs_get_mac_addr_arg(const char *key __rte_unused
,
368 const char *value
, void *out
)
370 struct ether_addr
*ea
= out
;
373 if ((value
== NULL
) || (out
== NULL
))
375 ret
= sscanf(value
, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
376 &ea
->addr_bytes
[0], &ea
->addr_bytes
[1],
377 &ea
->addr_bytes
[2], &ea
->addr_bytes
[3],
378 &ea
->addr_bytes
[4], &ea
->addr_bytes
[5]);
379 return ret
!= ETHER_ADDR_LEN
;
383 failsafe_args_parse(struct rte_eth_dev
*dev
, const char *params
)
385 struct fs_priv
*priv
;
386 char mut_params
[DEVARGS_MAXLEN
] = "";
387 struct rte_kvargs
*kvlist
= NULL
;
388 unsigned int arg_count
;
394 priv
->subs_tx
= FAILSAFE_MAX_ETHPORTS
;
395 /* default parameters */
396 n
= strlcpy(mut_params
, params
, sizeof(mut_params
));
397 if (n
>= sizeof(mut_params
)) {
398 ERROR("Parameter string too long (>=%zu)",
402 ret
= fs_parse_sub_devices(fs_parse_device_param
,
406 ret
= fs_remove_sub_devices_definition(mut_params
);
409 if (strnlen(mut_params
, sizeof(mut_params
)) > 0) {
410 kvlist
= rte_kvargs_parse(mut_params
,
411 pmd_failsafe_init_parameters
);
412 if (kvlist
== NULL
) {
413 ERROR("Error parsing parameters, usage:\n"
414 PMD_FAILSAFE_PARAM_STRING
);
417 /* PLUG_IN event poll timer */
418 arg_count
= rte_kvargs_count(kvlist
,
419 PMD_FAILSAFE_HOTPLUG_POLL_KVARG
);
420 if (arg_count
== 1) {
421 ret
= rte_kvargs_process(kvlist
,
422 PMD_FAILSAFE_HOTPLUG_POLL_KVARG
,
423 &fs_get_u64_arg
, &failsafe_hotplug_poll
);
428 arg_count
= rte_kvargs_count(kvlist
,
429 PMD_FAILSAFE_MAC_KVARG
);
431 ret
= rte_kvargs_process(kvlist
,
432 PMD_FAILSAFE_MAC_KVARG
,
433 &fs_get_mac_addr_arg
,
434 &dev
->data
->mac_addrs
[0]);
438 failsafe_mac_from_arg
= 1;
441 PRIV(dev
)->state
= DEV_PARSED
;
443 rte_kvargs_free(kvlist
);
448 failsafe_args_free(struct rte_eth_dev
*dev
)
450 struct sub_device
*sdev
;
453 FOREACH_SUBDEV(sdev
, i
, dev
) {
455 sdev
->cmdline
= NULL
;
458 free(sdev
->devargs
.args
);
459 sdev
->devargs
.args
= NULL
;
464 fs_count_device(struct rte_eth_dev
*dev
, const char *param
,
465 uint8_t head __rte_unused
)
469 while (param
[b
] != '(' &&
472 if (strncmp(param
, "dev", b
) != 0 &&
473 strncmp(param
, "exec", b
) != 0 &&
474 strncmp(param
, "fd(", b
) != 0) {
475 ERROR("Unrecognized device type: %.*s", (int)b
, param
);
478 PRIV(dev
)->subs_tail
+= 1;
483 failsafe_args_count_subdevice(struct rte_eth_dev
*dev
,
486 return fs_parse_sub_devices(fs_count_device
,
491 fs_parse_sub_device(struct sub_device
*sdev
)
493 struct rte_devargs
*da
;
494 char devstr
[DEVARGS_MAXLEN
] = "";
497 snprintf(devstr
, sizeof(devstr
), "%s,%s", da
->name
, da
->args
);
498 return fs_parse_device(sdev
, devstr
);
502 failsafe_args_parse_subs(struct rte_eth_dev
*dev
)
504 struct sub_device
*sdev
;
508 FOREACH_SUBDEV(sdev
, i
, dev
) {
509 if (sdev
->state
>= DEV_PARSED
)
512 ret
= fs_execute_cmd(sdev
, sdev
->cmdline
);
513 else if (sdev
->fd_str
)
514 ret
= fs_read_fd(sdev
, sdev
->fd_str
);
516 ret
= fs_parse_sub_device(sdev
);
518 sdev
->state
= DEV_PARSED
;