#include "sset.h"
#include "timer.h"
#include "vlog.h"
+#include "tunalloc.h"
VLOG_DEFINE_THIS_MODULE(netdev_linux);
COVERAGE_DEFINE(netdev_get_ifindex);
COVERAGE_DEFINE(netdev_get_hwaddr);
COVERAGE_DEFINE(netdev_set_hwaddr);
-COVERAGE_DEFINE(netdev_ethtool);
+COVERAGE_DEFINE(netdev_get_ethtool);
+COVERAGE_DEFINE(netdev_set_ethtool);
\f
/* These were introduced in Linux 2.6.14, so they might be missing if we have
return 0;
}
+ COVERAGE_INC(netdev_get_ethtool);
memset(&netdev_dev->drvinfo, 0, sizeof netdev_dev->drvinfo);
error = netdev_linux_do_ethtool(netdev_dev->netdev_dev.name,
(struct ethtool_cmd *)&netdev_dev->drvinfo,
netdev_dev->tc->ops->tc_destroy(netdev_dev->tc);
}
- if (class == &netdev_tap_class) {
+ if (class == &netdev_tap_class || class == &netdev_tap_pl_class) {
destroy_tap(netdev_dev);
}
free(netdev_dev);
}
}
- 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);
for (;;) {
ssize_t retval;
- retval = (netdev_->netdev_dev->netdev_class == &netdev_tap_class
+ retval = ((netdev_->netdev_dev->netdev_class == &netdev_tap_class ||
+ netdev_->netdev_dev->netdev_class == &netdev_tap_pl_class)
? read(netdev->fd, data, size)
: recv(netdev->fd, data, size, MSG_TRUNC));
if (retval >= 0) {
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");
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifindex;
- iov.iov_base = (void *) data;
+ iov.iov_base = CONST_CAST(void *, data);
iov.iov_len = size;
msg.msg_name = &sll;
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.*/
VLOG_DBG_RL(&rl, "%s: failed to query MII, falling back to ethtool",
name);
+ COVERAGE_INC(netdev_get_ethtool);
memset(&ecmd, 0, sizeof ecmd);
error = netdev_linux_do_ethtool(name, &ecmd, ETHTOOL_GLINK,
"ETHTOOL_GLINK");
return;
}
+ COVERAGE_INC(netdev_get_ethtool);
memset(&ecmd, 0, sizeof ecmd);
error = netdev_linux_do_ethtool(netdev_dev->netdev_dev.name, &ecmd,
ETHTOOL_GSET, "ETHTOOL_GSET");
struct ethtool_cmd ecmd;
int error;
+ COVERAGE_INC(netdev_get_ethtool);
memset(&ecmd, 0, sizeof ecmd);
error = netdev_linux_do_ethtool(netdev_get_name(netdev), &ecmd,
ETHTOOL_GSET, "ETHTOOL_GSET");
if (advertise & NETDEV_F_PAUSE_ASYM) {
ecmd.advertising |= ADVERTISED_Asym_Pause;
}
+ COVERAGE_INC(netdev_set_ethtool);
return netdev_linux_do_ethtool(netdev_get_name(netdev), &ecmd,
ETHTOOL_SSET, "ETHTOOL_SSET");
}
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)
{
return error;
}
+static int
+netdev_tap_pl_update_flags(struct netdev *netdev, enum netdev_flags off,
+ enum netdev_flags on, enum netdev_flags *old_flagsp)
+{
+ return 0;
+}
+
static unsigned int
netdev_linux_change_seq(const struct netdev *netdev)
{
}
#define NETDEV_LINUX_CLASS(NAME, CREATE, GET_STATS, SET_STATS, \
- GET_FEATURES, GET_STATUS) \
+ GET_FEATURES, GET_STATUS, \
+ UPDATE_FLAGS) \
{ \
NAME, \
\
GET_STATUS, \
netdev_linux_arp_lookup, \
\
- netdev_linux_update_flags, \
+ UPDATE_FLAGS, \
\
netdev_linux_change_seq \
}
netdev_linux_get_stats,
NULL, /* set_stats */
netdev_linux_get_features,
- netdev_linux_get_drv_info);
+ netdev_linux_get_drv_info,
+ netdev_linux_update_flags);
const struct netdev_class netdev_tap_class =
NETDEV_LINUX_CLASS(
netdev_tap_get_stats,
NULL, /* set_stats */
netdev_linux_get_features,
- netdev_linux_get_drv_info);
+ netdev_linux_get_drv_info,
+ netdev_linux_update_flags);
const struct netdev_class netdev_internal_class =
NETDEV_LINUX_CLASS(
netdev_internal_get_stats,
netdev_vport_set_stats,
NULL, /* get_features */
- netdev_internal_get_drv_info);
+ netdev_internal_get_drv_info,
+ netdev_linux_update_flags);
+
+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,
+ netdev_tap_pl_update_flags);
\f
/* HTB traffic control class. */
}
/* Instantiate it. */
- load_error = ops->tc_load((struct netdev *) netdev, qdisc);
+ load_error = ops->tc_load(CONST_CAST(struct netdev *, netdev), qdisc);
assert((load_error == 0) == (netdev_dev->tc != NULL));
ofpbuf_delete(qdisc);
uint32_t new_flags;
int error;
+ COVERAGE_INC(netdev_get_ethtool);
memset(&evalue, 0, sizeof evalue);
error = netdev_linux_do_ethtool(netdev_name,
(struct ethtool_cmd *)&evalue,
return error;
}
+ COVERAGE_INC(netdev_set_ethtool);
evalue.data = new_flags = (evalue.data & ~flag) | (enable ? flag : 0);
error = netdev_linux_do_ethtool(netdev_name,
(struct ethtool_cmd *)&evalue,
return error;
}
+ COVERAGE_INC(netdev_get_ethtool);
memset(&evalue, 0, sizeof evalue);
error = netdev_linux_do_ethtool(netdev_name,
(struct ethtool_cmd *)&evalue,
ifr.ifr_data = (caddr_t) ecmd;
ecmd->cmd = cmd;
- COVERAGE_INC(netdev_ethtool);
if (ioctl(af_inet_sock, SIOCETHTOOL, &ifr) == 0) {
return 0;
} else {