odp-util: Format tunnel attributes directly from netlink.
authorJesse Gross <jesse@nicira.com>
Sun, 17 May 2015 05:08:20 +0000 (22:08 -0700)
committerJesse Gross <jesse@nicira.com>
Fri, 29 May 2015 01:34:21 +0000 (18:34 -0700)
When we format most netlink attributes we do so from the netlink
itself, iterating through each one and printing the contents out.
However, for tunnels we don't do this - we first convert to the
OVS userspace representation and then format that. While convienient,
this isn't really ideal as the primary use of printing netlink
attributes is debugging and this conversion is lossy, particularly
when the attributes aren't as expected. The result is that unexpected
keys are silently ignored and the level of detail on errors is
minimal.

This situation becomes worse when we introduce support for Geneve.
The conversion to userspace format requires additional information
which we might not have (ovs-dpctl) and is more complicated than
other attributes so it is likely to be confusing in the event of a
bug. The information from the kernel is self-describing so it's
much more reliable to display it directly from the netlink.

This converts tunnel attribute formatting to be more similar to
other types of attributes. As a nice bonus the output becomes
more compact because it doesn't print zeroed out attributes in
cases where they aren't relevant and therefore not present.

Signed-off-by: Jesse Gross <jesse@nicira.com>
Acked-by: Andy Zhou <azhou@nicira.com>
lib/odp-util.c
tests/odp.at
tests/tunnel.at

index 1f4f7f4..a39933b 100644 (file)
@@ -69,6 +69,9 @@ static void format_odp_key_attr(const struct nlattr *a,
                                 const struct hmap *portno_names, struct ds *ds,
                                 bool verbose);
 
