From: Giuseppe Lettieri Date: Sun, 2 Mar 2014 16:11:50 +0000 (+0100) Subject: Merge branch 'mainstream' X-Git-Tag: sliver-openvswitch-2.2.90-1~9 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=3ba9c6a5a5468626dcfeb1f9a750bb0efc8c6a7a;hp=-c;p=sliver-openvswitch.git Merge branch 'mainstream' Conflicts: lib/dpif-netdev.c --- 3ba9c6a5a5468626dcfeb1f9a750bb0efc8c6a7a diff --combined lib/automake.mk index 0ec18a441,9c345e7f9..ac583c239 --- a/lib/automake.mk +++ b/lib/automake.mk @@@ -100,8 -100,6 +100,8 @@@ lib_libopenvswitch_la_SOURCES = lib/multipath.c \ lib/multipath.h \ lib/netdev-dummy.c \ + lib/netdev-tunnel.c \ + lib/netdev-pltap.c \ lib/netdev-provider.h \ lib/netdev-vport.c \ lib/netdev-vport.h \ @@@ -178,8 -176,6 +178,6 @@@ lib/shash.h \ lib/simap.c \ lib/simap.h \ - lib/signals.c \ - lib/signals.h \ lib/smap.c \ lib/smap.h \ lib/socket-util.c \ @@@ -190,7 -186,6 +188,6 @@@ lib/sset.h \ lib/stp.c \ lib/stp.h \ - lib/stream-fd.c \ lib/stream-fd.h \ lib/stream-provider.h \ lib/stream-ssl.h \ @@@ -211,8 -206,6 +208,8 @@@ lib/timeval.h \ lib/token-bucket.c \ lib/token-bucket.h \ + lib/tunalloc.c \ + lib/tunalloc.h \ lib/type-props.h \ lib/unaligned.h \ lib/unicode.c \ @@@ -243,11 -236,15 +240,15 @@@ if WIN3 lib_libopenvswitch_la_SOURCES += \ lib/daemon-windows.c \ lib/getopt_long.c \ - lib/latch-windows.c + lib/latch-windows.c \ + lib/stream-fd-windows.c else lib_libopenvswitch_la_SOURCES += \ lib/daemon.c \ - lib/latch.c \ + lib/latch-unix.c \ + lib/signals.c \ + lib/signals.h \ + lib/stream-fd-unix.c \ lib/stream-unix.c endif diff --combined lib/dpif-netdev.c index b1c25c82b,5897f8bae..5aff18a2c --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@@ -367,17 -367,10 +367,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"; } @@@ -406,8 -399,7 +406,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; @@@ -1314,47 -1306,82 +1314,82 @@@ dpif_netdev_flow_del(struct dpif *dpif } struct dp_netdev_flow_state { - uint32_t bucket; - uint32_t offset; struct dp_netdev_actions *actions; struct odputil_keybuf keybuf; struct odputil_keybuf maskbuf; struct dpif_flow_stats stats; }; - static int - dpif_netdev_flow_dump_start(const struct dpif *dpif OVS_UNUSED, void **statep) + struct dp_netdev_flow_iter { + uint32_t bucket; + uint32_t offset; + int status; + struct ovs_mutex mutex; + }; + + static void + dpif_netdev_flow_dump_state_init(void **statep) { struct dp_netdev_flow_state *state; *statep = state = xmalloc(sizeof *state); - state->bucket = 0; - state->offset = 0; state->actions = NULL; + } + + static void + dpif_netdev_flow_dump_state_uninit(void *state_) + { + struct dp_netdev_flow_state *state = state_; + + dp_netdev_actions_unref(state->actions); + free(state); + } + + static int + dpif_netdev_flow_dump_start(const struct dpif *dpif OVS_UNUSED, void **iterp) + { + struct dp_netdev_flow_iter *iter; + + *iterp = iter = xmalloc(sizeof *iter); + iter->bucket = 0; + iter->offset = 0; + iter->status = 0; + ovs_mutex_init(&iter->mutex); return 0; } static int - dpif_netdev_flow_dump_next(const struct dpif *dpif, void *state_, + dpif_netdev_flow_dump_next(const struct dpif *dpif, void *iter_, void *state_, const struct nlattr **key, size_t *key_len, const struct nlattr **mask, size_t *mask_len, const struct nlattr **actions, size_t *actions_len, const struct dpif_flow_stats **stats) { + struct dp_netdev_flow_iter *iter = iter_; struct dp_netdev_flow_state *state = state_; struct dp_netdev *dp = get_dp_netdev(dpif); struct dp_netdev_flow *netdev_flow; - struct hmap_node *node; + int error; - fat_rwlock_rdlock(&dp->cls.rwlock); - node = hmap_at_position(&dp->flow_table, &state->bucket, &state->offset); - if (node) { - netdev_flow = CONTAINER_OF(node, struct dp_netdev_flow, node); - dp_netdev_flow_ref(netdev_flow); + ovs_mutex_lock(&iter->mutex); + error = iter->status; + if (!error) { + struct hmap_node *node; + + fat_rwlock_rdlock(&dp->cls.rwlock); + node = hmap_at_position(&dp->flow_table, &iter->bucket, &iter->offset); + if (node) { + netdev_flow = CONTAINER_OF(node, struct dp_netdev_flow, node); + dp_netdev_flow_ref(netdev_flow); + } + fat_rwlock_unlock(&dp->cls.rwlock); + if (!node) { + iter->status = error = EOF; + } } - fat_rwlock_unlock(&dp->cls.rwlock); - if (!node) { - return EOF; + ovs_mutex_unlock(&iter->mutex); + if (error) { + return error; } if (key) { @@@ -1405,12 -1432,12 +1440,12 @@@ } static int - dpif_netdev_flow_dump_done(const struct dpif *dpif OVS_UNUSED, void *state_) + dpif_netdev_flow_dump_done(const struct dpif *dpif OVS_UNUSED, void *iter_) { - struct dp_netdev_flow_state *state = state_; + struct dp_netdev_flow_iter *iter = iter_; - dp_netdev_actions_unref(state->actions); - free(state); + ovs_mutex_destroy(&iter->mutex); + free(iter); return 0; } @@@ -1427,8 -1454,7 +1462,7 @@@ dpif_netdev_execute(struct dpif *dpif, } /* Extract flow key. */ - flow_extract(execute->packet, md->skb_priority, md->pkt_mark, &md->tunnel, - (union flow_in_port *)&md->in_port, &key); + flow_extract(execute->packet, md, &key); ovs_rwlock_rdlock(&dp->port_rwlock); dp_netdev_execute_actions(dp, &key, execute->packet, md, execute->actions, @@@ -1600,8 -1626,8 +1634,8 @@@ dp_forwarder_main(void *f_ if (!error) { struct pkt_metadata md = PKT_METADATA_INITIALIZER(port->port_no); - dp_netdev_port_input(dp, &packet, &md); + dp_netdev_port_input(dp, &packet, &md); received_anything = true; } else if (error != EAGAIN && error != EOPNOTSUPP) { static struct vlog_rate_limit rl @@@ -1701,8 -1727,7 +1735,7 @@@ dp_netdev_port_input(struct dp_netdev * if (packet->size < ETH_HEADER_LEN) { return; } - flow_extract(packet, md->skb_priority, md->pkt_mark, &md->tunnel, - (union flow_in_port *)&md->in_port, &key); + flow_extract(packet, md, &key); netdev_flow = dp_netdev_lookup_flow(dp, &key); if (netdev_flow) { struct dp_netdev_actions *actions; @@@ -1838,48 -1863,43 +1871,51 @@@ dp_netdev_execute_actions(struct dp_net odp_execute_actions(&aux, packet, md, actions, actions_len, dp_execute_cb); } +#define DPIF_NETDEV_CLASS_FUNCTIONS \ + dpif_netdev_enumerate, \ + dpif_netdev_port_open_type, \ + dpif_netdev_open, \ + dpif_netdev_close, \ + dpif_netdev_destroy, \ + NULL, \ + NULL, \ + dpif_netdev_get_stats, \ + dpif_netdev_port_add, \ + dpif_netdev_port_del, \ + dpif_netdev_port_query_by_number, \ + dpif_netdev_port_query_by_name, \ + 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_state_init, \ + dpif_netdev_flow_dump_start, \ + dpif_netdev_flow_dump_next, \ ++ NULL, \ + dpif_netdev_flow_dump_done, \ ++ dpif_netdev_flow_dump_state_uninit, \ + 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, - NULL, /* run */ - NULL, /* 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, - 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_state_init, - dpif_netdev_flow_dump_start, - dpif_netdev_flow_dump_next, - NULL, - dpif_netdev_flow_dump_done, - dpif_netdev_flow_dump_state_uninit, - 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 @@@ -1960,4 -1980,3 +1996,4 @@@ dpif_dummy_register(bool override "DP PORT NEW-NUMBER", 3, 3, dpif_dummy_change_port_number, NULL); } + diff --combined lib/dpif-provider.h index f41ab6b9b,dd4f74ef7..704a64278 --- a/lib/dpif-provider.h +++ b/lib/dpif-provider.h @@@ -262,18 -262,28 +262,28 @@@ struct dpif_class * packets. */ int (*flow_flush)(struct dpif *dpif); - /* Attempts to begin dumping the flows in a dpif. On success, returns 0 - * and initializes '*statep' with any data needed for iteration. On - * failure, returns a positive errno value. */ - int (*flow_dump_start)(const struct dpif *dpif, void **statep); + /* Allocates thread-local state for use with the function 'flow_dump_next'. + * On return, initializes '*statep' with any private data needed for + * iteration. */ + void (*flow_dump_state_init)(void **statep); - /* Attempts to retrieve another flow from 'dpif' for 'state', which was - * initialized by a successful call to the 'flow_dump_start' function for - * 'dpif'. On success, updates the output parameters as described below - * and returns 0. Returns EOF if the end of the flow table has been - * reached, or a positive errno value on error. This function will not be - * called again once it returns nonzero within a given iteration (but the - * 'flow_dump_done' function will be called afterward). + /* Attempts to begin dumping the flows in a dpif. On success, returns 0 + * and initializes '*iterp' with any shared data needed for iteration. + * On failure, returns a positive errno value. */ + int (*flow_dump_start)(const struct dpif *dpif, void **iterp); + + /* Attempts to retrieve another flow from 'dpif' for 'iter', using + * 'state' for storage. 'iter' must have been initialized by a successful + * call to the 'flow_dump_start' function for 'dpif'. 'state' must have + * been initialised with a call to the 'flow_dump_state_init' function for + * 'dpif. + * + * On success, updates the output parameters as described below and returns + * 0. Returns EOF if the end of the flow table has been reached, or a + * positive errno value on error. Multiple threads may use the same 'dpif' + * and 'iter' with this function, but all other parameters must be + * different for each thread. If this function returns non-zero, + * subsequent calls with the same arguments will also return non-zero. * * On success: * @@@ -295,16 -305,35 +305,35 @@@ * All of the returned data is owned by 'dpif', not by the caller, and the * caller must not modify or free it. 'dpif' must guarantee that it * remains accessible and unchanging until at least the next call to - * 'flow_dump_next' or 'flow_dump_done' for 'state'. */ - int (*flow_dump_next)(const struct dpif *dpif, void *state, + * 'flow_dump_next' or 'flow_dump_done' for 'iter' and 'state'. */ + int (*flow_dump_next)(const struct dpif *dpif, void *iter, void *state, const struct nlattr **key, size_t *key_len, const struct nlattr **mask, size_t *mask_len, const struct nlattr **actions, size_t *actions_len, const struct dpif_flow_stats **stats); - /* Releases resources from 'dpif' for 'state', which was initialized by a - * successful call to the 'flow_dump_start' function for 'dpif'. */ - int (*flow_dump_done)(const struct dpif *dpif, void *state); + /* Determines whether the next call to 'flow_dump_next' with 'state' will + * modify or free the keys that it previously returned. 'state' must have + * been initialized by a call to 'flow_dump_state_init' for 'dpif'. + * + * 'dpif' guarantees that data returned by flow_dump_next() will remain + * accessible and unchanging until the next call. This function provides a + * way for callers to determine whether that guarantee extends beyond the + * next call. + * + * Returns true if the next call to flow_dump_next() is expected to be + * destructive to previously returned keys for 'state', false otherwise. */ + bool (*flow_dump_next_may_destroy_keys)(void *state); + + /* Releases resources from 'dpif' for 'iter', which was initialized by a + * successful call to the 'flow_dump_start' function for 'dpif'. Callers + * must ensure that this function is called once within a given iteration, + * as the final flow dump operation. */ + int (*flow_dump_done)(const struct dpif *dpif, void *iter); + + /* Releases 'state' which was initialized by a call to the + * 'flow_dump_state_init' function for this 'dpif'. */ + void (*flow_dump_state_uninit)(void *statep); /* Performs the 'execute->actions_len' bytes of actions in * 'execute->actions' on the Ethernet frame in 'execute->packet' @@@ -363,7 -392,6 +392,7 @@@ extern const struct dpif_class dpif_linux_class; extern const struct dpif_class dpif_netdev_class; +extern const struct dpif_class dpif_planetlab_class; #ifdef __cplusplus } diff --combined lib/dpif.c index aa27d62c5,8cb2145ec..7d578ebbb --- a/lib/dpif.c +++ b/lib/dpif.c @@@ -61,7 -61,6 +61,7 @@@ static const struct dpif_class *base_dp &dpif_linux_class, #endif &dpif_netdev_class, + &dpif_planetlab_class, }; struct registered_dpif_class { @@@ -962,26 -961,47 +962,47 @@@ dpif_flow_del(struct dpif *dpif return dpif_flow_del__(dpif, &del); } - /* Initializes 'dump' to begin dumping the flows in a dpif. - * - * This function provides no status indication. An error status for the entire - * dump operation is provided when it is completed by calling - * dpif_flow_dump_done(). - */ + /* Allocates thread-local state for use with the 'flow_dump_next' function for + * 'dpif'. On return, initializes '*statep' with any private data needed for + * iteration. */ void + dpif_flow_dump_state_init(const struct dpif *dpif, void **statep) + { + dpif->dpif_class->flow_dump_state_init(statep); + } + + /* Releases 'state' which was initialized by a call to the + * 'flow_dump_state_init' function for 'dpif'. */ + void + dpif_flow_dump_state_uninit(const struct dpif *dpif, void *state) + { + dpif->dpif_class->flow_dump_state_uninit(state); + } + + /* Initializes 'dump' to begin dumping the flows in a dpif. On sucess, + * initializes 'dump' with any data needed for iteration and returns 0. + * Otherwise, returns a positive errno value describing the problem. */ + int dpif_flow_dump_start(struct dpif_flow_dump *dump, const struct dpif *dpif) { + int error; dump->dpif = dpif; - dump->error = dpif->dpif_class->flow_dump_start(dpif, &dump->state); - log_operation(dpif, "flow_dump_start", dump->error); + error = dpif->dpif_class->flow_dump_start(dpif, &dump->iter); + log_operation(dpif, "flow_dump_start", error); + return error; } - /* Attempts to retrieve another flow from 'dump', which must have been - * initialized with dpif_flow_dump_start(). On success, updates the output - * parameters as described below and returns true. Otherwise, returns false. - * Failure might indicate an actual error or merely the end of the flow table. - * An error status for the entire dump operation is provided when it is - * completed by calling dpif_flow_dump_done(). + /* Attempts to retrieve another flow from 'dump', using 'state' for + * thread-local storage. 'dump' must have been initialized with a successful + * call to dpif_flow_dump_start(), and 'state' must have been initialized with + * dpif_flow_state_init(). + * + * On success, updates the output parameters as described below and returns + * true. Otherwise, returns false. Failure might indicate an actual error or + * merely the end of the flow table. An error status for the entire dump + * operation is provided when it is completed by calling dpif_flow_dump_done(). + * Multiple threads may use the same 'dump' with this function, but all other + * parameters must not be shared. * * On success, if 'key' and 'key_len' are nonnull then '*key' and '*key_len' * will be set to Netlink attributes with types OVS_KEY_ATTR_* representing the @@@ -993,27 -1013,20 +1014,20 @@@ * All of the returned data is owned by 'dpif', not by the caller, and the * caller must not modify or free it. 'dpif' guarantees that it remains * accessible and unchanging until at least the next call to 'flow_dump_next' - * or 'flow_dump_done' for 'dump'. */ + * or 'flow_dump_done' for 'dump' and 'state'. */ bool - dpif_flow_dump_next(struct dpif_flow_dump *dump, + dpif_flow_dump_next(struct dpif_flow_dump *dump, void *state, const struct nlattr **key, size_t *key_len, const struct nlattr **mask, size_t *mask_len, const struct nlattr **actions, size_t *actions_len, const struct dpif_flow_stats **stats) { const struct dpif *dpif = dump->dpif; - int error = dump->error; + int error; - if (!error) { - error = dpif->dpif_class->flow_dump_next(dpif, dump->state, - key, key_len, - mask, mask_len, - actions, actions_len, - stats); - if (error) { - dpif->dpif_class->flow_dump_done(dpif, dump->state); - } - } + error = dpif->dpif_class->flow_dump_next(dpif, dump->iter, state, + key, key_len, mask, mask_len, + actions, actions_len, stats); if (error) { if (key) { *key = NULL; @@@ -1031,33 -1044,50 +1045,50 @@@ *stats = NULL; } } - if (!dump->error) { - if (error == EOF) { - VLOG_DBG_RL(&dpmsg_rl, "%s: dumped all flows", dpif_name(dpif)); - } else if (should_log_flow_message(error)) { - log_flow_message(dpif, error, "flow_dump", - key ? *key : NULL, key ? *key_len : 0, - mask ? *mask : NULL, mask ? *mask_len : 0, - stats ? *stats : NULL, actions ? *actions : NULL, - actions ? *actions_len : 0); - } + if (error == EOF) { + VLOG_DBG_RL(&dpmsg_rl, "%s: dumped all flows", dpif_name(dpif)); + } else if (should_log_flow_message(error)) { + log_flow_message(dpif, error, "flow_dump", + key ? *key : NULL, key ? *key_len : 0, + mask ? *mask : NULL, mask ? *mask_len : 0, + stats ? *stats : NULL, actions ? *actions : NULL, + actions ? *actions_len : 0); } - dump->error = error; return !error; } + /* Determines whether the next call to 'dpif_flow_dump_next' for 'dump' and + * 'state' will modify or free the keys that it previously returned. 'state' + * must have been initialized by a call to 'dpif_flow_dump_state_init' for + * 'dump'. + * + * 'dpif' guarantees that data returned by flow_dump_next() will remain + * accessible and unchanging until the next call. This function provides a way + * for callers to determine whether that guarantee extends beyond the next + * call. + * + * Returns true if the next call to flow_dump_next() is expected to be + * destructive to previously returned keys for 'state', false otherwise. */ + bool + dpif_flow_dump_next_may_destroy_keys(struct dpif_flow_dump *dump, void *state) + { + const struct dpif *dpif = dump->dpif; + return (dpif->dpif_class->flow_dump_next_may_destroy_keys + ? dpif->dpif_class->flow_dump_next_may_destroy_keys(state) + : true); + } + /* Completes flow table dump operation 'dump', which must have been initialized - * with dpif_flow_dump_start(). Returns 0 if the dump operation was - * error-free, otherwise a positive errno value describing the problem. */ + * with a successful call to dpif_flow_dump_start(). Returns 0 if the dump + * operation was error-free, otherwise a positive errno value describing the + * problem. */ int dpif_flow_dump_done(struct dpif_flow_dump *dump) { const struct dpif *dpif = dump->dpif; - if (!dump->error) { - dump->error = dpif->dpif_class->flow_dump_done(dpif, dump->state); - log_operation(dpif, "flow_dump_done", dump->error); - } - return dump->error == EOF ? 0 : dump->error; + int error = dpif->dpif_class->flow_dump_done(dpif, dump->iter); + log_operation(dpif, "flow_dump_done", error); + return error == EOF ? 0 : error; } struct dpif_execute_helper_aux {