Looks good. Ethan
On Tue, Sep 27, 2011 at 16:27, Ben Pfaff <[email protected]> wrote: > This will be used in an upcoming commit. > --- > lib/dpif-linux.c | 155 > +++++++++++++++++++++++++++++++++++++++++++-------- > lib/dpif-netdev.c | 1 + > lib/dpif-provider.h | 8 +++ > lib/dpif.c | 45 +++++++++++++++ > lib/dpif.h | 58 +++++++++++++++++++ > 5 files changed, 243 insertions(+), 24 deletions(-) > > diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c > index 84d224e..6caac22 100644 > --- a/lib/dpif-linux.c > +++ b/lib/dpif-linux.c > @@ -656,31 +656,44 @@ dpif_linux_flow_get(const struct dpif *dpif_, > return error; > } > > +static void > +dpif_linux_init_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_linux_flow *request) > +{ > + static struct nlattr dummy_action; > + > + struct dpif_linux *dpif = dpif_linux_cast(dpif_); > + > + dpif_linux_flow_init(request); > + request->cmd = (flags & DPIF_FP_CREATE > + ? OVS_FLOW_CMD_NEW : OVS_FLOW_CMD_SET); > + request->dp_ifindex = dpif->dp_ifindex; > + request->key = key; > + request->key_len = key_len; > + /* Ensure that OVS_FLOW_ATTR_ACTIONS will always be included. */ > + request->actions = actions ? actions : &dummy_action; > + request->actions_len = actions_len; > + request->upcall_pid = get_upcall_pid_flow(dpif, key, key_len); > + if (flags & DPIF_FP_ZERO_STATS) { > + request->clear = true; > + } > + request->nlmsg_flags = flags & DPIF_FP_MODIFY ? 0 : NLM_F_CREATE; > +} > + > static int > 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) > { > - struct dpif_linux *dpif = dpif_linux_cast(dpif_); > struct dpif_linux_flow request, reply; > - struct nlattr dummy_action; > struct ofpbuf *buf; > int error; > > - dpif_linux_flow_init(&request); > - request.cmd = flags & DPIF_FP_CREATE ? OVS_FLOW_CMD_NEW : > OVS_FLOW_CMD_SET; > - request.dp_ifindex = dpif->dp_ifindex; > - request.key = key; > - request.key_len = key_len; > - /* Ensure that OVS_FLOW_ATTR_ACTIONS will always be included. */ > - request.actions = actions ? actions : &dummy_action; > - request.actions_len = actions_len; > - request.upcall_pid = get_upcall_pid_flow(dpif, key, key_len); > - if (flags & DPIF_FP_ZERO_STATS) { > - request.clear = true; > - } > - request.nlmsg_flags = flags & DPIF_FP_MODIFY ? 0 : NLM_F_CREATE; > + dpif_linux_init_flow_put(dpif_, flags, key, key_len, actions, > actions_len, > + &request); > error = dpif_linux_flow_transact(&request, > stats ? &reply : NULL, > stats ? &buf : NULL); > @@ -807,15 +820,14 @@ dpif_linux_flow_dump_done(const struct dpif *dpif > OVS_UNUSED, void *state_) > return error; > } > > -static int > -dpif_linux_execute__(int dp_ifindex, uint32_t upcall_pid, > - const struct nlattr *key, size_t key_len, > - const struct nlattr *actions, size_t actions_len, > - const struct ofpbuf *packet) > +static struct ofpbuf * > +dpif_linux_encode_execute(int dp_ifindex, uint32_t upcall_pid, > + const struct nlattr *key, size_t key_len, > + const struct nlattr *actions, size_t actions_len, > + const struct ofpbuf *packet) > { > struct ovs_header *execute; > struct ofpbuf *buf; > - int error; > > buf = ofpbuf_new(128 + actions_len + packet->size); > > @@ -830,8 +842,24 @@ dpif_linux_execute__(int dp_ifindex, uint32_t upcall_pid, > nl_msg_put_unspec(buf, OVS_PACKET_ATTR_ACTIONS, actions, actions_len); > nl_msg_put_u32(buf, OVS_PACKET_ATTR_UPCALL_PID, upcall_pid); > > - error = nl_sock_transact(genl_sock, buf, NULL); > - ofpbuf_delete(buf); > + return buf; > +} > + > +static int > +dpif_linux_execute__(int dp_ifindex, uint32_t upcall_pid, > + const struct nlattr *key, size_t key_len, > + const struct nlattr *actions, size_t actions_len, > + const struct ofpbuf *packet) > +{ > + struct ofpbuf *request; > + int error; > + > + request = dpif_linux_encode_execute(dp_ifindex, upcall_pid, > + key, key_len, actions, actions_len, > + packet); > + error = nl_sock_transact(genl_sock, request, NULL); > + ofpbuf_delete(request); > + > return error; > } > > @@ -848,6 +876,85 @@ dpif_linux_execute(struct dpif *dpif_, > actions, actions_len, packet); > } > > +static void > +dpif_linux_operate(struct dpif *dpif_, union dpif_op **ops, size_t n_ops) > +{ > + struct dpif_linux *dpif = dpif_linux_cast(dpif_); > + struct nl_transaction **txnsp; > + struct nl_transaction *txns; > + size_t i; > + > + txns = xmalloc(n_ops * sizeof *txns); > + for (i = 0; i < n_ops; i++) { > + struct nl_transaction *txn = &txns[i]; > + union dpif_op *op = ops[i]; > + > + if (op->type == DPIF_OP_FLOW_PUT) { > + struct dpif_flow_put *put = &op->flow_put; > + struct dpif_linux_flow request; > + > + dpif_linux_init_flow_put(dpif_, put->flags, put->key, > put->key_len, > + put->actions, put->actions_len, > + &request); > + if (put->stats) { > + request.nlmsg_flags |= NLM_F_ECHO; > + } > + txn->request = ofpbuf_new(1024); > + dpif_linux_flow_to_ofpbuf(&request, txn->request); > + } else if (op->type == DPIF_OP_EXECUTE) { > + struct dpif_execute *execute = &op->execute; > + uint32_t upcall_pid; > + > + upcall_pid = get_upcall_pid_flow(dpif, execute->key, > + execute->key_len); > + txn->request = dpif_linux_encode_execute( > + dpif->dp_ifindex, upcall_pid, execute->key, execute->key_len, > + execute->actions, execute->actions_len, execute->packet); > + } else { > + NOT_REACHED(); > + } > + } > + > + txnsp = xmalloc(n_ops * sizeof *txnsp); > + for (i = 0; i < n_ops; i++) { > + txnsp[i] = &txns[i]; > + } > + > + nl_sock_transact_multiple(genl_sock, txnsp, n_ops); > + > + free(txnsp); > + > + for (i = 0; i < n_ops; i++) { > + struct nl_transaction *txn = &txns[i]; > + union dpif_op *op = ops[i]; > + > + if (op->type == DPIF_OP_FLOW_PUT) { > + struct dpif_flow_put *put = &op->flow_put; > + int error = txn->error; > + > + if (!error && put->stats) { > + struct dpif_linux_flow reply; > + > + error = dpif_linux_flow_from_ofpbuf(&reply, txn->reply); > + if (!error) { > + dpif_linux_flow_get_stats(&reply, put->stats); > + } > + } > + put->error = error; > + } else if (op->type == DPIF_OP_EXECUTE) { > + struct dpif_execute *execute = &op->execute; > + > + execute->error = txn->error; > + } else { > + NOT_REACHED(); > + } > + > + ofpbuf_delete(txn->request); > + ofpbuf_delete(txn->reply); > + } > + free(txns); > +} > + > static int > dpif_linux_recv_get_mask(const struct dpif *dpif_, int *listen_mask) > { > @@ -1197,6 +1304,7 @@ const struct dpif_class dpif_linux_class = { > dpif_linux_flow_dump_next, > dpif_linux_flow_dump_done, > dpif_linux_execute, > + dpif_linux_operate, > dpif_linux_recv_get_mask, > dpif_linux_recv_set_mask, > dpif_linux_get_sflow_probability, > @@ -1819,4 +1927,3 @@ dpif_linux_flow_get_stats(const struct dpif_linux_flow > *flow, > stats->used = flow->used ? get_unaligned_u64(flow->used) : 0; > stats->tcp_flags = flow->tcp_flags ? *flow->tcp_flags : 0; > } > - > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c > index 359c80b..afb14f8 100644 > --- a/lib/dpif-netdev.c > +++ b/lib/dpif-netdev.c > @@ -1377,6 +1377,7 @@ const struct dpif_class dpif_netdev_class = { > dpif_netdev_flow_dump_next, > dpif_netdev_flow_dump_done, > dpif_netdev_execute, > + NULL, /* operate */ > dpif_netdev_recv_get_mask, > dpif_netdev_recv_set_mask, > NULL, /* get_sflow_probability */ > diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h > index c6c39da..8bc12df 100644 > --- a/lib/dpif-provider.h > +++ b/lib/dpif-provider.h > @@ -291,6 +291,14 @@ struct dpif_class { > const struct nlattr *actions, size_t actions_len, > const struct ofpbuf *packet); > > + /* Executes each of the 'n_ops' operations in 'ops' on 'dpif', in the > order > + * in which they are specified, placing each operation's results in the > + * "output" members documented in comments. > + * > + * This function is optional. It is only worthwhile to implement it if > + * 'dpif' can perform operations in batch faster than individually. */ > + void (*operate)(struct dpif *dpif, union dpif_op **ops, size_t n_ops); > + > /* Retrieves 'dpif''s "listen mask" into '*listen_mask'. A 1-bit of value > * 2**X set in '*listen_mask' indicates that 'dpif' will receive messages > * of the type (from "enum dpif_upcall_type") with value X when its 'recv' > diff --git a/lib/dpif.c b/lib/dpif.c > index ad143c8..9cc4fa5 100644 > --- a/lib/dpif.c > +++ b/lib/dpif.c > @@ -951,6 +951,51 @@ dpif_execute(struct dpif *dpif, > return error; > } > > +/* Executes each of the 'n_ops' operations in 'ops' on 'dpif', in the order > in > + * which they are specified, placing each operation's results in the "output" > + * members documented in comments. > + * > + * This function exists because some datapaths can perform batched operations > + * faster than individual operations. */ > +void > +dpif_operate(struct dpif *dpif, union dpif_op **ops, size_t n_ops) > +{ > + size_t i; > + > + if (dpif->dpif_class->operate) { > + dpif->dpif_class->operate(dpif, ops, n_ops); > + return; > + } > + > + for (i = 0; i < n_ops; i++) { > + union dpif_op *op = ops[i]; > + struct dpif_flow_put *put; > + struct dpif_execute *execute; > + > + switch (op->type) { > + case DPIF_OP_FLOW_PUT: > + put = &op->flow_put; > + put->error = dpif_flow_put(dpif, put->flags, > + put->key, put->key_len, > + put->actions, put->actions_len, > + put->stats); > + break; > + > + case DPIF_OP_EXECUTE: > + execute = &op->execute; > + execute->error = dpif_execute(dpif, execute->key, > execute->key_len, > + execute->actions, > + execute->actions_len, > + execute->packet); > + break; > + > + default: > + NOT_REACHED(); > + } > + } > +} > + > + > /* Returns a string that represents 'type', for use in log messages. */ > const char * > dpif_upcall_type_to_string(enum dpif_upcall_type type) > diff --git a/lib/dpif.h b/lib/dpif.h > index c01010d..e6d6887 100644 > --- a/lib/dpif.h > +++ b/lib/dpif.h > @@ -61,6 +61,8 @@ int dpif_delete(struct dpif *); > int dpif_get_dp_stats(const struct dpif *, struct ovs_dp_stats *); > int dpif_get_drop_frags(const struct dpif *, bool *drop_frags); > int dpif_set_drop_frags(struct dpif *, bool drop_frags); > + > +/* Port operations. */ > > int dpif_port_add(struct dpif *, struct netdev *, uint16_t *port_nop); > int dpif_port_del(struct dpif *, uint16_t port_no); > @@ -107,6 +109,8 @@ int dpif_port_dump_done(struct dpif_port_dump *); > > int dpif_port_poll(const struct dpif *, char **devnamep); > void dpif_port_poll_wait(const struct dpif *); > + > +/* Flow table operations. */ > > struct dpif_flow_stats { > uint64_t n_packets; > @@ -146,11 +150,63 @@ bool dpif_flow_dump_next(struct dpif_flow_dump *, > const struct nlattr **actions, size_t *actions_len, > const struct dpif_flow_stats **); > int dpif_flow_dump_done(struct dpif_flow_dump *); > + > +/* Packet operations. */ > > int dpif_execute(struct dpif *, > const struct nlattr *key, size_t key_len, > const struct nlattr *actions, size_t actions_len, > const struct ofpbuf *); > + > +/* Operation batching interface. > + * > + * Some datapaths are faster at performing N operations together than the > same > + * N operations individually, hence an interface for batching. > + */ > + > +enum dpif_op_type { > + DPIF_OP_FLOW_PUT = 1, > + DPIF_OP_EXECUTE > +}; > + > +struct dpif_flow_put { > + enum dpif_op_type type; /* Always DPIF_OP_FLOW_PUT. */ > + > + /* Input. */ > + enum dpif_flow_put_flags flags; /* DPIF_FP_*. */ > + const struct nlattr *key; /* Flow to put. */ > + size_t key_len; /* Length of 'key' in bytes. */ > + const struct nlattr *actions; /* Actions to perform on flow. */ > + size_t actions_len; /* Length of 'actions' in bytes. */ > + > + /* Output. */ > + struct dpif_flow_stats *stats; /* Optional flow statistics. */ > + int error; /* 0 or positive errno value. */ > +}; > + > +struct dpif_execute { > + enum dpif_op_type type; /* Always DPIF_OP_EXECUTE. */ > + > + /* Input. */ > + const struct nlattr *key; /* Partial flow key (only for metadata). > */ > + size_t key_len; /* Length of 'key' in bytes. */ > + const struct nlattr *actions; /* Actions to execute on packet. */ > + size_t actions_len; /* Length of 'actions' in bytes. */ > + const struct ofpbuf *packet; /* Packet to execute. */ > + > + /* Output. */ > + int error; /* 0 or positive errno value. */ > +}; > + > +union dpif_op { > + enum dpif_op_type type; > + struct dpif_flow_put flow_put; > + struct dpif_execute execute; > +}; > + > +void dpif_operate(struct dpif *, union dpif_op **ops, size_t n_ops); > + > +/* Upcalls. */ > > enum dpif_upcall_type { > DPIF_UC_MISS, /* Miss in flow table. */ > @@ -191,6 +247,8 @@ int dpif_set_sflow_probability(struct dpif *, uint32_t > probability); > int dpif_recv(struct dpif *, struct dpif_upcall *); > void dpif_recv_purge(struct dpif *); > void dpif_recv_wait(struct dpif *); > + > +/* Miscellaneous. */ > > void dpif_get_netflow_ids(const struct dpif *, > uint8_t *engine_type, uint8_t *engine_id); > -- > 1.7.4.4 > > _______________________________________________ > dev mailing list > [email protected] > http://openvswitch.org/mailman/listinfo/dev > _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
