[ovs-dev] [PATCH 12/12] Expand tunnel IDs from 32 to 64 bits.

Ben Pfaff blp at nicira.com
Tue Dec 7 19:00:34 UTC 2010


We have a need to identify tunnels with keys longer than 32 bits.  This
commit adds basic datapath and OpenFlow support for such keys.  It doesn't
actually add any tunnel protocols that support 64-bit keys, so this is not
very useful yet.

The 'arg' member of struct odp_msg had to be expanded to 64-bits also,
because it sometimes contains a tunnel ID.  This member also contains the
argument passed to ODPAT_CONTROLLER, so I expanded that action's argument
to 64 bits also so that it can use the full width of the expanded 'arg'.
Userspace doesn't take advantage of the new space though (it was only
using 16 bits anyhow).

This commit has been tested only to the extent that it doesn't disrupt
basic Open vSwitch operation.  I have not tested it with tunnel traffic.

Signed-off-by: Ben Pfaff <blp at nicira.com>
Feature #3976.
---
 datapath/actions.c                      |    4 ++--
 datapath/datapath.c                     |    7 +++----
 datapath/datapath.h                     |    8 ++++----
 datapath/tunnel.c                       |   11 ++++++-----
 datapath/tunnel.h                       |    4 ++--
 datapath/vport-gre.c                    |   12 ++++++------
 include/openflow/nicira-ext.h           |   19 +++++++++++++++++--
 include/openvswitch/datapath-protocol.h |   10 ++++------
 include/openvswitch/tunnel.h            |   14 +++++++-------
 lib/classifier.c                        |    4 ++--
 lib/dpif-netdev.c                       |    6 +++---
 lib/dpif.h                              |    6 +++---
 lib/flow.c                              |    6 +++---
 lib/flow.h                              |    6 +++---
 lib/netdev-vport.c                      |    8 +++++---
 lib/nx-match.c                          |    8 ++++----
 lib/odp-util.c                          |   12 ++++++------
 lib/ofp-parse.c                         |   19 ++++++++++++++-----
 lib/ofp-print.c                         |    7 +++++++
 lib/ofp-util.c                          |    2 +-
 ofproto/ofproto.c                       |   22 +++++++++++++---------
 tests/test-classifier.c                 |    2 +-
 utilities/ovs-ofctl.8.in                |    7 +++++--
 23 files changed, 121 insertions(+), 83 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index 6e350db..5dfcb94 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -444,7 +444,7 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
 			break;
 
 		case ODPAT_CONTROLLER:
