dpif: When executing actions needs help, use "set" action to set tunnel.
authorBen Pfaff <blp@nicira.com>
Tue, 24 Jun 2014 23:39:33 +0000 (16:39 -0700)
committerBen Pfaff <blp@nicira.com>
Wed, 25 Jun 2014 00:16:18 +0000 (17:16 -0700)
Open vSwitch userspace is able to implement some actions that the kernel
doesn't support, such as modifying ARP fields.  When it does this for a
tunneled packet, it needs to supply the tunnel information with a "set"
action, because the Linux kernel datapath throws away tunnel information
supplied in the OVS_PACKET_CMD_EXECUTE metadata argument.

VMware-BZ: #1270110
Reported-by: Srinivas Neginhal <sneginha@vmware.com>
Signed-off-by: Ben Pfaff <blp@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
lib/dpif.c

index 48b2d1e..8ec8200 100644 (file)
@@ -1112,20 +1112,41 @@ dpif_execute_helper_cb(void *aux_, struct ofpbuf *packet,
                        const struct nlattr *action, bool may_steal OVS_UNUSED)
 {
     struct dpif_execute_helper_aux *aux = aux_;
-    struct dpif_execute execute;
     int type = nl_attr_type(action);
 
     switch ((enum ovs_action_attr)type) {
     case OVS_ACTION_ATTR_OUTPUT:
     case OVS_ACTION_ATTR_USERSPACE:
-    case OVS_ACTION_ATTR_RECIRC:
-        execute.actions = action;
-        execute.actions_len = NLA_ALIGN(action->nla_len);
+    case OVS_ACTION_ATTR_RECIRC: {
+        struct dpif_execute execute;
+        struct ofpbuf execute_actions;
+        uint64_t stub[256 / 8];
+
+        if (md->tunnel.ip_dst) {
+            /* The Linux kernel datapath throws away the tunnel information
+             * that we supply as metadata.  We have to use a "set" action to
+             * supply it. */
+            ofpbuf_use_stub(&execute_actions, stub, sizeof stub);
+            odp_put_tunnel_action(&md->tunnel, &execute_actions);
+            ofpbuf_put(&execute_actions, action, NLA_ALIGN(action->nla_len));
+
+            execute.actions = ofpbuf_data(&execute_actions);
+            execute.actions_len = ofpbuf_size(&execute_actions);
+        } else {
+            execute.actions = action;
+            execute.actions_len = NLA_ALIGN(action->nla_len);
+        }
+
         execute.packet = packet;
         execute.md = *md;
         execute.needs_help = false;
         aux->error = aux->dpif->dpif_class->execute(aux->dpif, &execute);
+
+        if (md->tunnel.ip_dst) {
+            ofpbuf_uninit(&execute_actions);
+        }
         break;
+    }
 
     case OVS_ACTION_ATTR_HASH:
     case OVS_ACTION_ATTR_PUSH_VLAN: