[ovs-dev] [tunid64 v3 8/8] Expand tunnel IDs from 32 to 64 bits.

Ben Pfaff blp at nicira.com
Thu Dec 9 22:48:32 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                     |    9 +++----
 datapath/datapath.h                     |    8 +++---
 datapath/tunnel.c                       |   11 +++++----
 datapath/tunnel.h                       |    4 +-
 datapath/vport-gre.c                    |   32 +++++++++++++++++++++++++-----
 include/openflow/nicira-ext.h           |   19 ++++++++++++++++-
 include/openvswitch/datapath-protocol.h |   12 +++++-----
 include/openvswitch/tunnel.h            |   14 ++++++------
 lib/classifier.c                        |    8 +++---
 lib/classifier.h                        |    2 +-
 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                          |   14 ++++++------
 lib/ofp-parse.c                         |   24 ++++++++++++++++------
 lib/ofp-print.c                         |    8 +++++++
 lib/ofp-util.c                          |   12 +++++++---
 ofproto/ofproto.c                       |   19 ++++++++++++-----
 tests/ovs-ofctl.at                      |    2 +
 tests/test-classifier.c                 |    4 ++-
 utilities/ovs-ofctl.8.in                |    9 ++++++-
 25 files changed, 165 insertions(+), 90 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 9580b0d..d8ac245 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,
@@ -677,7 +676,7 @@ static int validate_actions(const struct nlattr *actions,
                         [ODPAT_SET_NW_TOS] = 1,
                         [ODPAT_SET_TP_SRC] = 2,
                         [ODPAT_SET_TP_DST] = 2,
-                        [ODPAT_SET_TUNNEL] = 4,
+                        [ODPAT_SET_TUNNEL] = 8,
                         [ODPAT_SET_PRIORITY] = 4,
                         [ODPAT_POP_PRIORITY] = 0,
                         [ODPAT_DROP_SPOOFED_ARP] = 0,
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..eb10903 100644
--- a/datapath/vport-gre.c
+++ b/datapath/vport-gre.c
@@ -50,6 +50,16 @@ static int gre_hdr_len(const struct tnl_port_config *port_config)
 	return len;
 }
 
+/* Returns the least-significant 32 bits of a __be64. */
+static __be32 be64_get_low32(__be64 x)
+{
+#ifdef __BIG_ENDIAN
+	return x;
+#else
+	return x >> 32;
+#endif
+}
+
 static void gre_build_header(const struct vport *vport,
 			     const struct tnl_mutable_config *mutable,
 			     void *header)
@@ -71,7 +81,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 = be64_get_low32(mutable->port_config.out_key);
 }
 
 static struct sk_buff *gre_update_header(const struct vport *vport,
@@ -84,7 +94,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 = be64_get_low32(OVS_CB(skb)->tun_id);
 		options--;
 	}
 
@@ -102,7 +112,17 @@ static struct sk_buff *gre_update_header(const struct vport *vport,
 	return skb;
 }
 
-static int parse_header(struct iphdr *iph, __be16 *flags, __be32 *key)
+/* Zero-extends a __be32 into the least-significant 32 bits of a __be64. */
+static __be64 be32_extend_to_be64(__be32 x)
+{
+#ifdef __BIG_ENDIAN
+	return x;
+#else
+	return (__be64) x << 32;
+#endif
+}
+
+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 +147,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 = be32_extend_to_be64(*options);
 		options++;
 	} else
 		*key = 0;
@@ -149,7 +169,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 +313,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 de3c2e5..135f793 100644
--- a/include/openflow/nicira-ext.h
+++ b/include/openflow/nicira-ext.h
@@ -228,7 +228,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. */
@@ -279,7 +280,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. */
@@ -290,6 +292,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 731a849..ad68e9e 100644
--- a/include/openvswitch/datapath-protocol.h
+++ b/include/openvswitch/datapath-protocol.h
@@ -63,6 +63,8 @@
 
 #ifndef __aligned_u64
 #define __aligned_u64 __u64 __attribute__((aligned(8)))
+#define __aligned_be64 __be64 __attribute__((aligned(8)))
+#define __aligned_le64 __le64 __attribute__((aligned(8)))
 #endif
 
 #include <linux/if_link.h>
@@ -141,10 +143,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 +162,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 +219,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..d545e40 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_be64	in_key;
+	__aligned_be64	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 4905837..86d8269 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -128,7 +128,7 @@ cls_rule_set_reg_masked(struct cls_rule *rule, unsigned int reg_idx,
 }
 
 void
