[ovs-dev] [PATCH v1] ipfix: support tunnel information for Flow IPFIX

Benli Ye daniely at vmware.com
Thu Jun 2 10:34:53 UTC 2016


Add support to export tunnel information for flow-based IPFIX.
The original steps to configure flow level IPFIX:
    1) Create a new record in Flow_Sample_Collector_Set table:
       'ovs-vsctl -- create Flow_Sample_Collector_Set id=1 bridge="Bridge UUID"'
    2) Add IPFIX configuration which is referred by corresponding
       row in Flow_Sample_Collector_Set table:
       'ovs-vsctl -- set Flow_Sample_Collector_Set
       "Flow_Sample_Collector_Set UUID" ipfix=@i -- --id=@i create IPFIX
       targets=\"IP:4739\" obs_domain_id=123 obs_point_id=456
       cache_active_timeout=60 cache_max_flows=13'
    3) Add sample action to the flows:
       'ovs-ofctl add-flow mybridge in_port=1,
       actions=sample'('probability=65535,collector_set_id=1,
       obs_domain_id=123,obs_point_id=456')',output:3'
In order to support exporting tunnel information, the sample action in step 3
should be modified. In this patch, the step 3 should be configured like below:
       'ovs-ofctl add-flow mybridge in_port=1,
       actions=sample'('probability=65535,collector_set_id=1,
       sampling_port=3')',output:3'
'obs_domain_id' and 'obs_point_id' are deleted from flow sample action and
corresponding value in IPFIX table will be used by flow-based IPFIX.
'sampling_port' is added for leting 'xlate' know the output port of the flow.
If the output port is a tunnel port, OVS_USERSPACE_ATTR_EGRESS_TUN_PORT will
be set in the datapath flow sample action. When flow sample action upcall
happens, tunnel information will be retrieved from the datapath and then IPFIX
can export egress tunnel port information. Sampling port can be equel to
ingress port or one of egress ports. If samping_port=65535 (OFPP_NONE),
flow-based IPFIX will keep the same behavior as before.

This patch mainly do three tasks:
    1) Modify flow sample action to support exporting tunnel infromation
    2) Use 'other_configure: enable-tunnel-sampling' to enable or disable
       exporting tunnel information
    3) Make sure flow sample action of tunnel port, which is the egress port of
       corresponding flow is behind set_tunnel action.

How to test flow-based IPFIX:
    1) Setup a test environment with two Linux host with Docker supported
    2) Create a Docker container and a GRE tunnel port on each host
    3) Use ovs-docker to add the container on the bridge
    4) Listen on port 4739 on the collector machine and use wireshark to filter
       'cflow' packets.
    5) Configure flow-based IPFIX:
       - 'ovs-vsctl -- create Flow_Sample_Collector_Set id=1 bridge="Bridge UUID"'
       - 'ovs-vsctl -- set Flow_Sample_Collector_Set
          "Flow_Sample_Collector_Set UUID" ipfix=@i -- --id=@i create IPFIX \
          targets=\"IP:4739\" obs_domain_id=123 obs_point_id=456 \
          cache_active_timeout=60 cache_max_flows=13 \
          other_config:enable-tunnel-sampling=true'
       - 'ovs-ofctl add-flow mybridge in_port=1,
          actions=sample'('probability=65535,collector_set_id=1,
          sampling_port=3')',output:3'
       Note: The output port and sampling_port are both open flow port and the
             output port is the GRE tunnel port.
    6) Ping from the contain whose host enable IPFIX
    6) Get the IPFIX template pakcets and IPFIX information packets.

Signed-off-by: Benli Ye <daniely at vmware.com>
---
 include/openvswitch/ofp-actions.h |   3 +-
 lib/odp-util.c                    |  17 ++--
 lib/odp-util.h                    |   5 +-
 lib/ofp-actions.c                 |  22 ++---
 ofproto/ofproto-dpif-ipfix.c      |  78 +++++++++++++++--
 ofproto/ofproto-dpif-ipfix.h      |   7 +-
 ofproto/ofproto-dpif-upcall.c     |  11 ++-
 ofproto/ofproto-dpif-xlate.c      | 116 ++++++++++++++++++++++--
 ofproto/ofproto.h                 |   3 +
 tests/odp.at                      |   4 +-
 tests/ofp-actions.at              |   8 +-
 tests/ovs-ofctl.at                |  24 ++---
 vswitchd/bridge.c                 |   7 ++
 vswitchd/vswitch.xml              | 180 +++++++++++++++++++-------------------
 14 files changed, 330 insertions(+), 155 deletions(-)

diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp-actions.h
index 038ef87..fc098a1 100644
--- a/include/openvswitch/ofp-actions.h
+++ b/include/openvswitch/ofp-actions.h
@@ -780,8 +780,7 @@ struct ofpact_sample {
     struct ofpact ofpact;
     uint16_t probability;  // Always >0.
     uint32_t collector_set_id;
-    uint32_t obs_domain_id;
-    uint32_t obs_point_id;
+    uint16_t sampling_port;
 };
 
 /* OFPACT_DEC_TTL.
diff --git a/lib/odp-util.c b/lib/odp-util.c
index d9ace90..70d2ea9 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -310,12 +310,10 @@ format_odp_userspace_action(struct ds *ds, const struct nlattr *attr)
                        && cookie.type == USER_ACTION_COOKIE_FLOW_SAMPLE) {
                 ds_put_format(ds, ",flow_sample(probability=%"PRIu16
                               ",collector_set_id=%"PRIu32
-                              ",obs_domain_id=%"PRIu32
-                              ",obs_point_id=%"PRIu32")",
+                              ",output_port=%"PRIu32")",
                               cookie.flow_sample.probability,
                               cookie.flow_sample.collector_set_id,
-                              cookie.flow_sample.obs_domain_id,
-                              cookie.flow_sample.obs_point_id);
+                              cookie.flow_sample.output_odp_port);
             } else if (userdata_len >= sizeof cookie.ipfix
                        && cookie.type == USER_ACTION_COOKIE_IPFIX) {
                 ds_put_format(ds, ",ipfix(output_port=%"PRIu32")",
@@ -911,8 +909,6 @@ parse_odp_userspace_action(const char *s, struct ofpbuf *actions)
         uint32_t output;
         uint32_t probability;
         uint32_t collector_set_id;
-        uint32_t obs_domain_id;
-        uint32_t obs_point_id;
         int vid, pcp;
         int n1 = -1;
         if (ovs_scan(&s[n], ",sFlow(vid=%i,"
@@ -950,17 +946,15 @@ parse_odp_userspace_action(const char *s, struct ofpbuf *actions)
             user_data_size = sizeof cookie.slow_path;
         } else if (ovs_scan(&s[n], ",flow_sample(probability=%"SCNi32","
                             "collector_set_id=%"SCNi32","
-                            "obs_domain_id=%"SCNi32","
-                            "obs_point_id=%"SCNi32")%n",
+                            "output_port=%"SCNi32")%n",
                             &probability, &collector_set_id,
-                            &obs_domain_id, &obs_point_id, &n1)) {
+                            &output, &n1)) {
             n += n1;
 
             cookie.type = USER_ACTION_COOKIE_FLOW_SAMPLE;
             cookie.flow_sample.probability = probability;
             cookie.flow_sample.collector_set_id = collector_set_id;
-            cookie.flow_sample.obs_domain_id = obs_domain_id;
-            cookie.flow_sample.obs_point_id = obs_point_id;
+            cookie.flow_sample.output_odp_port = u32_to_odp(output);
             user_data = &cookie;
             user_data_size = sizeof cookie.flow_sample;
         } else if (ovs_scan(&s[n], ",ipfix(output_port=%"SCNi32")%n",
@@ -5325,6 +5319,7 @@ odp_put_userspace_action(uint32_t pid,
     return userdata_ofs;
 }
 
+/* Only support sample tunnel information when output_port is known */
 void
 odp_put_tunnel_action(const struct flow_tnl *tunnel,
                       struct ofpbuf *odp_actions)
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 51cf5c3..60b8858 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -301,8 +301,7 @@ union user_action_cookie {
         uint16_t type;          /* USER_ACTION_COOKIE_FLOW_SAMPLE. */
         uint16_t probability;   /* Sampling probability. */
         uint32_t collector_set_id; /* ID of IPFIX collector set. */
-        uint32_t obs_domain_id; /* Observation Domain ID. */
-        uint32_t obs_point_id;  /* Observation Point ID. */
+        odp_port_t output_odp_port;  /* The output odp port. */
     } flow_sample;
 
     struct {
@@ -310,7 +309,7 @@ union user_action_cookie {
         odp_port_t output_odp_port; /* The output odp port. */
     } ipfix;
 };
-BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 16);
+BUILD_ASSERT_DECL(sizeof(union user_action_cookie) == 12);
 
 size_t odp_put_userspace_action(uint32_t pid,
                                 const void *userdata, size_t userdata_size,
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index b1578c3..a4548c5 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -4692,8 +4692,8 @@ struct nx_action_sample {
     ovs_be16 subtype;               /* NXAST_SAMPLE. */
     ovs_be16 probability;           /* Fraction of packets to sample. */
     ovs_be32 collector_set_id;      /* ID of collector set in OVSDB. */
-    ovs_be32 obs_domain_id;         /* ID of sampling observation domain. */
-    ovs_be32 obs_point_id;          /* ID of sampling observation point. */
+    ovs_be16 sampling_port;         /* ID of sampling point. */
+    ovs_be32 pad;                   /* Pad for OFP_ACTION_ALIGN */
 };
 OFP_ASSERT(sizeof(struct nx_action_sample) == 24);
 
@@ -4707,8 +4707,7 @@ decode_NXAST_RAW_SAMPLE(const struct nx_action_sample *nas,
     sample = ofpact_put_SAMPLE(out);
     sample->probability = ntohs(nas->probability);
     sample->collector_set_id = ntohl(nas->collector_set_id);
-    sample->obs_domain_id = ntohl(nas->obs_domain_id);
-    sample->obs_point_id = ntohl(nas->obs_point_id);
+    sample->sampling_port = ntohs(nas->sampling_port);
 
     if (sample->probability == 0) {
         return OFPERR_OFPBAC_BAD_ARGUMENT;
@@ -4726,8 +4725,7 @@ encode_SAMPLE(const struct ofpact_sample *sample,
     nas = put_NXAST_SAMPLE(out);
     nas->probability = htons(sample->probability);
     nas->collector_set_id = htonl(sample->collector_set_id);
-    nas->obs_domain_id = htonl(sample->obs_domain_id);
-    nas->obs_point_id = htonl(sample->obs_point_id);
+    nas->sampling_port = htons(sample->sampling_port);
 }
 
 /* Parses 'arg' as the argument to a "sample" action, and appends such an
@@ -4752,10 +4750,8 @@ parse_SAMPLE(char *arg, struct ofpbuf *ofpacts,
             }
         } else if (!strcmp(key, "collector_set_id")) {
             error = str_to_u32(value, &os->collector_set_id);
-        } else if (!strcmp(key, "obs_domain_id")) {
-            error = str_to_u32(value, &os->obs_domain_id);
-        } else if (!strcmp(key, "obs_point_id")) {
-            error = str_to_u32(value, &os->obs_point_id);
+        } else if (!strcmp(key, "sampling_port")) {
+            error = str_to_u16(value, "sampling_port", &os->sampling_port);
         } else {
             error = xasprintf("invalid key \"%s\" in \"sample\" argument",
                               key);
@@ -4775,13 +4771,11 @@ format_SAMPLE(const struct ofpact_sample *a, struct ds *s)
 {
     ds_put_format(s, "%ssample(%s%sprobability=%s%"PRIu16
                   ",%scollector_set_id=%s%"PRIu32
-                  ",%sobs_domain_id=%s%"PRIu32
-                  ",%sobs_point_id=%s%"PRIu32"%s)%s",
+                  ",%ssampling_port=%s%"PRIu16"%s)%s",
                   colors.paren, colors.end,
                   colors.param, colors.end, a->probability,
                   colors.param, colors.end, a->collector_set_id,
-                  colors.param, colors.end, a->obs_domain_id,
-                  colors.param, colors.end, a->obs_point_id,
+                  colors.param, colors.end, a->sampling_port,
                   colors.paren, colors.end);
 }
 
diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
index 59cd884..b100468 100644
--- a/ofproto/ofproto-dpif-ipfix.c
+++ b/ofproto/ofproto-dpif-ipfix.c
@@ -465,8 +465,11 @@ ofproto_ipfix_flow_exporter_options_equal(
     const struct ofproto_ipfix_flow_exporter_options *b)
 {
     return (a->collector_set_id == b->collector_set_id
+            && a->obs_domain_id == b->obs_domain_id
+            && a->obs_point_id == b->obs_point_id
             && a->cache_active_timeout == b->cache_active_timeout
             && a->cache_max_flows == b->cache_max_flows
+            && a->enable_tunnel_sampling == b->enable_tunnel_sampling
             && sset_equals(&a->targets, &b->targets));
 }
 
@@ -903,7 +906,7 @@ bool
 dpif_ipfix_get_bridge_exporter_input_sampling(const struct dpif_ipfix *di)
     OVS_EXCLUDED(mutex)
 {
-    bool ret = true;
+    bool ret = false;
     ovs_mutex_lock(&mutex);
     if (di->bridge_exporter.options) {
         ret = di->bridge_exporter.options->enable_input_sampling;
@@ -916,7 +919,7 @@ bool
 dpif_ipfix_get_bridge_exporter_output_sampling(const struct dpif_ipfix *di)
     OVS_EXCLUDED(mutex)
 {
-    bool ret = true;
+    bool ret = false;
     ovs_mutex_lock(&mutex);
     if (di->bridge_exporter.options) {
         ret = di->bridge_exporter.options->enable_output_sampling;
@@ -938,6 +941,38 @@ dpif_ipfix_get_bridge_exporter_tunnel_sampling(const struct dpif_ipfix *di)
     return ret;
 }
 
+bool
+dpif_ipfix_flow_exporter_enable(const struct dpif_ipfix *di)
+    OVS_EXCLUDED(mutex)
+{
+    bool ret = false;
+
+    ovs_mutex_lock(&mutex);
+    if (hmap_count(&di->flow_exporter_map)) {
+        ret = true;
+    }
+    ovs_mutex_unlock(&mutex);
+    return ret;
+}
+
+bool
+dpif_ipfix_get_flow_exporter_tunnel_sampling(const struct dpif_ipfix *di,
+                                             const uint32_t collector_set_id)
+    OVS_EXCLUDED(mutex)
+{
+    bool ret = false;
+    struct dpif_ipfix_flow_exporter_map_node *node;
+
+    ovs_mutex_lock(&mutex);
+    node = dpif_ipfix_find_flow_exporter_map_node(di, collector_set_id);
+    if (node && node->exporter.options) {
+        ret = node->exporter.options->enable_tunnel_sampling;
+    }
+    ovs_mutex_unlock(&mutex);
+    return ret;
+}
+
+
 static void
 dpif_ipfix_clear(struct dpif_ipfix *di) OVS_REQUIRES(mutex)
 {
@@ -1744,10 +1779,26 @@ dpif_ipfix_bridge_sample(struct dpif_ipfix *di, const struct dp_packet *packet,
 void
 dpif_ipfix_flow_sample(struct dpif_ipfix *di, const struct dp_packet *packet,
                        const struct flow *flow, uint32_t collector_set_id,
-                       uint16_t probability, uint32_t obs_domain_id,
-                       uint32_t obs_point_id) OVS_EXCLUDED(mutex)
+                       uint16_t probability, odp_port_t input_odp_port,
+                       odp_port_t output_odp_port,
+                       const struct flow_tnl *output_tunnel_key)
+    OVS_EXCLUDED(mutex)
 {
     struct dpif_ipfix_flow_exporter_map_node *node;
+    const struct flow_tnl *tunnel_key = NULL;
+    struct dpif_ipfix_port * tunnel_port = NULL;
+
+    /* Skip BFD packets:
+     * Keep same behavior with dpif_ipfix_bridge_sample
+     */
+    if (is_ip_any(flow) &&
+        flow->nw_proto == IPPROTO_UDP &&
+        (flow->tp_dst == htons(BFD_CONTROL_DEST_PORT) ||
+         flow->tp_dst == htons(BFD_ECHO_DEST_PORT))) {
+        ovs_mutex_unlock(&mutex);
+        return;
+    }
+
     /* Use the sampling probability as an approximation of the number
      * of matched packets. */
     uint64_t packet_delta_count = USHRT_MAX / probability;
@@ -1755,9 +1806,24 @@ dpif_ipfix_flow_sample(struct dpif_ipfix *di, const struct dp_packet *packet,
     ovs_mutex_lock(&mutex);
     node = dpif_ipfix_find_flow_exporter_map_node(di, collector_set_id);
     if (node) {
+        if (node->exporter.options->enable_tunnel_sampling) {
+            if (output_odp_port == ODPP_NONE && flow->tunnel.ip_dst) {
+                /* Input tunnel. */
+                tunnel_key = &flow->tunnel;
+                tunnel_port = dpif_ipfix_find_port(di, input_odp_port);
+            }
+            if (output_odp_port != ODPP_NONE && output_tunnel_key) {
+                /* Output tunnel, output_tunnel_key must be valid. */
+                tunnel_key = output_tunnel_key;
+                tunnel_port = dpif_ipfix_find_port(di, output_odp_port);
+            }
+        }
+
         dpif_ipfix_sample(&node->exporter.exporter, packet, flow,
-                          packet_delta_count, obs_domain_id, obs_point_id,
-                          ODPP_NONE, NULL, NULL);
+                          packet_delta_count,
+                          node->exporter.options->obs_domain_id,
+                          node->exporter.options->obs_point_id,
+                          output_odp_port, tunnel_port, tunnel_key);
     }
     ovs_mutex_unlock(&mutex);
 }
diff --git a/ofproto/ofproto-dpif-ipfix.h b/ofproto/ofproto-dpif-ipfix.h
index 2bb0e43..865ea55 100644
--- a/ofproto/ofproto-dpif-ipfix.h
+++ b/ofproto/ofproto-dpif-ipfix.h
@@ -40,6 +40,9 @@ uint32_t dpif_ipfix_get_bridge_exporter_probability(const struct dpif_ipfix *);
 bool dpif_ipfix_get_bridge_exporter_tunnel_sampling(const struct dpif_ipfix *);
 bool dpif_ipfix_get_bridge_exporter_input_sampling(const struct dpif_ipfix *);
 bool dpif_ipfix_get_bridge_exporter_output_sampling(const struct dpif_ipfix *);
+bool dpif_ipfix_flow_exporter_enable(const struct dpif_ipfix *);
+bool dpif_ipfix_get_flow_exporter_tunnel_sampling(const struct dpif_ipfix *,
+                                                  const uint32_t);
 bool dpif_ipfix_get_tunnel_port(const struct dpif_ipfix *, odp_port_t);
 void dpif_ipfix_set_options(
     struct dpif_ipfix *,
@@ -50,8 +53,8 @@ void dpif_ipfix_bridge_sample(struct dpif_ipfix *, const struct dp_packet *,
                               const struct flow *,
                               odp_port_t, odp_port_t, const struct flow_tnl *);
 void dpif_ipfix_flow_sample(struct dpif_ipfix *, const struct dp_packet *,
-                            const struct flow *, uint32_t, uint16_t, uint32_t,
-                            uint32_t);
+                            const struct flow *, uint32_t, uint16_t, odp_port_t,
+                            odp_port_t, const struct flow_tnl *);
 
 void dpif_ipfix_run(struct dpif_ipfix *);
 void dpif_ipfix_wait(struct dpif_ipfix *);
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 1374950..2570d87 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -1256,17 +1256,24 @@ process_upcall(struct udpif *udpif, struct upcall *upcall,
     case FLOW_SAMPLE_UPCALL:
         if (upcall->ipfix) {
             union user_action_cookie cookie;
+            struct flow_tnl output_tunnel_key;
 
             memset(&cookie, 0, sizeof cookie);
             memcpy(&cookie, nl_attr_get(userdata), sizeof cookie.flow_sample);
 
+            if (upcall->out_tun_key) {
+                odp_tun_key_from_attr(upcall->out_tun_key, false,
+                                      &output_tunnel_key);
+            }
             /* The flow reflects exactly the contents of the packet.
              * Sample the packet using it. */
             dpif_ipfix_flow_sample(upcall->ipfix, packet, flow,
                                    cookie.flow_sample.collector_set_id,
                                    cookie.flow_sample.probability,
-                                   cookie.flow_sample.obs_domain_id,
-                                   cookie.flow_sample.obs_point_id);
+                                   flow->in_port.odp_port,
+                                   cookie.flow_sample.output_odp_port,
+                                   upcall->out_tun_key ?
+                                       &output_tunnel_key : NULL);
         }
         break;
 
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index cca5c5c..44dd50f 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -2655,8 +2655,76 @@ compose_sflow_action(struct xlate_ctx *ctx)
                                  true);
 }
 
