Merge branch 'mainstream'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Sun, 2 Mar 2014 16:11:50 +0000 (17:11 +0100)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Sun, 9 Mar 2014 15:03:52 +0000 (16:03 +0100)
Conflicts:
lib/dpif-netdev.c

1  2 
lib/automake.mk
lib/dpif-netdev.c
lib/dpif-provider.h
lib/dpif.c

diff --combined 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 \
        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 \
        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 \
        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
@@@ -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) {
  }
  
  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
@@@ -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:
       *
       * 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'
  
  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
@@@ -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
   * 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;
              *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 {