X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=lib%2Fdpif-linux.c;h=8d5c48963673147e68c429e40a96a38409377646;hb=c62b0064a0cdbd5f3ecfc2cda90999a9d7ec551d;hp=8e584ea5de051a012a823994495ba7ff1a67c3a8;hpb=c19e653509deb3f1002c4ed99714e16549ec74e9;p=openvswitch diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index 8e584ea5..8d5c4896 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -38,6 +38,7 @@ #include "netdev.h" #include "netdev-vport.h" #include "netlink.h" +#include "odp-util.h" #include "ofpbuf.h" #include "openvswitch/tunnel.h" #include "packets.h" @@ -365,6 +366,14 @@ dpif_linux_port_query_by_name(const struct dpif *dpif, const char *devname, 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_) { @@ -450,44 +459,159 @@ dpif_linux_port_poll_wait(const 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 @@ -645,6 +769,26 @@ dpif_linux_recv_wait(struct dpif *dpif_) 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, @@ -661,6 +805,7 @@ const struct dpif_class dpif_linux_class = { 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, @@ -681,6 +826,7 @@ const struct dpif_class dpif_linux_class = { dpif_linux_queue_to_priority, dpif_linux_recv, dpif_linux_recv_wait, + dpif_linux_recv_purge, }; static int get_openvswitch_major(void);