1a46f8d58SGaetan Rivet /*- 2a46f8d58SGaetan Rivet * BSD LICENSE 3a46f8d58SGaetan Rivet * 4a46f8d58SGaetan Rivet * Copyright 2017 6WIND S.A. 5a46f8d58SGaetan Rivet * Copyright 2017 Mellanox. 6a46f8d58SGaetan Rivet * 7a46f8d58SGaetan Rivet * Redistribution and use in source and binary forms, with or without 8a46f8d58SGaetan Rivet * modification, are permitted provided that the following conditions 9a46f8d58SGaetan Rivet * are met: 10a46f8d58SGaetan Rivet * 11a46f8d58SGaetan Rivet * * Redistributions of source code must retain the above copyright 12a46f8d58SGaetan Rivet * notice, this list of conditions and the following disclaimer. 13a46f8d58SGaetan Rivet * * Redistributions in binary form must reproduce the above copyright 14a46f8d58SGaetan Rivet * notice, this list of conditions and the following disclaimer in 15a46f8d58SGaetan Rivet * the documentation and/or other materials provided with the 16a46f8d58SGaetan Rivet * distribution. 17a46f8d58SGaetan Rivet * * Neither the name of 6WIND S.A. nor the names of its 18a46f8d58SGaetan Rivet * contributors may be used to endorse or promote products derived 19a46f8d58SGaetan Rivet * from this software without specific prior written permission. 20a46f8d58SGaetan Rivet * 21a46f8d58SGaetan Rivet * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22a46f8d58SGaetan Rivet * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23a46f8d58SGaetan Rivet * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24a46f8d58SGaetan Rivet * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25a46f8d58SGaetan Rivet * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26a46f8d58SGaetan Rivet * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27a46f8d58SGaetan Rivet * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28a46f8d58SGaetan Rivet * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29a46f8d58SGaetan Rivet * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30a46f8d58SGaetan Rivet * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31a46f8d58SGaetan Rivet * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32a46f8d58SGaetan Rivet */ 33a46f8d58SGaetan Rivet 34*d1b961dbSMatan Azrad #include <fcntl.h> 35*d1b961dbSMatan Azrad #include <stdio.h> 36*d1b961dbSMatan Azrad #include <stdlib.h> 37a46f8d58SGaetan Rivet #include <string.h> 38*d1b961dbSMatan Azrad #include <unistd.h> 39ebea83f8SGaetan Rivet #include <errno.h> 40a46f8d58SGaetan Rivet 41a0194d82SGaetan Rivet #include <rte_debug.h> 42a46f8d58SGaetan Rivet #include <rte_devargs.h> 43a46f8d58SGaetan Rivet #include <rte_malloc.h> 44a46f8d58SGaetan Rivet #include <rte_kvargs.h> 45a46f8d58SGaetan Rivet 46a46f8d58SGaetan Rivet #include "failsafe_private.h" 47a46f8d58SGaetan Rivet 48a46f8d58SGaetan Rivet #define DEVARGS_MAXLEN 4096 49a46f8d58SGaetan Rivet 50a46f8d58SGaetan Rivet /* Callback used when a new device is found in devargs */ 51a46f8d58SGaetan Rivet typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params, 52a46f8d58SGaetan Rivet uint8_t head); 53a46f8d58SGaetan Rivet 54ebea83f8SGaetan Rivet uint64_t hotplug_poll = FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS; 55a46f8d58SGaetan Rivet int mac_from_arg = 0; 56a46f8d58SGaetan Rivet 57a46f8d58SGaetan Rivet const char *pmd_failsafe_init_parameters[] = { 58ebea83f8SGaetan Rivet PMD_FAILSAFE_HOTPLUG_POLL_KVARG, 59a46f8d58SGaetan Rivet PMD_FAILSAFE_MAC_KVARG, 60a46f8d58SGaetan Rivet NULL, 61a46f8d58SGaetan Rivet }; 62a46f8d58SGaetan Rivet 63a46f8d58SGaetan Rivet /* 64a46f8d58SGaetan Rivet * input: text. 65a46f8d58SGaetan Rivet * output: 0: if text[0] != '(', 66a46f8d58SGaetan Rivet * 0: if there are no corresponding ')' 67a46f8d58SGaetan Rivet * n: distance to corresponding ')' otherwise 68a46f8d58SGaetan Rivet */ 69a46f8d58SGaetan Rivet static size_t 70a46f8d58SGaetan Rivet closing_paren(const char *text) 71a46f8d58SGaetan Rivet { 72a46f8d58SGaetan Rivet int nb_open = 0; 73a46f8d58SGaetan Rivet size_t i = 0; 74a46f8d58SGaetan Rivet 75a46f8d58SGaetan Rivet while (text[i] != '\0') { 76a46f8d58SGaetan Rivet if (text[i] == '(') 77a46f8d58SGaetan Rivet nb_open++; 78a46f8d58SGaetan Rivet if (text[i] == ')') 79a46f8d58SGaetan Rivet nb_open--; 80a46f8d58SGaetan Rivet if (nb_open == 0) 81a46f8d58SGaetan Rivet return i; 82a46f8d58SGaetan Rivet i++; 83a46f8d58SGaetan Rivet } 84a46f8d58SGaetan Rivet return 0; 85a46f8d58SGaetan Rivet } 86a46f8d58SGaetan Rivet 87a46f8d58SGaetan Rivet static int 88a46f8d58SGaetan Rivet fs_parse_device(struct sub_device *sdev, char *args) 89a46f8d58SGaetan Rivet { 90a46f8d58SGaetan Rivet struct rte_devargs *d; 91a46f8d58SGaetan Rivet int ret; 92a46f8d58SGaetan Rivet 93a46f8d58SGaetan Rivet d = &sdev->devargs; 94a46f8d58SGaetan Rivet DEBUG("%s", args); 95a46f8d58SGaetan Rivet ret = rte_eal_devargs_parse(args, d); 96a46f8d58SGaetan Rivet if (ret) { 97a46f8d58SGaetan Rivet DEBUG("devargs parsing failed with code %d", ret); 98a46f8d58SGaetan Rivet return ret; 99a46f8d58SGaetan Rivet } 100a46f8d58SGaetan Rivet sdev->bus = d->bus; 101a46f8d58SGaetan Rivet sdev->state = DEV_PARSED; 102a46f8d58SGaetan Rivet return 0; 103a46f8d58SGaetan Rivet } 104a46f8d58SGaetan Rivet 105a0194d82SGaetan Rivet static void 106a0194d82SGaetan Rivet fs_sanitize_cmdline(char *args) 107a0194d82SGaetan Rivet { 10879da7b91SGaetan Rivet char *nl; 109a0194d82SGaetan Rivet 11079da7b91SGaetan Rivet nl = strrchr(args, '\n'); 11179da7b91SGaetan Rivet if (nl) 11279da7b91SGaetan Rivet nl[0] = '\0'; 113a0194d82SGaetan Rivet } 114a0194d82SGaetan Rivet 115a0194d82SGaetan Rivet static int 116a0194d82SGaetan Rivet fs_execute_cmd(struct sub_device *sdev, char *cmdline) 117a0194d82SGaetan Rivet { 118a0194d82SGaetan Rivet FILE *fp; 119a0194d82SGaetan Rivet /* store possible newline as well */ 120a0194d82SGaetan Rivet char output[DEVARGS_MAXLEN + 1]; 121a0194d82SGaetan Rivet size_t len; 1224853f2beSGaetan Rivet int ret; 123a0194d82SGaetan Rivet 124a0194d82SGaetan Rivet RTE_ASSERT(cmdline != NULL || sdev->cmdline != NULL); 125a0194d82SGaetan Rivet if (sdev->cmdline == NULL) { 126a0194d82SGaetan Rivet size_t i; 127a0194d82SGaetan Rivet 128a0194d82SGaetan Rivet len = strlen(cmdline) + 1; 129a0194d82SGaetan Rivet sdev->cmdline = calloc(1, len); 130a0194d82SGaetan Rivet if (sdev->cmdline == NULL) { 131a0194d82SGaetan Rivet ERROR("Command line allocation failed"); 132a0194d82SGaetan Rivet return -ENOMEM; 133a0194d82SGaetan Rivet } 134a0194d82SGaetan Rivet snprintf(sdev->cmdline, len, "%s", cmdline); 135a0194d82SGaetan Rivet /* Replace all commas in the command line by spaces */ 136a0194d82SGaetan Rivet for (i = 0; i < len; i++) 137a0194d82SGaetan Rivet if (sdev->cmdline[i] == ',') 138a0194d82SGaetan Rivet sdev->cmdline[i] = ' '; 139a0194d82SGaetan Rivet } 140a0194d82SGaetan Rivet DEBUG("'%s'", sdev->cmdline); 141a0194d82SGaetan Rivet fp = popen(sdev->cmdline, "r"); 142a0194d82SGaetan Rivet if (fp == NULL) { 1434853f2beSGaetan Rivet ret = -errno; 144a0194d82SGaetan Rivet ERROR("popen: %s", strerror(errno)); 145a0194d82SGaetan Rivet return ret; 146a0194d82SGaetan Rivet } 147a0194d82SGaetan Rivet /* We only read one line */ 148a0194d82SGaetan Rivet if (fgets(output, sizeof(output) - 1, fp) == NULL) { 149a0194d82SGaetan Rivet DEBUG("Could not read command output"); 15035ffe420SRaslan Darawsheh ret = -ENODEV; 15135ffe420SRaslan Darawsheh goto ret_pclose; 152a0194d82SGaetan Rivet } 153a0194d82SGaetan Rivet fs_sanitize_cmdline(output); 15479da7b91SGaetan Rivet if (output[0] == '\0') { 15579da7b91SGaetan Rivet ret = -ENODEV; 15679da7b91SGaetan Rivet goto ret_pclose; 15779da7b91SGaetan Rivet } 158a0194d82SGaetan Rivet ret = fs_parse_device(sdev, output); 1594853f2beSGaetan Rivet if (ret) 160a0194d82SGaetan Rivet ERROR("Parsing device '%s' failed", output); 161a0194d82SGaetan Rivet ret_pclose: 1624853f2beSGaetan Rivet if (pclose(fp) == -1) 163a0194d82SGaetan Rivet ERROR("pclose: %s", strerror(errno)); 164a0194d82SGaetan Rivet return ret; 165a0194d82SGaetan Rivet } 166a0194d82SGaetan Rivet 167a46f8d58SGaetan Rivet static int 168*d1b961dbSMatan Azrad fs_read_fd(struct sub_device *sdev, char *fd_str) 169*d1b961dbSMatan Azrad { 170*d1b961dbSMatan Azrad FILE *fp = NULL; 171*d1b961dbSMatan Azrad int fd = -1; 172*d1b961dbSMatan Azrad /* store possible newline as well */ 173*d1b961dbSMatan Azrad char output[DEVARGS_MAXLEN + 1]; 174*d1b961dbSMatan Azrad int err = -ENODEV; 175*d1b961dbSMatan Azrad int oflags; 176*d1b961dbSMatan Azrad int lcount; 177*d1b961dbSMatan Azrad 178*d1b961dbSMatan Azrad RTE_ASSERT(fd_str != NULL || sdev->fd_str != NULL); 179*d1b961dbSMatan Azrad if (sdev->fd_str == NULL) { 180*d1b961dbSMatan Azrad sdev->fd_str = strdup(fd_str); 181*d1b961dbSMatan Azrad if (sdev->fd_str == NULL) { 182*d1b961dbSMatan Azrad ERROR("Command line allocation failed"); 183*d1b961dbSMatan Azrad return -ENOMEM; 184*d1b961dbSMatan Azrad } 185*d1b961dbSMatan Azrad } 186*d1b961dbSMatan Azrad errno = 0; 187*d1b961dbSMatan Azrad fd = strtol(fd_str, &fd_str, 0); 188*d1b961dbSMatan Azrad if (errno || *fd_str || fd < 0) { 189*d1b961dbSMatan Azrad ERROR("Parsing FD number failed"); 190*d1b961dbSMatan Azrad goto error; 191*d1b961dbSMatan Azrad } 192*d1b961dbSMatan Azrad /* Fiddle with copy of file descriptor */ 193*d1b961dbSMatan Azrad fd = dup(fd); 194*d1b961dbSMatan Azrad if (fd == -1) 195*d1b961dbSMatan Azrad goto error; 196*d1b961dbSMatan Azrad oflags = fcntl(fd, F_GETFL); 197*d1b961dbSMatan Azrad if (oflags == -1) 198*d1b961dbSMatan Azrad goto error; 199*d1b961dbSMatan Azrad if (fcntl(fd, F_SETFL, oflags | O_NONBLOCK) == -1) 200*d1b961dbSMatan Azrad goto error; 201*d1b961dbSMatan Azrad fp = fdopen(fd, "r"); 202*d1b961dbSMatan Azrad if (fp == NULL) 203*d1b961dbSMatan Azrad goto error; 204*d1b961dbSMatan Azrad fd = -1; 205*d1b961dbSMatan Azrad /* Only take the last line into account */ 206*d1b961dbSMatan Azrad lcount = 0; 207*d1b961dbSMatan Azrad while (fgets(output, sizeof(output), fp)) 208*d1b961dbSMatan Azrad ++lcount; 209*d1b961dbSMatan Azrad if (lcount == 0) 210*d1b961dbSMatan Azrad goto error; 211*d1b961dbSMatan Azrad else if (ferror(fp) && errno != EAGAIN) 212*d1b961dbSMatan Azrad goto error; 213*d1b961dbSMatan Azrad /* Line must end with a newline character */ 214*d1b961dbSMatan Azrad fs_sanitize_cmdline(output); 215*d1b961dbSMatan Azrad if (output[0] == '\0') 216*d1b961dbSMatan Azrad goto error; 217*d1b961dbSMatan Azrad err = fs_parse_device(sdev, output); 218*d1b961dbSMatan Azrad if (err) 219*d1b961dbSMatan Azrad ERROR("Parsing device '%s' failed", output); 220*d1b961dbSMatan Azrad error: 221*d1b961dbSMatan Azrad if (fp) 222*d1b961dbSMatan Azrad fclose(fp); 223*d1b961dbSMatan Azrad if (fd != -1) 224*d1b961dbSMatan Azrad close(fd); 225*d1b961dbSMatan Azrad return err; 226*d1b961dbSMatan Azrad } 227*d1b961dbSMatan Azrad 228*d1b961dbSMatan Azrad static int 229a46f8d58SGaetan Rivet fs_parse_device_param(struct rte_eth_dev *dev, const char *param, 230a46f8d58SGaetan Rivet uint8_t head) 231a46f8d58SGaetan Rivet { 232a46f8d58SGaetan Rivet struct fs_priv *priv; 233a46f8d58SGaetan Rivet struct sub_device *sdev; 234a46f8d58SGaetan Rivet char *args = NULL; 235a46f8d58SGaetan Rivet size_t a, b; 236a46f8d58SGaetan Rivet int ret; 237a46f8d58SGaetan Rivet 238a46f8d58SGaetan Rivet priv = PRIV(dev); 239a46f8d58SGaetan Rivet a = 0; 240a46f8d58SGaetan Rivet b = 0; 241a46f8d58SGaetan Rivet ret = 0; 242a46f8d58SGaetan Rivet while (param[b] != '(' && 243a46f8d58SGaetan Rivet param[b] != '\0') 244a46f8d58SGaetan Rivet b++; 245a46f8d58SGaetan Rivet a = b; 246a46f8d58SGaetan Rivet b += closing_paren(¶m[b]); 247a46f8d58SGaetan Rivet if (a == b) { 248a46f8d58SGaetan Rivet ERROR("Dangling parenthesis"); 249a46f8d58SGaetan Rivet return -EINVAL; 250a46f8d58SGaetan Rivet } 251a46f8d58SGaetan Rivet a += 1; 252a46f8d58SGaetan Rivet args = strndup(¶m[a], b - a); 253a46f8d58SGaetan Rivet if (args == NULL) { 254a46f8d58SGaetan Rivet ERROR("Not enough memory for parameter parsing"); 255a46f8d58SGaetan Rivet return -ENOMEM; 256a46f8d58SGaetan Rivet } 257a46f8d58SGaetan Rivet sdev = &priv->subs[head]; 258a46f8d58SGaetan Rivet if (strncmp(param, "dev", 3) == 0) { 259a46f8d58SGaetan Rivet ret = fs_parse_device(sdev, args); 260a46f8d58SGaetan Rivet if (ret) 261a46f8d58SGaetan Rivet goto free_args; 262a0194d82SGaetan Rivet } else if (strncmp(param, "exec", 4) == 0) { 263a0194d82SGaetan Rivet ret = fs_execute_cmd(sdev, args); 264a0194d82SGaetan Rivet if (ret == -ENODEV) { 265a0194d82SGaetan Rivet DEBUG("Reading device info from command line failed"); 266a0194d82SGaetan Rivet ret = 0; 267a0194d82SGaetan Rivet } 268a0194d82SGaetan Rivet if (ret) 269a0194d82SGaetan Rivet goto free_args; 270*d1b961dbSMatan Azrad } else if (strncmp(param, "fd(", 3) == 0) { 271*d1b961dbSMatan Azrad ret = fs_read_fd(sdev, args); 272*d1b961dbSMatan Azrad if (ret == -ENODEV) { 273*d1b961dbSMatan Azrad DEBUG("Reading device info from FD failed"); 274*d1b961dbSMatan Azrad ret = 0; 275*d1b961dbSMatan Azrad } 276*d1b961dbSMatan Azrad if (ret) 277*d1b961dbSMatan Azrad goto free_args; 278a46f8d58SGaetan Rivet } else { 279a46f8d58SGaetan Rivet ERROR("Unrecognized device type: %.*s", (int)b, param); 280a46f8d58SGaetan Rivet return -EINVAL; 281a46f8d58SGaetan Rivet } 282a46f8d58SGaetan Rivet free_args: 283a46f8d58SGaetan Rivet free(args); 284a46f8d58SGaetan Rivet return ret; 285a46f8d58SGaetan Rivet } 286a46f8d58SGaetan Rivet 287a46f8d58SGaetan Rivet static int 288a46f8d58SGaetan Rivet fs_parse_sub_devices(parse_cb *cb, 289a46f8d58SGaetan Rivet struct rte_eth_dev *dev, const char *params) 290a46f8d58SGaetan Rivet { 291a46f8d58SGaetan Rivet size_t a, b; 292a46f8d58SGaetan Rivet uint8_t head; 293a46f8d58SGaetan Rivet int ret; 294a46f8d58SGaetan Rivet 295a46f8d58SGaetan Rivet a = 0; 296a46f8d58SGaetan Rivet head = 0; 297a46f8d58SGaetan Rivet ret = 0; 298a46f8d58SGaetan Rivet while (params[a] != '\0') { 299a46f8d58SGaetan Rivet b = a; 300a46f8d58SGaetan Rivet while (params[b] != '(' && 301a46f8d58SGaetan Rivet params[b] != ',' && 302a46f8d58SGaetan Rivet params[b] != '\0') 303a46f8d58SGaetan Rivet b++; 304a46f8d58SGaetan Rivet if (b == a) { 305a46f8d58SGaetan Rivet ERROR("Invalid parameter"); 306a46f8d58SGaetan Rivet return -EINVAL; 307a46f8d58SGaetan Rivet } 308a46f8d58SGaetan Rivet if (params[b] == ',') { 309a46f8d58SGaetan Rivet a = b + 1; 310a46f8d58SGaetan Rivet continue; 311a46f8d58SGaetan Rivet } 312a46f8d58SGaetan Rivet if (params[b] == '(') { 313a46f8d58SGaetan Rivet size_t start = b; 314a46f8d58SGaetan Rivet 315a46f8d58SGaetan Rivet b += closing_paren(¶ms[b]); 316a46f8d58SGaetan Rivet if (b == start) { 317a46f8d58SGaetan Rivet ERROR("Dangling parenthesis"); 318a46f8d58SGaetan Rivet return -EINVAL; 319a46f8d58SGaetan Rivet } 320a46f8d58SGaetan Rivet ret = (*cb)(dev, ¶ms[a], head); 321a46f8d58SGaetan Rivet if (ret) 322a46f8d58SGaetan Rivet return ret; 323a46f8d58SGaetan Rivet head += 1; 324a46f8d58SGaetan Rivet b += 1; 325a46f8d58SGaetan Rivet if (params[b] == '\0') 326a46f8d58SGaetan Rivet return 0; 327a46f8d58SGaetan Rivet } 328a46f8d58SGaetan Rivet a = b + 1; 329a46f8d58SGaetan Rivet } 330a46f8d58SGaetan Rivet return 0; 331a46f8d58SGaetan Rivet } 332a46f8d58SGaetan Rivet 333a46f8d58SGaetan Rivet static int 334a46f8d58SGaetan Rivet fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN]) 335a46f8d58SGaetan Rivet { 336a46f8d58SGaetan Rivet char buffer[DEVARGS_MAXLEN] = {0}; 337a46f8d58SGaetan Rivet size_t a, b; 338a46f8d58SGaetan Rivet int i; 339a46f8d58SGaetan Rivet 340a46f8d58SGaetan Rivet a = 0; 341a46f8d58SGaetan Rivet i = 0; 342a46f8d58SGaetan Rivet while (params[a] != '\0') { 343a46f8d58SGaetan Rivet b = a; 344a46f8d58SGaetan Rivet while (params[b] != '(' && 345a46f8d58SGaetan Rivet params[b] != ',' && 346a46f8d58SGaetan Rivet params[b] != '\0') 347a46f8d58SGaetan Rivet b++; 348a46f8d58SGaetan Rivet if (b == a) { 349a46f8d58SGaetan Rivet ERROR("Invalid parameter"); 350a46f8d58SGaetan Rivet return -EINVAL; 351a46f8d58SGaetan Rivet } 352852be652SMatan Azrad if (params[b] == ',' || params[b] == '\0') { 353852be652SMatan Azrad size_t len = b - a; 354852be652SMatan Azrad 355852be652SMatan Azrad if (i > 0) 356852be652SMatan Azrad len += 1; 357852be652SMatan Azrad snprintf(&buffer[i], len + 1, "%s%s", 358852be652SMatan Azrad i ? "," : "", ¶ms[a]); 359852be652SMatan Azrad i += len; 360852be652SMatan Azrad } else if (params[b] == '(') { 361a46f8d58SGaetan Rivet size_t start = b; 362852be652SMatan Azrad 363a46f8d58SGaetan Rivet b += closing_paren(¶ms[b]); 364a46f8d58SGaetan Rivet if (b == start) 365a46f8d58SGaetan Rivet return -EINVAL; 366a46f8d58SGaetan Rivet b += 1; 367a46f8d58SGaetan Rivet if (params[b] == '\0') 368a46f8d58SGaetan Rivet goto out; 369a46f8d58SGaetan Rivet } 370a46f8d58SGaetan Rivet a = b + 1; 371a46f8d58SGaetan Rivet } 372a46f8d58SGaetan Rivet out: 373a46f8d58SGaetan Rivet snprintf(params, DEVARGS_MAXLEN, "%s", buffer); 374a46f8d58SGaetan Rivet return 0; 375a46f8d58SGaetan Rivet } 376a46f8d58SGaetan Rivet 377a46f8d58SGaetan Rivet static int 378ebea83f8SGaetan Rivet fs_get_u64_arg(const char *key __rte_unused, 379ebea83f8SGaetan Rivet const char *value, void *out) 380ebea83f8SGaetan Rivet { 381ebea83f8SGaetan Rivet uint64_t *u64 = out; 382ebea83f8SGaetan Rivet char *endptr = NULL; 383ebea83f8SGaetan Rivet 384ebea83f8SGaetan Rivet if ((value == NULL) || (out == NULL)) 385ebea83f8SGaetan Rivet return -EINVAL; 386ebea83f8SGaetan Rivet errno = 0; 387ebea83f8SGaetan Rivet *u64 = strtoull(value, &endptr, 0); 388ebea83f8SGaetan Rivet if (errno != 0) 389ebea83f8SGaetan Rivet return -errno; 390ebea83f8SGaetan Rivet if (endptr == value) 391ebea83f8SGaetan Rivet return -1; 392ebea83f8SGaetan Rivet return 0; 393ebea83f8SGaetan Rivet } 394ebea83f8SGaetan Rivet 395ebea83f8SGaetan Rivet static int 396a46f8d58SGaetan Rivet fs_get_mac_addr_arg(const char *key __rte_unused, 397a46f8d58SGaetan Rivet const char *value, void *out) 398a46f8d58SGaetan Rivet { 399a46f8d58SGaetan Rivet struct ether_addr *ea = out; 400a46f8d58SGaetan Rivet int ret; 401a46f8d58SGaetan Rivet 402a46f8d58SGaetan Rivet if ((value == NULL) || (out == NULL)) 403a46f8d58SGaetan Rivet return -EINVAL; 404a46f8d58SGaetan Rivet ret = sscanf(value, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 405a46f8d58SGaetan Rivet &ea->addr_bytes[0], &ea->addr_bytes[1], 406a46f8d58SGaetan Rivet &ea->addr_bytes[2], &ea->addr_bytes[3], 407a46f8d58SGaetan Rivet &ea->addr_bytes[4], &ea->addr_bytes[5]); 408a46f8d58SGaetan Rivet return ret != ETHER_ADDR_LEN; 409a46f8d58SGaetan Rivet } 410a46f8d58SGaetan Rivet 411a46f8d58SGaetan Rivet int 412a46f8d58SGaetan Rivet failsafe_args_parse(struct rte_eth_dev *dev, const char *params) 413a46f8d58SGaetan Rivet { 414a46f8d58SGaetan Rivet struct fs_priv *priv; 415a46f8d58SGaetan Rivet char mut_params[DEVARGS_MAXLEN] = ""; 416a46f8d58SGaetan Rivet struct rte_kvargs *kvlist = NULL; 417a46f8d58SGaetan Rivet unsigned int arg_count; 418a46f8d58SGaetan Rivet size_t n; 419a46f8d58SGaetan Rivet int ret; 420a46f8d58SGaetan Rivet 421a46f8d58SGaetan Rivet priv = PRIV(dev); 422a46f8d58SGaetan Rivet ret = 0; 423a46f8d58SGaetan Rivet priv->subs_tx = FAILSAFE_MAX_ETHPORTS; 424a46f8d58SGaetan Rivet /* default parameters */ 425a46f8d58SGaetan Rivet n = snprintf(mut_params, sizeof(mut_params), "%s", params); 426a46f8d58SGaetan Rivet if (n >= sizeof(mut_params)) { 427a46f8d58SGaetan Rivet ERROR("Parameter string too long (>=%zu)", 428a46f8d58SGaetan Rivet sizeof(mut_params)); 429a46f8d58SGaetan Rivet return -ENOMEM; 430a46f8d58SGaetan Rivet } 431a46f8d58SGaetan Rivet ret = fs_parse_sub_devices(fs_parse_device_param, 432a46f8d58SGaetan Rivet dev, params); 433a46f8d58SGaetan Rivet if (ret < 0) 434a46f8d58SGaetan Rivet return ret; 435a46f8d58SGaetan Rivet ret = fs_remove_sub_devices_definition(mut_params); 436a46f8d58SGaetan Rivet if (ret < 0) 437a46f8d58SGaetan Rivet return ret; 438a46f8d58SGaetan Rivet if (strnlen(mut_params, sizeof(mut_params)) > 0) { 439a46f8d58SGaetan Rivet kvlist = rte_kvargs_parse(mut_params, 440a46f8d58SGaetan Rivet pmd_failsafe_init_parameters); 441a46f8d58SGaetan Rivet if (kvlist == NULL) { 442a46f8d58SGaetan Rivet ERROR("Error parsing parameters, usage:\n" 443a46f8d58SGaetan Rivet PMD_FAILSAFE_PARAM_STRING); 444a46f8d58SGaetan Rivet return -1; 445a46f8d58SGaetan Rivet } 446ebea83f8SGaetan Rivet /* PLUG_IN event poll timer */ 447ebea83f8SGaetan Rivet arg_count = rte_kvargs_count(kvlist, 448ebea83f8SGaetan Rivet PMD_FAILSAFE_HOTPLUG_POLL_KVARG); 449ebea83f8SGaetan Rivet if (arg_count == 1) { 450ebea83f8SGaetan Rivet ret = rte_kvargs_process(kvlist, 451ebea83f8SGaetan Rivet PMD_FAILSAFE_HOTPLUG_POLL_KVARG, 452ebea83f8SGaetan Rivet &fs_get_u64_arg, &hotplug_poll); 453ebea83f8SGaetan Rivet if (ret < 0) 454ebea83f8SGaetan Rivet goto free_kvlist; 455ebea83f8SGaetan Rivet } 456a46f8d58SGaetan Rivet /* MAC addr */ 457a46f8d58SGaetan Rivet arg_count = rte_kvargs_count(kvlist, 458a46f8d58SGaetan Rivet PMD_FAILSAFE_MAC_KVARG); 459a46f8d58SGaetan Rivet if (arg_count > 0) { 460a46f8d58SGaetan Rivet ret = rte_kvargs_process(kvlist, 461a46f8d58SGaetan Rivet PMD_FAILSAFE_MAC_KVARG, 462a46f8d58SGaetan Rivet &fs_get_mac_addr_arg, 463a46f8d58SGaetan Rivet &dev->data->mac_addrs[0]); 464a46f8d58SGaetan Rivet if (ret < 0) 465a46f8d58SGaetan Rivet goto free_kvlist; 466852be652SMatan Azrad 467a46f8d58SGaetan Rivet mac_from_arg = 1; 468a46f8d58SGaetan Rivet } 469a46f8d58SGaetan Rivet } 470ebea83f8SGaetan Rivet PRIV(dev)->state = DEV_PARSED; 471a46f8d58SGaetan Rivet free_kvlist: 472a46f8d58SGaetan Rivet rte_kvargs_free(kvlist); 473a46f8d58SGaetan Rivet return ret; 474a46f8d58SGaetan Rivet } 475a46f8d58SGaetan Rivet 476a46f8d58SGaetan Rivet void 477a46f8d58SGaetan Rivet failsafe_args_free(struct rte_eth_dev *dev) 478a46f8d58SGaetan Rivet { 479a46f8d58SGaetan Rivet struct sub_device *sdev; 480a46f8d58SGaetan Rivet uint8_t i; 481a46f8d58SGaetan Rivet 482a46f8d58SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 4839720e325SAdrien Mazarguil free(sdev->cmdline); 484a0194d82SGaetan Rivet sdev->cmdline = NULL; 485*d1b961dbSMatan Azrad free(sdev->fd_str); 486*d1b961dbSMatan Azrad sdev->fd_str = NULL; 487a46f8d58SGaetan Rivet free(sdev->devargs.args); 488a46f8d58SGaetan Rivet sdev->devargs.args = NULL; 489a46f8d58SGaetan Rivet } 490a46f8d58SGaetan Rivet } 491a46f8d58SGaetan Rivet 492a46f8d58SGaetan Rivet static int 493a46f8d58SGaetan Rivet fs_count_device(struct rte_eth_dev *dev, const char *param, 494a46f8d58SGaetan Rivet uint8_t head __rte_unused) 495a46f8d58SGaetan Rivet { 496a46f8d58SGaetan Rivet size_t b = 0; 497a46f8d58SGaetan Rivet 498a46f8d58SGaetan Rivet while (param[b] != '(' && 499a46f8d58SGaetan Rivet param[b] != '\0') 500a46f8d58SGaetan Rivet b++; 501a0194d82SGaetan Rivet if (strncmp(param, "dev", b) != 0 && 502*d1b961dbSMatan Azrad strncmp(param, "exec", b) != 0 && 503*d1b961dbSMatan Azrad strncmp(param, "fd(", b) != 0) { 504a46f8d58SGaetan Rivet ERROR("Unrecognized device type: %.*s", (int)b, param); 505a46f8d58SGaetan Rivet return -EINVAL; 506a46f8d58SGaetan Rivet } 507a46f8d58SGaetan Rivet PRIV(dev)->subs_tail += 1; 508a46f8d58SGaetan Rivet return 0; 509a46f8d58SGaetan Rivet } 510a46f8d58SGaetan Rivet 511a46f8d58SGaetan Rivet int 512a46f8d58SGaetan Rivet failsafe_args_count_subdevice(struct rte_eth_dev *dev, 513a46f8d58SGaetan Rivet const char *params) 514a46f8d58SGaetan Rivet { 515a46f8d58SGaetan Rivet return fs_parse_sub_devices(fs_count_device, 516a46f8d58SGaetan Rivet dev, params); 517a46f8d58SGaetan Rivet } 518a0194d82SGaetan Rivet 519598fb8aeSGaetan Rivet static int 520598fb8aeSGaetan Rivet fs_parse_sub_device(struct sub_device *sdev) 521598fb8aeSGaetan Rivet { 522598fb8aeSGaetan Rivet struct rte_devargs *da; 523598fb8aeSGaetan Rivet char devstr[DEVARGS_MAXLEN] = ""; 524598fb8aeSGaetan Rivet 525598fb8aeSGaetan Rivet da = &sdev->devargs; 526598fb8aeSGaetan Rivet snprintf(devstr, sizeof(devstr), "%s,%s", da->name, da->args); 527598fb8aeSGaetan Rivet return fs_parse_device(sdev, devstr); 528598fb8aeSGaetan Rivet } 529598fb8aeSGaetan Rivet 530a0194d82SGaetan Rivet int 531a0194d82SGaetan Rivet failsafe_args_parse_subs(struct rte_eth_dev *dev) 532a0194d82SGaetan Rivet { 533a0194d82SGaetan Rivet struct sub_device *sdev; 534a0194d82SGaetan Rivet uint8_t i; 535a0194d82SGaetan Rivet int ret = 0; 536a0194d82SGaetan Rivet 537a0194d82SGaetan Rivet FOREACH_SUBDEV(sdev, i, dev) { 538a0194d82SGaetan Rivet if (sdev->state >= DEV_PARSED) 539a0194d82SGaetan Rivet continue; 540a0194d82SGaetan Rivet if (sdev->cmdline) 541a0194d82SGaetan Rivet ret = fs_execute_cmd(sdev, sdev->cmdline); 542*d1b961dbSMatan Azrad else if (sdev->fd_str) 543*d1b961dbSMatan Azrad ret = fs_read_fd(sdev, sdev->fd_str); 544598fb8aeSGaetan Rivet else 545598fb8aeSGaetan Rivet ret = fs_parse_sub_device(sdev); 546a0194d82SGaetan Rivet if (ret == 0) 547a0194d82SGaetan Rivet sdev->state = DEV_PARSED; 548a0194d82SGaetan Rivet } 549a0194d82SGaetan Rivet return 0; 550a0194d82SGaetan Rivet } 551