+static struct nlattr *generate_all_wildcard_mask(const struct attr_len_tbl tbl[],
+                                                 int max, struct ofpbuf *,
+                                                 const struct nlattr *key);
 /* Returns one the following for the action with the given OVS_ACTION_ATTR_*
  * 'type':
  *
@@ -1770,6 +1773,228 @@ format_tun_flags(struct ds *ds, const char *name, uint16_t key,
     }
 }
 
+static bool
+check_attr_len(struct ds *ds, const struct nlattr *a, const struct nlattr *ma,
+               const struct attr_len_tbl tbl[], int max_len, bool need_key)
+{
+    int expected_len;
+
+    expected_len = odp_key_attr_len(tbl, max_len, nl_attr_type(a));
+    if (expected_len != ATTR_LEN_VARIABLE &&
+        expected_len != ATTR_LEN_NESTED) {
+
+        bool bad_key_len = nl_attr_get_size(a) != expected_len;
+        bool bad_mask_len = ma && nl_attr_get_size(ma) != expected_len;
+
+        if (bad_key_len || bad_mask_len) {
+            if (need_key) {
+                ds_put_format(ds, "key%u", nl_attr_type(a));
+            }
+            if (bad_key_len) {
+                ds_put_format(ds, "(bad key length %"PRIuSIZE", expected %d)(",
+                              nl_attr_get_size(a), expected_len);
+            }
+            format_generic_odp_key(a, ds);
+            if (ma) {
+                ds_put_char(ds, '/');
+                if (bad_mask_len) {
+                    ds_put_format(ds, "(bad mask length %"PRIuSIZE", expected %d)(",
+                                  nl_attr_get_size(ma), expected_len);
+                }
+                format_generic_odp_key(ma, ds);
+            }
+            ds_put_char(ds, ')');
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static void
+format_unknown_key(struct ds *ds, const struct nlattr *a,
+                   const struct nlattr *ma)
+{
+    ds_put_format(ds, "key%u(", nl_attr_type(a));
+    format_generic_odp_key(a, ds);
+    if (ma && !odp_mask_attr_is_exact(ma)) {
+        ds_put_char(ds, '/');
+        format_generic_odp_key(ma, ds);
+    }
+    ds_put_cstr(ds, "),");
+}
+
+static void
+format_odp_tun_vxlan_opt(const struct nlattr *attr,
+                         const struct nlattr *mask_attr, struct ds *ds,
+                         bool verbose)
+{
+    unsigned int left;
+    const struct nlattr *a;
+    struct ofpbuf ofp;
+
+    ofpbuf_init(&ofp, 100);
+    NL_NESTED_FOR_EACH(a, left, attr) {
+        uint16_t type = nl_attr_type(a);
+        const struct nlattr *ma = NULL;
+
+        if (mask_attr) {
+            ma = nl_attr_find__(nl_attr_get(mask_attr),
+                                nl_attr_get_size(mask_attr), type);
+            if (!ma) {
+                ma = generate_all_wildcard_mask(ovs_vxlan_ext_attr_lens,
+                                                OVS_VXLAN_EXT_MAX,
+                                                &ofp, a);
+            }
+        }
+
+        if (!check_attr_len(ds, a, ma, ovs_vxlan_ext_attr_lens,
+                            OVS_VXLAN_EXT_MAX, true)) {
+            continue;
+        }
+
+        switch (type) {
+        case OVS_VXLAN_EXT_GBP: {
+            uint32_t key = nl_attr_get_u32(a);
+            ovs_be16 id, id_mask;
+            uint8_t flags, flags_mask;
+
+            id = htons(key & 0xFFFF);
+            flags = (key >> 16) & 0xFF;
+            if (ma) {
+                uint32_t mask = nl_attr_get_u32(ma);
+                id_mask = htons(mask & 0xFFFF);
+                flags_mask = (mask >> 16) & 0xFF;
+            }
+
+            ds_put_cstr(ds, "gbp(");
+            format_be16(ds, "id", id, ma ? &id_mask : NULL, verbose);
+            format_u8x(ds, "flags", flags, ma ? &flags_mask : NULL, verbose);
+            ds_chomp(ds, ',');
+            ds_put_cstr(ds, "),");
+            break;
+        }
+
+        default:
+            format_unknown_key(ds, a, ma);
+        }
+        ofpbuf_clear(&ofp);
+    }
+
+    ds_chomp(ds, ',');
+    ofpbuf_uninit(&ofp);
+}
+
+static void
+format_odp_tun_attr(const struct nlattr *attr, const struct nlattr *mask_attr,
+                    struct ds *ds, bool verbose)
+{
+    unsigned int left;
+    const struct nlattr *a;
+    uint16_t flags = 0;
+    uint16_t mask_flags = 0;
+    struct ofpbuf ofp;
+
+    ofpbuf_init(&ofp, 100);
+    NL_NESTED_FOR_EACH(a, left, attr) {
+        enum ovs_tunnel_key_attr type = nl_attr_type(a);
+        const struct nlattr *ma = NULL;
+
+        if (mask_attr) {
+            ma = nl_attr_find__(nl_attr_get(mask_attr),
+                                nl_attr_get_size(mask_attr), type);
+            if (!ma) {
+                ma = generate_all_wildcard_mask(ovs_tun_key_attr_lens,
+                                                OVS_TUNNEL_KEY_ATTR_MAX,
+                                                &ofp, a);
+            }
+        }
+
+        if (!check_attr_len(ds, a, ma, ovs_tun_key_attr_lens,
+                            OVS_TUNNEL_KEY_ATTR_MAX, true)) {
+            continue;
+        }
+
+        switch (type) {
+        case OVS_TUNNEL_KEY_ATTR_ID:
+            format_be64(ds, "tun_id", nl_attr_get_be64(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+           flags |= FLOW_TNL_F_KEY;
+            if (ma) {
+                mask_flags |= FLOW_TNL_F_KEY;
+            }
+            break;
+        case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
+            format_ipv4(ds, "src", nl_attr_get_be32(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
+            format_ipv4(ds, "dst", nl_attr_get_be32(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_TUNNEL_KEY_ATTR_TOS:
+            format_u8x(ds, "tos", nl_attr_get_u8(a),
+                       ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_TUNNEL_KEY_ATTR_TTL:
+            format_u8u(ds, "ttl", nl_attr_get_u8(a),
+                       ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:
+           flags |= FLOW_TNL_F_DONT_FRAGMENT;
+            break;
+        case OVS_TUNNEL_KEY_ATTR_CSUM:
+           flags |= FLOW_TNL_F_CSUM;
+            break;
+        case OVS_TUNNEL_KEY_ATTR_TP_SRC:
+            format_be16(ds, "tp_src", nl_attr_get_be16(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_TUNNEL_KEY_ATTR_TP_DST:
+            format_be16(ds, "tp_dst", nl_attr_get_be16(a),
+                        ma ? nl_attr_get(ma) : NULL, verbose);
+            break;
+        case OVS_TUNNEL_KEY_ATTR_OAM:
+           flags |= FLOW_TNL_F_OAM;
+            break;
+        case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS:
+            ds_put_cstr(ds, "vxlan(");
+            format_odp_tun_vxlan_opt(a, ma, ds, verbose);
+            ds_put_cstr(ds, "),");
+            break;
+        case OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS:
+            /* Not really implemented yet, handle as unknown. */
+        case __OVS_TUNNEL_KEY_ATTR_MAX:
+        default:
+            format_unknown_key(ds, a, ma);
+        }
+        ofpbuf_clear(&ofp);
+    }
+
+    /* Flags can have a valid mask even if the attribute is not set, so
+     * we need to collect these separately. */
+    if (mask_attr) {
+        NL_NESTED_FOR_EACH(a, left, mask_attr) {
+            switch (nl_attr_type(a)) {
+            case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:
+                mask_flags |= FLOW_TNL_F_DONT_FRAGMENT;
+                break;
+            case OVS_TUNNEL_KEY_ATTR_CSUM:
+                mask_flags |= FLOW_TNL_F_CSUM;
+                break;
+            case OVS_TUNNEL_KEY_ATTR_OAM:
+                mask_flags |= FLOW_TNL_F_OAM;
+                break;
+            }
+        }
+    }
+
+    format_tun_flags(ds, "flags", flags, mask_attr ? &mask_flags : NULL,
+                     verbose);
+    ds_chomp(ds, ',');
+    ofpbuf_uninit(&ofp);
+}
+
 static void
 format_frag(struct ds *ds, const char *name, uint8_t key,
             const uint8_t *mask, bool verbose)
