From 6bc6002490ae127a6d0c1dc6f6b8843cac8e0c22 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 27 Sep 2011 15:08:50 -0700 Subject: dpif: New function dpif_operate() and dpif-linux implementation. This will be used in an upcoming commit. --- lib/dpif-linux.c | 148 ++++++++++++++++++++++++++++++++++++++++++++-------- lib/dpif-netdev.c | 1 + lib/dpif-provider.h | 8 +++ lib/dpif.c | 45 ++++++++++++++++ lib/dpif.h | 58 ++++++++++++++++++++ 5 files changed, 238 insertions(+), 22 deletions(-) (limited to 'lib') diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c index b09d80d3..fa6a05e0 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -687,30 +687,43 @@ 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; + 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; - 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); @@ -837,14 +850,14 @@ dpif_linux_flow_dump_done(const struct dpif *dpif OVS_UNUSED, void *state_) return error; } -static int -dpif_linux_execute__(int dp_ifindex, 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, + 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); @@ -858,8 +871,23 @@ dpif_linux_execute__(int dp_ifindex, const struct nlattr *key, size_t key_len, nl_msg_put_unspec(buf, OVS_PACKET_ATTR_KEY, key, key_len); nl_msg_put_unspec(buf, OVS_PACKET_ATTR_ACTIONS, actions, actions_len); - error = nl_sock_transact(genl_sock, buf, NULL); - ofpbuf_delete(buf); + return buf; +} + +static int +dpif_linux_execute__(int dp_ifindex, 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, + key, key_len, actions, actions_len, + packet); + error = nl_sock_transact(genl_sock, request, NULL); + ofpbuf_delete(request); + return error; } @@ -875,6 +903,82 @@ 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; + + txn->request = dpif_linux_encode_execute( + dpif->dp_ifindex, 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) { @@ -1123,6 +1227,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_queue_to_priority, @@ -1725,4 +1830,3 @@ dpif_linux_flow_get_stats(const struct dpif_linux_flow *flow, stats->used = flow->used ? get_32aligned_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 99673226..f78cda26 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -1356,6 +1356,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, /* queue_to_priority */ diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h index 8cdedcd1..ec662e7d 100644 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@ -303,6 +303,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 aae0ffea..a95985a1 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -988,6 +988,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 30f9b6dd..404c05a1 100644 --- a/lib/dpif.h +++ b/lib/dpif.h @@ -71,6 +71,8 @@ int dpif_get_dp_stats(const struct dpif *, struct dpif_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); @@ -118,6 +120,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; @@ -159,11 +163,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. */ @@ -196,6 +252,8 @@ int dpif_recv_set_mask(struct dpif *, int listen_mask); 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); -- cgit v1.2.3