In case of flow-miss kernel sends skb to userspace and then
userspace sends execute netlink msg to switch the packet.  But
in this process skb rxhash is not restored. skb rxhash is used
for calculating tunnel source port for vxlan. If rxhash is not
restored packet which is sent to miss call handler can get
different source port compared to rest of packet of the flow.

Following patch adds support for packet metadata which is part
of packet-attributes.  Kernel can send packet metadata and
userspace echoes it back to kernel.
Currently packet metadata consist of skb rxhash.

Signed-off-by: Pravin B Shelar <pshe...@nicira.com>
---
 datapath/datapath.c           |   11 +++++++++++
 include/linux/openvswitch.h   |    1 +
 lib/dpif-linux.c              |   12 ++++++++++++
 lib/dpif.h                    |   10 ++++++----
 ofproto/ofproto-dpif-upcall.c |    1 +
 5 files changed, 31 insertions(+), 4 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index 1808c36..b6fa8c4 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -393,6 +393,9 @@ static size_t upcall_msg_size(const struct sk_buff *skb,
        if (userdata)
                size += NLA_ALIGN(userdata->nla_len);
 
+       if (skb->rxhash)
+               size += NLA_ALIGN(sizeof(u32));
+
        return size;
 }
 
@@ -447,6 +450,10 @@ static int queue_userspace_packet(struct net *net, int 
dp_ifindex,
        ovs_nla_put_flow(upcall_info->key, upcall_info->key, user_skb);
        nla_nest_end(user_skb, nla);
 
+       if (skb->rxhash)
+               __nla_put(user_skb, OVS_PACKET_ATTR_METADATA,
+                         sizeof(u32), &skb->rxhash);
+
        if (upcall_info->userdata)
                __nla_put(user_skb, OVS_PACKET_ATTR_USERDATA,
                          nla_len(upcall_info->userdata),
@@ -530,6 +537,9 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, 
struct genl_info *info)
        packet->priority = flow->key.phy.priority;
        packet->mark = flow->key.phy.skb_mark;
 
+       if (a[OVS_PACKET_ATTR_METADATA])
+               skb->rxhash = nla_get_u32(a[OVS_PACKET_ATTR_METADATA]);
+
        rcu_read_lock();
        dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
        err = -ENODEV;
@@ -558,6 +568,7 @@ static const struct nla_policy 
packet_policy[OVS_PACKET_ATTR_MAX + 1] = {
        [OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN },
        [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED },
        [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED },
+       [OVS_PACKET_ATTR_METADATA] = { .type = NLA_U32 },
 };
 
 static struct genl_ops dp_packet_genl_ops[] = {
diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
index b429201..160c491 100644
--- a/include/linux/openvswitch.h
+++ b/include/linux/openvswitch.h
@@ -172,6 +172,7 @@ enum ovs_packet_attr {
        OVS_PACKET_ATTR_KEY,         /* Nested OVS_KEY_ATTR_* attributes. */
        OVS_PACKET_ATTR_ACTIONS,     /* Nested OVS_ACTION_ATTR_* attributes. */
        OVS_PACKET_ATTR_USERDATA,    /* OVS_ACTION_ATTR_USERSPACE arg. */
+       OVS_PACKET_ATTR_METADATA,
        __OVS_PACKET_ATTR_MAX
 };
 
diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index 25715f4..df9fe6f 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -1068,6 +1068,12 @@ dpif_linux_encode_execute(int dp_ifindex, const struct 
dpif_execute *d_exec,
     nl_msg_put_unspec(buf, OVS_PACKET_ATTR_KEY, d_exec->key, d_exec->key_len);
     nl_msg_put_unspec(buf, OVS_PACKET_ATTR_ACTIONS,
                       d_exec->actions, d_exec->actions_len);
+
+    if (d_exec->packet_md) {
+        nl_msg_put_unspec(buf, OVS_PACKET_ATTR_METADATA,
+                          nl_attr_get(d_exec->packet_md),
+                          nl_attr_get_size(d_exec->packet_md));
+    }
 }
 
 static int
@@ -1346,6 +1352,7 @@ parse_odp_packet(struct ofpbuf *buf, struct dpif_upcall 
*upcall,
 
         /* OVS_PACKET_CMD_ACTION only. */
         [OVS_PACKET_ATTR_USERDATA] = { .type = NL_A_UNSPEC, .optional = true },
+        [OVS_PACKET_ATTR_METADATA] = { .type = NL_A_UNSPEC, .optional = true },
     };
 
     struct ovs_header *ovs_header;
@@ -1383,6 +1390,11 @@ parse_odp_packet(struct ofpbuf *buf, struct dpif_upcall 
*upcall,
     upcall->key = CONST_CAST(struct nlattr *,
                              nl_attr_get(a[OVS_PACKET_ATTR_KEY]));
     upcall->key_len = nl_attr_get_size(a[OVS_PACKET_ATTR_KEY]);
+
+    if (a[OVS_PACKET_ATTR_METADATA]) {
+        upcall->packet_md = a[OVS_PACKET_ATTR_METADATA];
+    }
+
     upcall->userdata = a[OVS_PACKET_ATTR_USERDATA];
     *dp_ifindex = ovs_header->dp_ifindex;
 
diff --git a/lib/dpif.h b/lib/dpif.h
index 499ee79..d5903af 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -566,6 +566,7 @@ struct dpif_execute {
     const struct nlattr *actions;   /* Actions to execute on packet. */
     size_t actions_len;             /* Length of 'actions' in bytes. */
     const struct ofpbuf *packet;    /* Packet to execute. */
+    const struct nlattr *packet_md; /* Packet metadata. */
 
     /* Some dpif providers do not implement every action.  The Linux kernel
      * datapath, in particular, does not implement ARP field modification.
@@ -601,10 +602,10 @@ const char *dpif_upcall_type_to_string(enum 
dpif_upcall_type);
 
 /* A packet passed up from the datapath to userspace.
  *
- * If 'key', 'actions', or 'userdata' is nonnull, then it points into data
- * owned by 'packet', so their memory cannot be freed separately.  (This is
- * hardly a great way to do things but it works out OK for the dpif providers
- * and clients that exist so far.)
+ * If 'key', 'actions', metadata, or 'userdata' is nonnull, then it points
+ * into data owned by 'packet', so their memory cannot be freed separately.
+ * (This is hardly a great way to do things but it works out OK for the
+ * dpif providers and clients that exist so far.)
  */
 struct dpif_upcall {
     /* All types. */
@@ -612,6 +613,7 @@ struct dpif_upcall {
     struct ofpbuf *packet;      /* Packet data. */
     struct nlattr *key;         /* Flow key. */
     size_t key_len;             /* Length of 'key' in bytes. */
+    struct nlattr *packet_md;  /* Optional. */
 
     /* DPIF_UC_ACTION only. */
     struct nlattr *userdata;    /* Argument to OVS_ACTION_ATTR_USERSPACE. */
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index dde6430..b5e5ed6 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -816,6 +816,7 @@ handle_upcalls(struct udpif *udpif, struct list *upcalls)
             op->u.execute.key = miss->key;
             op->u.execute.key_len = miss->key_len;
             op->u.execute.packet = packet;
+            op->u.execute.packet_md = upcall->dpif_upcall.packet_md;
             op->u.execute.actions = miss->xout.odp_actions.data;
             op->u.execute.actions_len = miss->xout.odp_actions.size;
             op->u.execute.needs_help = (miss->xout.slow & SLOW_ACTION) != 0;
-- 
1.7.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to