@@ -1798,39 +2023,15 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
 {
     enum ovs_key_attr attr = nl_attr_type(a);
     char namebuf[OVS_KEY_ATTR_BUFSIZE];
-    int expected_len;
     bool is_exact;
 
     is_exact = ma ? odp_mask_attr_is_exact(ma) : true;
 
     ds_put_cstr(ds, ovs_key_attr_to_string(attr, namebuf, sizeof namebuf));
 
-    {
-        expected_len = odp_key_attr_len(ovs_flow_key_attr_lens,
-                                        OVS_KEY_ATTR_MAX, nl_attr_type(a));
-        if (expected_len != ATTR_LEN_VARIABLE &&
-            expected_len != ATTR_LEN_NESTED) {
-            bool bad_key_len = nl_attr_get_size(a) != expected_len;
-            bool bad_mask_len = ma && nl_attr_get_size(ma) != expected_len;
-
-            if (bad_key_len || bad_mask_len) {
-                if (bad_key_len) {
-                    ds_put_format(ds, "(bad key length %"PRIuSIZE", expected %d)(",
-                                  nl_attr_get_size(a), expected_len);
-                }
-                format_generic_odp_key(a, ds);
-                if (ma) {
-                    ds_put_char(ds, '/');
-                    if (bad_mask_len) {
-                        ds_put_format(ds, "(bad mask length %"PRIuSIZE", expected %d)(",
-                                      nl_attr_get_size(ma), expected_len);
-                    }
-                    format_generic_odp_key(ma, ds);
-                }
-                ds_put_char(ds, ')');
-                return;
-            }
-        }
+    if (!check_attr_len(ds, a, ma, ovs_flow_key_attr_lens,
+                        OVS_KEY_ATTR_MAX, false)) {
+        return;
     }
 
     ds_put_char(ds, '(');
@@ -1856,32 +2057,10 @@ format_odp_key_attr(const struct nlattr *a, const struct nlattr *ma,
         }
         break;
 
-    case OVS_KEY_ATTR_TUNNEL: {
-        struct flow_tnl key, mask_;
-        struct flow_tnl *mask = ma ? &mask_ : NULL;
-
-        if (mask) {
-            memset(mask, 0, sizeof *mask);
-            odp_tun_key_from_attr(ma, mask);
-        }
-        memset(&key, 0, sizeof key);
-        if (odp_tun_key_from_attr(a, &key) == ODP_FIT_ERROR) {
-            ds_put_format(ds, "error");
-            return;
-        }
-        format_be64(ds, "tun_id", key.tun_id, MASK(mask, tun_id), verbose);
-        format_ipv4(ds, "src", key.ip_src, MASK(mask, ip_src), verbose);
-        format_ipv4(ds, "dst", key.ip_dst, MASK(mask, ip_dst), verbose);
-        format_u8x(ds, "tos", key.ip_tos, MASK(mask, ip_tos), verbose);
-        format_u8u(ds, "ttl", key.ip_ttl, MASK(mask, ip_ttl), verbose);
-        format_be16(ds, "tp_src", key.tp_src, MASK(mask, tp_src), verbose);
-        format_be16(ds, "tp_dst", key.tp_dst, MASK(mask, tp_dst), verbose);
-        format_be16(ds, "gbp_id", key.gbp_id, MASK(mask, gbp_id), verbose);
-        format_u8x(ds, "gbp_flags", key.gbp_flags, MASK(mask, gbp_flags), verbose);
-        format_tun_flags(ds, "flags", key.flags, MASK(mask, flags), verbose);
-        ds_chomp(ds, ',');
+    case OVS_KEY_ATTR_TUNNEL:
+        format_odp_tun_attr(a, ma, ds, verbose);
         break;
-    }
+
     case OVS_KEY_ATTR_IN_PORT:
         if (portno_names && verbose && is_exact) {
             char *name = odp_portno_names_get(portno_names,
@@ -2622,14 +2801,84 @@ scan_mpls_bos(const char *s, ovs_be32 *key, ovs_be32 *mask)
     return scan_be32_bf(s, key, mask, 1, MPLS_BOS_SHIFT);
 }
 
-/* ATTR is compile-time constant, so only the case with correct data type
- * will be used.  However, the compiler complains about the data  type for
- * the other cases, so we must cast to make the compiler silent. */
-#define SCAN_PUT_ATTR(BUF, ATTR, DATA)                          \
-    if ((ATTR) == OVS_KEY_ATTR_TUNNEL) {                              \
-        tun_key_to_attr(BUF, (const struct flow_tnl *)(void *)&(DATA)); \
-    } else {                                                    \
-        nl_msg_put_unspec(BUF, ATTR, &(DATA), sizeof (DATA));   \
+static int
+scan_vxlan_gbp(const char *s, uint32_t *key, uint32_t *mask)
+{
+    const char *s_base = s;
+    ovs_be16 id, id_mask;
+    uint8_t flags, flags_mask;
+
+    if (!strncmp(s, "id=", 3)) {
+        s += 3;
+        s += scan_be16(s, &id, mask ? &id_mask : NULL);
+    } else if (mask) {
+        memset(&id_mask, 0, sizeof id_mask);
+    }
+
+    if (s[0] == ',') {
+        s++;
+    }
+    if (!strncmp(s, "flags=", 6)) {
+        s += 6;
+        s += scan_u8(s, &flags, mask ? &flags_mask : NULL);
+    } else if (mask) {
+        memset(&flags_mask, 0, sizeof flags_mask);
+    }
+
+    if (!strncmp(s, "))", 2)) {
+        s += 2;
+
+        *key = (flags << 16) | ntohs(id);
+        if (mask) {
+            *mask = (flags_mask << 16) | ntohs(id_mask);
+        }
+
+        return s - s_base;
+    }
+
+    return 0;
+}
+
+static void
+tun_flags_to_attr(struct ofpbuf *a, const void *data_)
+{
+    const uint16_t *flags = data_;
+
+    if (*flags & FLOW_TNL_F_DONT_FRAGMENT) {
+        nl_msg_put_flag(a, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT);
+    }
+    if (*flags & FLOW_TNL_F_CSUM) {
+        nl_msg_put_flag(a, OVS_TUNNEL_KEY_ATTR_CSUM);
+    }
+    if (*flags & FLOW_TNL_F_OAM) {
+        nl_msg_put_flag(a, OVS_TUNNEL_KEY_ATTR_OAM);
+    }
+}
+
+static void
+vxlan_gbp_to_attr(struct ofpbuf *a, const void *data_)
+{
+    const uint32_t *gbp = data_;
+
+    if (*gbp) {
+        size_t vxlan_opts_ofs;
+
+        vxlan_opts_ofs = nl_msg_start_nested(a, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS);
+        nl_msg_put_u32(a, OVS_VXLAN_EXT_GBP, *gbp);
+        nl_msg_end_nested(a, vxlan_opts_ofs);
+    }
+}
+
+#define SCAN_PUT_ATTR(BUF, ATTR, DATA, FUNC)                      \
+    {                                                             \
+        unsigned long call_fn = (unsigned long)FUNC;              \
+        if (call_fn) {                                            \
+            typedef void (*fn)(struct ofpbuf *, const void *);    \
+            fn func = FUNC;                                       \
+            func(BUF, &(DATA));                                   \
+        } else {                                                  \
+            nl_msg_put_unspec(BUF, ATTR, &(DATA), sizeof (DATA)); \
+        }                                                         \
     }
 
 #define SCAN_IF(NAME)                           \
@@ -2693,23 +2942,60 @@ scan_mpls_bos(const char *s, ovs_be32 *key, ovs_be32 *mask)
             return -EINVAL;                     \
         }
 
-#define SCAN_PUT(ATTR)                                  \
+/* Beginning of nested attribute. */
+#define SCAN_BEGIN_NESTED(NAME, ATTR)                      \
+    SCAN_IF(NAME);                                         \
+        size_t key_offset, mask_offset;                    \
+        key_offset = nl_msg_start_nested(key, ATTR);       \
+        if (mask) {                                        \
+            mask_offset = nl_msg_start_nested(mask, ATTR); \
+        }                                                  \
+        do {                                               \
+            len = 0;
+
+#define SCAN_END_NESTED()                               \
+        SCAN_FINISH();                                  \
+        nl_msg_end_nested(key, key_offset);             \
+        if (mask) {                                     \
+            nl_msg_end_nested(mask, mask_offset);       \
+        }                                               \
+        return s - start;                               \
+    }
+
+#define SCAN_FIELD_NESTED__(NAME, TYPE, SCAN_AS, ATTR, FUNC)  \
+    if (strncmp(s, NAME, strlen(NAME)) == 0) {                \
+        TYPE skey, smask;                                     \
+        memset(&skey, 0, sizeof skey);                        \
+        memset(&smask, 0xff, sizeof smask);                   \
+        s += strlen(NAME);                                    \
+        SCAN_TYPE(SCAN_AS, &skey, &smask);                    \
+        SCAN_PUT(ATTR, FUNC);                                 \
+        continue;                                             \
+    }
+
+#define SCAN_FIELD_NESTED(NAME, TYPE, SCAN_AS, ATTR)  \
+        SCAN_FIELD_NESTED__(NAME, TYPE, SCAN_AS, ATTR, NULL)
+
+#define SCAN_FIELD_NESTED_FUNC(NAME, TYPE, SCAN_AS, FUNC)  \
+        SCAN_FIELD_NESTED__(NAME, TYPE, SCAN_AS, 0, FUNC)
+
+#define SCAN_PUT(ATTR, FUNC)                            \
         if (!mask || !is_all_zeros(&smask, sizeof smask)) { \
-            SCAN_PUT_ATTR(key, ATTR, skey);             \
+            SCAN_PUT_ATTR(key, ATTR, skey, FUNC);       \
             if (mask) {                                 \
-                SCAN_PUT_ATTR(mask, ATTR, smask);       \
+                SCAN_PUT_ATTR(mask, ATTR, smask, FUNC); \
             }                                           \
         }
 
 #define SCAN_END(ATTR)                                  \
         SCAN_FINISH();                                  \
-        SCAN_PUT(ATTR);                                 \
+        SCAN_PUT(ATTR, NULL);                           \
         return s - start;                               \
     }
 
 #define SCAN_END_SINGLE(ATTR)                           \
         SCAN_FINISH_SINGLE();                           \
-        SCAN_PUT(ATTR);                                 \
+        SCAN_PUT(ATTR, NULL);                           \
         return s - start;                               \
     }
 
@@ -2754,18 +3040,17 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
                              OVS_KEY_ATTR_RECIRC_ID);
     SCAN_SINGLE("dp_hash(", uint32_t, u32, OVS_KEY_ATTR_DP_HASH);
 
