#include "netdev.h"
#include "netdev-vport.h"
#include "netlink.h"
+#include "odp-util.h"
#include "ofpbuf.h"
#include "openvswitch/tunnel.h"
#include "packets.h"
return dpif_linux_port_query__(dpif, 0, devname, dpif_port);
}
+static int
+dpif_linux_get_max_ports(const struct dpif *dpif OVS_UNUSED)
+{
+ /* If the datapath increases its range of supported ports, then it should
+ * start reporting that. */
+ return 1024;
+}
+
static int
dpif_linux_flow_flush(struct dpif *dpif_)
{
}
}
+static void
+odp_flow_stats_to_dpif_flow_stats(const struct odp_flow_stats *ofs,
+ struct dpif_flow_stats *dfs)
+{
+ dfs->n_packets = ofs->n_packets;
+ dfs->n_bytes = ofs->n_bytes;
+ dfs->used = ofs->used_sec * 1000 + ofs->used_nsec / 1000000;
+ dfs->tcp_flags = ofs->tcp_flags;
+}
+
static int
-dpif_linux_flow_get(const struct dpif *dpif_, struct odp_flow flows[], int n)
+dpif_linux_flow_get(const struct dpif *dpif_, int flags,
+ const struct nlattr *key, size_t key_len,
+ struct ofpbuf **actionsp, struct dpif_flow_stats *stats)
{
- struct odp_flowvec fv;
- fv.flows = flows;
- fv.n_flows = n;
- return do_ioctl(dpif_, ODP_FLOW_GET, &fv);
+ struct ofpbuf *actions = NULL;
+ struct odp_flow odp_flow;
+ int error;
+
+ memset(&odp_flow, 0, sizeof odp_flow);
+ odp_flow.key = (struct nlattr *) key;
+ odp_flow.key_len = key_len;
+ if (actionsp) {
+ actions = *actionsp = ofpbuf_new(65536);
+ odp_flow.actions = actions->base;
+ odp_flow.actions_len = actions->allocated;
+ }
+ odp_flow.flags = flags;
+
+ error = do_ioctl(dpif_, ODP_FLOW_GET, &odp_flow);
+ if (!error) {
+ if (stats) {
+ odp_flow_stats_to_dpif_flow_stats(&odp_flow.stats, stats);
+ }
+ if (actions) {
+ actions->size = odp_flow.actions_len;
+ ofpbuf_trim(actions);
+ }
+ } else {
+ if (actions) {
+ ofpbuf_delete(actions);
+ }
+ }
+ return error;
}
static int
-dpif_linux_flow_put(struct dpif *dpif_, struct odp_flow_put *put)
+dpif_linux_flow_put(struct dpif *dpif_, enum dpif_flow_put_flags flags,
+ const struct nlattr *key, size_t key_len,
+ const struct nlattr *actions, size_t actions_len,
+ struct dpif_flow_stats *stats)
{
- return do_ioctl(dpif_, ODP_FLOW_PUT, put);
+ struct odp_flow_put put;
+ int error;
+
+ memset(&put, 0, sizeof put);
+ put.flow.key = (struct nlattr *) key;
+ put.flow.key_len = key_len;
+ put.flow.actions = (struct nlattr *) actions;
+ put.flow.actions_len = actions_len;
+ put.flow.flags = 0;
+ put.flags = 0;
+ if (flags & DPIF_FP_CREATE) {
+ put.flags |= ODPPF_CREATE;
+ }
+ if (flags & DPIF_FP_MODIFY) {
+ put.flags |= ODPPF_MODIFY;
+ }
+ if (flags & DPIF_FP_ZERO_STATS) {
+ put.flags |= ODPPF_ZERO_STATS;
+ }
+ error = do_ioctl(dpif_, ODP_FLOW_PUT, &put);
+ if (!error && stats) {
+ odp_flow_stats_to_dpif_flow_stats(&put.flow.stats, stats);
+ }
+ return error;
}
static int
-dpif_linux_flow_del(struct dpif *dpif_, struct odp_flow *flow)
+dpif_linux_flow_del(struct dpif *dpif_,
+ const struct nlattr *key, size_t key_len,
+ struct dpif_flow_stats *stats)
{
- return do_ioctl(dpif_, ODP_FLOW_DEL, flow);
+ struct odp_flow odp_flow;
+ int error;
+
+ memset(&odp_flow, 0, sizeof odp_flow);
+ odp_flow.key = (struct nlattr *) key;
+ odp_flow.key_len = key_len;
+ error = do_ioctl(dpif_, ODP_FLOW_DEL, &odp_flow);
+ if (!error && stats) {
+ odp_flow_stats_to_dpif_flow_stats(&odp_flow.stats, stats);
+ }
+ return error;
}
+struct dpif_linux_flow_state {
+ struct odp_flow_dump dump;
+ struct odp_flow flow;
+ uint32_t keybuf[ODPUTIL_FLOW_KEY_U32S];
+ uint32_t actionsbuf[65536 / sizeof(uint32_t)];
+ struct dpif_flow_stats stats;
+};
+
static int
dpif_linux_flow_dump_start(const struct dpif *dpif OVS_UNUSED, void **statep)
{
- *statep = xzalloc(sizeof(struct odp_flow_dump));
+ struct dpif_linux_flow_state *state;
+
+ *statep = state = xmalloc(sizeof *state);
+ state->dump.state[0] = 0;
+ state->dump.state[1] = 0;
+ state->dump.flow = &state->flow;
return 0;
}
static int
-dpif_linux_flow_dump_next(const struct dpif *dpif, void *state,
- struct odp_flow *flow)
+dpif_linux_flow_dump_next(const struct dpif *dpif, void *state_,
+ const struct nlattr **key, size_t *key_len,
+ const struct nlattr **actions, size_t *actions_len,
+ const struct dpif_flow_stats **stats)
{
- struct odp_flow_dump *dump = state;
+ struct dpif_linux_flow_state *state = state_;
int error;
- dump->flow = flow;
- error = do_ioctl(dpif, ODP_FLOW_DUMP, dump);
- return error ? error : flow->flags & ODPFF_EOF ? EOF : 0;
+ memset(&state->flow, 0, sizeof state->flow);
+ state->flow.key = (struct nlattr *) state->keybuf;
+ state->flow.key_len = sizeof state->keybuf;
+ if (actions) {
+ state->flow.actions = (struct nlattr *) state->actionsbuf;
+ state->flow.actions_len = sizeof state->actionsbuf;
+ }
+
+ error = do_ioctl(dpif, ODP_FLOW_DUMP, &state->dump);
+ if (!error) {
+ if (state->flow.flags & ODPFF_EOF) {
+ return EOF;
+ }
+ if (key) {
+ *key = (const struct nlattr *) state->keybuf;
+ *key_len = state->flow.key_len;
+ }
+ if (actions) {
+ *actions = (const struct nlattr *) state->actionsbuf;
+ *actions_len = state->flow.actions_len;
+ }
+ if (stats) {
+ odp_flow_stats_to_dpif_flow_stats(&state->flow.stats,
+ &state->stats);
+ *stats = &state->stats;
+ }
+ }
+ return error;
}
static int
poll_fd_wait(dpif->fd, POLLIN);
}
+static void
+dpif_linux_recv_purge(struct dpif *dpif_)
+{
+ struct dpif_linux *dpif = dpif_linux_cast(dpif_);
+ int i;
+
+ /* This is somewhat bogus because it assumes that the following macros have
+ * fixed values, but it's going to go away later. */
+#define DP_N_QUEUES 3
+#define DP_MAX_QUEUE_LEN 100
+ for (i = 0; i < DP_N_QUEUES * DP_MAX_QUEUE_LEN; i++) {
+ /* Reading even 1 byte discards a whole datagram and saves time. */
+ char buffer;
+
+ if (read(dpif->fd, &buffer, 1) != 1) {
+ break;
+ }
+ }
+}
+
const struct dpif_class dpif_linux_class = {
"system",
NULL,
dpif_linux_port_del,
dpif_linux_port_query_by_number,
dpif_linux_port_query_by_name,
+ dpif_linux_get_max_ports,
dpif_linux_port_dump_start,
dpif_linux_port_dump_next,
dpif_linux_port_dump_done,
dpif_linux_queue_to_priority,
dpif_linux_recv,
dpif_linux_recv_wait,
+ dpif_linux_recv_purge,
};
\f
static int get_openvswitch_major(void);