New upstream version 18.02
[deb_dpdk.git] / drivers / net / vdev_netvsc / vdev_netvsc.c
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 < 0)
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 }