[ovs-dev] [tun_id64 4/4] Expand tunnel IDs from 32 to 64 bits.

Ben Pfaff blp at nicira.com
Wed Dec 1 01:16:10 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.

Because datapath (ODP) actions are a fixed 64 bits in length, with 16 bits
dedicated to the action type, it requires two actions to set the full 64
bits of the tunnel ID: ODPAT_SET_TUNNEL followed by ODPAT_SET_TUNNEL_HI.

It is awkward to extract or set the low or high 32 bits of an integer that
is in network byte order, so this commit also changes the various tunnel
ID fields to be in host byte order.

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>
---
 datapath/actions.c                      |    5 +++++
 datapath/datapath.c                     |    5 ++---
 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 |   22 +++++++++++++---------
 include/openvswitch/tunnel.h            |   14 +++++++-------
 lib/classifier.c                        |    4 ++--
 lib/dpif.h                              |    6 +++---
 lib/flow.c                              |    6 +++---
 lib/flow.h                              |    6 +++---
 lib/netdev-vport.c                      |    7 ++++---
 lib/nx-match.c                          |    8 ++++----
 lib/odp-util.c                          |   10 +++++++---
 lib/ofp-parse.c                         |   19 ++++++++++++++-----
 lib/ofp-print.c                         |    7 +++++++
 lib/ofp-util.c                          |    2 +-
 ofproto/ofproto.c                       |   28 ++++++++++++++++++++++++----
 tests/test-classifier.c                 |    2 +-
 utilities/ovs-ofctl.8.in                |    7 +++++--
 22 files changed, 140 insertions(+), 72 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index 5904c83..ce40764 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -462,6 +462,11 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
 			OVS_CB(skb)->tun_id = a->tunnel.tun_id;
 			break;
 
+		case ODPAT_SET_TUNNEL_HI:
+			OVS_CB(skb)->tun_id &= 0xffffffff;
+			OVS_CB(skb)->tun_id |= (u64) a->tunnel.tun_id << 32;
+			break;
+
 		case ODPAT_SET_DL_TCI:
 			skb = modify_vlan_tci(dp, skb, key, a, n_actions);
 			if (IS_ERR(skb))
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 522d4ec..d519e8d 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -760,7 +760,7 @@ void forward_ip_summed(struct sk_buff *skb)
 /* 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;
@@ -785,7 +785,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);
 
@@ -803,7 +802,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;
diff --git a/datapath/datapath.h b/datapath/datapath.h
index 3a38235..a2e35ac 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -138,14 +138,14 @@ enum csum_type {
  * @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 dp_port		*dp_port;
 	struct sw_flow		*flow;
 	enum csum_type		ip_summed;
-	__be32			tun_id;
+	u64			tun_id;
 };
 #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb)
 
@@ -154,7 +154,7 @@ extern int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
 
 void dp_process_received_packet(struct dp_port *, struct sk_buff *);
 int dp_detach_port(struct dp_port *, int may_delete);
-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 d47ca1e..9806527 100644
--- a/datapath/tunnel.c
+++ b/datapath/tunnel.c
@@ -165,11 +165,11 @@ static unsigned int *find_port_pool(const struct tnl_mutable_config *mutable)
 }
 
 struct port_lookup_key {
+	const struct tnl_mutable_config *mutable;
+	u64 key;
 	u32 tunnel_type;
 	__be32 saddr;
 	__be32 daddr;
-	__be32 key;
-	const struct tnl_mutable_config *mutable;
 };
 
 /*
@@ -191,7 +191,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)
@@ -301,7 +302,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, u64 key,
 			    int tunnel_type,
 			    const struct tnl_mutable_config **mutable)
 {
@@ -583,7 +584,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, u64 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 8ffb7bf..df71d2d 100644
--- a/datapath/tunnel.h
+++ b/datapath/tunnel.h
@@ -197,12 +197,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, u64 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, u64 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 be8fb53..883e583 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(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, u32 *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 = 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;
+	u32 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;
+	u32 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 1a59d3b..19126fe 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_tunnel64s */
 };
 
 /* 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_TUNNEL. */