-    SCAN_BEGIN("tunnel(", struct flow_tnl) {
-        SCAN_FIELD("tun_id=", be64, tun_id);
-        SCAN_FIELD("src=", ipv4, ip_src);
-        SCAN_FIELD("dst=", ipv4, ip_dst);
-        SCAN_FIELD("tos=", u8, ip_tos);
-        SCAN_FIELD("ttl=", u8, ip_ttl);
-        SCAN_FIELD("tp_src=", be16, tp_src);
-        SCAN_FIELD("tp_dst=", be16, tp_dst);
-        SCAN_FIELD("gbp_id=", be16, gbp_id);
-        SCAN_FIELD("gbp_flags=", u8, gbp_flags);
-        SCAN_FIELD("flags(", tun_flags, flags);
-    } SCAN_END(OVS_KEY_ATTR_TUNNEL);
+    SCAN_BEGIN_NESTED("tunnel(", OVS_KEY_ATTR_TUNNEL) {
+        SCAN_FIELD_NESTED("tun_id=", ovs_be64, be64, OVS_TUNNEL_KEY_ATTR_ID);
+        SCAN_FIELD_NESTED("src=", ovs_be32, ipv4, OVS_TUNNEL_KEY_ATTR_IPV4_SRC);
+        SCAN_FIELD_NESTED("dst=", ovs_be32, ipv4, OVS_TUNNEL_KEY_ATTR_IPV4_DST);
+        SCAN_FIELD_NESTED("tos=", uint8_t, u8, OVS_TUNNEL_KEY_ATTR_TOS);
+        SCAN_FIELD_NESTED("ttl=", uint8_t, u8, OVS_TUNNEL_KEY_ATTR_TTL);
+        SCAN_FIELD_NESTED("tp_src=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_SRC);
+        SCAN_FIELD_NESTED("tp_dst=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_DST);
+        SCAN_FIELD_NESTED_FUNC("vxlan(gbp(", uint32_t, vxlan_gbp, vxlan_gbp_to_attr);
+        SCAN_FIELD_NESTED_FUNC("flags(", uint16_t, tun_flags, tun_flags_to_attr);
+    } SCAN_END_NESTED();
 
     SCAN_SINGLE_PORT("in_port(", uint32_t, OVS_KEY_ATTR_IN_PORT);
 
index 16a58e7..c3cea2d 100644 (file)
@@ -39,7 +39,7 @@ s/^/skb_priority(0),skb_mark(0),recirc_id(0),dp_hash(0),/
 
  echo
  echo '# Valid forms with tunnel header.'
- sed 's/^/skb_priority(0),tunnel(tun_id=0x7f10354,src=10.10.10.10,dst=20.20.20.20,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(csum,key)),skb_mark(0x1234),recirc_id(0),dp_hash(0),/' odp-base.txt
+ sed 's/^/skb_priority(0),tunnel(tun_id=0x7f10354,src=10.10.10.10,dst=20.20.20.20,ttl=64,flags(csum,key)),skb_mark(0x1234),recirc_id(0),dp_hash(0),/' odp-base.txt
 
  echo
  echo '# Valid forms with VLAN header.'
@@ -59,13 +59,13 @@ s/\(eth([[^)]]*),?\)/\1,eth_type(0x8848),mpls(label=100,tc=7,ttl=64,bos=1)/' odp
 
  echo
  echo '# Valid forms with tunnel and VLAN headers.'
- sed 's/^/skb_priority(0),tunnel(tun_id=0xfedcba9876543210,src=10.0.0.1,dst=10.0.0.2,tos=0x8,ttl=128,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key)),skb_mark(0),recirc_id(0),dp_hash(0),/
+ sed 's/^/skb_priority(0),tunnel(tun_id=0xfedcba9876543210,src=10.0.0.1,dst=10.0.0.2,tos=0x8,ttl=128,flags(key)),skb_mark(0),recirc_id(0),dp_hash(0),/
 s/\(eth([[^)]]*)\),*/\1,eth_type(0x8100),vlan(vid=99,pcp=7),encap(/
 s/$/)/' odp-base.txt
 
  echo
  echo '# Valid forms with QOS priority, tunnel, and VLAN headers.'
