#include "svec.h"
#include "vlog.h"
-VLOG_DEFINE_THIS_MODULE(netdev)
+VLOG_DEFINE_THIS_MODULE(netdev);
+
+COVERAGE_DEFINE(netdev_received);
+COVERAGE_DEFINE(netdev_sent);
+COVERAGE_DEFINE(netdev_add_router);
+COVERAGE_DEFINE(netdev_get_stats);
static struct shash netdev_classes = SHASH_INITIALIZER(&netdev_classes);
#ifdef HAVE_NETLINK
netdev_register_provider(&netdev_linux_class);
+ netdev_register_provider(&netdev_internal_class);
netdev_register_provider(&netdev_tap_class);
netdev_vport_register();
#endif
return 0;
}
+const struct netdev_class *
+netdev_lookup_provider(const char *type)
+{
+ netdev_initialize();
+ return shash_find_data(&netdev_classes, type && type[0] ? type : "system");
+}
+
/* Clears 'types' and enumerates the types of all currently registered netdev
* providers into it. The caller must first initialize the svec. */
void
qsort(dev->args, dev->n_args, sizeof *dev->args, compare_args);
}
-static int
-create_device(struct netdev_options *options, struct netdev_dev **netdev_devp)
-{
- struct netdev_class *netdev_class;
-
- if (!options->type || strlen(options->type) == 0) {
- /* Default to system. */
- options->type = "system";
- }
-
- netdev_class = shash_find_data(&netdev_classes, options->type);
- if (!netdev_class) {
- return EAFNOSUPPORT;
- }
-
- return netdev_class->create(netdev_class, options->name, options->args,
- netdev_devp);
-}
-
/* Opens the network device named 'name' (e.g. "eth0") and returns zero if
* successful, otherwise a positive errno value. On success, sets '*netdevp'
* to the new network device, otherwise to null.
netdev_dev = shash_find_data(&netdev_dev_shash, options->name);
if (!netdev_dev) {
- error = create_device(options, &netdev_dev);
+ const struct netdev_class *class;
+
+ class = netdev_lookup_provider(options->type);
+ if (!class) {
+ VLOG_WARN("could not create netdev %s of unknown type %s",
+ options->name, options->type);
+ return EAFNOSUPPORT;
+ }
+ error = class->create(class, options->name, options->args,
+ &netdev_dev);
if (error) {
- if (error == EAFNOSUPPORT) {
- VLOG_WARN("could not create netdev %s of unknown type %s",
- options->name, options->type);
- }
return error;
}
+ assert(netdev_dev->netdev_class == class);
update_device_args(netdev_dev, options->args);
} else if (!shash_is_empty(options->args) &&
return error;
}
-/* Sets 'carrier' to true if carrier is active (link light is on) on
- * 'netdev'. */
-int
-netdev_get_carrier(const struct netdev *netdev, bool *carrier)
+/* Returns true if carrier is active (link light is on) on 'netdev'. */
+bool
+netdev_get_carrier(const struct netdev *netdev)
{
- int error = (netdev_get_dev(netdev)->netdev_class->get_carrier
- ? netdev_get_dev(netdev)->netdev_class->get_carrier(netdev,
- carrier)
- : EOPNOTSUPP);
+ int error;
+ enum netdev_flags flags;
+ bool carrier;
+
+ netdev_get_flags(netdev, &flags);
+ if (!(flags & NETDEV_UP)) {
+ return false;
+ }
+
+ if (!netdev_get_dev(netdev)->netdev_class->get_carrier) {
+ return true;
+ }
+
+ error = netdev_get_dev(netdev)->netdev_class->get_carrier(netdev,
+ &carrier);
if (error) {
- *carrier = false;
+ VLOG_DBG("%s: failed to get network device carrier status, assuming "
+ "down: %s", netdev_get_name(netdev), strerror(error));
+ carrier = false;
}
- return error;
+
+ return carrier;
}
/* Retrieves current device stats for 'netdev'. */