netdev-linux: Make netdev_linux_get_in6() conform to API definition.
authorAlex Wang <alexw@nicira.com>
Thu, 23 Jul 2015 23:25:32 +0000 (16:25 -0700)
committerAlex Wang <alexw@nicira.com>
Tue, 28 Jul 2015 16:34:31 +0000 (09:34 -0700)
The get_in6() API defined in netdev-provider.h requires the return
of error values when the 'netdev' has no assigned IPv6 address or
the 'netdev' does not support IPv6.  However, the netdev_linux_get_in6()
implementation does not follow this (always return 0).  And this
causes the a bug in deleting vlan interfaces created for vlan
splinter.

This commit makes netdev_linux_get_in6() conform to the API definition
and returns the specified error value when failing to get IPv6 address.

VMware-BZ: #1485521
Reported-by: Ronald Lee <ronaldlee@vmware.com>
Signed-off-by: Alex Wang <alexw@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
lib/netdev-linux.c

index 08c624e..bdc672d 100644 (file)
@@ -458,6 +458,7 @@ struct netdev_linux {
     int netdev_policing_error;  /* Cached error code from set policing. */
     int get_features_error;     /* Cached error code from ETHTOOL_GSET. */
     int get_ifindex_error;      /* Cached error code from SIOCGIFINDEX. */
+    int in6_error;              /* Cached error code from reading in6 addr. */
 
     enum netdev_features current;    /* Cached from ETHTOOL_GSET. */
     enum netdev_features advertised; /* Cached from ETHTOOL_GSET. */
@@ -2481,12 +2482,14 @@ parse_if_inet6_line(const char *line,
                     ifname);
 }
 
-/* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address (if
- * 'in6' is non-null) and returns true.  Otherwise, returns false. */
+/* If 'netdev' has an assigned IPv6 address, sets '*in6' to that address.
+ * Otherwise, sets '*in6' to 'in6addr_any' and returns the corresponding
+ * error. */
 static int
 netdev_linux_get_in6(const struct netdev *netdev_, struct in6_addr *in6)
 {
     struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+    int error;
 
     ovs_mutex_lock(&netdev->mutex);
     if (!(netdev->cache_valid & VALID_IN6)) {
@@ -2494,6 +2497,7 @@ netdev_linux_get_in6(const struct netdev *netdev_, struct in6_addr *in6)
         char line[128];
 
         netdev->in6 = in6addr_any;
+        netdev->in6_error = EADDRNOTAVAIL;
 
         file = fopen("/proc/net/if_inet6", "r");
         if (file != NULL) {
@@ -2505,17 +2509,21 @@ netdev_linux_get_in6(const struct netdev *netdev_, struct in6_addr *in6)
                     && !strcmp(name, ifname))
                 {
                     netdev->in6 = in6_tmp;
+                    netdev->in6_error = 0;
                     break;
                 }
             }
             fclose(file);
+        } else {
+            netdev->in6_error = EOPNOTSUPP;
         }
         netdev->cache_valid |= VALID_IN6;
     }
     *in6 = netdev->in6;
+    error = netdev->in6_error;
     ovs_mutex_unlock(&netdev->mutex);
 
-    return 0;
+    return error;
 }
 
 static void