-/* If IPFIX is enabled, this appends a "sample" action to implement IPFIX to
- * 'ctx->odp_actions'. */
+static void
+adjust_sample_action(struct xlate_ctx *ctx, odp_port_t output_odp_port)
+{
+    const struct nlattr *nla, *nla_nested_lay1, *nla_nested_lay2;
+    const struct nlattr *tunnel_out_port_attr;
+    size_t step_length = 0;
+    struct ofpbuf *odp_actions;
+
+    if (output_odp_port == ODPP_NONE) {
+        return;
+    }
+
+    odp_actions = ctx->odp_actions;
+    size_t offset = odp_actions->size;
+    /* set_tunnel action should be in front
+     * of sample action which contains OVS_USERSPACE_ATTR_EGRESS_TUN_PORT
+     * attribute */
+    while (step_length < offset) {
+        nla = nl_attr_find(odp_actions, step_length, OVS_ACTION_ATTR_SAMPLE);
+
+        if (nla) {
+            nla_nested_lay1 = nl_attr_find_nested(nla,
+                                              OVS_SAMPLE_ATTR_ACTIONS);
+            if (nla_nested_lay1) {
+                nla_nested_lay2 = nl_attr_find_nested(nla_nested_lay1,
+                                                  OVS_ACTION_ATTR_USERSPACE);
+            } else {
+                return;
+            }
+        } else {
+            return;
+        }
+
+        tunnel_out_port_attr = nl_attr_find_nested(nla_nested_lay2,
+                                       OVS_USERSPACE_ATTR_EGRESS_TUN_PORT);
+        if (tunnel_out_port_attr) {
+            size_t len = nla->nla_len;
+            if (output_odp_port != nl_attr_get_u32(tunnel_out_port_attr)) {
+                step_length = (char *) nla - (char *) odp_actions->data +
+                              nla->nla_len;
+                continue;
+            }
+
+            if (offset == (char *) nla - (char *) odp_actions->data +
+                          len) {
+                break;
+            }
+
+            size_t remain_len = (char *) odp_actions->data +
+                                offset - (char *) nla - len;
+            char *tmpBuffer = xmalloc(len);
+            memcpy(tmpBuffer, (char *) nla, len);
+            memmove((char *) nla, (char *) nla + len, remain_len);
+            memcpy((char *) nla + remain_len, tmpBuffer, len);
+            free(tmpBuffer);
+            break;
+        } else {
+            /* continue to find sample action, if the first sample action
+             * is input action */
+            step_length = (char *) nla - ((char *) odp_actions->data) +
+                          nla->nla_len;
+        }
+    }
+
+}
+
+/* If bridge IPFIX is enabled, this appends a "sample" action to
+ * implement IPFIX to 'ctx->odp_actions'. If flow IPFIX is enabled,
+ * make sure IPFIX flow sample action of tunnel port is in front
+ * of corresponding output action */
 static void
 compose_ipfix_action(struct xlate_ctx *ctx, odp_port_t output_odp_port)
 {
@@ -2667,6 +2735,12 @@ compose_ipfix_action(struct xlate_ctx *ctx, odp_port_t output_odp_port)
         return;
     }
 
