#include "hash.h"
#include "list.h"
#include "netdev-provider.h"
+#include "netdev-vport.h"
#include "ofpbuf.h"
#include "openflow/openflow.h"
#include "packets.h"
#include "svec.h"
#include "vlog.h"
-VLOG_DEFINE_THIS_MODULE(netdev)
+VLOG_DEFINE_THIS_MODULE(netdev);
-static const struct netdev_class *base_netdev_classes[] = {
-#ifdef HAVE_NETLINK
- &netdev_linux_class,
- &netdev_tap_class,
- &netdev_patch_class,
- &netdev_gre_class,
- &netdev_capwap_class,
-#endif
-};
+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);
static void
netdev_initialize(void)
{
- static int status = -1;
+ static bool inited;
- if (status < 0) {
- int i;
+ if (!inited) {
+ inited = true;
fatal_signal_add_hook(close_all_netdevs, NULL, NULL, true);
- status = 0;
- for (i = 0; i < ARRAY_SIZE(base_netdev_classes); i++) {
- netdev_register_provider(base_netdev_classes[i]);
- }
+#ifdef HAVE_NETLINK
+ netdev_register_provider(&netdev_linux_class);
+ netdev_register_provider(&netdev_tap_class);
+ netdev_vport_register();
+#endif
}
}
int
netdev_register_provider(const struct netdev_class *new_class)
{
- struct netdev_class *new_provider;
-
if (shash_find(&netdev_classes, new_class->type)) {
VLOG_WARN("attempted to register duplicate netdev provider: %s",
new_class->type);
}
}
- new_provider = xmalloc(sizeof *new_provider);
- memcpy(new_provider, new_class, sizeof *new_provider);
-
- shash_add(&netdev_classes, new_class->type, new_provider);
+ shash_add(&netdev_classes, new_class->type, new_class);
return 0;
}
}
shash_delete(&netdev_classes, del_node);
- free(del_node->data);
return 0;
}
create_device(struct netdev_options *options, struct netdev_dev **netdev_devp)
{
struct netdev_class *netdev_class;
+ int error;
if (!options->type || strlen(options->type) == 0) {
/* Default to system. */
return EAFNOSUPPORT;
}
- return netdev_class->create(options->name, options->type, options->args,
- netdev_devp);
+ error = netdev_class->create(netdev_class, options->name, options->args,
+ netdev_devp);
+ assert(error || (*netdev_devp)->netdev_class == netdev_class);
+ return error;
}
/* Opens the network device named 'name' (e.g. "eth0") and returns zero if
* to the new network device, otherwise to null.
*
* If this is the first time the device has been opened, then create is called
- * before opening. The device is created using the given type and arguments.
+ * before opening. The device is created using the given type and arguments.
*
* 'ethertype' may be a 16-bit Ethernet protocol value in host byte order to
* capture frames of that type received on the device. It may also be one of
* the 'enum netdev_pseudo_ethertype' values to receive frames in one of those
* categories. */
-
int
netdev_open(struct netdev_options *options, struct netdev **netdevp)
{
* be returned.
*
* Some network devices may not implement support for this function. In such
- * cases this function will always return EOPNOTSUPP.
- */
+ * cases this function will always return EOPNOTSUPP. */
int
netdev_recv(struct netdev *netdev, struct ofpbuf *buffer)
{
* passed-in values are set to 0.
*
* Some network devices may not implement support for this function. In such
- * cases this function will always return EOPNOTSUPP.
- */
+ * cases this function will always return EOPNOTSUPP. */
int
netdev_get_features(struct netdev *netdev,
uint32_t *current, uint32_t *advertised,
*
* - EOPNOTSUPP: No IPv4 network stack attached to 'netdev'.
*
- * 'address' or 'netmask' or both may be null, in which case the address or netmask
- * is not reported. */
+ * 'address' or 'netmask' or both may be null, in which case the address or
+ * netmask is not reported. */
int
netdev_get_in4(const struct netdev *netdev,
struct in_addr *address_, struct in_addr *netmask_)
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'. */
* the current form of QoS (e.g. as returned by netdev_get_n_queues(netdev)).
*
* This function does not modify 'details', and the caller retains ownership of
- * it.
- */
+ * it. */
int
netdev_set_queue(struct netdev *netdev,
unsigned int queue_id, const struct shash *details)
* sets '*devnamep' to the name of a device that has changed and returns 0.
* The caller is responsible for freeing '*devnamep' (with free()).
*
- * If no devices have changed, sets '*devnamep' to NULL and returns EAGAIN.
- */
+ * If no devices have changed, sets '*devnamep' to NULL and returns EAGAIN. */
int
netdev_monitor_poll(struct netdev_monitor *monitor, char **devnamep)
{
*devnamep = NULL;
return EAGAIN;
} else {
- *devnamep = xstrdup(node->name);
- shash_delete(&monitor->changed_netdevs, node);
+ *devnamep = shash_steal(&monitor->changed_netdevs, node);
return 0;
}
}
close_all_netdevs(void *aux OVS_UNUSED)
{
struct netdev *netdev, *next;
- LIST_FOR_EACH_SAFE(netdev, next, struct netdev, node, &netdev_list) {
+ LIST_FOR_EACH_SAFE(netdev, next, node, &netdev_list) {
netdev_close(netdev);
}
}