- sed 's/^/skb_priority(0x1234),tunnel(tun_id=0xfedcba9876543210,src=10.10.10.10,dst=20.20.20.20,tos=0x8,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key)),skb_mark(0),recirc_id(0),dp_hash(0),/
+ sed 's/^/skb_priority(0x1234),tunnel(tun_id=0xfedcba9876543210,src=10.10.10.10,dst=20.20.20.20,tos=0x8,ttl=64,flags(key)),skb_mark(0),recirc_id(0),dp_hash(0),/
 s/\(eth([[^)]]*)\),*/\1,eth_type(0x8100),vlan(vid=99,pcp=7),encap(/
 s/$/)/' odp-base.txt
 
@@ -117,11 +117,11 @@ skb_mark(0x1234/0xfff0),in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:
 
  echo
  echo '# Valid forms with tunnel header.'
- sed 's/^/tunnel(tun_id=0x7f10354\/0xff,src=10.10.10.10\/255.255.255.0,dst=20.20.20.20\/255.255.255.0,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(csum,key)),/' odp-base.txt
+ sed 's/^/tunnel(tun_id=0x7f10354\/0xff,src=10.10.10.10\/255.255.255.0,dst=20.20.20.20\/255.255.255.0,ttl=64,vxlan(gbp(id=10\/0xff,flags=0xb)),flags(csum,key)),/' odp-base.txt
 
  echo
  echo '# Valid forms with tunnel header (wildcard flag).'
- sed 's/^/tunnel(tun_id=0x7f10354\/0xff,src=10.10.10.10\/255.255.255.0,dst=20.20.20.20\/255.255.255.0,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(-df+csum+key)),/' odp-base.txt
+ sed 's/^/tunnel(tun_id=0x7f10354\/0xff,src=10.10.10.10\/255.255.255.0,dst=20.20.20.20\/255.255.255.0,ttl=64,flags(-df+csum+key)),/' odp-base.txt
 
  echo
  echo '# Valid forms with VLAN header.'
@@ -138,13 +138,13 @@ s/$/)/' odp-base.txt
 
  echo
  echo '# Valid forms with tunnel and VLAN headers.'
- sed 's/^/tunnel(tun_id=0xfedcba9876543210,src=10.0.0.1,dst=10.0.0.2,tos=0x8,ttl=128,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key)),/
+ sed 's/^/tunnel(tun_id=0xfedcba9876543210,src=10.0.0.1,dst=10.0.0.2,tos=0x8,ttl=128,flags(key)),/
 s/\(eth([[^)]]*)\),*/\1,eth_type(0x8100),vlan(vid=99/0xff0,pcp=7/0xe),encap(/
 s/$/)/' odp-base.txt
 
  echo
  echo '# Valid forms with QOS priority, tunnel, and VLAN headers.'
- sed 's/^/skb_priority(0x1234),tunnel(tun_id=0xfedcba9876543210,src=10.10.10.10,dst=20.20.20.20,tos=0x8,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key)),/
+ sed 's/^/skb_priority(0x1234),tunnel(tun_id=0xfedcba9876543210,src=10.10.10.10,dst=20.20.20.20,tos=0x8,ttl=64,flags(key)),/
 s/\(eth([[^)]]*)\),*/\1,eth_type(0x8100),vlan(vid=99,pcp=7),encap(/
 s/$/)/' odp-base.txt
 
@@ -280,8 +280,8 @@ push_vlan(tpid=0x9100,vid=13,pcp=5)
 push_vlan(tpid=0x9100,vid=13,pcp=5,cfi=0)
 pop_vlan
 sample(sample=9.7%,actions(1,2,3,push_vlan(vid=1,pcp=2)))
-set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,csum,key)))
-set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key)))
+set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,ttl=64,flags(df,csum,key)))
+set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,ttl=64,flags(key)))
 tnl_pop(4)
 tnl_push(tnl_port(4),header(size=42,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0x2000,proto=0x6558),key=0x1e241)),out_port(1))
 tnl_push(tnl_port(4),header(size=46,type=3,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x0800),ipv4(src=1.1.2.88,dst=1.1.2.92,proto=47,tos=0,ttl=64,frag=0x40),gre((flags=0xa000,proto=0x6558),csum=0x0,key=0x1e241)),out_port(1))
