datapath: Change ODP_PORT_LIST semantics.
[openvswitch] / lib / dpif.c
index 877cfc823d1577e710b8b2d45025563d5a3f97ad..85d05bb714ce61df9078aa8654f71a183c02dab7 100644 (file)
@@ -218,25 +218,7 @@ dpif_set_drop_frags(struct dpif *dpif, bool drop_frags)
 }
 
 int
-dpif_get_listen_mask(const struct dpif *dpif, int *listen_mask)
-{
-    int error = do_ioctl(dpif, ODP_GET_LISTEN_MASK, "ODP_GET_LISTEN_MASK",
-                         listen_mask);
-    if (error) {
-        *listen_mask = 0;
-    }
-    return error;
-}
-
-int
-dpif_set_listen_mask(struct dpif *dpif, int listen_mask)
-{
-    return do_ioctl(dpif, ODP_SET_LISTEN_MASK, "ODP_SET_LISTEN_MASK",
-                    &listen_mask);
-}
-
-int
-dpif_purge(struct dpif *dpif)
+dpif_recv_purge(struct dpif *dpif)
 {
     struct odp_stats stats;
     unsigned int i;
@@ -261,25 +243,33 @@ dpif_purge(struct dpif *dpif)
 }
 
 int
-dpif_port_add(struct dpif *dpif, const char *devname, uint16_t port_no,
-              uint16_t flags)
+dpif_port_add(struct dpif *dpif, const char *devname, uint16_t flags,
+              uint16_t *port_nop)
 {
     struct odp_port port;
+    uint16_t port_no;
+    int error;
 
     COVERAGE_INC(dpif_port_add);
+
     memset(&port, 0, sizeof port);
     strncpy(port.devname, devname, sizeof port.devname);
-    port.port = port_no;
     port.flags = flags;
-    if (!ioctl(dpif->fd, ODP_PORT_ADD, &port)) {
+
+    error = do_ioctl(dpif, ODP_PORT_ADD, NULL, &port);
+    if (!error) {
+        port_no = port.port;
         VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu16,
                     dpif_name(dpif), devname, port_no);
-        return 0;
     } else {
-        VLOG_WARN_RL(&error_rl, "%s: failed to add %s as port %"PRIu16": %s",
-                     dpif_name(dpif), devname, port_no, strerror(errno));
-        return errno;
+        port_no = UINT16_MAX;
+        VLOG_WARN_RL(&error_rl, "%s: failed to add %s as port: %s",
+                     dpif_name(dpif), devname, strerror(errno));
+    }
+    if (port_nop) {
+        *port_nop = port_no;
     }
+    return error;
 }
 
 int
@@ -347,33 +337,48 @@ dpif_port_get_name(struct dpif *dpif, uint16_t port_no,
 
 int
 dpif_port_list(const struct dpif *dpif,
-               struct odp_port **ports, size_t *n_ports)
+               struct odp_port **portsp, size_t *n_portsp)
 {
-    struct odp_portvec pv;
-    struct odp_stats stats;
+    struct odp_port *ports;
+    size_t n_ports;
     int error;
 
-    do {
+    for (;;) {
+        struct odp_stats stats;
+        struct odp_portvec pv;
+
         error = dpif_get_dp_stats(dpif, &stats);
         if (error) {
-            goto error;
+            goto exit;
         }
 
-        *ports = xcalloc(1, stats.n_ports * sizeof **ports);
-        pv.ports = *ports;
+        ports = xcalloc(stats.n_ports, sizeof *ports);
+        pv.ports = ports;
         pv.n_ports = stats.n_ports;
         error = do_ioctl(dpif, ODP_PORT_LIST, "ODP_PORT_LIST", &pv);
         if (error) {
-            free(*ports);
-            goto error;
+            /* Hard error. */
+            free(ports);
+            goto exit;
+        } else if (pv.n_ports <= stats.n_ports) {
+            /* Success. */
+            error = 0;
+            n_ports = pv.n_ports;
+            goto exit;
+        } else {
+            /* Soft error: port count increased behind our back.  Try again. */
+            free(ports);
         }
-    } while (pv.n_ports != stats.n_ports);
-    *n_ports = pv.n_ports;
-    return 0;
+    }
 
-error:
-    *ports = NULL;
-    *n_ports = 0;
+exit:
+    if (error) {
+        *portsp = NULL;
+        *n_portsp = 0;
+    } else {
+        *portsp = ports;
+        *n_portsp = n_ports;
+    }
     return error;
 }
 
