dpif-linux: Clean up vports that are no longer in config.
[openvswitch] / lib / dpif-linux.c
index ddf9298e5220b5a2fe8e89323592a5e398c44008..87c9f327c79bf95b5357d64e3cd923c78df5bcd0 100644 (file)
@@ -31,6 +31,7 @@
 #include <unistd.h>
 
 #include "dpif-provider.h"
+#include "netdev.h"
 #include "ofpbuf.h"
 #include "poll-loop.h"
 #include "rtnetlink.h"
@@ -107,7 +108,7 @@ dpif_linux_enumerate(struct svec *all_dps)
 }
 
 static int
-dpif_linux_open(const char *name, const char *type UNUSED, bool create,
+dpif_linux_open(const char *name, const char *type OVS_UNUSED, bool create,
                 struct dpif **dpifp)
 {
     int minor;
@@ -190,6 +191,28 @@ dpif_linux_get_all_names(const struct dpif *dpif_, struct svec *all_names)
 static int
 dpif_linux_destroy(struct dpif *dpif_)
 {
+    struct odp_port *ports;
+    size_t n_ports;
+    int err;
+    int i;
+
+    err = dpif_port_list(dpif_, &ports, &n_ports);
+    if (err) {
+        return err;
+    }
+
+    for (i = 0; i < n_ports; i++) {
+        if (ports[i].port != ODPP_LOCAL) {
+            err = do_ioctl(dpif_, ODP_VPORT_DEL, ports[i].devname);
+            if (err) {
+                VLOG_WARN_RL(&error_rl, "%s: error deleting port %s (%s)",
+                             dpif_name(dpif_), ports[i].devname, strerror(err));
+            }
+        }
+    }
+
+    free(ports);
+
     return do_ioctl(dpif_, ODP_DP_DESTROY, NULL);
 }
 
@@ -230,7 +253,7 @@ dpif_linux_port_add(struct dpif *dpif_, const char *devname, uint16_t flags,
     memset(&port, 0, sizeof port);
     strncpy(port.devname, devname, sizeof port.devname);
     port.flags = flags;
-    error = do_ioctl(dpif_, ODP_PORT_ADD, &port);
+    error = do_ioctl(dpif_, ODP_PORT_ATTACH, &port);
     if (!error) {
         *port_no = port.port;
     }
@@ -241,7 +264,27 @@ static int
 dpif_linux_port_del(struct dpif *dpif_, uint16_t port_no)
 {
     int tmp = port_no;
-    return do_ioctl(dpif_, ODP_PORT_DEL, &tmp);
+    int err;
+    struct odp_port port;
+
+    err = dpif_port_query_by_number(dpif_, port_no, &port);
+    if (err) {
+        return err;
+    }
+
+    err = do_ioctl(dpif_, ODP_PORT_DETACH, &tmp);
+    if (err) {
+        return err;
+    }
+
+    if (!netdev_is_open(port.devname)) {
+        /* Try deleting the port if no one has it open.  This shouldn't
+         * actually be necessary unless the config changed while we weren't
+         * running but it won't hurt anything if the port is already gone. */
+        do_ioctl(dpif_, ODP_VPORT_DEL, port.devname);
+    }
+
+    return 0;
 }
 
 static int
@@ -677,6 +720,8 @@ get_major(const char *target)
         }
     }
 
+    fclose(file);
+
     VLOG_ERR("%s: %s major not found (is the module loaded?)", fn, target);
     return -ENODEV;
 }