index fae2fac..7ff1ba4 100644 (file)
@@ -23,15 +23,15 @@ AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
 ])
 
 dnl remote_ip
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=1.2.3.4,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=1.2.3.4,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(tunnel(tun_id=0x0,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df))),1
+  [Datapath actions: set(tunnel(dst=1.1.1.1,ttl=64,flags(df))),1
 ])
 
 dnl local_ip, remote_ip
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=2.2.2.2,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(tunnel(tun_id=0x0,src=2.2.2.2,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df))),1
+  [Datapath actions: set(tunnel(src=2.2.2.2,dst=1.1.1.1,ttl=64,flags(df))),1
 ])
 
 dnl reconfigure, local_ip, remote_ip
@@ -44,17 +44,17 @@ AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
                p2 2/1: (gre: csum=true, df_default=false, local_ip=2.2.2.3, remote_ip=1.1.1.1, ttl=1)
                p3 3/64: (gre64: remote_ip=2.2.2.2)
 ])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=2.2.2.2,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(tunnel(tun_id=0x0,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df))),1
+  [Datapath actions: set(tunnel(dst=1.1.1.1,ttl=64,flags(df))),1
 ])
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.3,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=2.2.2.3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(tunnel(tun_id=0x0,src=2.2.2.3,dst=1.1.1.1,tos=0,ttl=1,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(csum))),1
+  [Datapath actions: set(tunnel(src=2.2.2.3,dst=1.1.1.1,ttl=1,flags(csum))),1
 ])
 
 dnl nonexistent tunnel
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=5.5.5.5,dst=6.6.6.6,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [2], [ignore], [dnl
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=5.5.5.5,dst=6.6.6.6,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [2], [ignore], [dnl
 Invalid datapath flow
 ovs-appctl: ovs-vswitchd: server returned an error
 ])
@@ -80,28 +80,28 @@ AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
 ])
 
 dnl Tunnel CE and encapsulated packet CE
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=3,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=3,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: pkt_mark=0,recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_ttl=64,,in_port=1,nw_ecn=3,nw_frag=no
 Datapath actions: 2
 ])
 
 dnl Tunnel CE and encapsulated packet ECT(1)
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=1,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=1,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: pkt_mark=0,recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_ttl=64,,in_port=1,nw_ecn=1,nw_frag=no
 Datapath actions: set(ipv4(tos=0x3/0x3)),2
 ])
 
 dnl Tunnel CE and encapsulated packet ECT(2)
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=2,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=2,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: pkt_mark=0,recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_ttl=64,,in_port=1,nw_ecn=2,nw_frag=no
 Datapath actions: set(ipv4(tos=0x3/0x3)),2
 ])
 
 dnl Tunnel CE and encapsulated packet Non-ECT
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: pkt_mark=0,recirc_id=0,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_ttl=64,,in_port=1,nw_ecn=0,nw_frag=no
 Datapath actions: drop