-cls_rule_set_tun_id(struct cls_rule *rule, ovs_be32 tun_id)
+cls_rule_set_tun_id(struct cls_rule *rule, ovs_be64 tun_id)
 {
     rule->wc.wildcards &= ~FWW_TUN_ID;
     rule->flow.tun_id = tun_id;
@@ -394,7 +394,7 @@ cls_rule_format(const struct cls_rule *rule, struct ds *s)
         }
     }
     if (!(w & FWW_TUN_ID)) {
-        ds_put_format(s, "tun_id=0x%"PRIx32",", ntohl(f->tun_id));
+        ds_put_format(s, "tun_id=0x%"PRIx64",", ntohll(f->tun_id));
     }
     if (!(w & FWW_IN_PORT)) {
         ds_put_format(s, "in_port=%"PRIu16",",
@@ -932,7 +932,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]) {
@@ -968,7 +968,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/classifier.h b/lib/classifier.h
index 927423e..453417d 100644
--- a/lib/classifier.h
+++ b/lib/classifier.h
@@ -77,7 +77,7 @@ void cls_rule_zero_wildcarded_fields(struct cls_rule *);
 void cls_rule_set_reg(struct cls_rule *, unsigned int reg_idx, uint32_t value);
 void cls_rule_set_reg_masked(struct cls_rule *, unsigned int reg_idx,
                              uint32_t value, uint32_t mask);
-void cls_rule_set_tun_id(struct cls_rule *, ovs_be32 tun_id);
+void cls_rule_set_tun_id(struct cls_rule *, ovs_be64 tun_id);
 void cls_rule_set_in_port(struct cls_rule *, uint16_t odp_port);
 void cls_rule_set_dl_type(struct cls_rule *, ovs_be16);
 void cls_rule_set_dl_src(struct cls_rule *, const uint8_t[6]);
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 0f95c5f..29f3cc9 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 bcb6482..6fea2ff 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 = 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, flow->tun_id);
     }
 
     /* Registers. */
@@ -1104,7 +1104,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 ntohll(flow->tun_id);
 
 #define NXM_READ_REGISTER(IDX)                  \
     case NFI_NXM_NX_REG##IDX:                   \
@@ -1166,7 +1166,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 = htonll(new_data);
     } else {
         NOT_REACHED();
     }
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 2ed551d..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;
@@ -67,7 +67,7 @@ odp_action_len(uint16_t type)
     case ODPAT_SET_NW_TOS: return 1;
     case ODPAT_SET_TP_SRC: return 2;
     case ODPAT_SET_TP_DST: return 2;
-    case ODPAT_SET_TUNNEL: return 4;
+    case ODPAT_SET_TUNNEL: return 8;
     case ODPAT_SET_PRIORITY: return 4;
     case ODPAT_POP_PRIORITY: return 0;
     case ODPAT_DROP_SPOOFED_ARP: return 0;
@@ -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 1c7ce4f..a72d1aa 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -257,12 +257,22 @@ str_to_action(char *str, struct ofpbuf *b)
             nar->vendor = htonl(NX_VENDOR_ID);
             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));