+    /* For ipfix flow sample action, output sample action of tunnel port
+     * should be placed in front of output action */
+    if (dpif_ipfix_flow_exporter_enable(ipfix)) {
+        adjust_sample_action(ctx, output_odp_port);
+    }
+
     /* For input case, output_odp_port is ODPP_NONE, which is an invalid port
      * number. */
     if (output_odp_port == ODPP_NONE &&
@@ -4145,19 +4219,48 @@ static void
 xlate_sample_action(struct xlate_ctx *ctx,
                     const struct ofpact_sample *os)
 {
+    odp_port_t output_odp_port = ODPP_NONE;
+    odp_port_t tunnel_out_port = ODPP_NONE;
+    struct dpif_ipfix *ipfix = ctx->xbridge->ipfix;
+
+    if (!ipfix || ctx->xin->flow.in_port.ofp_port == OFPP_NONE) {
+        return;
+    }
+
     /* Scale the probability from 16-bit to 32-bit while representing
      * the same percentage. */
     uint32_t probability = (os->probability << 16) | os->probability;
+    static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
 
     if (!ctx->xbridge->support.variable_length_userdata) {
-        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
-
         VLOG_ERR_RL(&rl, "ignoring NXAST_SAMPLE action because datapath "
                     "lacks support (needs Linux 3.10+ or kernel module from "
                     "OVS 1.11+)");
         return;
     }
 
+    if (os->sampling_port != OFPP_NONE) {
+        /* If ofp_port in flow sample action is equel to ofp_port,
+         * this sample action is a input port action */
+        if (os->sampling_port == ctx->xin->flow.in_port.ofp_port) {
+            output_odp_port = ODPP_NONE;
+        } else {
+            output_odp_port = ofp_port_to_odp_port(ctx->xbridge,
+                                  (ofp_port_t) os->sampling_port);
+            if (output_odp_port == ODPP_NONE) {
+                VLOG_ERR_RL(&rl, "openflow port: %d in flow sample action "
+                            "is illegal", os->sampling_port);
+                return;
+            }
+
+            if (dpif_ipfix_get_flow_exporter_tunnel_sampling(ipfix,
+                    os->collector_set_id) &&
+                    dpif_ipfix_get_tunnel_port(ipfix, output_odp_port)) {
+                tunnel_out_port = output_odp_port;
+            }
+        }
+    }
+
     xlate_commit_actions(ctx);
 
     union user_action_cookie cookie = {
@@ -4165,12 +4268,11 @@ xlate_sample_action(struct xlate_ctx *ctx,
             .type = USER_ACTION_COOKIE_FLOW_SAMPLE,
             .probability = os->probability,
             .collector_set_id = os->collector_set_id,
-            .obs_domain_id = os->obs_domain_id,
-            .obs_point_id = os->obs_point_id,
+            .output_odp_port = output_odp_port,
         }
     };
     compose_sample_action(ctx, probability, &cookie, sizeof cookie.flow_sample,
-                          ODPP_NONE, false);
+                          tunnel_out_port, false);
 }
 
 static bool
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 8588872..6c014de 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -87,8 +87,11 @@ struct ofproto_ipfix_bridge_exporter_options {
 struct ofproto_ipfix_flow_exporter_options {
     uint32_t collector_set_id;
     struct sset targets;
+    uint32_t obs_domain_id;
+    uint32_t obs_point_id;
     uint32_t cache_active_timeout;
     uint32_t cache_max_flows;
+    bool enable_tunnel_sampling;
 };
 
 struct ofproto_rstp_status {
diff --git a/tests/odp.at b/tests/odp.at
index 808a83b..0bac0fa 100644
--- a/tests/odp.at
+++ b/tests/odp.at
@@ -255,8 +255,8 @@ userspace(pid=9765,slow_path(cfm))
 userspace(pid=9765,slow_path(cfm),tunnel_out_port=10)
 userspace(pid=1234567,userdata(0102030405060708090a0b0c0d0e0f),actions)
 userspace(pid=1234567,userdata(0102030405060708090a0b0c0d0e0f),tunnel_out_port=10)
-userspace(pid=6633,flow_sample(probability=123,collector_set_id=1234,obs_domain_id=2345,obs_point_id=3456))
-userspace(pid=6633,flow_sample(probability=123,collector_set_id=1234,obs_domain_id=2345,obs_point_id=3456),tunnel_out_port=10)
+userspace(pid=6633,flow_sample(probability=123,collector_set_id=1234,output_port=10))
+userspace(pid=6633,flow_sample(probability=123,collector_set_id=1234,output_port=10),tunnel_out_port=10)
 userspace(pid=6633,ipfix(output_port=10))
 userspace(pid=6633,ipfix(output_port=10),tunnel_out_port=10)
 set(in_port(2))
diff --git a/tests/ofp-actions.at b/tests/ofp-actions.at
index 83a2301..81cb371 100644
--- a/tests/ofp-actions.at
+++ b/tests/ofp-actions.at
@@ -124,8 +124,8 @@ ffff 0040 00002320 0025   000000000000 dnl
 # actions=dec_ttl(32768,12345,90,765,1024)
 ffff 0020 00002320 0015 000500000000 80003039005A02fd 0400000000000000
 
-# actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
-ffff 0018 00002320 001d 3039 00005BA0 00008707 0000B26E
+# actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
+ffff 0018 00002320 001d 3039 00005BA0 87070000 00000000
 
 # bad OpenFlow10 actions: OFPBAC_BAD_LEN
 & ofp_actions|WARN|OpenFlow action OFPAT_OUTPUT length 240 exceeds action buffer length 8
@@ -407,8 +407,8 @@ ffff 0010 00002320 0014 04d2 162e 02 00
 # actions=dec_ttl(32768,12345,90,765,1024)
 ffff 0020 00002320 0015 000500000000 80003039005A02fd 0400000000000000
 
-# actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
-ffff 0018 00002320 001d 3039 00005BA0 00008707 0000B26E
+# actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
+ffff 0018 00002320 001d 3039 00005BA0 87070000 00000000
 
 # bad OpenFlow11 actions: OFPBAC_BAD_OUT_PORT
 & ofp_actions|WARN|bad action at offset 0 (OFPBAC_BAD_OUT_PORT):
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index 8287cd2..046b1d1 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -159,7 +159,7 @@ ip,actions=set_field:10.4.3.77->ip_src
 sctp actions=drop
 sctp actions=drop
 in_port=0 actions=resubmit:0
-actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
+actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
 actions=ct(nat)
 actions=ct(commit,nat(dst))
 actions=ct(commit,nat(src))
@@ -189,7 +189,7 @@ OFPT_FLOW_MOD: ADD ip actions=mod_nw_src:10.4.3.77
 OFPT_FLOW_MOD: ADD sctp actions=drop
 OFPT_FLOW_MOD: ADD sctp actions=drop
 OFPT_FLOW_MOD: ADD in_port=0 actions=resubmit:0
-OFPT_FLOW_MOD: ADD actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
+OFPT_FLOW_MOD: ADD actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
 OFPT_FLOW_MOD: ADD actions=ct(nat)
 OFPT_FLOW_MOD: ADD actions=ct(commit,nat(dst))
 OFPT_FLOW_MOD: ADD actions=ct(commit,nat(src))
@@ -218,7 +218,7 @@ ip,actions=mod_nw_ttl:1,set_field:10.4.3.77->ip_src
 sctp actions=drop
 sctp actions=drop
 in_port=0 actions=resubmit:0
-actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
+actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
 ]])
 
 AT_CHECK([ovs-ofctl --protocols OpenFlow11 parse-flows flows.txt
@@ -237,7 +237,7 @@ OFPT_FLOW_MOD (OF1.1): ADD ip actions=mod_nw_ttl:1,mod_nw_src:10.4.3.77
 OFPT_FLOW_MOD (OF1.1): ADD sctp actions=drop
 OFPT_FLOW_MOD (OF1.1): ADD sctp actions=drop
 OFPT_FLOW_MOD (OF1.1): ADD in_port=0 actions=resubmit:0
-OFPT_FLOW_MOD (OF1.1): ADD actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
+OFPT_FLOW_MOD (OF1.1): ADD actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
 ]])
 AT_CLEANUP
 
