From: Giuseppe Lettieri Date: Mon, 14 Oct 2013 10:11:59 +0000 (+0200) Subject: Merge branch 'mainstream' X-Git-Tag: sliver-openvswitch-2.0.90-1~8 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=093f56c5c5c8b0891e837beb1defd84bc165ac6a;hp=-c;p=sliver-openvswitch.git Merge branch 'mainstream' --- 093f56c5c5c8b0891e837beb1defd84bc165ac6a diff --combined lib/dpif-netdev.c index 461e0dc09,0f6a71c74..85ccaac80 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@@ -201,17 -201,10 +201,17 @@@ dpif_netdev_class_is_dummy(const struc return class != &dpif_netdev_class; } +static bool +dpif_netdev_class_is_planetlab(const struct dpif_class *class) +{ + return class == &dpif_planetlab_class; +} + static const char * dpif_netdev_port_open_type(const struct dpif_class *class, const char *type) { return strcmp(type, "internal") ? type + : dpif_netdev_class_is_planetlab(class) ? "pltap" : dpif_netdev_class_is_dummy(class) ? "dummy" : "tap"; } @@@ -239,8 -232,7 +239,8 @@@ choose_port(struct dp_netdev *dp, cons { uint32_t port_no; - if (dp->class != &dpif_netdev_class) { + if (dp->class != &dpif_netdev_class && + dp->class != &dpif_planetlab_class) { const char *p; int start_no = 0; @@@ -1234,10 -1226,11 +1234,11 @@@ dpif_netdev_wait(struct dpif *dpif } static void - dp_netdev_output_port(void *dp_, struct ofpbuf *packet, uint32_t out_port) + dp_netdev_output_port(void *dp_, struct ofpbuf *packet, + const struct flow *flow OVS_UNUSED, odp_port_t out_port) { struct dp_netdev *dp = dp_; - struct dp_netdev_port *p = dp->ports[out_port]; + struct dp_netdev_port *p = dp->ports[odp_to_u32(out_port)]; if (p) { netdev_send(p->netdev, packet); } @@@ -1297,8 -1290,11 +1298,11 @@@ dp_netdev_output_userspace(struct dp_ne static void dp_netdev_action_userspace(void *dp, struct ofpbuf *packet, const struct flow *key, - const struct nlattr *userdata) + const struct nlattr *a) { + const struct nlattr *userdata; + + userdata = nl_attr_find_nested(a, OVS_USERSPACE_ATTR_USERDATA); dp_netdev_output_userspace(dp, packet, DPIF_UC_ACTION, key, userdata); } @@@ -1312,49 -1308,41 +1316,49 @@@ dp_netdev_execute_actions(struct dp_net dp_netdev_output_port, dp_netdev_action_userspace); } +#define DPIF_NETDEV_CLASS_FUNCTIONS \ + dpif_netdev_enumerate, \ + dpif_netdev_port_open_type, \ + dpif_netdev_open, \ + dpif_netdev_close, \ + dpif_netdev_destroy, \ + dpif_netdev_run, \ + dpif_netdev_wait, \ + dpif_netdev_get_stats, \ + dpif_netdev_port_add, \ + dpif_netdev_port_del, \ + dpif_netdev_port_query_by_number, \ + dpif_netdev_port_query_by_name, \ + dpif_netdev_get_max_ports, \ + NULL, /* port_get_pid */ \ + dpif_netdev_port_dump_start, \ + dpif_netdev_port_dump_next, \ + dpif_netdev_port_dump_done, \ + dpif_netdev_port_poll, \ + dpif_netdev_port_poll_wait, \ + dpif_netdev_flow_get, \ + dpif_netdev_flow_put, \ + dpif_netdev_flow_del, \ + dpif_netdev_flow_flush, \ + dpif_netdev_flow_dump_start, \ + dpif_netdev_flow_dump_next, \ + dpif_netdev_flow_dump_done, \ + dpif_netdev_execute, \ + NULL, /* operate */ \ + dpif_netdev_recv_set, \ + dpif_netdev_queue_to_priority, \ + dpif_netdev_recv, \ + dpif_netdev_recv_wait, \ + dpif_netdev_recv_purge, \ + const struct dpif_class dpif_netdev_class = { "netdev", - dpif_netdev_enumerate, - dpif_netdev_port_open_type, - dpif_netdev_open, - dpif_netdev_close, - dpif_netdev_destroy, - dpif_netdev_run, - dpif_netdev_wait, - dpif_netdev_get_stats, - dpif_netdev_port_add, - dpif_netdev_port_del, - dpif_netdev_port_query_by_number, - dpif_netdev_port_query_by_name, - dpif_netdev_get_max_ports, - NULL, /* port_get_pid */ - dpif_netdev_port_dump_start, - dpif_netdev_port_dump_next, - dpif_netdev_port_dump_done, - dpif_netdev_port_poll, - dpif_netdev_port_poll_wait, - dpif_netdev_flow_get, - dpif_netdev_flow_put, - dpif_netdev_flow_del, - dpif_netdev_flow_flush, - dpif_netdev_flow_dump_start, - dpif_netdev_flow_dump_next, - dpif_netdev_flow_dump_done, - dpif_netdev_execute, - NULL, /* operate */ - dpif_netdev_recv_set, - dpif_netdev_queue_to_priority, - dpif_netdev_recv, - dpif_netdev_recv_wait, - dpif_netdev_recv_purge, + DPIF_NETDEV_CLASS_FUNCTIONS +}; + +const struct dpif_class dpif_planetlab_class = { + "planetlab", + DPIF_NETDEV_CLASS_FUNCTIONS }; static void @@@ -1426,4 -1414,3 +1430,4 @@@ dpif_dummy_register(bool override "DP PORT NEW-NUMBER", 3, 3, dpif_dummy_change_port_number, NULL); } + diff --combined lib/dpif.c index 16819113f,b284e13c1..1bac8e8e3 --- a/lib/dpif.c +++ b/lib/dpif.c @@@ -28,6 -28,7 +28,7 @@@ #include "flow.h" #include "netdev.h" #include "netlink.h" + #include "odp-execute.h" #include "odp-util.h" #include "ofp-errors.h" #include "ofp-print.h" @@@ -53,13 -54,13 +54,14 @@@ COVERAGE_DEFINE(dpif_flow_put) COVERAGE_DEFINE(dpif_flow_del); COVERAGE_DEFINE(dpif_execute); COVERAGE_DEFINE(dpif_purge); + COVERAGE_DEFINE(dpif_execute_with_help); static const struct dpif_class *base_dpif_classes[] = { #ifdef LINUX_DATAPATH &dpif_linux_class, #endif &dpif_netdev_class, + &dpif_planetlab_class, }; struct registered_dpif_class { @@@ -1062,6 -1063,94 +1064,94 @@@ dpif_flow_dump_done(struct dpif_flow_du return dump->error == EOF ? 0 : dump->error; } + struct dpif_execute_helper_aux { + struct dpif *dpif; + int error; + }; + + static void + dpif_execute_helper_execute__(void *aux_, struct ofpbuf *packet, + const struct flow *flow, + const struct nlattr *actions, size_t actions_len) + { + struct dpif_execute_helper_aux *aux = aux_; + struct dpif_execute execute; + struct odputil_keybuf key_stub; + struct ofpbuf key; + int error; + + ofpbuf_use_stub(&key, &key_stub, sizeof key_stub); + odp_flow_key_from_flow(&key, flow, flow->in_port.odp_port); + + execute.key = key.data; + execute.key_len = key.size; + execute.actions = actions; + execute.actions_len = actions_len; + execute.packet = packet; + execute.needs_help = false; + + error = aux->dpif->dpif_class->execute(aux->dpif, &execute); + if (error) { + aux->error = error; + } + } + + static void + dpif_execute_helper_output_cb(void *aux, struct ofpbuf *packet, + const struct flow *flow, odp_port_t out_port) + { + uint64_t actions_stub[DIV_ROUND_UP(NL_A_U32_SIZE, 8)]; + struct ofpbuf actions; + + ofpbuf_use_stack(&actions, actions_stub, sizeof actions_stub); + nl_msg_put_u32(&actions, OVS_ACTION_ATTR_OUTPUT, odp_to_u32(out_port)); + + dpif_execute_helper_execute__(aux, packet, flow, + actions.data, actions.size); + } + + static void + dpif_execute_helper_userspace_cb(void *aux, struct ofpbuf *packet, + const struct flow *flow, + const struct nlattr *action) + { + dpif_execute_helper_execute__(aux, packet, flow, + action, NLA_ALIGN(action->nla_len)); + } + + /* Executes 'execute' by performing most of the actions in userspace and + * passing the fully constructed packets to 'dpif' for output and userspace + * actions. + * + * This helps with actions that a given 'dpif' doesn't implement directly. */ + static int + dpif_execute_with_help(struct dpif *dpif, const struct dpif_execute *execute) + { + struct dpif_execute_helper_aux aux; + enum odp_key_fitness fit; + struct ofpbuf *packet; + struct flow flow; + + COVERAGE_INC(dpif_execute_with_help); + + fit = odp_flow_key_to_flow(execute->key, execute->key_len, &flow); + if (fit == ODP_FIT_ERROR) { + return EINVAL; + } + + aux.dpif = dpif; + aux.error = 0; + + packet = ofpbuf_clone_with_headroom(execute->packet, VLAN_HEADER_LEN); + odp_execute_actions(&aux, packet, &flow, + execute->actions, execute->actions_len, + dpif_execute_helper_output_cb, + dpif_execute_helper_userspace_cb); + ofpbuf_delete(packet); + + return aux.error; + } + static int dpif_execute__(struct dpif *dpif, const struct dpif_execute *execute) { @@@ -1069,7 -1158,9 +1159,9 @@@ COVERAGE_INC(dpif_execute); if (execute->actions_len > 0) { - error = dpif->dpif_class->execute(dpif, execute); + error = (execute->needs_help + ? dpif_execute_with_help(dpif, execute) + : dpif->dpif_class->execute(dpif, execute)); } else { error = 0; } @@@ -1085,12 -1176,20 +1177,20 @@@ * it contains some metadata that cannot be recovered from 'packet', such as * tunnel and in_port.) * + * Some dpif providers do not implement every action. The Linux kernel + * datapath, in particular, does not implement ARP field modification. If + * 'needs_help' is true, the dpif layer executes in userspace all of the + * actions that it can, and for OVS_ACTION_ATTR_OUTPUT and + * OVS_ACTION_ATTR_USERSPACE actions it passes the packet through to the dpif + * implementation. + * * Returns 0 if successful, otherwise a positive errno value. */ int dpif_execute(struct dpif *dpif, const struct nlattr *key, size_t key_len, const struct nlattr *actions, size_t actions_len, - const struct ofpbuf *buf) + const struct ofpbuf *buf, + bool needs_help) { struct dpif_execute execute; @@@ -1099,6 -1198,7 +1199,7 @@@ execute.actions = actions; execute.actions_len = actions_len; execute.packet = buf; + execute.needs_help = needs_help; return dpif_execute__(dpif, &execute); } @@@ -1111,54 -1211,83 +1212,83 @@@ void dpif_operate(struct dpif *dpif, struct dpif_op **ops, size_t n_ops) { - size_t i; - if (dpif->dpif_class->operate) { - dpif->dpif_class->operate(dpif, ops, n_ops); + while (n_ops > 0) { + size_t chunk; + + /* Count 'chunk', the number of ops that can be executed without + * needing any help. Ops that need help should be rare, so we + * expect this to ordinarily be 'n_ops', that is, all the ops. */ + for (chunk = 0; chunk < n_ops; chunk++) { + struct dpif_op *op = ops[chunk]; + + if (op->type == DPIF_OP_EXECUTE && op->u.execute.needs_help) { + break; + } + } + + if (chunk) { + /* Execute a chunk full of ops that the dpif provider can + * handle itself, without help. */ + size_t i; + + dpif->dpif_class->operate(dpif, ops, chunk); + + for (i = 0; i < chunk; i++) { + struct dpif_op *op = ops[i]; + + switch (op->type) { + case DPIF_OP_FLOW_PUT: + log_flow_put_message(dpif, &op->u.flow_put, op->error); + break; + + case DPIF_OP_FLOW_DEL: + log_flow_del_message(dpif, &op->u.flow_del, op->error); + break; + + case DPIF_OP_EXECUTE: + log_execute_message(dpif, &op->u.execute, op->error); + break; + } + } + + ops += chunk; + n_ops -= chunk; + } else { + /* Help the dpif provider to execute one op. */ + struct dpif_op *op = ops[0]; + + op->error = dpif_execute__(dpif, &op->u.execute); + ops++; + n_ops--; + } + } + } else { + size_t i; for (i = 0; i < n_ops; i++) { struct dpif_op *op = ops[i]; switch (op->type) { case DPIF_OP_FLOW_PUT: - log_flow_put_message(dpif, &op->u.flow_put, op->error); + op->error = dpif_flow_put__(dpif, &op->u.flow_put); break; case DPIF_OP_FLOW_DEL: - log_flow_del_message(dpif, &op->u.flow_del, op->error); + op->error = dpif_flow_del__(dpif, &op->u.flow_del); break; case DPIF_OP_EXECUTE: - log_execute_message(dpif, &op->u.execute, op->error); + op->error = dpif_execute__(dpif, &op->u.execute); break; - } - } - return; - } - - for (i = 0; i < n_ops; i++) { - struct dpif_op *op = ops[i]; - - switch (op->type) { - case DPIF_OP_FLOW_PUT: - op->error = dpif_flow_put__(dpif, &op->u.flow_put); - break; - - case DPIF_OP_FLOW_DEL: - op->error = dpif_flow_del__(dpif, &op->u.flow_del); - break; - case DPIF_OP_EXECUTE: - op->error = dpif_execute__(dpif, &op->u.execute); - break; - - default: - NOT_REACHED(); + 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)