Merge "master" into "wdp".
[sliver-openvswitch.git] / lib / netdev.c
index 3102e6e..58f6ceb 100644 (file)
@@ -304,7 +304,6 @@ create_device(struct netdev_options *options, struct netdev_dev **netdev_devp)
  * If the 'may_open' flag is set then the call will succeed even if another
  * caller has already opened it.  It may be to false if the device should not
  * currently be open. */
-
 int
 netdev_open(struct netdev_options *options, struct netdev **netdevp)
 {
@@ -371,6 +370,14 @@ netdev_open_default(const char *name, struct netdev **netdevp)
     return netdev_open(&options, netdevp);
 }
 
+/* Increments the reference count on 'netdev'.  Returns 'netdev'. */
+struct netdev *
+netdev_reopen(struct netdev *netdev)
+{
+    netdev->ref_cnt++;
+    return netdev;
+}
+
 /* Reconfigures the device 'netdev' with 'args'.  'args' may be empty
  * or NULL if none are needed. */
 int
@@ -396,11 +403,13 @@ netdev_reconfigure(struct netdev *netdev, const struct shash *args)
     return 0;
 }
 
-/* Closes and destroys 'netdev'. */
+/* Decrements the reference count on 'netdev'.  If the reference count reaches
+ * zero, closes and destroys 'netdev'. */
 void
 netdev_close(struct netdev *netdev)
 {
-    if (netdev) {
+    assert(!netdev || netdev->ref_cnt > 0);
+    if (netdev && !--netdev->ref_cnt) {
         struct netdev_dev *netdev_dev = netdev_get_dev(netdev);
 
         assert(netdev_dev->ref_cnt);
@@ -629,23 +638,37 @@ netdev_get_mtu(const struct netdev *netdev, int *mtup)
  * value should be unique within a host and remain stable at least until
  * reboot.  SNMP says an ifindex "ranges between 1 and the value of ifNumber"
  * but many systems do not follow this rule anyhow.
+ *
+ * Some network devices may not implement support for this function.  In such
+ * cases this function will always return -EOPNOTSUPP.
  */
 int
 netdev_get_ifindex(const struct netdev *netdev)
 {
-    return netdev_get_dev(netdev)->netdev_class->get_ifindex(netdev);
+    int (*get_ifindex)(const struct netdev *);
+
+    get_ifindex = netdev_get_dev(netdev)->netdev_class->get_ifindex;
+
+    return get_ifindex ? get_ifindex(netdev) : -EOPNOTSUPP;
 }
 
 /* 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. */
+ * passed-in values are set to 0.
+ *
+ * Some network devices may not implement support for this function.  In such
+ * cases this function will always return EOPNOTSUPP.
+ */
 int
 netdev_get_features(struct netdev *netdev,
                     uint32_t *current, uint32_t *advertised,
                     uint32_t *supported, uint32_t *peer)
 {
+    int (*get_features)(struct netdev *netdev,
+                        uint32_t *current, uint32_t *advertised,
+                        uint32_t *supported, uint32_t *peer);
     uint32_t dummy[4];
     int error;
 
@@ -662,8 +685,10 @@ netdev_get_features(struct netdev *netdev,
         peer = &dummy[3];
     }
 
-    error = netdev_get_dev(netdev)->netdev_class->get_features(netdev, current,
-            advertised, supported, peer);
+    get_features = netdev_get_dev(netdev)->netdev_class->get_features;
+    error = get_features
+                    ? get_features(netdev, current, advertised, supported, peer)
+                    : EOPNOTSUPP;
     if (error) {
         *current = *advertised = *supported = *peer = 0;
     }
@@ -942,6 +967,19 @@ netdev_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
     return error;
 }
 
+/* Attempts to change the stats for 'netdev' to those provided in 'stats'.
+ * Returns 0 if successful, otherwise a positive errno value.
+ *
+ * This will probably fail for most network devices.  Some devices might only
+ * allow setting their stats to 0. */
+int
+netdev_set_stats(struct netdev *netdev, const struct netdev_stats *stats)
+{
+    return (netdev_get_dev(netdev)->netdev_class->set_stats
+             ? netdev_get_dev(netdev)->netdev_class->set_stats(netdev, stats)
+             : EOPNOTSUPP);
+}
+
 /* Attempts to set input rate limiting (policing) policy, such that up to
  * 'kbits_rate' kbps of traffic is accepted, with a maximum accumulative burst
  * size of 'kbits' kb. */
@@ -1103,6 +1141,7 @@ netdev_init(struct netdev *netdev, struct netdev_dev *netdev_dev)
 {
     memset(netdev, 0, sizeof *netdev);
     netdev->netdev_dev = netdev_dev;
+    netdev->ref_cnt = 1;
     list_push_back(&netdev_list, &netdev->node);
 }
 
@@ -1110,7 +1149,7 @@ netdev_init(struct netdev *netdev, struct netdev_dev *netdev_dev)
  *
  * Normally this function only needs to be called from netdev_close().
  * However, it may be called by providers due to an error on opening
- * that occurs after initialization.  It this case netdev_close() would
+ * that occurs after initialization.  In this case netdev_close() would
  * never be called. */
 void
 netdev_uninit(struct netdev *netdev, bool close)