@@ -259,7 +259,7 @@ udp actions=mod_tp_src:1111
 ip actions=mod_nw_src:10.1.1.2,mod_nw_dst:192.168.10.1,mod_nw_ttl:1,mod_nw_tos:16,mod_nw_ecn:2
 in_port=0 actions=mod_dl_src:11:22:33:44:55:66,mod_dl_dst:10:20:30:40:50:60
 in_port=0 actions=resubmit:0
-actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
+actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
 ]])
 
 AT_CHECK([ovs-ofctl --protocols OpenFlow12 parse-flows flows.txt
@@ -282,7 +282,7 @@ OFPT_FLOW_MOD (OF1.2): ADD udp actions=set_field:1111->udp_src
 OFPT_FLOW_MOD (OF1.2): ADD ip actions=set_field:10.1.1.2->ip_src,set_field:192.168.10.1->ip_dst,mod_nw_ttl:1,set_field:4->ip_dscp,set_field:2->nw_ecn
 OFPT_FLOW_MOD (OF1.2): ADD in_port=0 actions=set_field:11:22:33:44:55:66->eth_src,set_field:10:20:30:40:50:60->eth_dst
 OFPT_FLOW_MOD (OF1.2): ADD in_port=0 actions=resubmit:0
-OFPT_FLOW_MOD (OF1.2): ADD actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
+OFPT_FLOW_MOD (OF1.2): ADD actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
 ]])
 AT_CLEANUP
 
