Expand tunnel IDs from 32 to 64 bits.
authorBen Pfaff <blp@nicira.com>
Fri, 10 Dec 2010 18:42:42 +0000 (10:42 -0800)
committerBen Pfaff <blp@nicira.com>
Fri, 10 Dec 2010 19:14:13 +0000 (11:14 -0800)
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@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
Feature #3976.

25 files changed:
datapath/actions.c
datapath/datapath.c
datapath/datapath.h
datapath/tunnel.c
datapath/tunnel.h
datapath/vport-gre.c
include/openflow/nicira-ext.h
include/openvswitch/datapath-protocol.h
include/openvswitch/tunnel.h
lib/classifier.c
lib/classifier.h
lib/dpif-netdev.c
lib/dpif.h
lib/flow.c
lib/flow.h
lib/netdev-vport.c
lib/nx-match.c
lib/odp-util.c
lib/ofp-parse.c
lib/ofp-print.c
lib/ofp-util.c
ofproto/ofproto.c
tests/ovs-ofctl.at
tests/test-classifier.c
utilities/ovs-ofctl.8.in

index 7290a898fb5095814d5ae3f5e007527e141a1d1e..67f6cd41d3dd346f00d89168b5c5f2a139762072 100644 (file)
@@ -424,7 +424,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;
@@ -432,7 +432,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:
index 7a70163a0a35912505a55afa05f0cfafb5625d82..ffe3bd86943d2f0e0030ce8f593e431539a04b14 100644 (file)
@@ -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;
@@ -666,7 +665,7 @@ static int validate_actions(const struct nlattr *actions, u32 actions_len)
         nla_for_each_attr(a, actions, actions_len, rem) {
                 static const u32 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,
@@ -676,7 +675,7 @@ static int validate_actions(const struct nlattr *actions, u32 actions_len)
                         [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,
index e1bdb7b4ce17f621d0fbc67d6608b774244c2185..c55e2059409274ac8c50380f3a20784a45641369 100644 (file)
@@ -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);
 
index c0e8b1e860d25db7acb0fa7ec3f57eca9e41d644..3534909313622bc6cb2d2153d99434c753f3edcf 100644 (file)
@@ -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)
@@ -305,7 +306,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)
 {
@@ -598,7 +599,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;
index 3ed7ef37f1f10688ccce02d704fb83fdf55544db..5615f6ada9d2280475ef35ebd9db6cdf3b7e2ed0 100644 (file)
@@ -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)
index f6996ed4004e4e2b32eb4669989a7ab9a018cb35..eb109035a3bfb55db1ab5535f4f6512e43a86358 100644 (file)
@@ -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;
index de3c2e5ef9b9aa1f320e8ddd0c578760ccd6e46d..135f793edb38820d47b1cb241625a55695a93870 100644 (file)
@@ -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
index 731a84935b68e4ca680798276b7101f0e934b58c..ad68e9e11fb873a88c77547fd471c89855f56296 100644 (file)
@@ -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. */
index e7d3fce7162d9ae079f2ff4709c69a0449f46e60..d545e40e3e434db298110fb91b5cc36d296f5b17 100644 (file)
 
 /* 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 */
index 49058379561fbca8597dd58c5c647791abcdc6c9..86d8269021342c071fb766e3e21133b05666d9ea 100644 (file)
@@ -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];
index 927423e38798d5542825e749933d4da07d547917..453417da6a4859f7a925d7dff109526fab046930 100644 (file)
@@ -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]);
index 0f95c5fd089cdcdbb6eb66660b2da822178cfc74..29f3cc98c3429bc594d2cffb2c517627be009ff5 100644 (file)
@@ -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:
index 825a00c5d3f4bd117c3bcff77b1516b77c420187..dfd179bd0f0da42ae261c41150d7b017bef5066f 100644 (file)
@@ -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);
index ebbd927aeb1fcfd33708ddb07ad0f0bee730826f..e7ed2a97efe1b33e58d72765653289cea61573c6 100644 (file)
@@ -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),
index 1509a7d121913da7961e6c1376a0f35bc0fb9eb5..72f62e8a6f5c9730cb37e64a93a4ca46866a402c 100644 (file)
@@ -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);
index f101b938c172edf5fc6a01c6b5d13153f8cb2335..55662890f86a4ca4ea94936924311df5339c9d1c 100644 (file)
@@ -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")) {
index 359441da6c8ced4db66a5b928d0249e588811130..764ec61d29285256400ad503a6094ed4ff8cfa69 100644 (file)
@@ -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. */
@@ -1092,7 +1092,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:                   \
@@ -1154,7 +1154,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();
     }
index 2ed551d2af9c7a911c07a12e0a0870ae0edbb5c9..dd6b6295b5d5c590a2c0980e63ed3febfb7e9f02 100644 (file)
@@ -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)",
index 1c7ce4fcff83ca9c594daee0790401b3a6e78562..a72d1aa455ba9ff5387e0b1805653bd97d14f078 100644 (file)
@@ -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:
index 5370c9aaf5d7fb44e11785f6cdab052efc620bff..2d9e02657d7dd6f034bff7340a97930cb12649d2 100644 (file)
@@ -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;
index 1cafd862bac2cb9b8ac2641f105820a57cf48ca0..b4b7ecddd33138ae76b4a08e45290fa5f770b758 100644 (file)
@@ -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);
index 01470f04ed2601c7c75277266ee74bb03ef4c395..339b9605dbf4f3198a834f2f283934e8ff0c01cb 100644 (file)
@@ -2053,7 +2053,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
@@ -2064,8 +2064,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);
 
@@ -2734,7 +2733,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);
@@ -2876,6 +2875,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) {
@@ -2886,8 +2886,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:
@@ -2917,6 +2918,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. */
 
index 85d191d03cdee5ca536df94abd00926610984191..94013e7add1d6c3da408e238748582ca61e45426 100644 (file)
@@ -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
index 461074d6f364c0b832403c0ebaffa29f650ca2ab..63a7adacc7db4c8be8818e08282393e145e5f12e 100644 (file)
@@ -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[]
index 30a7a435772ad599faae50c31cdecf77f59e6d24..c3cbbf1e0d43a9747a36eff9dd715476647b4327 100644 (file)
@@ -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