#include <linux/gen_stats.h>
#include <linux/if_ether.h>
#include <linux/if_tun.h>
-#include <linux/ip.h>
#include <linux/types.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include "sset.h"
#include "timer.h"
#include "vlog.h"
+#include "tunalloc.h"
VLOG_DEFINE_THIS_MODULE(netdev_linux);
}
}
- if (!strcmp(netdev_dev_get_type(netdev_dev_), "tap") &&
+ if (!strncmp(netdev_dev_get_type(netdev_dev_), "tap", 3) &&
!netdev_dev->state.tap.opened) {
/* We assume that the first user of the tap device is the primary user
{
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
- if (netdev->fd > 0 && strcmp(netdev_get_type(netdev_), "tap")) {
+ if (netdev->fd > 0 && strncmp(netdev_get_type(netdev_), "tap", 3)) {
close(netdev->fd);
}
free(netdev);
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
if (netdev->fd < 0) {
return 0;
- } else if (!strcmp(netdev_get_type(netdev_), "tap")) {
+ } else if (!strncmp(netdev_get_type(netdev_), "tap", 3)) {
struct ifreq ifr;
int error = netdev_linux_do_ioctl(netdev_get_name(netdev_), &ifr,
SIOCGIFTXQLEN, "SIOCGIFTXQLEN");
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
if (netdev->fd < 0) {
/* Nothing to do. */
- } else if (strcmp(netdev_get_type(netdev_), "tap")) {
+ } else if (strncmp(netdev_get_type(netdev_), "tap", 3)) {
poll_fd_wait(netdev->fd, POLLOUT);
} else {
/* TAP device always accepts packets.*/
return 0;
}
+static int
+netdev_linux_create_tap_pl(const struct netdev_class *class OVS_UNUSED,
+ const char *name, struct netdev_dev **netdev_devp)
+{
+ struct netdev_dev_linux *netdev_dev;
+ struct tap_state *state;
+ char real_name[IFNAMSIZ];
+ int error;
+
+ netdev_dev = xzalloc(sizeof *netdev_dev);
+ state = &netdev_dev->state.tap;
+
+ error = cache_notifier_ref();
+ if (error) {
+ goto error;
+ }
+
+ /* Open tap device. */
+ state->fd = tun_alloc(IFF_TAP, real_name);
+ if (state->fd < 0) {
+ error = errno;
+ VLOG_WARN("tun_alloc(IFF_TAP, %s) failed: %s", name, strerror(error));
+ goto error_unref_notifier;
+ }
+ if (strcmp(name, real_name)) {
+ VLOG_WARN("tap_pl: requested %s, created %s", name, real_name);
+ }
+
+ /* Make non-blocking. */
+ error = set_nonblocking(state->fd);
+ if (error) {
+ goto error_unref_notifier;
+ }
+
+ netdev_dev_init(&netdev_dev->netdev_dev, name, &netdev_tap_pl_class);
+ *netdev_devp = &netdev_dev->netdev_dev;
+ return 0;
+
+error_unref_notifier:
+ cache_notifier_unref();
+error:
+ free(netdev_dev);
+ return error;
+}
+
static const struct tc_ops *
tc_lookup_ovs_name(const char *name)
{
{
struct netdev_dev_linux *netdev_dev =
netdev_dev_linux_cast(netdev_get_dev(netdev));
- struct tc_queue *queue;
+ struct tc_queue *queue, *next_queue;
struct shash details;
int last_error;
int error;
last_error = 0;
shash_init(&details);
- HMAP_FOR_EACH (queue, hmap_node, &netdev_dev->tc->queues) {
+ HMAP_FOR_EACH_SAFE (queue, next_queue, hmap_node,
+ &netdev_dev->tc->queues) {
shash_clear(&details);
error = netdev_dev->tc->ops->class_get(netdev, queue, &details);
}
static int
-netdev_linux_get_status(const struct netdev *netdev, struct shash *sh)
+netdev_linux_get_drv_info(const struct netdev *netdev, struct shash *sh)
{
int error;
struct netdev_dev_linux *netdev_dev =
}
static int
-netdev_internal_get_status(const struct netdev *netdev OVS_UNUSED, struct shash *sh)
+netdev_internal_get_drv_info(const struct netdev *netdev OVS_UNUSED, struct shash *sh)
{
shash_add(sh, "driver_name", xstrdup("openvswitch"));
return 0;
netdev_linux_get_stats,
NULL, /* set_stats */
netdev_linux_get_features,
- netdev_linux_get_status);
+ netdev_linux_get_drv_info);
const struct netdev_class netdev_tap_class =
NETDEV_LINUX_CLASS(
netdev_tap_get_stats,
NULL, /* set_stats */
netdev_linux_get_features,
- netdev_linux_get_status);
+ netdev_linux_get_drv_info);
const struct netdev_class netdev_internal_class =
NETDEV_LINUX_CLASS(
netdev_internal_get_stats,
netdev_vport_set_stats,
NULL, /* get_features */
- netdev_internal_get_status);
+ netdev_internal_get_drv_info);
+
+const struct netdev_class netdev_tap_pl_class =
+ NETDEV_LINUX_CLASS(
+ "tap_pl",
+ netdev_linux_create_tap_pl,
+ netdev_tap_get_stats,
+ NULL, /* set_stats */
+ netdev_linux_get_features,
+ netdev_linux_get_drv_info);
\f
/* HTB traffic control class. */