@@ -374,7 +374,7 @@ send_flow_rem,actions=output:1,output:NXM_NX_REG0[],output:2,output:NXM_NX_REG1[
 check_overlap,actions=output:1,exit,output:2
 tcp,actions=fin_timeout(idle_timeout=5,hard_timeout=15)
 actions=controller(max_len=123,reason=invalid_ttl,id=555)
-actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
+actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
 ip,actions=ct(commit,zone=5)
 ip,actions=ct(commit,exec(load(1->NXM_NX_CT_MARK[])))
 ip,actions=ct(commit,exec(load(0x1->NXM_NX_CT_LABEL[])))
@@ -416,7 +416,7 @@ NXT_FLOW_MOD: ADD table:255 send_flow_rem actions=output:1,output:NXM_NX_REG0[],
 NXT_FLOW_MOD: ADD table:255 check_overlap actions=output:1,exit,output:2
 NXT_FLOW_MOD: ADD table:255 tcp actions=fin_timeout(idle_timeout=5,hard_timeout=15)
 NXT_FLOW_MOD: ADD table:255 actions=controller(reason=invalid_ttl,max_len=123,id=555)
-NXT_FLOW_MOD: ADD table:255 actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
+NXT_FLOW_MOD: ADD table:255 actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
 NXT_FLOW_MOD: ADD table:255 ip actions=ct(commit,zone=5)
 NXT_FLOW_MOD: ADD table:255 ip actions=ct(commit,exec(load:0x1->NXM_NX_CT_MARK[]))
 NXT_FLOW_MOD: ADD table:255 ip actions=ct(commit,exec(load:0x1->NXM_NX_CT_LABEL[0..63],load:0->NXM_NX_CT_LABEL[64..127]))
@@ -456,7 +456,7 @@ dl_dst=01:00:00:00:00:00/01:00:00:00:00:00,actions=drop
 dl_dst=00:00:00:00:00:00/01:00:00:00:00:00,actions=drop
 dl_dst=aa:bb:cc:dd:ee:ff/fe:ff:ff:ff:ff:ff,actions=drop
 dl_dst=aa:bb:cc:dd:ee:ff/00:00:00:00:00:00,actions=drop
-actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
+actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
 ip,actions=ct(commit,zone=5)
 ip,actions=ct(commit,exec(load(1->NXM_NX_CT_MARK[[]])))
 ip,actions=ct(commit,exec(load(0x1->NXM_NX_CT_LABEL[[]])))
@@ -492,7 +492,7 @@ NXT_FLOW_MOD: ADD dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=drop
 NXT_FLOW_MOD: ADD dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 actions=drop
 NXT_FLOW_MOD: ADD dl_dst=aa:bb:cc:dd:ee:ff/fe:ff:ff:ff:ff:ff actions=drop
 NXT_FLOW_MOD: ADD actions=drop
-NXT_FLOW_MOD: ADD actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
+NXT_FLOW_MOD: ADD actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
 NXT_FLOW_MOD: ADD ip actions=ct(commit,zone=5)
 NXT_FLOW_MOD: ADD ip actions=ct(commit,exec(load:0x1->NXM_NX_CT_MARK[[]]))
 NXT_FLOW_MOD: ADD ip actions=ct(commit,exec(load:0x1->NXM_NX_CT_LABEL[[0..63]],load:0->NXM_NX_CT_LABEL[[64..127]]))
@@ -528,7 +528,7 @@ reg0=123,actions=move:NXM_NX_REG0[0..5]->NXM_NX_REG1[26..31],load:55->NXM_NX_REG
 actions=move:OXM_OF_ETH_DST[]->OXM_OF_ETH_SRC[]
 actions=push:NXM_NX_REG0[0..31],pop:NXM_NX_REG0[]
 vlan_tci=0x1123/0x1fff,actions=drop
-actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
+actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
 ip,actions=ct(commit,zone=5)
 ip,actions=ct(commit,exec(load(1->NXM_NX_CT_MARK[])))
 ip,actions=ct(commit,exec(load(1->NXM_NX_CT_LABEL[])))
@@ -564,7 +564,7 @@ NXT_FLOW_MOD: ADD NXM_NX_REG0(0000007b) actions=move:NXM_NX_REG0[0..5]->NXM_NX_R
 NXT_FLOW_MOD: ADD <any> actions=move:NXM_OF_ETH_DST[]->NXM_OF_ETH_SRC[]
 NXT_FLOW_MOD: ADD <any> actions=push:NXM_NX_REG0[],pop:NXM_NX_REG0[]
 NXT_FLOW_MOD: ADD NXM_OF_VLAN_TCI_W(1123/1fff) actions=drop
-NXT_FLOW_MOD: ADD <any> actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678)
+NXT_FLOW_MOD: ADD <any> actions=sample(probability=12345,collector_set_id=23456,sampling_port=34567)
 NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0800) actions=ct(commit,zone=5)
 NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0800) actions=ct(commit,exec(load:0x1->NXM_NX_CT_MARK[]))
 NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0800) actions=ct(commit,exec(load:0x1->NXM_NX_CT_LABEL[0..63],load:0->NXM_NX_CT_LABEL[64..127]))
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 41ec4ba..cd1457b 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -1221,10 +1221,17 @@ bridge_configure_ipfix(struct bridge *br)
                 sset_init(&opts->targets);
                 sset_add_array(&opts->targets, fe_cfg->ipfix->targets,
                                fe_cfg->ipfix->n_targets);
+                opts->obs_domain_id = fe_cfg->ipfix->obs_domain_id
+                    ? *fe_cfg->ipfix->obs_domain_id : 0;
+                opts->obs_point_id = fe_cfg->ipfix->obs_point_id
+                    ? *fe_cfg->ipfix->obs_point_id : 0;
                 opts->cache_active_timeout = fe_cfg->ipfix->cache_active_timeout
                     ? *fe_cfg->ipfix->cache_active_timeout : 0;
                 opts->cache_max_flows = fe_cfg->ipfix->cache_max_flows
                     ? *fe_cfg->ipfix->cache_max_flows : 0;
+                opts->enable_tunnel_sampling = smap_get_bool(
+                                                   &fe_cfg->ipfix->other_config,
+                                                   "enable-tunnel-sampling", true);
                 opts++;
             }
         }
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index 0c9e60c..733cadb 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -4620,6 +4620,96 @@
       disabled.
     </column>
 
+    <column name="obs_domain_id">
+      The IPFIX Observation Domain ID sent in each IPFIX packet.  If not
+      specified, defaults to 0.
+    </column>
+
+    <column name="obs_point_id">
+      The IPFIX Observation Point ID sent in each IPFIX flow record.  If not
+      specified, defaults to 0.
+    </column>
+
+    <column name="other_config" key="enable-tunnel-sampling"
+            type='{"type": "boolean"}'>
+      <p>
+        Set to <code>true</code> to enable sampling and reporting tunnel
+        header 7-tuples in IPFIX flow records.  Tunnel sampling is disabled
+        by default.
+      </p>
+
+      <p>
+        The following enterprise entities report the sampled tunnel info:
+      </p>
+
+      <dl>
+        <dt>tunnelType:</dt>
+        <dd>
+          <p>ID: 891, and enterprise ID 6876 (VMware).</p>
+          <p>type: unsigned 8-bit integer.</p>
+          <p>data type semantics: identifier.</p>
+          <p>description: Identifier of the layer 2 network overlay network
+          encapsulation type: 0x01 VxLAN, 0x02 GRE, 0x03 LISP, 0x05 IPsec+GRE,
+          0x07 GENEVE.</p>
+        </dd>
+        <dt>tunnelKey:</dt>
+        <dd>
+          <p>ID: 892, and enterprise ID 6876 (VMware).</p>
+          <p>type: variable-length octetarray.</p>
+          <p>data type semantics: identifier.</p>
+          <p>description: Key which is used for identifying an individual
+          traffic flow within a VxLAN (24-bit VNI), GENEVE (24-bit VNI),
+          GRE (32-bit key), or LISP (24-bit instance ID) tunnel. The
+          key is encoded in this octetarray as a 3-, 4-, or 8-byte integer
+          ID in network byte order.</p>
+        </dd>
+        <dt>tunnelSourceIPv4Address:</dt>
+        <dd>
+          <p>ID: 893, and enterprise ID 6876 (VMware).</p>
+          <p>type: unsigned 32-bit integer.</p>
+          <p>data type semantics: identifier.</p>
+          <p>description: The IPv4 source address in the tunnel IP packet
+          header.</p>
+        </dd>
+        <dt>tunnelDestinationIPv4Address:</dt>
+        <dd>
+          <p>ID: 894, and enterprise ID 6876 (VMware).</p>
+          <p>type: unsigned 32-bit integer.</p>
+          <p>data type semantics: identifier.</p>
+          <p>description: The IPv4 destination address in the tunnel IP
+          packet header.</p>
+        </dd>
+        <dt>tunnelProtocolIdentifier:</dt>
+        <dd>
+          <p>ID: 895, and enterprise ID 6876 (VMware).</p>
+          <p>type: unsigned 8-bit integer.</p>
+          <p>data type semantics: identifier.</p>
+          <p>description: The value of the protocol number in the tunnel
+          IP packet header. The protocol number identifies the tunnel IP
+          packet payload type.</p>
+        </dd>
+        <dt>tunnelSourceTransportPort:</dt>
+        <dd>
+          <p>ID: 896, and enterprise ID 6876 (VMware).</p>
+          <p>type: unsigned 16-bit integer.</p>
+          <p>data type semantics: identifier.</p>
+          <p>description: The source port identifier in the tunnel transport
+          header. For the transport protocols UDP, TCP, and SCTP, this is
+          the source port number given in the respective header.</p>
+        </dd>
+        <dt>tunnelDestinationTransportPort:</dt>
+        <dd>
+          <p>ID: 897, and enterprise ID 6876 (VMware).</p>
+          <p>type: unsigned 16-bit integer.</p>
+          <p>data type semantics: identifier.</p>
+          <p>description: The destination port identifier in the tunnel
+          transport header. For the transport protocols UDP, TCP, and SCTP,
+          this is the destination port number given in the respective header.
+          </p>
+        </dd>
+      </dl>
+    </column>
+
     <group title="Per-Bridge Sampling">
       <p>
         These values affect only per-bridge sampling.  See above for a
