dpif: New function dpif_create_and_open().
[sliver-openvswitch.git] / lib / netdev-linux.c
index 2faffa3..b8e8015 100644 (file)
@@ -239,9 +239,11 @@ netdev_linux_open(const char *name, char *suffix, int ethertype,
 
         /* Create tap device. */
         ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
-        error = netdev_linux_do_ioctl(&netdev->netdev, &ifr,
-                                      TUNSETIFF, "TUNSETIFF");
-        if (error) {
+        strncpy(ifr.ifr_name, suffix, sizeof ifr.ifr_name);
+        if (ioctl(netdev->tap_fd, TUNSETIFF, &ifr) == -1) {
+            VLOG_WARN("%s: creating tap device failed: %s", suffix,
+                      strerror(errno));
+            error = errno;
             goto error;
         }
 
@@ -368,7 +370,7 @@ netdev_linux_recv(struct netdev *netdev_, void *data, size_t size)
 
     if (netdev->tap_fd < 0) {
         /* Device was opened with NETDEV_ETH_TYPE_NONE. */
-        return EAGAIN;
+        return -EAGAIN;
     }
 
     for (;;) {
@@ -380,7 +382,7 @@ netdev_linux_recv(struct netdev *netdev_, void *data, size_t size)
                 VLOG_WARN_RL(&rl, "error receiving Ethernet packet on %s: %s",
                              strerror(errno), netdev_get_name(netdev_));
             }
-            return errno;
+            return -errno;
         }
     }
 }
@@ -490,9 +492,17 @@ netdev_linux_set_etheraddr(struct netdev *netdev_,
                            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;
 }
@@ -538,6 +548,17 @@ netdev_linux_get_mtu(const struct netdev *netdev_, int *mtup)
     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)
 {
@@ -710,8 +731,7 @@ netdev_linux_get_stats(const struct netdev *netdev_, struct netdev_stats *stats)
 /* 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,
@@ -1379,6 +1399,7 @@ const struct netdev_class netdev_linux_class = {
     netdev_linux_set_etheraddr,
     netdev_linux_get_etheraddr,
     netdev_linux_get_mtu,
+    netdev_linux_get_ifindex,
     netdev_linux_get_carrier,
     netdev_linux_get_stats,
 
@@ -1423,6 +1444,7 @@ const struct netdev_class netdev_tap_class = {
     netdev_linux_set_etheraddr,
     netdev_linux_get_etheraddr,
     netdev_linux_get_mtu,
+    netdev_linux_get_ifindex,
     netdev_linux_get_carrier,
     netdev_linux_get_stats,
 
@@ -1496,6 +1518,7 @@ get_stats_via_netlink(int ifindex, struct netdev_stats *stats)
 
     if (!attrs[IFLA_STATS]) {
         VLOG_WARN_RL(&rl, "RTM_GETLINK reply lacks stats");
+        ofpbuf_delete(reply);
         return EPROTO;
     }
 
@@ -1522,6 +1545,8 @@ get_stats_via_netlink(int ifindex, struct netdev_stats *stats)
     stats->tx_heartbeat_errors = rtnl_stats->tx_heartbeat_errors;
     stats->tx_window_errors = rtnl_stats->tx_window_errors;
 
+    ofpbuf_delete(reply);
+
     return 0;
 }