vswitchd: Make the maximum size of MAC learning tables user-configurable.
[sliver-openvswitch.git] / lib / netdev-linux.c
index 0460c06..9b59bc9 100644 (file)
@@ -743,7 +743,6 @@ netdev_linux_destroy(struct netdev_dev *netdev_dev_)
 static int
 netdev_linux_open(struct netdev_dev *netdev_dev_, struct netdev **netdevp)
 {
-    struct netdev_dev_linux *netdev_dev = netdev_dev_linux_cast(netdev_dev_);
     struct netdev_linux *netdev;
     enum netdev_flags flags;
     int error;
@@ -768,17 +767,6 @@ netdev_linux_open(struct netdev_dev *netdev_dev_, struct netdev **netdevp)
         }
     }
 
-    if (!strcmp(netdev_dev_get_type(netdev_dev_), "tap") &&
-        !netdev_dev->state.tap.opened) {
-
-        /* We assume that the first user of the tap device is the primary user
-         * and give them the tap FD.  Subsequent users probably just expect
-         * this to be a system device so open it normally to avoid send/receive
-         * directions appearing to be reversed. */
-        netdev->fd = netdev_dev->state.tap.fd;
-        netdev_dev->state.tap.opened = true;
-    }
-
     *netdevp = &netdev->netdev;
     return 0;
 
@@ -803,6 +791,8 @@ static int
 netdev_linux_listen(struct netdev *netdev_)
 {
     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+    struct netdev_dev_linux *netdev_dev =
+                                netdev_dev_linux_cast(netdev_get_dev(netdev_));
     struct sockaddr_ll sll;
     int ifindex;
     int error;
@@ -812,6 +802,13 @@ netdev_linux_listen(struct netdev *netdev_)
         return 0;
     }
 
+    if (!strcmp(netdev_get_type(netdev_), "tap")
+        && !netdev_dev->state.tap.opened) {
+        netdev->fd = netdev_dev->state.tap.fd;
+        netdev_dev->state.tap.opened = true;
+        return 0;
+    }
+
     /* Create file descriptor. */
     fd = socket(PF_PACKET, SOCK_RAW, 0);
     if (fd < 0) {
@@ -1028,6 +1025,7 @@ netdev_linux_set_etheraddr(struct netdev *netdev_,
     struct netdev_dev_linux *netdev_dev =
                                 netdev_dev_linux_cast(netdev_get_dev(netdev_));
     int error;
+    bool up_again = false;
 
     if (netdev_dev->cache_valid & VALID_ETHERADDR) {
         if (netdev_dev->ether_addr_error) {
@@ -1039,6 +1037,15 @@ netdev_linux_set_etheraddr(struct netdev *netdev_,
         netdev_dev->cache_valid &= ~VALID_ETHERADDR;
     }
 
+    /* Tap devices must be brought down before setting the address. */
+    if (!strcmp(netdev_get_type(netdev_), "tap")) {
+        enum netdev_flags flags;
+
+        if (!netdev_get_flags(netdev_, &flags) && (flags & NETDEV_UP)) {
+            netdev_turn_flags_off(netdev_, NETDEV_UP, false);
+            up_again = true;
+        }
+    }
     error = set_etheraddr(netdev_get_name(netdev_), mac);
     if (!error || error == ENODEV) {
         netdev_dev->ether_addr_error = error;
@@ -1048,6 +1055,10 @@ netdev_linux_set_etheraddr(struct netdev *netdev_,
         }
     }
 
+    if (up_again) {
+        netdev_turn_flags_on(netdev_, NETDEV_UP, false);
+    }
+
     return error;
 }
 
@@ -1333,7 +1344,7 @@ get_stats_via_vport(const struct netdev *netdev_,
         int error;
 
         error = netdev_vport_get_stats(netdev_, stats);
-        if (error) {
+        if (error && error != ENOENT) {
             VLOG_WARN_RL(&rl, "%s: obtaining netdev stats via vport failed "
                          "(%s)", netdev_get_name(netdev_), strerror(error));
         }