Merge branch 'mainstream'
authorGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Mon, 14 Oct 2013 10:11:59 +0000 (12:11 +0200)
committerGiuseppe Lettieri <g.lettieri@iet.unipi.it>
Mon, 14 Oct 2013 10:11:59 +0000 (12:11 +0200)
1  2 
lib/dpif-netdev.c
lib/dpif.c

diff --combined 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
@@@ -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)
  {
  
      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;
      }
   * 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;
  
      execute.actions = actions;
      execute.actions_len = actions_len;
      execute.packet = buf;
+     execute.needs_help = needs_help;
      return dpif_execute__(dpif, &execute);
  }
  
  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)