/*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#define ADVERTISED_Asym_Pause (1 << 14)
#endif
+/* Provider-specific netdev object. Netdev objects are devices that are
+ * created by the netdev library through a netdev_create() call. */
+struct netdev_obj_linux {
+ struct netdev_obj netdev_obj;
+
+ int tap_fd; /* File descriptor for TAP device. */
+};
+
struct netdev_linux {
struct netdev netdev;
static int get_stats_via_netlink(int ifindex, struct netdev_stats *stats);
static int get_stats_via_proc(const char *netdev_name, struct netdev_stats *stats);
+static struct netdev_obj_linux *
+netdev_obj_linux_cast(const struct netdev_obj *netdev_obj)
+{
+ netdev_obj_assert_class(netdev_obj, &netdev_linux_class);
+ return CONTAINER_OF(netdev_obj, struct netdev_obj_linux, netdev_obj);
+}
+
static struct netdev_linux *
netdev_linux_cast(const struct netdev *netdev)
{
static void
netdev_linux_cache_cb(const struct rtnetlink_change *change,
- void *aux UNUSED)
+ void *aux OVS_UNUSED)
{
struct netdev_linux_cache *cache;
if (change) {
}
}
+/* Creates the netdev object of 'type' with 'name'. */
+static int
+netdev_linux_create(const char *name, const char *type,
+ const struct shash *args, bool created)
+{
+ struct netdev_obj_linux *netdev_obj;
+ static const char tap_dev[] = "/dev/net/tun";
+ struct ifreq ifr;
+ int error;
+
+ if (!shash_is_empty(args)) {
+ VLOG_WARN("arguments for %s devices should be empty", type);
+ }
+
+ /* Create the name binding in the netdev library for this object. */
+ netdev_obj = xcalloc(1, sizeof *netdev_obj);
+ netdev_obj_init(&netdev_obj->netdev_obj, name, &netdev_linux_class,
+ created);
+ netdev_obj->tap_fd = -1;
+
+ if (strcmp(type, "tap")) {
+ return 0;
+ }
+
+ /* Open tap device. */
+ netdev_obj->tap_fd = open(tap_dev, O_RDWR);
+ if (netdev_obj->tap_fd < 0) {
+ error = errno;
+ VLOG_WARN("opening \"%s\" failed: %s", tap_dev, strerror(error));
+ goto error;
+ }
+
+ /* Create tap device. */
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+ if (ioctl(netdev_obj->tap_fd, TUNSETIFF, &ifr) == -1) {
+ VLOG_WARN("%s: creating tap device failed: %s", name,
+ strerror(errno));
+ error = errno;
+ goto error;
+ }
+
+ /* Make non-blocking. */
+ error = set_nonblocking(netdev_obj->tap_fd);
+ if (error) {
+ goto error;
+ }
+
+ return 0;
+
+error:
+ netdev_destroy(name);
+ return error;
+}
+
+/* Destroys the netdev object 'netdev_obj_'. */
+static void
+netdev_linux_destroy(struct netdev_obj *netdev_obj_)
+{
+ struct netdev_obj_linux *netdev_obj = netdev_obj_linux_cast(netdev_obj_);
+
+ if (netdev_obj->tap_fd >= 0) {
+ close(netdev_obj->tap_fd);
+ }
+ free(netdev_obj);
+
+ return;
+}
+
static int
-netdev_linux_open(const char *name, char *suffix, int ethertype,
- struct netdev **netdevp)
+netdev_linux_open(const char *name, int ethertype, struct netdev **netdevp)
{
struct netdev_linux *netdev;
enum netdev_flags flags;
/* Allocate network device. */
netdev = xcalloc(1, sizeof *netdev);
- netdev_init(&netdev->netdev, suffix, &netdev_linux_class);
+ netdev_init(&netdev->netdev, name, &netdev_linux_class);
netdev->netdev_fd = -1;
netdev->tap_fd = -1;
- netdev->cache = shash_find_data(&cache_map, suffix);
+ netdev->cache = shash_find_data(&cache_map, name);
if (!netdev->cache) {
if (shash_is_empty(&cache_map)) {
int error = rtnetlink_notifier_register(
}
}
netdev->cache = xmalloc(sizeof *netdev->cache);
- netdev->cache->shash_node = shash_add(&cache_map, suffix,
+ netdev->cache->shash_node = shash_add(&cache_map, name,
netdev->cache);
netdev->cache->valid = 0;
netdev->cache->ref_cnt = 0;
}
netdev->cache->ref_cnt++;
- if (!strncmp(name, "tap:", 4)) {
+ if (!strcmp(netdev_get_type(&netdev->netdev), "tap")) {
static const char tap_dev[] = "/dev/net/tun";
struct ifreq ifr;
/* Create tap device. */
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
- strncpy(ifr.ifr_name, suffix, sizeof ifr.ifr_name);
+ strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
if (ioctl(netdev->tap_fd, TUNSETIFF, &ifr) == -1) {
- VLOG_WARN("%s: creating tap device failed: %s", suffix,
+ VLOG_WARN("%s: creating tap device failed: %s", name,
strerror(errno));
error = errno;
goto error;
if (bind(netdev->netdev_fd,
(struct sockaddr *) &sll, sizeof sll) < 0) {
error = errno;
- VLOG_ERR("bind to %s failed: %s", suffix, strerror(error));
+ VLOG_ERR("bind to %s failed: %s", name, strerror(error));
goto error;
}
const uint8_t mac[ETH_ADDR_LEN])
{
struct netdev_linux *netdev = netdev_linux_cast(netdev_);
- int error = set_etheraddr(netdev_get_name(netdev_), ARPHRD_ETHER, mac);
- if (!error) {
- memcpy(netdev->cache->etheraddr, mac, ETH_ADDR_LEN);
+ int error;
+
+ if (!(netdev->cache->valid & VALID_ETHERADDR)
+ || !eth_addr_equals(netdev->cache->etheraddr, mac)) {
+ error = set_etheraddr(netdev_get_name(netdev_), ARPHRD_ETHER, mac);
+ if (!error) {
+ netdev->cache->valid |= VALID_ETHERADDR;
+ memcpy(netdev->cache->etheraddr, mac, ETH_ADDR_LEN);
+ }
+ } else {
+ error = 0;
}
return error;
}
return 0;
}
+/* Returns the ifindex of 'netdev', if successful, as a positive number.
+ * On failure, returns a negative errno value. */
+static int
+netdev_linux_get_ifindex(const struct netdev *netdev)
+{
+ int ifindex, error;
+
+ error = get_ifindex(netdev, &ifindex);
+ return error ? -error : ifindex;
+}
+
static int
netdev_linux_get_carrier(const struct netdev *netdev_, bool *carrier)
{
/* Stores the features supported by 'netdev' into each of '*current',
* '*advertised', '*supported', and '*peer' that are non-null. Each value is a
* bitmap of "enum ofp_port_features" bits, in host byte order. Returns 0 if
- * successful, otherwise a positive errno value. On failure, all of the
- * passed-in values are set to 0. */
+ * successful, otherwise a positive errno value. */
static int
netdev_linux_get_features(struct netdev *netdev,
uint32_t *current, uint32_t *advertised,
/* Adds 'router' as a default IP gateway. */
static int
-netdev_linux_add_router(struct netdev *netdev UNUSED, struct in_addr router)
+netdev_linux_add_router(struct netdev *netdev OVS_UNUSED, struct in_addr router)
{
struct in_addr any = { INADDR_ANY };
struct rtentry rt;
static void
netdev_linux_poll_cb(const struct rtnetlink_change *change,
- void *aux UNUSED)
+ void *aux OVS_UNUSED)
{
if (change) {
struct list *list = shash_find_data(&netdev_linux_notifiers,
}
const struct netdev_class netdev_linux_class = {
- "", /* prefix */
- "linux", /* name */
+ "system", /* type */
netdev_linux_init,
netdev_linux_run,
netdev_linux_wait,
+ netdev_linux_create,
+ netdev_linux_destroy,
+ NULL, /* reconfigure */
+
netdev_linux_open,
netdev_linux_close,
netdev_linux_set_etheraddr,
netdev_linux_get_etheraddr,
netdev_linux_get_mtu,
+ netdev_linux_get_ifindex,
netdev_linux_get_carrier,
netdev_linux_get_stats,
};
const struct netdev_class netdev_tap_class = {
- "tap", /* prefix */
- "tap", /* name */
+ "tap", /* type */
netdev_linux_init,
NULL, /* run */
NULL, /* wait */
+ netdev_linux_create,
+ netdev_linux_destroy,
+ NULL, /* reconfigure */
+
netdev_linux_open,
netdev_linux_close,
netdev_linux_set_etheraddr,
netdev_linux_get_etheraddr,
netdev_linux_get_mtu,
+ netdev_linux_get_ifindex,
netdev_linux_get_carrier,
netdev_linux_get_stats,