+    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 4885906..bee1bc9 100644
--- a/include/openvswitch/datapath-protocol.h
+++ b/include/openvswitch/datapath-protocol.h
@@ -139,10 +139,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
@@ -159,11 +158,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;
+    uint64_t arg;
 };
 
 /**
@@ -213,7 +211,7 @@ struct odp_flow_stats {
 #define ODP_TCI_PRESENT 0x1000  /* CFI bit */
 
 struct odp_flow_key {
-    ovs_be32 tun_id;            /* Encapsulating tunnel ID. */
+    uint64_t 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. */
@@ -272,7 +270,8 @@ struct odp_flowvec {
 #define ODPAT_SET_PRIORITY      14   /* Set skb->priority. */
 #define ODPAT_POP_PRIORITY      15   /* Restore original skb->priority. */
 #define ODPAT_DROP_SPOOFED_ARP  16   /* Drop ARPs with spoofed source MAC. */
-#define ODPAT_N_ACTIONS         17
+#define ODPAT_SET_TUNNEL_HI     17   /* Set high bits of tunnel ID. */
+#define ODPAT_N_ACTIONS         18
 
 struct odp_action_output {
     uint16_t type;              /* ODPAT_OUTPUT. */
@@ -287,10 +286,15 @@ struct odp_action_controller {
     uint32_t arg;               /* Copied to struct odp_msg 'arg' member. */
 };
 
+/* ODPAT_SET_TUNNEL sets the low 32 bits of the tunnel ID to 'tun_id' and the
+ * high bits to 0.
+ *
+ * ODPAT_SET_TUNNEL_HI sets the high 32 bits of the tunnel ID to 'tun_id' and
+ * leaves the low 32 bits unchanged. */
 struct odp_action_tunnel {
-    uint16_t type;              /* ODPAT_SET_TUNNEL. */
+    uint16_t type;              /* ODPAT_SET_TUNNEL or ODPAT_SET_TUNNEL_HI. */
     uint16_t reserved;
-    ovs_be32 tun_id;            /* Tunnel ID. */
+    uint32_t tun_id;            /* Low or high 32 bits of tunnel ID. */
 };
 
 /* Action structure for ODPAT_SET_DL_TCI. */
diff --git a/include/openvswitch/tunnel.h b/include/openvswitch/tunnel.h
index dd700d0..957cb74 100644
--- a/include/openvswitch/tunnel.h
+++ b/include/openvswitch/tunnel.h
@@ -51,13 +51,13 @@
 #define TNL_F_HDR_CACHE		(1 << 7) /* Enable tunnel header caching. */
 
 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 52a77d7..459c601 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -761,7 +761,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]) {
@@ -797,7 +797,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.h b/lib/dpif.h
index c844289..0f66288 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -89,10 +89,10 @@ int dpif_execute(struct dpif *, const union odp_action[], size_t n_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 7198f7d..f9e836f 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, uint64_t 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 fd3246b..cbbdc2c 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 {
+    uint64_t 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 197e74b..743d4ba 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -491,19 +491,20 @@ parse_tunnel_config(struct vport_info *port, 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 = 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 = 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 = 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 6b4f5fa..b68d0e7 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -19,6 +19,7 @@
 #include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
+#include "byte-order.h"
 #include "coverage.h"
 #include "dynamic-string.h"
 #include "flow.h"
@@ -42,8 +43,8 @@ odp_actions_add(struct odp_actions *actions, uint16_t type)
 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(",
+                  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),
@@ -70,7 +71,10 @@ format_odp_action(struct ds *ds, const union odp_action *a)
         ds_put_format(ds, "ctl(%"PRIu32")", a->controller.arg);
         break;
     case ODPAT_SET_TUNNEL:
-        ds_put_format(ds, "set_tunnel(%#"PRIx32")", ntohl(a->tunnel.tun_id));
+        ds_put_format(ds, "set_tunnel(%#"PRIx32")", a->tunnel.tun_id);
+        break;
+    case ODPAT_SET_TUNNEL_HI:
+        ds_put_format(ds, "set_tunnel_hi(%#"PRIx32")", a->tunnel.tun_id);
         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 12df5ad..36d7146 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -236,6 +236,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 d58f7ea..b32ae74 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -125,7 +125,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 = 0;
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index bf557cf..9829d00 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2011,7 +2011,6 @@ 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 = actions[0].controller.arg;
 
         send_packet_in(ofproto, packet);
@@ -2836,13 +2835,30 @@ xlate_reg_move_action(struct action_xlate_ctx *ctx,
 }
 
 static void
+xlate_set_tunnel_action(struct action_xlate_ctx *ctx, uint64_t tun_id)
+{
+    uint32_t low = tun_id;
+    uint32_t high = tun_id >> 32;
+
+    /* Set the low 32 bits and zero the top 32 bits. */
+    odp_actions_add(ctx->out, ODPAT_SET_TUNNEL)->tunnel.tun_id = low;
+
+    /* If the top 32 bits should be nonzero then set them too. */
+    if (high) {
+        odp_actions_add(ctx->out, ODPAT_SET_TUNNEL_HI)->tunnel.tun_id = high;
+    }
+
+    ctx->flow.tun_id = tun_id;
+}
+
+static void
 xlate_nicira_action(struct action_xlate_ctx *ctx,
                     const struct nx_action_header *nah)
 {
     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;
-    union odp_action *oa;
     int subtype = ntohs(nah->subtype);
 
     assert(nah->vendor == htonl(NX_VENDOR_ID));
@@ -2854,8 +2870,7 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
 
     case NXAST_SET_TUNNEL:
         nast = (const struct nx_action_set_tunnel *) nah;
-        oa = odp_actions_add(ctx->out, ODPAT_SET_TUNNEL);
-        ctx->flow.tun_id = oa->tunnel.tun_id = nast->tun_id;
+        xlate_set_tunnel_action(ctx, ntohl(nast->tun_id));
         break;
 
     case NXAST_DROP_SPOOFED_ARP:
@@ -2885,6 +2900,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;
+        xlate_set_tunnel_action(ctx, ntohll(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. */
 
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