+        } else if (!strcasecmp(act, "set_tunnel")
+                   || !strcasecmp(act, "set_tunnel64")) {
+            uint64_t tun_id = str_to_u64(arg);
+            if (!strcasecmp(act, "set_tunnel64") || tun_id > UINT32_MAX) {
+                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 {
+                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 if (!strcasecmp(act, "drop_spoofed_arp")) {
             struct nx_action_header *nah;
             nah = put_action(b, sizeof *nah, OFPAT_VENDOR);
@@ -451,7 +461,7 @@ parse_field_value(struct cls_rule *rule, enum field_index index,
 
     switch (index) {
     case F_TUN_ID:
-        cls_rule_set_tun_id(rule, htonl(str_to_u32(value)));
+        cls_rule_set_tun_id(rule, htonll(str_to_u64(value)));
         break;
 
     case F_IN_PORT:
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 5370c9a..2d9e026 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -215,6 +215,7 @@ nx_action_len(enum nx_action_subtype subtype)
     case NXAST_REG_MOVE: return sizeof(struct nx_action_reg_move);
     case NXAST_REG_LOAD: return sizeof(struct nx_action_reg_load);
     case NXAST_NOTE: return -1;
+    case NXAST_SET_TUNNEL64: return sizeof(struct nx_action_set_tunnel64);
     default: return -1;
     }
 }
@@ -233,6 +234,7 @@ ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah)
     }
 
     if (subtype <= TYPE_MAXIMUM(enum nx_action_subtype)) {
+        const struct nx_action_set_tunnel64 *nast64;
         const struct nx_action_set_tunnel *nast;
         const struct nx_action_set_queue *nasq;
         const struct nx_action_resubmit *nar;
@@ -278,6 +280,12 @@ ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah)
             nxm_format_reg_load(load, string);
             return;
 
+        case NXAST_SET_TUNNEL64:
+            nast64 = (struct nx_action_set_tunnel64 *) nah;
+            ds_put_format(string, "set_tunnel64:%#"PRIx64,
+                          ntohll(nast64->tun_id));
+            return;
+
         case NXAST_SNAT__OBSOLETE:
         default:
             break;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 1cafd86..b4b7ecd 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -127,10 +127,10 @@ 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 = htonll(ntohll(cookie) >> 32);
     } else {
         wc->wildcards |= FWW_TUN_ID;
-        rule->flow.tun_id = htonl(0);
+        rule->flow.tun_id = htonll(0);
     }
 
     if (ofpfw & OFPFW_DL_DST) {
@@ -233,7 +233,7 @@ ofputil_cls_rule_to_match(const struct cls_rule *rule,
             ofpfw |= NXFW_TUN_ID;
         } else {
             uint32_t cookie_lo = ntohll(cookie_in);
-            uint32_t cookie_hi = ntohl(rule->flow.tun_id);
+            uint32_t cookie_hi = ntohll(rule->flow.tun_id);
             cookie_in = htonll(cookie_lo | ((uint64_t) cookie_hi << 32));
         }
     }
@@ -856,7 +856,7 @@ ofputil_min_flow_format(const struct cls_rule *rule, bool cookie_support,
         || !regs_fully_wildcarded(wc)
         || (!(wc->wildcards & FWW_TUN_ID)
             && (!cookie_support
-                || (cookie_hi && cookie_hi != rule->flow.tun_id)))) {
+                || (cookie_hi && cookie_hi != ntohll(rule->flow.tun_id))))) {
         return NXFF_NXM;
     } else if (!(wc->wildcards & FWW_TUN_ID)) {
         return NXFF_TUN_ID_FROM_COOKIE;
@@ -1741,6 +1741,10 @@ check_nicira_action(const union ofp_action *a, unsigned int len,
     case NXAST_NOTE:
         return 0;
 
+    case NXAST_SET_TUNNEL64:
+        return check_action_exact_len(a, len,
+                                      sizeof(struct nx_action_set_tunnel64));
+
     case NXAST_SNAT__OBSOLETE:
     default:
         return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE);
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 60d2643..2161442 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);
@@ -2838,6 +2837,7 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
     const struct nx_action_set_tunnel *nast;
     const struct nx_action_set_queue *nasq;
     enum nx_action_subtype subtype = ntohs(nah->subtype);
+    ovs_be64 tun_id;
 
     assert(nah->vendor == htonl(NX_VENDOR_ID));
     switch (subtype) {
@@ -2848,8 +2848,9 @@ 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);
-        ctx->flow.tun_id = nast->tun_id;
+        tun_id = htonll(ntohl(nast->tun_id));
+        nl_msg_put_be64(ctx->odp_actions, ODPAT_SET_TUNNEL, tun_id);
+        ctx->flow.tun_id = tun_id;
         break;
 
     case NXAST_DROP_SPOOFED_ARP:
@@ -2879,6 +2880,12 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
         /* Nothing to do. */
         break;
 
+    case NXAST_SET_TUNNEL64:
+        tun_id = ((const struct nx_action_set_tunnel64 *) nah)->tun_id;
+        nl_msg_put_be64(ctx->odp_actions, ODPAT_SET_TUNNEL, tun_id);
+        ctx->flow.tun_id = 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. */
 
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index 85d191d..94013e7 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -12,6 +12,7 @@ udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
 cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller
 actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note
 tun_id=0x1234,cookie=0x5678,actions=flood
+actions=set_tunnel:0x1234,set_tunnel64:0x9876,set_tunnel:0x123456789
 actions=drop
 ])
 AT_CHECK([ovs-ofctl parse-flows flows.txt], [0], [stdout], [stderr])
@@ -26,6 +27,7 @@ OFPT_FLOW_MOD: ADD priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTR
 OFPT_FLOW_MOD: ADD actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
 NXT_TUN_ID_FROM_COOKIE: set=1
 OFPT_FLOW_MOD: ADD cookie:0x123400005678 actions=FLOOD
+OFPT_FLOW_MOD: ADD actions=set_tunnel:0x1234,set_tunnel64:0x9876,set_tunnel64:0x123456789
 OFPT_FLOW_MOD: ADD actions=drop
 ])
 AT_CHECK([sed 's/.*|//' stderr], [0], [dnl
diff --git a/tests/test-classifier.c b/tests/test-classifier.c
index 461074d..63a7ada 100644
--- a/tests/test-classifier.c
+++ b/tests/test-classifier.c
@@ -246,7 +246,9 @@ 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 ovs_be64 tun_id_values[] = {
+    0,
+    CONSTANT_HTONLL(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 30a7a43..c3cbbf1 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -495,8 +495,13 @@ 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.
+.IQ \fBset_tunnel64\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 the \fBset_tunnel\fR form is used and \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