@@ -131,13 +131,13 @@ AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
 dnl Basic
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=4,ttl=128,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(tunnel(tun_id=0x5,src=2.2.2.2,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1
+  [Datapath actions: set(tunnel(tun_id=0x5,src=2.2.2.2,dst=1.1.1.1,ttl=64,flags(df,key))),1
 ])
 
 dnl ECN
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=1,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(tunnel(tun_id=0x5,src=2.2.2.2,dst=1.1.1.1,tos=0x1,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1
+  [Datapath actions: set(tunnel(tun_id=0x5,src=2.2.2.2,dst=1.1.1.1,tos=0x1,ttl=64,flags(df,key))),1
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -164,19 +164,19 @@ AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
 dnl Basic
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=4,ttl=128,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(tunnel(tun_id=0x0,src=0.0.0.0,dst=1.1.1.1,tos=0x4,ttl=128,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df))),1
+  [Datapath actions: set(tunnel(dst=1.1.1.1,tos=0x4,ttl=128,flags(df))),1
 ])
 
 dnl ECN
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=5,ttl=128,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(tunnel(tun_id=0x0,src=0.0.0.0,dst=1.1.1.1,tos=0x5,ttl=128,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df))),1
+  [Datapath actions: set(tunnel(dst=1.1.1.1,tos=0x5,ttl=128,flags(df))),1
 ])
 
 dnl non-IP
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0806),arp(sip=1.2.3.4,tip=5.6.7.8,op=1,sha=00:0f:10:11:12:13,tha=00:14:15:16:17:18)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(tunnel(tun_id=0x0,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df))),1
+  [Datapath actions: set(tunnel(dst=1.1.1.1,ttl=64,flags(df))),1
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -208,10 +208,10 @@ AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
 
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(100),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0], [Datapath actions: dnl
-set(tunnel(tun_id=0x1,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1,dnl
-set(tunnel(tun_id=0x2,src=0.0.0.0,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1,dnl
-set(tunnel(tun_id=0x3,src=0.0.0.0,dst=3.3.3.3,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1,dnl
-set(tunnel(tun_id=0x5,src=0.0.0.0,dst=4.4.4.4,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1
+set(tunnel(tun_id=0x1,dst=1.1.1.1,ttl=64,flags(df,key))),1,dnl
+set(tunnel(tun_id=0x2,dst=2.2.2.2,ttl=64,flags(df,key))),1,dnl
+set(tunnel(tun_id=0x3,dst=3.3.3.3,ttl=64,flags(df,key))),1,dnl
+set(tunnel(tun_id=0x5,dst=4.4.4.4,ttl=64,flags(df,key))),1
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -238,28 +238,28 @@ AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
                p3 3/1: (gre: out_key=5, remote_ip=1.1.1.1)
 ])
 
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x1,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x1,src=1.1.1.1,dst=2.2.2.2,ttl=64,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0], [Datapath actions: dnl
-set(tunnel(tun_id=0x1,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1,dnl
-set(tunnel(tun_id=0x3,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1,dnl
-set(tunnel(tun_id=0x5,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1
+set(tunnel(tun_id=0x1,dst=1.1.1.1,ttl=64,flags(df,key))),1,dnl
+set(tunnel(tun_id=0x3,dst=1.1.1.1,ttl=64,flags(df,key))),1,dnl
+set(tunnel(tun_id=0x5,dst=1.1.1.1,ttl=64,flags(df,key))),1
 ])
 
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x2,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x2,src=1.1.1.1,dst=2.2.2.2,ttl=64,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0], [Datapath actions: dnl
-set(tunnel(tun_id=0x3,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1,dnl
-set(tunnel(tun_id=0x1,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1,dnl
-set(tunnel(tun_id=0x5,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1
+set(tunnel(tun_id=0x3,dst=1.1.1.1,ttl=64,flags(df,key))),1,dnl
+set(tunnel(tun_id=0x1,dst=1.1.1.1,ttl=64,flags(df,key))),1,dnl
+set(tunnel(tun_id=0x5,dst=1.1.1.1,ttl=64,flags(df,key))),1
 ])
 
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=2.2.2.2,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0], [Datapath actions: dnl
-set(tunnel(tun_id=0x5,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1,dnl
-set(tunnel(tun_id=0x1,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1,dnl
-set(tunnel(tun_id=0x3,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1
+set(tunnel(tun_id=0x5,dst=1.1.1.1,ttl=64,flags(df,key))),1,dnl
+set(tunnel(tun_id=0x1,dst=1.1.1.1,ttl=64,flags(df,key))),1,dnl
+set(tunnel(tun_id=0x3,dst=1.1.1.1,ttl=64,flags(df,key))),1
 ])
 
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0xf,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [2], [ignore], [dnl
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0xf,src=1.1.1.1,dst=2.2.2.2,ttl=64,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [2], [ignore], [dnl
 Invalid datapath flow
 ovs-appctl: ovs-vswitchd: server returned an error
 ])
@@ -293,22 +293,22 @@ AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
                p5 5/5: (dummy)
 ])
 
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x2,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x2,src=1.1.1.1,dst=2.2.2.2,ttl=64,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0], [dnl
 Datapath actions: 3
 ])
 
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x3,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x3,src=1.1.1.1,dst=2.2.2.2,ttl=64,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0], [dnl
-Datapath actions: 4,3,set(tunnel(tun_id=0x3,src=0.0.0.0,dst=3.3.3.3,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1,5
+Datapath actions: 4,3,set(tunnel(tun_id=0x3,dst=3.3.3.3,ttl=64,flags(df,key))),1,5
 ])
 
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x3,src=3.3.3.3,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x3,src=3.3.3.3,dst=2.2.2.2,ttl=64,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0], [dnl
 Datapath actions: 4,3,5
 ])
 
-AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,ttl=64,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0], [dnl
 Datapath actions: drop
 ])
@@ -407,7 +407,7 @@ in_port=5 actions=set_field:5->tun_id
 AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(90),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: set(tunnel(tun_id=0x2a,src=0.0.0.0,dst=1.1.1.1,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1,set(tunnel(tun_id=0x2a,src=0.0.0.0,dst=3.3.3.3,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1,set(tunnel(tun_id=0x2a,src=1.1.1.1,dst=4.4.4.4,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1,set(tunnel(tun_id=0x3,src=0.0.0.0,dst=2.2.2.2,tos=0,ttl=64,tp_src=0,tp_dst=0,gbp_id=0,gbp_flags=0,flags(df,key))),1
+  [Datapath actions: set(tunnel(tun_id=0x2a,dst=1.1.1.1,ttl=64,flags(df,key))),1,set(tunnel(tun_id=0x2a,dst=3.3.3.3,ttl=64,flags(df,key))),1,set(tunnel(tun_id=0x2a,src=1.1.1.1,dst=4.4.4.4,ttl=64,flags(df,key))),1,set(tunnel(tun_id=0x3,dst=2.2.2.2,ttl=64,flags(df,key))),1
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP