dpif-linux: Clean up vports that are no longer in config.
[openvswitch] / lib / dpif-linux.c
index 94c3cf5c5a756af34c100d4facc3b4bc4bdf30d5..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;
@@ -188,14 +189,37 @@ dpif_linux_get_all_names(const struct dpif *dpif_, struct svec *all_names)
 }
 
 static int
-dpif_linux_delete(struct dpif *dpif_)
+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);
 }
 
 static int
 dpif_linux_get_stats(const struct dpif *dpif_, struct odp_stats *stats)
 {
+    memset(stats, 0, sizeof *stats);
     return do_ioctl(dpif_, ODP_DP_STATS, stats);
 }
 
@@ -229,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;
     }
@@ -240,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
@@ -395,6 +439,19 @@ dpif_linux_recv_set_mask(struct dpif *dpif_, int listen_mask)
     return do_ioctl(dpif_, ODP_SET_LISTEN_MASK, &listen_mask);
 }
 
+static int
+dpif_linux_get_sflow_probability(const struct dpif *dpif_,
+                                 uint32_t *probability)
+{
+    return do_ioctl(dpif_, ODP_GET_SFLOW_PROBABILITY, probability);
+}
+
+static int
+dpif_linux_set_sflow_probability(struct dpif *dpif_, uint32_t probability)
+{
+    return do_ioctl(dpif_, ODP_SET_SFLOW_PROBABILITY, &probability);
+}
+
 static int
 dpif_linux_recv(struct dpif *dpif_, struct ofpbuf **bufp)
 {
@@ -453,7 +510,7 @@ const struct dpif_class dpif_linux_class = {
     dpif_linux_open,
     dpif_linux_close,
     dpif_linux_get_all_names,
-    dpif_linux_delete,
+    dpif_linux_destroy,
     dpif_linux_get_stats,
     dpif_linux_get_drop_frags,
     dpif_linux_set_drop_frags,
@@ -474,6 +531,8 @@ const struct dpif_class dpif_linux_class = {
     dpif_linux_execute,
     dpif_linux_recv_get_mask,
     dpif_linux_recv_set_mask,
+    dpif_linux_get_sflow_probability,
+    dpif_linux_set_sflow_probability,
     dpif_linux_recv,
     dpif_linux_recv_wait,
 };
@@ -554,13 +613,14 @@ make_openvswitch_device(int minor, char **fnp)
     struct stat s;
     char fn[128];
 
+    *fnp = NULL;
+
     major = get_openvswitch_major();
     if (major < 0) {
         return -major;
     }
     dev = makedev(major, minor);
 
-    *fnp = NULL;
     sprintf(fn, "%s/dp%d", dirname, minor);
     if (!stat(fn, &s)) {
         if (!S_ISCHR(s.st_mode)) {
@@ -660,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;
 }