Merge 'master' into 'next'.
[sliver-openvswitch.git] / lib / dpif-linux.c
index 10ddd51..7e6c491 100644 (file)
@@ -35,6 +35,7 @@
 #include "bitmap.h"
 #include "dpif-provider.h"
 #include "netdev.h"
+#include "netdev-linux.h"
 #include "netdev-vport.h"
 #include "netlink-socket.h"
 #include "netlink.h"
@@ -431,6 +432,12 @@ dpif_linux_port_query__(const struct dpif *dpif, uint32_t port_no,
         dpif_port->name = xstrdup(reply.name);
         dpif_port->type = xstrdup(netdev_vport_get_netdev_type(&reply));
         dpif_port->port_no = reply.port_no;
+        if (reply.stats) {
+            netdev_stats_from_rtnl_link_stats64(&dpif_port->stats,
+                                                reply.stats);
+        } else {
+            memset(&dpif_port->stats, 0xff, sizeof dpif_port->stats);
+        }
         ofpbuf_delete(buf);
     }
     return error;
@@ -472,6 +479,8 @@ dpif_linux_flow_flush(struct dpif *dpif_)
 
 struct dpif_linux_port_state {
     struct nl_dump dump;
+    unsigned long *port_bitmap; /* Ports in the datapath. */
+    bool complete;              /* Dump completed without error. */
 };
 
 static int
@@ -483,6 +492,8 @@ dpif_linux_port_dump_start(const struct dpif *dpif_, void **statep)
     struct ofpbuf *buf;
 
     *statep = state = xmalloc(sizeof *state);
+    state->port_bitmap = bitmap_allocate(LRU_MAX_PORTS);
+    state->complete = false;
 
     dpif_linux_vport_init(&request);
     request.cmd = ODP_DP_CMD_GET;
@@ -506,6 +517,7 @@ dpif_linux_port_dump_next(const struct dpif *dpif OVS_UNUSED, void *state_,
     int error;
 
     if (!nl_dump_next(&state->dump, &buf)) {
+        state->complete = true;
         return EOF;
     }
 
@@ -514,17 +526,39 @@ dpif_linux_port_dump_next(const struct dpif *dpif OVS_UNUSED, void *state_,
         return error;
     }
 
+    if (vport.port_no < LRU_MAX_PORTS) {
+        bitmap_set1(state->port_bitmap, vport.port_no);
+    }
+
     dpif_port->name = (char *) vport.name;
     dpif_port->type = (char *) netdev_vport_get_netdev_type(&vport);
     dpif_port->port_no = vport.port_no;
+    if (vport.stats) {
+        netdev_stats_from_rtnl_link_stats64(&dpif_port->stats, vport.stats);
+    } else {
+        memset(&dpif_port->stats, 0xff, sizeof dpif_port->stats);
+    }
     return 0;
 }
 
 static int
-dpif_linux_port_dump_done(const struct dpif *dpif OVS_UNUSED, void *state_)
+dpif_linux_port_dump_done(const struct dpif *dpif_, void *state_)
 {
+    struct dpif_linux *dpif = dpif_linux_cast(dpif_);
     struct dpif_linux_port_state *state = state_;
     int error = nl_dump_done(&state->dump);
+
+    if (state->complete) {
+        uint16_t i;
+
+        for (i = 0; i < LRU_MAX_PORTS; i++) {
+            if (!bitmap_is_set(state->port_bitmap, i)) {
+                dpif_linux_push_port(dpif, i);
+            }
+        }
+    }
+
+    free(state->port_bitmap);
     free(state);
     return error;
 }
@@ -994,12 +1028,12 @@ dpif_linux_recv_purge(struct dpif *dpif_)
 
 const struct dpif_class dpif_linux_class = {
     "system",
-    NULL,                       /* run */
-    NULL,                       /* wait */
     dpif_linux_enumerate,
     dpif_linux_open,
     dpif_linux_close,
     dpif_linux_destroy,
+    NULL,                       /* run */
+    NULL,                       /* wait */
     dpif_linux_get_stats,
     dpif_linux_get_drop_frags,
     dpif_linux_set_drop_frags,
@@ -1072,7 +1106,7 @@ dpif_linux_is_internal_device(const char *name)
     error = dpif_linux_vport_get(name, &reply, &buf);
     if (!error) {
         ofpbuf_delete(buf);
-    } else if (error != ENODEV) {
+    } else if (error != ENODEV && error != ENOENT) {
         VLOG_WARN_RL(&error_rl, "%s: vport query failed (%s)",
                      name, strerror(error));
     }
@@ -1282,6 +1316,15 @@ dpif_linux_vport_transact(const struct dpif_linux_vport *request,
 
     assert((reply != NULL) == (bufp != NULL));
 
+    error = dpif_linux_init();
+    if (error) {
+        if (reply) {
+            *bufp = NULL;
+            dpif_linux_vport_init(reply);
+        }
+        return error;
+    }
+
     request_buf = ofpbuf_new(1024);
     dpif_linux_vport_to_ofpbuf(request, request_buf);
     error = nl_sock_transact(genl_sock, request_buf, bufp);