@@ -4633,96 +4723,6 @@
         400 packets, on average, will be sent to each target collector.
       </column>
 
-      <column name="obs_domain_id">
-        The IPFIX Observation Domain ID sent in each IPFIX packet.  If not
-        specified, defaults to 0.
-      </column>
-
-      <column name="obs_point_id">
-        The IPFIX Observation Point ID sent in each IPFIX flow record.  If not
-        specified, defaults to 0.
-      </column>
-
-      <column name="other_config" key="enable-tunnel-sampling"
-              type='{"type": "boolean"}'>
-        <p>
-          Set to <code>true</code> to enable sampling and reporting tunnel
-          header 7-tuples in IPFIX flow records.  Tunnel sampling is disabled
-          by default.
-        </p>
-
-        <p>
-          The following enterprise entities report the sampled tunnel info:
-        </p>
-
-        <dl>
-          <dt>tunnelType:</dt>
-          <dd>
-            <p>ID: 891, and enterprise ID 6876 (VMware).</p>
-            <p>type: unsigned 8-bit integer.</p>
-            <p>data type semantics: identifier.</p>
-            <p>description: Identifier of the layer 2 network overlay network
-            encapsulation type: 0x01 VxLAN, 0x02 GRE, 0x03 LISP, 0x05 IPsec+GRE,
-            0x07 GENEVE.</p>
-          </dd>
-          <dt>tunnelKey:</dt>
-          <dd>
-            <p>ID: 892, and enterprise ID 6876 (VMware).</p>
-            <p>type: variable-length octetarray.</p>
-            <p>data type semantics: identifier.</p>
-            <p>description: Key which is used for identifying an individual
-            traffic flow within a VxLAN (24-bit VNI), GENEVE (24-bit VNI),
-            GRE (32-bit key), or LISP (24-bit instance ID) tunnel. The
-            key is encoded in this octetarray as a 3-, 4-, or 8-byte integer
-            ID in network byte order.</p>
-          </dd>
-          <dt>tunnelSourceIPv4Address:</dt>
-          <dd>
-            <p>ID: 893, and enterprise ID 6876 (VMware).</p>
-            <p>type: unsigned 32-bit integer.</p>
-            <p>data type semantics: identifier.</p>
-            <p>description: The IPv4 source address in the tunnel IP packet
-            header.</p>
-          </dd>
-          <dt>tunnelDestinationIPv4Address:</dt>
-          <dd>
-            <p>ID: 894, and enterprise ID 6876 (VMware).</p>
-            <p>type: unsigned 32-bit integer.</p>
-            <p>data type semantics: identifier.</p>
-            <p>description: The IPv4 destination address in the tunnel IP
-            packet header.</p>
-          </dd>
-          <dt>tunnelProtocolIdentifier:</dt>
-          <dd>
-            <p>ID: 895, and enterprise ID 6876 (VMware).</p>
-            <p>type: unsigned 8-bit integer.</p>
-            <p>data type semantics: identifier.</p>
-            <p>description: The value of the protocol number in the tunnel
-            IP packet header. The protocol number identifies the tunnel IP
-            packet payload type.</p>
-          </dd>
-          <dt>tunnelSourceTransportPort:</dt>
-          <dd>
-            <p>ID: 896, and enterprise ID 6876 (VMware).</p>
-            <p>type: unsigned 16-bit integer.</p>
-            <p>data type semantics: identifier.</p>
-            <p>description: The source port identifier in the tunnel transport
-            header. For the transport protocols UDP, TCP, and SCTP, this is
-            the source port number given in the respective header.</p>
-          </dd>
-          <dt>tunnelDestinationTransportPort:</dt>
-          <dd>
-            <p>ID: 897, and enterprise ID 6876 (VMware).</p>
-            <p>type: unsigned 16-bit integer.</p>
-            <p>data type semantics: identifier.</p>
-            <p>description: The destination port identifier in the tunnel
-            transport header. For the transport protocols UDP, TCP, and SCTP,
-            this is the destination port number given in the respective header.
-            </p>
-          </dd>
-        </dl>
-      </column>
-
       <column name="other_config" key="enable-input-sampling"
               type='{"type": "boolean"}'>
         By default, Open vSwitch samples and reports flows at bridge port input
-- 
1.9.1




More information about the dev mailing list