-			err = output_control(dp, skb, nla_get_u32(a));
+			err = output_control(dp, skb, nla_get_u64(a));
 			if (err) {
 				kfree_skb(skb);
 				return err;
@@ -452,7 +452,7 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
 			break;
 
 		case ODPAT_SET_TUNNEL:
-			OVS_CB(skb)->tun_id = nla_get_be32(a);
+			OVS_CB(skb)->tun_id = nla_get_be64(a);
 			break;
 
 		case ODPAT_SET_DL_TCI:
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 3a21236..2cfc8c7 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -544,7 +544,7 @@ out:
 /* Append each packet in 'skb' list to 'queue'.  There will be only one packet
  * unless we broke up a GSO packet. */
 static int queue_control_packets(struct sk_buff *skb, struct sk_buff_head *queue,
-				 int queue_no, u32 arg)
+				 int queue_no, u64 arg)
 {
 	struct sk_buff *nskb;
 	int port_no;
@@ -569,7 +569,6 @@ static int queue_control_packets(struct sk_buff *skb, struct sk_buff_head *queue
 		header->type = queue_no;
 		header->length = skb->len;
 		header->port = port_no;
-		header->reserved = 0;
 		header->arg = arg;
 		skb_queue_tail(queue, skb);
 
@@ -587,7 +586,7 @@ err_kfree_skbs:
 }
 
 int dp_output_control(struct datapath *dp, struct sk_buff *skb, int queue_no,
-		      u32 arg)
+		      u64 arg)
 {
 	struct dp_stats_percpu *stats;
 	struct sk_buff_head *queue;
@@ -667,7 +666,7 @@ static int validate_actions(const struct nlattr *actions,
         nla_for_each_attr (a, actions, actions_len, rem) {
                 static const int action_lens[ODPAT_MAX + 1] = {
                         [ODPAT_OUTPUT] = 4,
-                        [ODPAT_CONTROLLER] = 4,
+                        [ODPAT_CONTROLLER] = 8,
                         [ODPAT_SET_DL_TCI] = 2,
                         [ODPAT_STRIP_VLAN] = 0,
                         [ODPAT_SET_DL_SRC] = ETH_ALEN,
diff --git a/datapath/datapath.h b/datapath/datapath.h
index e1bdb7b..c55e205 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -108,8 +108,8 @@ struct datapath {
  * @flow: The flow associated with this packet.  May be %NULL if no flow.
  * @ip_summed: Consistently stores L4 checksumming status across different
  * kernel versions.
- * @tun_id: ID (in network byte order) of the tunnel that encapsulated this
- * packet. It is 0 if the packet was not received on a tunnel.
+ * @tun_id: ID of the tunnel that encapsulated this packet.  It is 0 if the
+ * packet was not received on a tunnel.
  */
 struct ovs_skb_cb {
 	struct vport		*vport;
@@ -117,7 +117,7 @@ struct ovs_skb_cb {
 #ifdef NEED_CSUM_NORMALIZE
 	enum csum_type		ip_summed;
 #endif
-	__be32			tun_id;
+	__be64			tun_id;
 };
 #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
 
@@ -126,7 +126,7 @@ extern int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
 
 void dp_process_received_packet(struct vport *, struct sk_buff *);
 int dp_detach_port(struct vport *);
-int dp_output_control(struct datapath *, struct sk_buff *, int, u32 arg);
+int dp_output_control(struct datapath *, struct sk_buff *, int, u64 arg);
 int dp_min_mtu(const struct datapath *dp);
 void set_internal_devs_mtu(const struct datapath *dp);
 
diff --git a/datapath/tunnel.c b/datapath/tunnel.c
index ec3ad93..95291a8 100644
--- a/datapath/tunnel.c
+++ b/datapath/tunnel.c
@@ -166,11 +166,11 @@ static unsigned int *find_port_pool(const struct tnl_mutable_config *mutable)
 }
 
 struct port_lookup_key {
+	const struct tnl_mutable_config *mutable;
+	__be64 key;
 	u32 tunnel_type;
 	__be32 saddr;
 	__be32 daddr;
-	__be32 key;
-	const struct tnl_mutable_config *mutable;
 };
 
 /*
@@ -192,7 +192,8 @@ static int port_cmp(const struct tbl_node *node, void *target)
 
 static u32 port_hash(struct port_lookup_key *k)
 {
-	return jhash_3words(k->key, k->saddr, k->daddr, k->tunnel_type);
+	u32 x = jhash_3words(k->saddr, k->daddr, k->tunnel_type, 0);
+	return jhash_2words(k->key >> 32, k->key, x);
 }
 
 static u32 mutable_hash(const struct tnl_mutable_config *mutable)
@@ -302,7 +303,7 @@ static int del_port(struct vport *vport)
 	return 0;
 }
 
-struct vport *tnl_find_port(__be32 saddr, __be32 daddr, __be32 key,
+struct vport *tnl_find_port(__be32 saddr, __be32 daddr, __be64 key,
 			    int tunnel_type,
 			    const struct tnl_mutable_config **mutable)
 {
@@ -584,7 +585,7 @@ static void ipv6_build_icmp(struct sk_buff *skb, struct sk_buff *nskb,
 #endif /* IPv6 */
 
 bool tnl_frag_needed(struct vport *vport, const struct tnl_mutable_config *mutable,
-		     struct sk_buff *skb, unsigned int mtu, __be32 flow_key)
+		     struct sk_buff *skb, unsigned int mtu, __be64 flow_key)
 {
 	unsigned int eth_hdr_len = ETH_HLEN;
 	unsigned int total_length = 0, header_length = 0, payload_length;
diff --git a/datapath/tunnel.h b/datapath/tunnel.h
index 3ed7ef3..5615f6a 100644
--- a/datapath/tunnel.h
+++ b/datapath/tunnel.h
@@ -196,12 +196,12 @@ int tnl_get_mtu(const struct vport *vport);
 int tnl_send(struct vport *vport, struct sk_buff *skb);
 void tnl_rcv(struct vport *vport, struct sk_buff *skb);
 
-struct vport *tnl_find_port(__be32 saddr, __be32 daddr, __be32 key,
+struct vport *tnl_find_port(__be32 saddr, __be32 daddr, __be64 key,
 			    int tunnel_type,
 			    const struct tnl_mutable_config **mutable);
 bool tnl_frag_needed(struct vport *vport,
 		     const struct tnl_mutable_config *mutable,
-		     struct sk_buff *skb, unsigned int mtu, __be32 flow_key);
+		     struct sk_buff *skb, unsigned int mtu, __be64 flow_key);
 void tnl_free_linked_skbs(struct sk_buff *skb);
 
 static inline struct tnl_vport *tnl_vport_priv(const struct vport *vport)
diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c
index f6996ed..b7e256c 100644
--- a/datapath/vport-gre.c
+++ b/datapath/vport-gre.c
@@ -71,7 +71,7 @@ static void gre_build_header(const struct vport *vport,
 		greh->flags |= GRE_KEY;
 
 	if (mutable->port_config.out_key)
-		*options = mutable->port_config.out_key;
+		*options = htonl(be64_to_cpu(mutable->port_config.out_key));
 }
 
 static struct sk_buff *gre_update_header(const struct vport *vport,
@@ -84,7 +84,7 @@ static struct sk_buff *gre_update_header(const struct vport *vport,
 
 	/* Work backwards over the options so the checksum is last. */
 	if (mutable->port_config.flags & TNL_F_OUT_KEY_ACTION) {
-		*options = OVS_CB(skb)->tun_id;
+		*options = htonl(OVS_CB(skb)->tun_id);
 		options--;
 	}
 
@@ -102,7 +102,7 @@ static struct sk_buff *gre_update_header(const struct vport *vport,
 	return skb;
 }
 
-static int parse_header(struct iphdr *iph, __be16 *flags, __be32 *key)
+static int parse_header(struct iphdr *iph, __be16 *flags, __be64 *key)
 {
 	/* IP and ICMP protocol handlers check that the IHL is valid. */
 	struct gre_base_hdr *greh = (struct gre_base_hdr *)((u8 *)iph + (iph->ihl << 2));
@@ -127,7 +127,7 @@ static int parse_header(struct iphdr *iph, __be16 *flags, __be32 *key)
 	if (greh->flags & GRE_KEY) {
 		hdr_len += GRE_HEADER_SECTION;
 
-		*key = *options;
+		*key = cpu_to_be64(ntohl(*options));
 		options++;
 	} else
 		*key = 0;
@@ -149,7 +149,7 @@ static void gre_err(struct sk_buff *skb, u32 info)
 
 	struct iphdr *iph;
 	__be16 flags;
-	__be32 key;
+	__be64 key;
 	int tunnel_hdr_len, tot_hdr_len;
 	unsigned int orig_mac_header;
 	unsigned int orig_nw_header;
@@ -293,7 +293,7 @@ static int gre_rcv(struct sk_buff *skb)
 	int hdr_len;
 	struct iphdr *iph;
 	__be16 flags;
-	__be32 key;
+	__be64 key;
 
 	if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr) + ETH_HLEN)))
 		goto error;
diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h
index 8140edf..2b758b0 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -230,7 +230,8 @@ enum nx_action_subtype {
     NXAST_POP_QUEUE,            /* struct nx_action_pop_queue */
     NXAST_REG_MOVE,             /* struct nx_action_reg_move */
     NXAST_REG_LOAD,             /* struct nx_action_reg_load */
-    NXAST_NOTE                  /* struct nx_action_note */
+    NXAST_NOTE,                 /* struct nx_action_note */
+    NXAST_SET_TUNNEL64,         /* struct nx_action_set_tunnel64 */
 };
 
 /* Header for Nicira-defined actions. */
@@ -281,7 +282,8 @@ OFP_ASSERT(sizeof(struct nx_action_resubmit) == 16);
 
 /* Action structure for NXAST_SET_TUNNEL.
  *
- * Sets the encapsulating tunnel ID. */
+ * Sets the encapsulating tunnel ID to a 32-bit value.  The most-significant 32
+ * bits of the tunnel ID are set to 0. */
 struct nx_action_set_tunnel {
     uint16_t type;                  /* OFPAT_VENDOR. */
     uint16_t len;                   /* Length is 16. */
@@ -292,6 +294,19 @@ struct nx_action_set_tunnel {
 };
 OFP_ASSERT(sizeof(struct nx_action_set_tunnel) == 16);
 
+/* Action structure for NXAST_SET_TUNNEL64.
+ *
+ * Sets the encapsulating tunnel ID to a 64-bit value. */
+struct nx_action_set_tunnel64 {
+    ovs_be16 type;                  /* OFPAT_VENDOR. */
+    ovs_be16 len;                   /* Length is 16. */
+    ovs_be32 vendor;                /* NX_VENDOR_ID. */
+    ovs_be16 subtype;               /* NXAST_SET_TUNNEL64. */
+    uint8_t pad[6];
+    ovs_be64 tun_id;                /* Tunnel ID. */
+};
+OFP_ASSERT(sizeof(struct nx_action_set_tunnel64) == 24);
+
 /* Action structure for NXAST_DROP_SPOOFED_ARP.
  *
  * Stops processing further actions, if the packet being processed is an
diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h
index 8658d59..b8305b7 100644
--- a/include/openvswitch/datapath-protocol.h
+++ b/include/openvswitch/datapath-protocol.h
@@ -141,10 +141,9 @@ struct odp_stats {
 
 /**
  * struct odp_msg - format of messages read from datapath fd.
- * @type: One of the %_ODPL_* constants.
  * @length: Total length of message, including this header.
+ * @type: One of the %_ODPL_* constants.
  * @port: Port that received the packet embedded in this message.
- * @reserved: Not currently used.  Should be set to 0.
  * @arg: Argument value whose meaning depends on @type.
  *
  * For @type == %_ODPL_MISS_NR, the header is followed by packet data.  The
@@ -161,11 +160,10 @@ struct odp_stats {
  * data.
  */
 struct odp_msg {
-    uint32_t type;
     uint32_t length;
+    uint16_t type;
     uint16_t port;
-    uint16_t reserved;
-    uint32_t arg;
+    __aligned_u64 arg;
 };
 
 /**
@@ -219,7 +217,7 @@ struct odp_flow_stats {
 #define ODP_TCI_PRESENT 0x1000  /* CFI bit */
 
 struct odp_flow_key {
-    ovs_be32 tun_id;            /* Encapsulating tunnel ID. */
+    ovs_be64 tun_id;            /* Encapsulating tunnel ID. */
     ovs_be32 nw_src;            /* IP source address. */
     ovs_be32 nw_dst;            /* IP destination address. */
     uint16_t in_port;           /* Input switch port. */
diff --git a/include/openvswitch/tunnel.h b/include/openvswitch/tunnel.h
index e7d3fce..c338cd0 100644
--- a/include/openvswitch/tunnel.h
+++ b/include/openvswitch/tunnel.h
@@ -53,13 +53,13 @@
 
 /* This goes in the "config" member of struct odp_port for tunnel vports. */
 struct tnl_port_config {
-	__u32	flags;
-	__be32	saddr;
-	__be32	daddr;
-	__be32	in_key;
-	__be32	out_key;
-	__u8	tos;
-	__u8	ttl;
+	__aligned_u64	in_key;
+	__aligned_u64	out_key;
+	__u32		flags;
+	__be32		saddr;
+	__be32		daddr;
+	__u8		tos;
+	__u8		ttl;
 };
 
 #endif /* openvswitch/tunnel.h */
diff --git a/lib/classifier.c b/lib/classifier.c
index ec94385..9519304 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -783,7 +783,7 @@ flow_equal_except(const struct flow *a, const struct flow *b,
     const flow_wildcards_t wc = wildcards->wildcards;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 36 + FLOW_N_REGS * 4);
+    BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 40 + FLOW_N_REGS * 4);
 
     for (i = 0; i < FLOW_N_REGS; i++) {
         if ((a->regs[i] ^ b->regs[i]) & wildcards->reg_masks[i]) {
@@ -819,7 +819,7 @@ zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
     const flow_wildcards_t wc = wildcards->wildcards;
     int i;
 
-    BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 36 + 4 * FLOW_N_REGS);
+    BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 40 + 4 * FLOW_N_REGS);
 
     for (i = 0; i < FLOW_N_REGS; i++) {
         flow->regs[i] &= wildcards->reg_masks[i];
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 9415811..812aa8e 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -138,7 +138,7 @@ static int do_del_port(struct dp_netdev *, uint16_t port_no);
 static int dpif_netdev_open(const struct dpif_class *, const char *name,
                             bool create, struct dpif **);
 static int dp_netdev_output_control(struct dp_netdev *, const struct ofpbuf *,
-                                    int queue_no, int port_no, uint32_t arg);
+                                    int queue_no, int port_no, uint64_t arg);
 static int dp_netdev_execute_actions(struct dp_netdev *,
                                      struct ofpbuf *, struct flow *,
                                      const struct nlattr *actions,
@@ -1140,7 +1140,7 @@ dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet,
 
 static int
 dp_netdev_output_control(struct dp_netdev *dp, const struct ofpbuf *packet,
-                         int queue_no, int port_no, uint32_t arg)
+                         int queue_no, int port_no, uint64_t arg)
 {
     struct odp_msg *header;
     struct ofpbuf *msg;
@@ -1210,7 +1210,7 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
 
         case ODPAT_CONTROLLER:
             dp_netdev_output_control(dp, packet, _ODPL_ACTION_NR,
-                                     key->in_port, nl_attr_get_u32(a));
+                                     key->in_port, nl_attr_get_u64(a));
             break;
 
         case ODPAT_SET_DL_TCI:
diff --git a/lib/dpif.h b/lib/dpif.h
index 825a00c..dfd179b 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -90,10 +90,10 @@ int dpif_execute(struct dpif *, const struct nlattr *actions,
 /* Minimum number of bytes of headroom for a packet returned by dpif_recv()
  * member function.  This headroom allows "struct odp_msg" to be replaced by
  * "struct ofp_packet_in" without copying the buffer. */
-#define DPIF_RECV_MSG_PADDING (sizeof(struct ofp_packet_in) \
-                               - sizeof(struct odp_msg))
+#define DPIF_RECV_MSG_PADDING \
+        ROUND_UP(sizeof(struct ofp_packet_in) - sizeof(struct odp_msg), 8)
 BUILD_ASSERT_DECL(sizeof(struct ofp_packet_in) > sizeof(struct odp_msg));
-BUILD_ASSERT_DECL(DPIF_RECV_MSG_PADDING % 4 == 0);
+BUILD_ASSERT_DECL(DPIF_RECV_MSG_PADDING % 8 == 0);
 
 int dpif_recv_get_mask(const struct dpif *, int *listen_mask);
 int dpif_recv_set_mask(struct dpif *, int listen_mask);
diff --git a/lib/flow.c b/lib/flow.c
index ebbd927..e7ed2a9 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -138,7 +138,7 @@ parse_ethertype(struct ofpbuf *b)
  *      present and has a correct length, and otherwise NULL.
  */
 int
-flow_extract(struct ofpbuf *packet, ovs_be32 tun_id, uint16_t in_port,
+flow_extract(struct ofpbuf *packet, ovs_be64 tun_id, uint16_t in_port,
              struct flow *flow)
 {
     struct ofpbuf b = *packet;
@@ -261,8 +261,8 @@ flow_to_string(const struct flow *flow)
 void
 flow_format(struct ds *ds, const struct flow *flow)
 {
-    ds_put_format(ds, "tunnel%#"PRIx32":in_port%04"PRIx16":tci(",
-                  ntohl(flow->tun_id), flow->in_port);
+    ds_put_format(ds, "tunnel%#"PRIx64":in_port%04"PRIx16":tci(",
+                  flow->tun_id, flow->in_port);
     if (flow->vlan_tci) {
         ds_put_format(ds, "vlan%"PRIu16",pcp%d",
                       vlan_tci_to_vid(flow->vlan_tci),
diff --git a/lib/flow.h b/lib/flow.h
index 1509a7d..72f62e8 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -36,8 +36,8 @@ struct ofpbuf;
 BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS);
 
 struct flow {
+    ovs_be64 tun_id;            /* Encapsulating tunnel ID. */
     uint32_t regs[FLOW_N_REGS]; /* Registers. */
-    ovs_be32 tun_id;            /* Encapsulating tunnel ID. */
     ovs_be32 nw_src;            /* IP source address. */
     ovs_be32 nw_dst;            /* IP destination address. */
     uint16_t in_port;           /* Input switch port. */
@@ -53,13 +53,13 @@ struct flow {
 
 /* Assert that there are FLOW_SIG_SIZE bytes of significant data in "struct
  * flow", followed by FLOW_PAD_SIZE bytes of padding. */
-#define FLOW_SIG_SIZE (36 + FLOW_N_REGS * 4)
+#define FLOW_SIG_SIZE (40 + FLOW_N_REGS * 4)
 #define FLOW_PAD_SIZE 0
 BUILD_ASSERT_DECL(offsetof(struct flow, nw_tos) == FLOW_SIG_SIZE - 1);
 BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->nw_tos) == 1);
 BUILD_ASSERT_DECL(sizeof(struct flow) == FLOW_SIG_SIZE + FLOW_PAD_SIZE);
 
-int flow_extract(struct ofpbuf *, ovs_be32 tun_id, uint16_t in_port,
+int flow_extract(struct ofpbuf *, uint64_t tun_id, uint16_t in_port,
                  struct flow *);
 void flow_extract_stats(const struct flow *flow, struct ofpbuf *packet,
         struct odp_flow_stats *stats);
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index f101b93..5566289 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -23,6 +23,7 @@
 #include <net/if.h>
 #include <sys/ioctl.h>
 
+#include "byte-order.h"
 #include "list.h"
 #include "netdev-provider.h"
 #include "openvswitch/datapath-protocol.h"
@@ -462,19 +463,20 @@ parse_tunnel_config(const struct netdev_dev *dev, const struct shash *args,
                 config.flags |= TNL_F_IN_KEY_MATCH;
                 config.flags |= TNL_F_OUT_KEY_ACTION;
             } else {
-                config.out_key = config.in_key = htonl(atoi(node->data));
+                uint64_t key = strtoull(node->data, NULL, 0);
+                config.out_key = config.in_key = htonll(key);
             }
         } else if (!strcmp(node->name, "in_key") && is_gre) {
             if (!strcmp(node->data, "flow")) {
                 config.flags |= TNL_F_IN_KEY_MATCH;
             } else {
-                config.in_key = htonl(atoi(node->data));
+                config.in_key = htonll(strtoull(node->data, NULL, 0));
             }
         } else if (!strcmp(node->name, "out_key") && is_gre) {
             if (!strcmp(node->data, "flow")) {
                 config.flags |= TNL_F_OUT_KEY_ACTION;
             } else {
-                config.out_key = htonl(atoi(node->data));
+                config.out_key = htonll(strtoull(node->data, NULL, 0));
             }
         } else if (!strcmp(node->name, "tos")) {
             if (!strcmp(node->data, "inherit")) {
diff --git a/lib/nx-match.c b/lib/nx-match.c
index ea31c79..b63ab86 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -318,7 +318,7 @@ parse_nxm_entry(struct cls_rule *rule, const struct nxm_field *f,
 
         /* Tunnel ID. */
     case NFI_NXM_NX_TUN_ID:
-        flow->tun_id = htonl(ntohll(get_unaligned_be64(value)));
+        flow->tun_id = ntohll(get_unaligned_be64(value));
         return 0;
 
         /* Registers. */
@@ -646,7 +646,7 @@ nx_put_match(struct ofpbuf *b, const struct cls_rule *cr)
 
     /* Tunnel ID. */
     if (!(wc & FWW_TUN_ID)) {
-        nxm_put_64(b, NXM_NX_TUN_ID, htonll(ntohl(flow->tun_id)));
+        nxm_put_64(b, NXM_NX_TUN_ID, htonll(flow->tun_id));
     }
 
     /* Registers. */
@@ -924,7 +924,7 @@ nxm_read_field(const struct nxm_field *src, const struct flow *flow)
         return ntohs(flow->tp_dst) & 0xff;
 
     case NFI_NXM_NX_TUN_ID:
-        return ntohl(flow->tun_id);
+        return flow->tun_id;
 
 #define NXM_READ_REGISTER(IDX)                  \
     case NFI_NXM_NX_REG##IDX:                   \
@@ -986,7 +986,7 @@ nxm_execute_reg_move(const struct nx_action_reg_move *action,
     } else if (dst->header == NXM_OF_VLAN_TCI) {
         flow->vlan_tci = htons(new_data);
     } else if (dst->header == NXM_NX_TUN_ID) {
-        flow->tun_id = htonl(new_data);
+        flow->tun_id = new_data;
     } else {
         NOT_REACHED();
     }
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 8089cd3..dd6b629 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -31,8 +31,8 @@
 void
 format_odp_flow_key(struct ds *ds, const struct odp_flow_key *key)
 {
-    ds_put_format(ds, "tun_id%#"PRIx32" in_port%d tci(",
-                  ntohl(key->tun_id), key->in_port);
+    ds_put_format(ds, "tun_id%#"PRIx64" in_port%d tci(",
+                  ntohll(key->tun_id), key->in_port);
     if (key->dl_tci) {
         ds_put_format(ds, "vlan%"PRIu16",pcp%d",
                       vlan_tci_to_vid(key->dl_tci),
@@ -57,7 +57,7 @@ odp_action_len(uint16_t type)
 
     switch ((enum odp_action_type) type) {
     case ODPAT_OUTPUT: return 4;
-    case ODPAT_CONTROLLER: return 4;
+    case ODPAT_CONTROLLER: return 8;
     case ODPAT_SET_DL_TCI: return 2;
     case ODPAT_STRIP_VLAN: return 0;
     case ODPAT_SET_DL_SRC: return ETH_ADDR_LEN;
@@ -115,11 +115,11 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
         ds_put_format(ds, "%"PRIu16, nl_attr_get_u32(a));
         break;
     case ODPAT_CONTROLLER:
-        ds_put_format(ds, "ctl(%"PRIu32")", nl_attr_get_u32(a));
+        ds_put_format(ds, "ctl(%"PRIu64")", nl_attr_get_u64(a));
         break;
     case ODPAT_SET_TUNNEL:
-        ds_put_format(ds, "set_tunnel(%#"PRIx32")",
-                      ntohl(nl_attr_get_be32(a)));
+        ds_put_format(ds, "set_tunnel(%#"PRIx64")",
+                      ntohll(nl_attr_get_be64(a)));
         break;
     case ODPAT_SET_DL_TCI:
         ds_put_format(ds, "set_tci(vid=%"PRIu16",pcp=%d)",
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 490c9df..5c804d4 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -256,11 +256,20 @@ str_to_action(char *str, struct ofpbuf *b)
             nar->subtype = htons(NXAST_RESUBMIT);
             nar->in_port = htons(str_to_u32(arg));
         } else if (!strcasecmp(act, "set_tunnel")) {
-            struct nx_action_set_tunnel *nast;
-            nast = put_action(b, sizeof *nast, OFPAT_VENDOR);
-            nast->vendor = htonl(NX_VENDOR_ID);
-            nast->subtype = htons(NXAST_SET_TUNNEL);
-            nast->tun_id = htonl(str_to_u32(arg));
+            uint64_t tun_id = str_to_u64(arg);
+            if (tun_id <= UINT32_MAX) {
+                struct nx_action_set_tunnel *nast;
+                nast = put_action(b, sizeof *nast, OFPAT_VENDOR);
+                nast->vendor = htonl(NX_VENDOR_ID);
+                nast->subtype = htons(NXAST_SET_TUNNEL);
+                nast->tun_id = htonl(tun_id);
+            } else {
+                struct nx_action_set_tunnel64 *nast64;
+                nast64 = put_action(b, sizeof *nast64, OFPAT_VENDOR);
+                nast64->vendor = htonl(NX_VENDOR_ID);
+                nast64->subtype = htons(NXAST_SET_TUNNEL64);
+                nast64->tun_id = htonll(tun_id);
+            }
         } else if (!strcasecmp(act, "drop_spoofed_arp")) {
             struct nx_action_header *nah;
             nah = put_action(b, sizeof *nah, OFPAT_VENDOR);
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index d801236..cb4dc03 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -233,6 +233,13 @@ ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah)
         print_note(string, (const struct nx_action_note *) nah);
         break;
 
+    case NXAST_SET_TUNNEL64: {
+        const struct nx_action_set_tunnel64 *nast64 =
+            (struct nx_action_set_tunnel64 *)nah;
+        ds_put_format(string, "set_tunnel64:%#"PRIx64, ntohll(nast64->tun_id));
+        break;
+    }
+
     default:
         ds_put_format(string, "***unknown Nicira action:%d***",
                       ntohs(nah->subtype));
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 93805ba..5c84ec0 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -126,7 +126,7 @@ ofputil_cls_rule_from_match(const struct ofp_match *match,
     wc->nw_dst_mask = ofputil_wcbits_to_netmask(ofpfw >> OFPFW_NW_DST_SHIFT);
 
     if (flow_format == NXFF_TUN_ID_FROM_COOKIE && !(ofpfw & NXFW_TUN_ID)) {
-        rule->flow.tun_id = htonl(ntohll(cookie) >> 32);
+        rule->flow.tun_id = ntohll(cookie) >> 32;
     } else {
         wc->wildcards |= FWW_TUN_ID;
         rule->flow.tun_id = htonl(0);
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 88b7124..4c43a4f 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2002,7 +2002,7 @@ execute_odp_actions(struct ofproto *ofproto, uint16_t in_port,
                     const struct nlattr *odp_actions, unsigned int actions_len,
                     struct ofpbuf *packet)
 {
-    if (actions_len == NLA_ALIGN(NLA_HDRLEN + sizeof(uint32_t))
+    if (actions_len == NLA_ALIGN(NLA_HDRLEN + sizeof(uint64_t))
         && odp_actions->nla_type == ODPAT_CONTROLLER) {
         /* As an optimization, avoid a round-trip from userspace to kernel to
          * userspace.  This also avoids possibly filling up kernel packet
@@ -2013,8 +2013,7 @@ execute_odp_actions(struct ofproto *ofproto, uint16_t in_port,
         msg->type = _ODPL_ACTION_NR;
         msg->length = sizeof(struct odp_msg) + packet->size;
         msg->port = in_port;
-        msg->reserved = 0;
-        msg->arg = nl_attr_get_u32(odp_actions);
+        msg->arg = nl_attr_get_u64(odp_actions);
 
         send_packet_in(ofproto, packet);
 
@@ -2696,7 +2695,7 @@ xlate_output_action__(struct action_xlate_ctx *ctx,
                       &ctx->nf_output_iface, ctx->odp_actions);
         break;
     case OFPP_CONTROLLER:
-        nl_msg_put_u32(ctx->odp_actions, ODPAT_CONTROLLER, max_len);
+        nl_msg_put_u64(ctx->odp_actions, ODPAT_CONTROLLER, max_len);
         break;
     case OFPP_LOCAL:
         add_output_action(ctx, ODPP_LOCAL);
@@ -2836,6 +2835,7 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
 {
     const struct nx_action_resubmit *nar;
     const struct nx_action_set_tunnel *nast;
+    const struct nx_action_set_tunnel64 *nast64;
     const struct nx_action_set_queue *nasq;
     int subtype = ntohs(nah->subtype);
 
@@ -2848,7 +2848,8 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
 
     case NXAST_SET_TUNNEL:
         nast = (const struct nx_action_set_tunnel *) nah;
-        nl_msg_put_be32(ctx->odp_actions, ODPAT_SET_TUNNEL, nast->tun_id);
+        nl_msg_put_be64(ctx->odp_actions, ODPAT_SET_TUNNEL,
+                        htonll(ntohl(nast->tun_id)));
         break;
 
     case NXAST_DROP_SPOOFED_ARP:
@@ -2878,6 +2879,11 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
         /* Nothing to do. */
         break;
 
+    case NXAST_SET_TUNNEL64:
+        nast64 = (const struct nx_action_set_tunnel64 *) nah;
+        nl_msg_put_be64(ctx->odp_actions, ODPAT_SET_TUNNEL, nast64->tun_id);
+        break;
+
     /* If you add a new action here that modifies flow data, don't forget to
      * update the flow key in ctx->flow at the same time. */
 
@@ -4396,13 +4402,11 @@ handle_odp_miss_msg(struct ofproto *p, struct ofpbuf *packet)
      * to the local port regardless of the flow table. */
     if (in_band_msg_in_hook(p->in_band, &flow, &payload)) {
         struct ofpbuf odp_actions;
-        uint64_t buf[1];
 
-        ofpbuf_use_stack(&odp_actions, buf, sizeof buf);
+        ofpbuf_init(&odp_actions, 32);
         nl_msg_put_u32(&odp_actions, ODPAT_OUTPUT, ODPP_LOCAL);
-        assert(odp_actions.base == buf);
-
         dpif_execute(p->dpif, odp_actions.data, odp_actions.size, &payload);
+        ofpbuf_uninit(&odp_actions);
     }
 
     facet = facet_lookup_valid(p, &flow);
diff --git a/tests/test-classifier.c b/tests/test-classifier.c
index 461074d..e5d30ef 100644
--- a/tests/test-classifier.c
+++ b/tests/test-classifier.c
@@ -246,7 +246,7 @@ static ovs_be32 nw_src_values[] = { CONSTANT_HTONL(0xc0a80001),
                                     CONSTANT_HTONL(0xc0a04455) };
 static ovs_be32 nw_dst_values[] = { CONSTANT_HTONL(0xc0a80002),
                                     CONSTANT_HTONL(0xc0a04455) };
-static ovs_be32 tun_id_values[] = { 0, 0xffff0000 };
+static uint64_t tun_id_values[] = { 0, UINT64_C(0xfedcba9876543210) };
 static uint16_t in_port_values[] = { 1, ODPP_LOCAL };
 static ovs_be16 vlan_tci_values[] = { CONSTANT_HTONS(101), CONSTANT_HTONS(0) };
 static ovs_be16 dl_type_values[]
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 7ffad2b..c75c1af 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -457,8 +457,11 @@ addition to any other actions in this flow entry.  Recursive
 \fBresubmit\fR actions are ignored.
 .
 .IP \fBset_tunnel\fB:\fIid\fR
-If outputting to a port that encapsulates the packet in a tunnel and supports
-an identifier (such as GRE), sets the identifier to \fBid\fR.
+If outputting to a port that encapsulates the packet in a tunnel and
+supports an identifier (such as GRE), sets the identifier to \fBid\fR.
+If \fIid\fR fits in 32 bits, then this uses an action extension that
+is supported by Open vSwitch 1.0 and later.  Otherwise, if \fIid\fR is
+a 64-bit value, it requires Open vSwitch 1.1 or later.
 .
 .IP \fBdrop_spoofed_arp\fR
 Stops processing further actions, if the packet being processed is an
-- 
1.7.1





More information about the dev mailing list