@@ -391,21 +396,39 @@ dpif_port_group_set(struct dpif *dpif, uint16_t group,
     return do_ioctl(dpif, ODP_PORT_GROUP_SET, "ODP_PORT_GROUP_SET", &pg);
 }
 
-/* Careful: '*n_out' can be greater than 'n_ports' on return, if 'n_ports' is
- * less than the number of ports in 'group'. */
 int
 dpif_port_group_get(const struct dpif *dpif, uint16_t group,
-                    uint16_t ports[], size_t n_ports, size_t *n_out)
+                    uint16_t **ports, size_t *n_ports)
 {
-    struct odp_port_group pg;
     int error;
 
-    assert(n_ports <= UINT16_MAX);
-    pg.group = group;
-    pg.ports = ports;
-    pg.n_ports = n_ports;
-    error = do_ioctl(dpif, ODP_PORT_GROUP_GET, "ODP_PORT_GROUP_GET", &pg);
-    *n_out = error ? 0 : pg.n_ports;
+    *ports = NULL;
+    *n_ports = 0;
+    for (;;) {
+        struct odp_port_group pg;
+        pg.group = group;
+        pg.ports = *ports;
+        pg.n_ports = *n_ports;
+
+        error = do_ioctl(dpif, ODP_PORT_GROUP_GET, "ODP_PORT_GROUP_GET", &pg);
+        if (error) {
+            /* Hard error. */
+            free(*ports);
+            *ports = NULL;
+            *n_ports = 0;
+            break;
+        } else if (pg.n_ports <= *n_ports) {
+            /* Success. */
+            *n_ports = pg.n_ports;
+            break;
+        } else {
+            /* Soft error: there were more ports than we expected in the
+             * group.  Try again. */
+            free(*ports);
+            *ports = xcalloc(pg.n_ports, sizeof **ports);
+            *n_ports = pg.n_ports;
+        }
+    }
     return error;
 }
 
@@ -514,10 +537,23 @@ dpif_flow_del(struct dpif *dpif, struct odp_flow *flow)
 int
 dpif_flow_get(const struct dpif *dpif, struct odp_flow *flow)
 {
-    COVERAGE_INC(dpif_flow_query);
+    struct odp_flowvec fv;
+    int error;
+
+    COVERAGE_INC(dpif_flow_get);
+
     check_rw_odp_flow(flow);
-    memset(&flow->stats, 0, sizeof flow->stats);
-    return do_flow_ioctl(dpif, ODP_FLOW_GET, flow, "get flow", true);
+    fv.flows = flow;
+    fv.n_flows = 1;
+    error = do_ioctl(dpif, ODP_FLOW_GET, "ODP_FLOW_GET", &fv);
+    if (!error) {
+        error = flow->stats.error;
+        if (error) {
+            VLOG_WARN_RL(&error_rl, "%s: ioctl(ODP_FLOW_GET) failed (%s)",
+                         dpif_name(dpif), strerror(error));
+        }
+    }
+    return error;
 }
 
 int
@@ -533,7 +569,7 @@ dpif_flow_get_multiple(const struct dpif *dpif,
     for (i = 0; i < n; i++) {
         check_rw_odp_flow(&flows[i]);
     }
-    return do_ioctl(dpif, ODP_FLOW_GET_MULTIPLE, "ODP_FLOW_GET_MULTIPLE",
+    return do_ioctl(dpif, ODP_FLOW_GET, "ODP_FLOW_GET",
                     &fv);
 }
 
@@ -641,6 +677,24 @@ dpif_execute(struct dpif *dpif, uint16_t in_port,
     return error;
 }
 
+int
+dpif_recv_get_mask(const struct dpif *dpif, int *listen_mask)
+{
+    int error = do_ioctl(dpif, ODP_GET_LISTEN_MASK, "ODP_GET_LISTEN_MASK",
+                         listen_mask);
+    if (error) {
+        *listen_mask = 0;
+    }
+    return error;
+}
+
+int
+dpif_recv_set_mask(struct dpif *dpif, int listen_mask)
+{
+    return do_ioctl(dpif, ODP_SET_LISTEN_MASK, "ODP_SET_LISTEN_MASK",
+                    &listen_mask);
+}
+
 int
 dpif_recv(struct dpif *dpif, struct ofpbuf **bufp)
 {