Merge branch 'master' of git://openvswitch.org/openvswitch
[sliver-openvswitch.git] / lib / netdev.c
index 653f5bc..d5a51fa 100644 (file)
@@ -89,6 +89,8 @@ netdev_initialize(void)
         netdev_register_provider(&netdev_tap_class);
         netdev_register_provider(&netdev_bsd_class);
 #endif
+       netdev_register_provider(&netdev_tunnel_class);
+       netdev_register_provider(&netdev_pltap_class);
     }
 }
 
@@ -139,7 +141,7 @@ netdev_register_provider(const struct netdev_class *new_class)
         int error = new_class->init();
         if (error) {
             VLOG_ERR("failed to initialize %s network device class: %s",
-                     new_class->type, strerror(error));
+                     new_class->type, ovs_strerror(error));
             return error;
         }
     }
@@ -277,14 +279,17 @@ netdev_open(const char *name, const char *type, struct netdev **netdevp)
     return 0;
 }
 
-/* Returns a reference to 'netdev_' for the caller to own. */
+/* Returns a reference to 'netdev_' for the caller to own. Returns null if
+ * 'netdev_' is null. */
 struct netdev *
 netdev_ref(const struct netdev *netdev_)
 {
     struct netdev *netdev = CONST_CAST(struct netdev *, netdev_);
 
-    ovs_assert(netdev->ref_cnt > 0);
-    netdev->ref_cnt++;
+    if (netdev) {
+        ovs_assert(netdev->ref_cnt > 0);
+        netdev->ref_cnt++;
+    }
     return netdev;
 }
 
@@ -523,7 +528,7 @@ netdev_get_mtu(const struct netdev *netdev, int *mtup)
         *mtup = 0;
         if (error != EOPNOTSUPP) {
             VLOG_DBG_RL(&rl, "failed to retrieve MTU for network device %s: "
-                         "%s", netdev_get_name(netdev), strerror(error));
+                         "%s", netdev_get_name(netdev), ovs_strerror(error));
         }
     }
     return error;
@@ -544,7 +549,7 @@ netdev_set_mtu(const struct netdev *netdev, int mtu)
     error = class->set_mtu ? class->set_mtu(netdev, mtu) : EOPNOTSUPP;
     if (error && error != EOPNOTSUPP) {
         VLOG_DBG_RL(&rl, "failed to set MTU for network device %s: %s",
-                     netdev_get_name(netdev), strerror(error));
+                     netdev_get_name(netdev), ovs_strerror(error));
     }
 
     return error;
@@ -822,7 +827,7 @@ do_update_flags(struct netdev *netdev, enum netdev_flags off,
     if (error) {
         VLOG_WARN_RL(&rl, "failed to %s flags for network device %s: %s",
                      off || on ? "set" : "get", netdev_get_name(netdev),
-                     strerror(error));
+                     ovs_strerror(error));
         old_flags = 0;
     } else if ((off || on) && sfp) {
         enum netdev_flags new_flags = (old_flags & ~off) | on;
@@ -923,8 +928,7 @@ netdev_arp_lookup(const struct netdev *netdev,
                   ovs_be32 ip, uint8_t mac[ETH_ADDR_LEN])
 {
     int error = (netdev->netdev_class->arp_lookup
-                 ? netdev->netdev_class->arp_lookup(netdev,
-                        ip, mac)
+                 ? netdev->netdev_class->arp_lookup(netdev, ip, mac)
                  : EOPNOTSUPP);
     if (error) {
         memset(mac, 0, ETH_ADDR_LEN);
@@ -949,11 +953,10 @@ netdev_get_carrier(const struct netdev *netdev)
         return true;
     }
 
-    error = netdev->netdev_class->get_carrier(netdev,
-                                                              &carrier);
+    error = netdev->netdev_class->get_carrier(netdev, &carrier);
     if (error) {
         VLOG_DBG("%s: failed to get network device carrier status, assuming "
-                 "down: %s", netdev_get_name(netdev), strerror(error));
+                 "down: %s", netdev_get_name(netdev), ovs_strerror(error));
         carrier = false;
     }
 
@@ -1243,7 +1246,8 @@ netdev_delete_queue(struct netdev *netdev, unsigned int queue_id)
 /* Obtains statistics about 'queue_id' on 'netdev'.  On success, returns 0 and
  * fills 'stats' with the queue's statistics; individual members of 'stats' may
  * be set to all-1-bits if the statistic is unavailable.  On failure, returns a
- * positive errno value and fills 'stats' with all-1-bits. */
+ * positive errno value and fills 'stats' with values indicating unsupported
+ * statistics. */
 int
 netdev_get_queue_stats(const struct netdev *netdev, unsigned int queue_id,
                        struct netdev_queue_stats *stats)
@@ -1255,7 +1259,10 @@ netdev_get_queue_stats(const struct netdev *netdev, unsigned int queue_id,
               ? class->get_queue_stats(netdev, queue_id, stats)
               : EOPNOTSUPP);
     if (retval) {
-        memset(stats, 0xff, sizeof *stats);
+        stats->tx_bytes = UINT64_MAX;
+        stats->tx_packets = UINT64_MAX;
+        stats->tx_errors = UINT64_MAX;
+        stats->created = LLONG_MIN;
     }
     return retval;
 }
@@ -1381,17 +1388,24 @@ netdev_get_class(const struct netdev *netdev)
 
 /* Returns the netdev with 'name' or NULL if there is none.
  *
- * The caller must not free the returned value. */
+ * The caller must free the returned netdev with netdev_close(). */
 struct netdev *
 netdev_from_name(const char *name)
 {
-    return shash_find_data(&netdev_shash, name);
+    struct netdev *netdev;
+
+    netdev = shash_find_data(&netdev_shash, name);
+    if (netdev) {
+        netdev_ref(netdev);
+    }
+
+    return netdev;
 }
 
 /* Fills 'device_list' with devices that match 'netdev_class'.
  *
- * The caller is responsible for initializing and destroying 'device_list'
- * but the contained netdevs must not be freed. */
+ * The caller is responsible for initializing and destroying 'device_list' and
+ * must close each device on the list. */
 void
 netdev_get_devices(const struct netdev_class *netdev_class,
                    struct shash *device_list)
@@ -1401,6 +1415,7 @@ netdev_get_devices(const struct netdev_class *netdev_class,
         struct netdev *dev = node->data;
 
         if (dev->netdev_class == netdev_class) {
+            dev->ref_cnt++;
             shash_add(device_list, node->name, node->data);
         }
     }
@@ -1409,8 +1424,10 @@ netdev_get_devices(const struct netdev_class *netdev_class,
 const char *
 netdev_get_type_from_name(const char *name)
 {
-    const struct netdev *dev = netdev_from_name(name);
-    return dev ? netdev_get_type(dev) : NULL;
+    struct netdev *dev = netdev_from_name(name);
+    const char *type = dev ? netdev_get_type(dev) : NULL;
+    netdev_close(dev);
+    return type;
 }
 \f
 void