xref: /dpdk/drivers/net/vdev_netvsc/vdev_netvsc.c (revision 89f0711f9ddfb5822da9d34f384b92f72a61c4dc)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2017 6WIND S.A.
3  * Copyright 2017 Mellanox Technologies, Ltd.
4  */
5 
6 #include <errno.h>
7 #include <fcntl.h>
8 #include <inttypes.h>
9 #include <linux/sockios.h>
10 #include <net/if.h>
11 #include <net/if_arp.h>
12 #include <netinet/ip.h>
13 #include <stdarg.h>
14 #include <stddef.h>
15 #include <stdlib.h>
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <sys/ioctl.h>
20 #include <sys/queue.h>
21 #include <sys/socket.h>
22 #include <unistd.h>
23 
24 #include <rte_alarm.h>
25 #include <rte_bus.h>
26 #include <rte_bus_vdev.h>
27 #include <rte_common.h>
28 #include <rte_config.h>
29 #include <rte_dev.h>
30 #include <rte_errno.h>
31 #include <rte_ethdev.h>
32 #include <rte_ether.h>
33 #include <rte_hypervisor.h>
34 #include <rte_kvargs.h>
35 #include <rte_log.h>
36 
37 #define VDEV_NETVSC_DRIVER net_vdev_netvsc
38 #define VDEV_NETVSC_DRIVER_NAME RTE_STR(VDEV_NETVSC_DRIVER)
39 #define VDEV_NETVSC_ARG_IFACE "iface"
40 #define VDEV_NETVSC_ARG_MAC "mac"
41 #define VDEV_NETVSC_ARG_FORCE "force"
42 #define VDEV_NETVSC_ARG_IGNORE "ignore"
43 #define VDEV_NETVSC_PROBE_MS 1000
44 
45 #define NETVSC_CLASS_ID "{f8615163-df3e-46c5-913f-f2d2f965ed0e}"
46 #define NETVSC_MAX_ROUTE_LINE_SIZE 300
47 
48 #define DRV_LOG(level, ...) \
49 	rte_log(RTE_LOG_ ## level, \
50 		vdev_netvsc_logtype, \
51 		RTE_FMT(VDEV_NETVSC_DRIVER_NAME ": " \
52 			RTE_FMT_HEAD(__VA_ARGS__,) "\n", \
53 		RTE_FMT_TAIL(__VA_ARGS__,)))
54 
55 /** Driver-specific log messages type. */
56 static int vdev_netvsc_logtype;
57 
58 /** Context structure for a vdev_netvsc instance. */
59 struct vdev_netvsc_ctx {
60 	LIST_ENTRY(vdev_netvsc_ctx) entry; /**< Next entry in list. */
61 	unsigned int id;		   /**< Unique ID. */
62 	char name[64];			   /**< Unique name. */
63 	char devname[64];		   /**< Fail-safe instance name. */
64 	char devargs[256];		   /**< Fail-safe device arguments. */
65 	char if_name[IF_NAMESIZE];	   /**< NetVSC netdevice name. */
66 	unsigned int if_index;		   /**< NetVSC netdevice index. */
67 	struct ether_addr if_addr;	   /**< NetVSC MAC address. */
68 	int pipe[2];			   /**< Fail-safe communication pipe. */
69 	char yield[256];		   /**< PCI sub-device arguments. */
70 };
71 
72 /** Context list is common to all driver instances. */
73 static LIST_HEAD(, vdev_netvsc_ctx) vdev_netvsc_ctx_list =
74 	LIST_HEAD_INITIALIZER(vdev_netvsc_ctx_list);
75 
76 /** Number of entries in context list. */
77 static unsigned int vdev_netvsc_ctx_count;
78 
79 /** Number of driver instances relying on context list. */
80 static unsigned int vdev_netvsc_ctx_inst;
81 
82 /**
83  * Destroy a vdev_netvsc context instance.
84  *
85  * @param ctx
86  *   Context to destroy.
87  */
88 static void
89 vdev_netvsc_ctx_destroy(struct vdev_netvsc_ctx *ctx)
90 {
91 	if (ctx->pipe[0] != -1)
92 		close(ctx->pipe[0]);
93 	if (ctx->pipe[1] != -1)
94 		close(ctx->pipe[1]);
95 	free(ctx);
96 }
97 
98 /**
99  * Iterate over system network interfaces.
100  *
101  * This function runs a given callback function for each netdevice found on
102  * the system.
103  *
104  * @param func
105  *   Callback function pointer. List traversal is aborted when this function
106  *   returns a nonzero value.
107  * @param ...
108  *   Variable parameter list passed as @p va_list to @p func.
109  *
110  * @return
111  *   0 when the entire list is traversed successfully, a negative error code
112  *   in case or failure, or the nonzero value returned by @p func when list
113  *   traversal is aborted.
114  */
115 static int
116 vdev_netvsc_foreach_iface(int (*func)(const struct if_nameindex *iface,
117 				      const struct ether_addr *eth_addr,
118 				      va_list ap), ...)
119 {
120 	struct if_nameindex *iface = if_nameindex();
121 	int s = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
122 	unsigned int i;
123 	int ret = 0;
124 
125 	if (!iface) {
126 		ret = -ENOBUFS;
127 		DRV_LOG(ERR, "cannot retrieve system network interfaces");
128 		goto error;
129 	}
130 	if (s == -1) {
131 		ret = -errno;
132 		DRV_LOG(ERR, "cannot open socket: %s", rte_strerror(errno));
133 		goto error;
134 	}
135 	for (i = 0; iface[i].if_name; ++i) {
136 		struct ifreq req;
137 		struct ether_addr eth_addr;
138 		va_list ap;
139 
140 		strncpy(req.ifr_name, iface[i].if_name, sizeof(req.ifr_name));
141 		if (ioctl(s, SIOCGIFHWADDR, &req) == -1) {
142 			DRV_LOG(WARNING, "cannot retrieve information about"
143 					 " interface \"%s\": %s",
144 					 req.ifr_name, rte_strerror(errno));
145 			continue;
146 		}
147 		if (req.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
148 			DRV_LOG(DEBUG, "interface %s is non-ethernet device",
149 				req.ifr_name);
150 			continue;
151 		}
152 		memcpy(eth_addr.addr_bytes, req.ifr_hwaddr.sa_data,
153 		       RTE_DIM(eth_addr.addr_bytes));
154 		va_start(ap, func);
155 		ret = func(&iface[i], &eth_addr, ap);
156 		va_end(ap);
157 		if (ret)
158 			break;
159 	}
160 error:
161 	if (s != -1)
162 		close(s);
163 	if (iface)
164 		if_freenameindex(iface);
165 	return ret;
166 }
167 
168 /**
169  * Determine if a network interface is NetVSC.
170  *
171  * @param[in] iface
172  *   Pointer to netdevice description structure (name and index).
173  *
174  * @return
175  *   A nonzero value when interface is detected as NetVSC. In case of error,
176  *   rte_errno is updated and 0 returned.
177  */
178 static int
179 vdev_netvsc_iface_is_netvsc(const struct if_nameindex *iface)
180 {
181 	static const char temp[] = "/sys/class/net/%s/device/class_id";
182 	char path[sizeof(temp) + IF_NAMESIZE];
183 	FILE *f;
184 	int ret;
185 	int len = 0;
186 
187 	ret = snprintf(path, sizeof(path), temp, iface->if_name);
188 	if (ret == -1 || (size_t)ret >= sizeof(path)) {
189 		rte_errno = ENOBUFS;
190 		return 0;
191 	}
192 	f = fopen(path, "r");
193 	if (!f) {
194 		rte_errno = errno;
195 		return 0;
196 	}
197 	ret = fscanf(f, NETVSC_CLASS_ID "%n", &len);
198 	if (ret == EOF)
199 		rte_errno = errno;
200 	ret = len == (int)strlen(NETVSC_CLASS_ID);
201 	fclose(f);
202 	return ret;
203 }
204 
205 /**
206  * Determine if a network interface has a route.
207  *
208  * @param[in] name
209  *   Network device name.
210  *
211  * @return
212  *   A nonzero value when interface has an route. In case of error,
213  *   rte_errno is updated and 0 returned.
214  */
215 static int
216 vdev_netvsc_has_route(const char *name)
217 {
218 	FILE *fp;
219 	int ret = 0;
220 	char route[NETVSC_MAX_ROUTE_LINE_SIZE];
221 	char *netdev;
222 
223 	fp = fopen("/proc/net/route", "r");
224 	if (!fp) {
225 		rte_errno = errno;
226 		return 0;
227 	}
228 	while (fgets(route, NETVSC_MAX_ROUTE_LINE_SIZE, fp) != NULL) {
229 		netdev = strtok(route, "\t");
230 		if (strcmp(netdev, name) == 0) {
231 			ret = 1;
232 			break;
233 		}
234 		/* Move file pointer to the next line. */
235 		while (strchr(route, '\n') == NULL &&
236 		       fgets(route, NETVSC_MAX_ROUTE_LINE_SIZE, fp) != NULL)
237 			;
238 	}
239 	fclose(fp);
240 	return ret;
241 }
242 
243 /**
244  * Retrieve network interface data from sysfs symbolic link.
245  *
246  * @param[out] buf
247  *   Output data buffer.
248  * @param size
249  *   Output buffer size.
250  * @param[in] if_name
251  *   Netdevice name.
252  * @param[in] relpath
253  *   Symbolic link path relative to netdevice sysfs entry.
254  *
255  * @return
256  *   0 on success, a negative error code otherwise.
257  */
258 static int
259 vdev_netvsc_sysfs_readlink(char *buf, size_t size, const char *if_name,
260 			   const char *relpath)
261 {
262 	int ret;
263 
264 	ret = snprintf(buf, size, "/sys/class/net/%s/%s", if_name, relpath);
265 	if (ret == -1 || (size_t)ret >= size)
266 		return -ENOBUFS;
267 	ret = readlink(buf, buf, size);
268 	if (ret == -1)
269 		return -errno;
270 	if ((size_t)ret >= size - 1)
271 		return -ENOBUFS;
272 	buf[ret] = '\0';
273 	return 0;
274 }
275 
276 /**
277  * Probe a network interface to associate with vdev_netvsc context.
278  *
279  * This function determines if the network device matches the properties of
280  * the NetVSC interface associated with the vdev_netvsc context and
281  * communicates its bus address to the fail-safe PMD instance if so.
282  *
283  * It is normally used with vdev_netvsc_foreach_iface().
284  *
285  * @param[in] iface
286  *   Pointer to netdevice description structure (name and index).
287  * @param[in] eth_addr
288  *   MAC address associated with @p iface.
289  * @param ap
290  *   Variable arguments list comprising:
291  *
292  *   - struct vdev_netvsc_ctx *ctx:
293  *     Context to associate network interface with.
294  *
295  * @return
296  *   A nonzero value when interface matches, 0 otherwise or in case of
297  *   error.
298  */
299 static int
300 vdev_netvsc_device_probe(const struct if_nameindex *iface,
301 		    const struct ether_addr *eth_addr,
302 		    va_list ap)
303 {
304 	struct vdev_netvsc_ctx *ctx = va_arg(ap, struct vdev_netvsc_ctx *);
305 	char buf[RTE_MAX(sizeof(ctx->yield), 256u)];
306 	const char *addr;
307 	size_t len;
308 	int ret;
309 
310 	/* Skip non-matching or unwanted NetVSC interfaces. */
311 	if (ctx->if_index == iface->if_index) {
312 		if (!strcmp(ctx->if_name, iface->if_name))
313 			return 0;
314 		DRV_LOG(DEBUG,
315 			"NetVSC interface \"%s\" (index %u) renamed \"%s\"",
316 			ctx->if_name, ctx->if_index, iface->if_name);
317 		strncpy(ctx->if_name, iface->if_name, sizeof(ctx->if_name));
318 		return 0;
319 	}
320 	if (vdev_netvsc_iface_is_netvsc(iface))
321 		return 0;
322 	if (!is_same_ether_addr(eth_addr, &ctx->if_addr))
323 		return 0;
324 	/* Look for associated PCI device. */
325 	ret = vdev_netvsc_sysfs_readlink(buf, sizeof(buf), iface->if_name,
326 					 "device/subsystem");
327 	if (ret)
328 		return 0;
329 	addr = strrchr(buf, '/');
330 	addr = addr ? addr + 1 : buf;
331 	if (strcmp(addr, "pci"))
332 		return 0;
333 	ret = vdev_netvsc_sysfs_readlink(buf, sizeof(buf), iface->if_name,
334 					 "device");
335 	if (ret)
336 		return 0;
337 	addr = strrchr(buf, '/');
338 	addr = addr ? addr + 1 : buf;
339 	len = strlen(addr);
340 	if (!len)
341 		return 0;
342 	/* Send PCI device argument to fail-safe PMD instance. */
343 	if (strcmp(addr, ctx->yield))
344 		DRV_LOG(DEBUG, "associating PCI device \"%s\" with NetVSC"
345 			" interface \"%s\" (index %u)", addr, ctx->if_name,
346 			ctx->if_index);
347 	memmove(buf, addr, len + 1);
348 	addr = buf;
349 	buf[len] = '\n';
350 	ret = write(ctx->pipe[1], addr, len + 1);
351 	buf[len] = '\0';
352 	if (ret == -1) {
353 		if (errno == EINTR || errno == EAGAIN)
354 			return 1;
355 		DRV_LOG(WARNING, "cannot associate PCI device name \"%s\" with"
356 			" interface \"%s\": %s", addr, ctx->if_name,
357 			rte_strerror(errno));
358 		return 1;
359 	}
360 	if ((size_t)ret != len + 1) {
361 		/*
362 		 * Attempt to override previous partial write, no need to
363 		 * recover if that fails.
364 		 */
365 		ret = write(ctx->pipe[1], "\n", 1);
366 		(void)ret;
367 		return 1;
368 	}
369 	fsync(ctx->pipe[1]);
370 	memcpy(ctx->yield, addr, len + 1);
371 	return 1;
372 }
373 
374 /**
375  * Alarm callback that regularly probes system network interfaces.
376  *
377  * This callback runs at a frequency determined by VDEV_NETVSC_PROBE_MS as
378  * long as an vdev_netvsc context instance exists.
379  *
380  * @param arg
381  *   Ignored.
382  */
383 static void
384 vdev_netvsc_alarm(__rte_unused void *arg)
385 {
386 	struct vdev_netvsc_ctx *ctx;
387 	int ret;
388 
389 	LIST_FOREACH(ctx, &vdev_netvsc_ctx_list, entry) {
390 		ret = vdev_netvsc_foreach_iface(vdev_netvsc_device_probe, ctx);
391 		if (ret)
392 			break;
393 	}
394 	if (!vdev_netvsc_ctx_count)
395 		return;
396 	ret = rte_eal_alarm_set(VDEV_NETVSC_PROBE_MS * 1000,
397 				vdev_netvsc_alarm, NULL);
398 	if (ret < 0) {
399 		DRV_LOG(ERR, "unable to reschedule alarm callback: %s",
400 			rte_strerror(-ret));
401 	}
402 }
403 
404 /**
405  * Probe a NetVSC interface to generate a vdev_netvsc context from.
406  *
407  * This function instantiates vdev_netvsc contexts either for all NetVSC
408  * devices found on the system or only a subset provided as device
409  * arguments.
410  *
411  * It is normally used with vdev_netvsc_foreach_iface().
412  *
413  * @param[in] iface
414  *   Pointer to netdevice description structure (name and index).
415  * @param[in] eth_addr
416  *   MAC address associated with @p iface.
417  * @param ap
418  *   Variable arguments list comprising:
419  *
420  *   - const char *name:
421  *     Name associated with current driver instance.
422  *
423  *   - struct rte_kvargs *kvargs:
424  *     Device arguments provided to current driver instance.
425  *
426  *   - int force:
427  *     Accept specified interface even if not detected as NetVSC.
428  *
429  *   - unsigned int specified:
430  *     Number of specific netdevices provided as device arguments.
431  *
432  *   - unsigned int *matched:
433  *     The number of specified netdevices matched by this function.
434  *
435  * @return
436  *   A nonzero value when interface matches, 0 otherwise or in case of
437  *   error.
438  */
439 static int
440 vdev_netvsc_netvsc_probe(const struct if_nameindex *iface,
441 			 const struct ether_addr *eth_addr,
442 			 va_list ap)
443 {
444 	const char *name = va_arg(ap, const char *);
445 	struct rte_kvargs *kvargs = va_arg(ap, struct rte_kvargs *);
446 	int force = va_arg(ap, int);
447 	unsigned int specified = va_arg(ap, unsigned int);
448 	unsigned int *matched = va_arg(ap, unsigned int *);
449 	unsigned int i;
450 	struct vdev_netvsc_ctx *ctx;
451 	int ret;
452 
453 	/* Probe all interfaces when none are specified. */
454 	if (specified) {
455 		for (i = 0; i != kvargs->count; ++i) {
456 			const struct rte_kvargs_pair *pair = &kvargs->pairs[i];
457 
458 			if (!strcmp(pair->key, VDEV_NETVSC_ARG_IFACE)) {
459 				if (!strcmp(pair->value, iface->if_name))
460 					break;
461 			} else if (!strcmp(pair->key, VDEV_NETVSC_ARG_MAC)) {
462 				struct ether_addr tmp;
463 
464 				if (sscanf(pair->value,
465 					   "%" SCNx8 ":%" SCNx8 ":%" SCNx8 ":"
466 					   "%" SCNx8 ":%" SCNx8 ":%" SCNx8,
467 					   &tmp.addr_bytes[0],
468 					   &tmp.addr_bytes[1],
469 					   &tmp.addr_bytes[2],
470 					   &tmp.addr_bytes[3],
471 					   &tmp.addr_bytes[4],
472 					   &tmp.addr_bytes[5]) != 6) {
473 					DRV_LOG(ERR,
474 						"invalid MAC address format"
475 						" \"%s\"",
476 						pair->value);
477 					return -EINVAL;
478 				}
479 				if (is_same_ether_addr(eth_addr, &tmp))
480 					break;
481 			}
482 		}
483 		if (i == kvargs->count)
484 			return 0;
485 		++(*matched);
486 	}
487 	/* Weed out interfaces already handled. */
488 	LIST_FOREACH(ctx, &vdev_netvsc_ctx_list, entry)
489 		if (ctx->if_index == iface->if_index)
490 			break;
491 	if (ctx) {
492 		if (!specified)
493 			return 0;
494 		DRV_LOG(WARNING,
495 			"interface \"%s\" (index %u) is already handled,"
496 			" skipping",
497 			iface->if_name, iface->if_index);
498 		return 0;
499 	}
500 	if (!vdev_netvsc_iface_is_netvsc(iface)) {
501 		if (!specified || !force)
502 			return 0;
503 		DRV_LOG(WARNING,
504 			"using non-NetVSC interface \"%s\" (index %u)",
505 			iface->if_name, iface->if_index);
506 	}
507 	/* Routed NetVSC should not be probed. */
508 	if (vdev_netvsc_has_route(iface->if_name)) {
509 		if (!specified || !force)
510 			return 0;
511 		DRV_LOG(WARNING, "using routed NetVSC interface \"%s\""
512 			" (index %u)", iface->if_name, iface->if_index);
513 	}
514 	/* Create interface context. */
515 	ctx = calloc(1, sizeof(*ctx));
516 	if (!ctx) {
517 		ret = -errno;
518 		DRV_LOG(ERR, "cannot allocate context for interface \"%s\": %s",
519 			iface->if_name, rte_strerror(errno));
520 		goto error;
521 	}
522 	ctx->id = vdev_netvsc_ctx_count;
523 	strncpy(ctx->if_name, iface->if_name, sizeof(ctx->if_name));
524 	ctx->if_index = iface->if_index;
525 	ctx->if_addr = *eth_addr;
526 	ctx->pipe[0] = -1;
527 	ctx->pipe[1] = -1;
528 	ctx->yield[0] = '\0';
529 	if (pipe(ctx->pipe) == -1) {
530 		ret = -errno;
531 		DRV_LOG(ERR,
532 			"cannot allocate control pipe for interface \"%s\": %s",
533 			ctx->if_name, rte_strerror(errno));
534 		goto error;
535 	}
536 	for (i = 0; i != RTE_DIM(ctx->pipe); ++i) {
537 		int flf = fcntl(ctx->pipe[i], F_GETFL);
538 
539 		if (flf != -1 &&
540 		    fcntl(ctx->pipe[i], F_SETFL, flf | O_NONBLOCK) != -1)
541 			continue;
542 		ret = -errno;
543 		DRV_LOG(ERR, "cannot toggle non-blocking flag on control file"
544 			" descriptor #%u (%d): %s", i, ctx->pipe[i],
545 			rte_strerror(errno));
546 		goto error;
547 	}
548 	/* Generate virtual device name and arguments. */
549 	i = 0;
550 	ret = snprintf(ctx->name, sizeof(ctx->name), "%s_id%u",
551 		       name, ctx->id);
552 	if (ret == -1 || (size_t)ret >= sizeof(ctx->name))
553 		++i;
554 	ret = snprintf(ctx->devname, sizeof(ctx->devname), "net_failsafe_%s",
555 		       ctx->name);
556 	if (ret == -1 || (size_t)ret >= sizeof(ctx->devname))
557 		++i;
558 	ret = snprintf(ctx->devargs, sizeof(ctx->devargs),
559 		       "fd(%d),dev(net_tap_%s,remote=%s)",
560 		       ctx->pipe[0], ctx->name, ctx->if_name);
561 	if (ret == -1 || (size_t)ret >= sizeof(ctx->devargs))
562 		++i;
563 	if (i) {
564 		ret = -ENOBUFS;
565 		DRV_LOG(ERR, "generated virtual device name or argument list"
566 			" too long for interface \"%s\"", ctx->if_name);
567 		goto error;
568 	}
569 	/* Request virtual device generation. */
570 	DRV_LOG(DEBUG, "generating virtual device \"%s\" with arguments \"%s\"",
571 		ctx->devname, ctx->devargs);
572 	vdev_netvsc_foreach_iface(vdev_netvsc_device_probe, ctx);
573 	ret = rte_eal_hotplug_add("vdev", ctx->devname, ctx->devargs);
574 	if (ret)
575 		goto error;
576 	LIST_INSERT_HEAD(&vdev_netvsc_ctx_list, ctx, entry);
577 	++vdev_netvsc_ctx_count;
578 	DRV_LOG(DEBUG, "added NetVSC interface \"%s\" to context list",
579 		ctx->if_name);
580 	return 0;
581 error:
582 	if (ctx)
583 		vdev_netvsc_ctx_destroy(ctx);
584 	return ret;
585 }
586 
587 /**
588  * Probe NetVSC interfaces.
589  *
590  * This function probes system netdevices according to the specified device
591  * arguments and starts a periodic alarm callback to notify the resulting
592  * fail-safe PMD instances of their sub-devices whereabouts.
593  *
594  * @param dev
595  *   Virtual device context for driver instance.
596  *
597  * @return
598  *    Always 0, even in case of errors.
599  */
600 static int
601 vdev_netvsc_vdev_probe(struct rte_vdev_device *dev)
602 {
603 	static const char *const vdev_netvsc_arg[] = {
604 		VDEV_NETVSC_ARG_IFACE,
605 		VDEV_NETVSC_ARG_MAC,
606 		VDEV_NETVSC_ARG_FORCE,
607 		VDEV_NETVSC_ARG_IGNORE,
608 		NULL,
609 	};
610 	const char *name = rte_vdev_device_name(dev);
611 	const char *args = rte_vdev_device_args(dev);
612 	struct rte_kvargs *kvargs = rte_kvargs_parse(args ? args : "",
613 						     vdev_netvsc_arg);
614 	unsigned int specified = 0;
615 	unsigned int matched = 0;
616 	int force = 0;
617 	int ignore = 0;
618 	unsigned int i;
619 	int ret;
620 
621 	DRV_LOG(DEBUG, "invoked as \"%s\", using arguments \"%s\"", name, args);
622 	if (!kvargs) {
623 		DRV_LOG(ERR, "cannot parse arguments list");
624 		goto error;
625 	}
626 	for (i = 0; i != kvargs->count; ++i) {
627 		const struct rte_kvargs_pair *pair = &kvargs->pairs[i];
628 
629 		if (!strcmp(pair->key, VDEV_NETVSC_ARG_FORCE))
630 			force = !!atoi(pair->value);
631 		else if (!strcmp(pair->key, VDEV_NETVSC_ARG_IGNORE))
632 			ignore = !!atoi(pair->value);
633 		else if (!strcmp(pair->key, VDEV_NETVSC_ARG_IFACE) ||
634 			 !strcmp(pair->key, VDEV_NETVSC_ARG_MAC))
635 			++specified;
636 	}
637 	if (ignore) {
638 		if (kvargs)
639 			rte_kvargs_free(kvargs);
640 		return 0;
641 	}
642 	rte_eal_alarm_cancel(vdev_netvsc_alarm, NULL);
643 	/* Gather interfaces. */
644 	ret = vdev_netvsc_foreach_iface(vdev_netvsc_netvsc_probe, name, kvargs,
645 					force, specified, &matched);
646 	if (ret < 0)
647 		goto error;
648 	if (matched < specified)
649 		DRV_LOG(WARNING,
650 			"some of the specified parameters did not match"
651 			" recognized network interfaces");
652 	ret = rte_eal_alarm_set(VDEV_NETVSC_PROBE_MS * 1000,
653 				vdev_netvsc_alarm, NULL);
654 	if (ret < 0) {
655 		DRV_LOG(ERR, "unable to schedule alarm callback: %s",
656 			rte_strerror(-ret));
657 		goto error;
658 	}
659 error:
660 	if (kvargs)
661 		rte_kvargs_free(kvargs);
662 	++vdev_netvsc_ctx_inst;
663 	return 0;
664 }
665 
666 /**
667  * Remove driver instance.
668  *
669  * The alarm callback and underlying vdev_netvsc context instances are only
670  * destroyed after the last PMD instance is removed.
671  *
672  * @param dev
673  *   Virtual device context for driver instance.
674  *
675  * @return
676  *   Always 0.
677  */
678 static int
679 vdev_netvsc_vdev_remove(__rte_unused struct rte_vdev_device *dev)
680 {
681 	if (--vdev_netvsc_ctx_inst)
682 		return 0;
683 	rte_eal_alarm_cancel(vdev_netvsc_alarm, NULL);
684 	while (!LIST_EMPTY(&vdev_netvsc_ctx_list)) {
685 		struct vdev_netvsc_ctx *ctx = LIST_FIRST(&vdev_netvsc_ctx_list);
686 
687 		LIST_REMOVE(ctx, entry);
688 		--vdev_netvsc_ctx_count;
689 		vdev_netvsc_ctx_destroy(ctx);
690 	}
691 	return 0;
692 }
693 
694 /** Virtual device descriptor. */
695 static struct rte_vdev_driver vdev_netvsc_vdev = {
696 	.probe = vdev_netvsc_vdev_probe,
697 	.remove = vdev_netvsc_vdev_remove,
698 };
699 
700 RTE_PMD_REGISTER_VDEV(VDEV_NETVSC_DRIVER, vdev_netvsc_vdev);
701 RTE_PMD_REGISTER_ALIAS(VDEV_NETVSC_DRIVER, eth_vdev_netvsc);
702 RTE_PMD_REGISTER_PARAM_STRING(net_vdev_netvsc,
703 			      VDEV_NETVSC_ARG_IFACE "=<string> "
704 			      VDEV_NETVSC_ARG_MAC "=<string> "
705 			      VDEV_NETVSC_ARG_FORCE "=<int> "
706 			      VDEV_NETVSC_ARG_IGNORE "=<int>");
707 
708 /** Initialize driver log type. */
709 RTE_INIT(vdev_netvsc_init_log)
710 {
711 	vdev_netvsc_logtype = rte_log_register("pmd.vdev_netvsc");
712 	if (vdev_netvsc_logtype >= 0)
713 		rte_log_set_level(vdev_netvsc_logtype, RTE_LOG_NOTICE);
714 }
715 
716 /** Compare function for vdev find device operation. */
717 static int
718 vdev_netvsc_cmp_rte_device(const struct rte_device *dev1,
719 			   __rte_unused const void *_dev2)
720 {
721 	return strcmp(dev1->devargs->name, VDEV_NETVSC_DRIVER_NAME);
722 }
723 
724 /**
725  * A callback called by vdev bus scan function to ensure this driver probing
726  * automatically in Hyper-V VM system unless it already exists in the
727  * devargs list.
728  */
729 static void
730 vdev_netvsc_scan_callback(__rte_unused void *arg)
731 {
732 	struct rte_vdev_device *dev;
733 	struct rte_devargs *devargs;
734 	struct rte_bus *vbus = rte_bus_find_by_name("vdev");
735 
736 	TAILQ_FOREACH(devargs, &devargs_list, next)
737 		if (!strcmp(devargs->name, VDEV_NETVSC_DRIVER_NAME))
738 			return;
739 	dev = (struct rte_vdev_device *)vbus->find_device(NULL,
740 		vdev_netvsc_cmp_rte_device, VDEV_NETVSC_DRIVER_NAME);
741 	if (dev)
742 		return;
743 	if (rte_eal_devargs_add(RTE_DEVTYPE_VIRTUAL, VDEV_NETVSC_DRIVER_NAME))
744 		DRV_LOG(ERR, "unable to add netvsc devargs.");
745 }
746 
747 /** Initialize the custom scan. */
748 RTE_INIT(vdev_netvsc_custom_scan_add)
749 {
750 	if (rte_hypervisor_get() == RTE_HYPERVISOR_HYPERV)
751 		rte_vdev_add_custom_scan(vdev_netvsc_scan_callback, NULL);
752 }
753