[ovs-dev] [PATCHv3] ofproto-dpif-sflow: Add snaplen for sample action and sFlow.

William Tu u9012063 at gmail.com
Tue Jul 5 22:05:50 UTC 2016


This patch adds a 'snaplen' field in sample action (nx_action_sample2).
Currently, sample action is used by sFlow and IPFIX. For IPFIX, nothing
is changed.  For sFlow configuration, the patch translates header=N to
a sample action with snaplen=N, then the snaplen=N translates to trunc(N)
in kernel datapath.  Thus, only N bytes instead of full-packet size will
be copied from kernel to userspace, saving the copying overhead.

Also, the patch parses OVS_PACKET_ATTR_LEN from nlattr to upcall related
structures so the sFlow receiver knows the original packet size before it
is truncated.

Tested-at: https://travis-ci.org/williamtu/ovs-travis/builds/142593443
Signed-off-by: William Tu <u9012063 at gmail.com>
---
v2->v3
http://openvswitch.org/pipermail/dev/2016-July/074288.html
- Update NEWS and ovs-ofctl
- Make snaplen default UINT16_MAX
- Fix encode_SAMPLE() and format_SAMPLE()
- Prevent user from setting snaplen < 14 at ovsschema
- Add userspace testcase
v1->v2
http://openvswitch.org/pipermail/dev/2016-June/072404.html
- Add snaplen to nx_action_sample2
- Since truncate then userspace action is supported in userspace datapath,
  ,commit aaca4fe0ce9e (ofp-actions: Add truncate action.), remove
  datapath-specific implementation and testcase.
---
 NEWS                              |  3 +++
 include/openvswitch/ofp-actions.h |  1 +
 lib/dpif-netlink.c                |  4 +++-
 lib/dpif.h                        |  2 +-
 lib/ofp-actions.c                 | 18 ++++++++++++++++--
 ofproto/ofproto-dpif-sflow.c      | 16 +++++++++++++---
 ofproto/ofproto-dpif-sflow.h      |  2 ++
 ofproto/ofproto-dpif-upcall.c     | 21 ++++++++++++++++-----
 ofproto/ofproto-dpif-xlate.c      | 25 +++++++++++++++++++++++--
 tests/ofp-actions.at              |  4 ++--
 tests/ofproto-dpif.at             | 19 +++++++++++++++++++
 tests/ovs-ofctl.at                | 24 ++++++++++++------------
 tests/system-traffic.at           | 36 ++++++++++++++++++++++++++++++++++++
 utilities/ovs-ofctl.8.in          |  4 ++++
 vswitchd/vswitch.ovsschema        |  7 +++++--
 15 files changed, 156 insertions(+), 30 deletions(-)

diff --git a/NEWS b/NEWS
index f7b202b..4bc0c70 100644
--- a/NEWS
+++ b/NEWS
@@ -78,6 +78,9 @@ Post-v2.5.0
      watch with tcpdump
    - Introduce --no-self-confinement flag that allows daemons to work with
      sockets outside their run directory.
+   - sFlow:
+     * New "snaplen" option for sample action to allow specifying maximum
+       per-packet number of bytes to sample.
 
 v2.5.0 - 26 Feb 2016
 ---------------------
diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp-actions.h
index 0b8ccbb..cfecc25 100644
--- a/include/openvswitch/ofp-actions.h
+++ b/include/openvswitch/ofp-actions.h
@@ -789,6 +789,7 @@ struct ofpact_note {
 struct ofpact_sample {
     struct ofpact ofpact;
     uint16_t probability;  /* Always positive. */
+    uint16_t snaplen;
     uint32_t collector_set_id;
     uint32_t obs_domain_id;
     uint32_t obs_point_id;
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index e2bea23..db58fcc 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -1969,7 +1969,8 @@ parse_odp_packet(const struct dpif_netlink *dpif, struct ofpbuf *buf,
         [OVS_PACKET_ATTR_USERDATA] = { .type = NL_A_UNSPEC, .optional = true },
         [OVS_PACKET_ATTR_EGRESS_TUN_KEY] = { .type = NL_A_NESTED, .optional = true },
         [OVS_PACKET_ATTR_ACTIONS] = { .type = NL_A_NESTED, .optional = true },
-        [OVS_PACKET_ATTR_MRU] = { .type = NL_A_U16, .optional = true }
+        [OVS_PACKET_ATTR_MRU] = { .type = NL_A_U16, .optional = true },
+        [OVS_PACKET_ATTR_LEN] = { .type = NL_A_U32, .optional = true },
     };
 
     struct ofpbuf b = ofpbuf_const_initializer(buf->data, buf->size);
@@ -2002,6 +2003,7 @@ parse_odp_packet(const struct dpif_netlink *dpif, struct ofpbuf *buf,
     upcall->out_tun_key = a[OVS_PACKET_ATTR_EGRESS_TUN_KEY];
     upcall->actions = a[OVS_PACKET_ATTR_ACTIONS];
     upcall->mru = a[OVS_PACKET_ATTR_MRU];
+    upcall->len = a[OVS_PACKET_ATTR_LEN];
 
     /* Allow overwriting the netlink attribute header without reallocating. */
     dp_packet_use_stub(&upcall->packet,
diff --git a/lib/dpif.h b/lib/dpif.h
index 981868c..070d2f9 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -784,7 +784,7 @@ struct dpif_upcall {
     size_t key_len;             /* Length of 'key' in bytes. */
     ovs_u128 ufid;              /* Unique flow identifier for 'key'. */
     struct nlattr *mru;         /* Maximum receive unit. */
-    struct nlattr *cutlen;      /* Number of bytes shrink from the end. */
+    struct nlattr *len;         /* Original packet length. */
 
     /* DPIF_UC_ACTION only. */
     struct nlattr *userdata;    /* Argument to OVS_ACTION_ATTR_USERSPACE. */
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 997cc15..41476ef 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -4756,7 +4756,8 @@ struct nx_action_sample2 {
     ovs_be32 obs_domain_id;         /* ID of sampling observation domain. */
     ovs_be32 obs_point_id;          /* ID of sampling observation point. */
     ovs_be16 sampling_port;         /* Sampling port. */
-    uint8_t  pad[6];                /* Pad to a multiple of 8 bytes */
+    ovs_be16 snaplen;               /* Max sampled packet size in byte. */
+    uint8_t  pad[4];                /* Pad to a multiple of 8 bytes */
  };
  OFP_ASSERT(sizeof(struct nx_action_sample2) == 32);
 
@@ -4775,6 +4776,7 @@ decode_NXAST_RAW_SAMPLE(const struct nx_action_sample *nas,
     sample->obs_point_id = ntohl(nas->obs_point_id);
     /* Default value for sampling port is OFPP_NONE */
     sample->sampling_port = OFPP_NONE;
+    sample->snaplen = UINT16_MAX;
 
     if (sample->probability == 0) {
         return OFPERR_OFPBAC_BAD_ARGUMENT;
@@ -4797,6 +4799,7 @@ decode_NXAST_RAW_SAMPLE2(const struct nx_action_sample2 *nas,
     sample->obs_domain_id = ntohl(nas->obs_domain_id);
     sample->obs_point_id = ntohl(nas->obs_point_id);
     sample->sampling_port = u16_to_ofp(ntohs(nas->sampling_port));
+    sample->snaplen = ntohs(nas->snaplen);
 
     if (sample->probability == 0) {
         return OFPERR_OFPBAC_BAD_ARGUMENT;
@@ -4810,9 +4813,11 @@ encode_SAMPLE(const struct ofpact_sample *sample,
               enum ofp_version ofp_version OVS_UNUSED, struct ofpbuf *out)
 {
     if (sample->ofpact.raw == NXAST_RAW_SAMPLE2
-        || sample->sampling_port != OFPP_NONE) {
+        || sample->sampling_port != OFPP_NONE
+        || (sample->snaplen != 0 && sample->snaplen != UINT16_MAX)) {
         struct nx_action_sample2 *nas = put_NXAST_SAMPLE2(out);
         nas->probability = htons(sample->probability);
+        nas->snaplen = htons(sample->snaplen);
         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);
@@ -4837,6 +4842,7 @@ parse_SAMPLE(char *arg, struct ofpbuf *ofpacts,
 {
     struct ofpact_sample *os = ofpact_put_SAMPLE(ofpacts);
     os->sampling_port = OFPP_NONE;
+    os->snaplen = UINT16_MAX;
 
     char *key, *value;
     while (ofputil_parse_key_value(&arg, &key, &value)) {
@@ -4857,6 +4863,8 @@ parse_SAMPLE(char *arg, struct ofpbuf *ofpacts,
             if (!ofputil_port_from_string(value, &os->sampling_port)) {
                 error = xasprintf("%s: unknown port", value);
             }
+        } else if (!strcmp(key, "snaplen")) {
+            error = str_to_u16(value, "snaplen", &os->snaplen);
         } else {
             error = xasprintf("invalid key \"%s\" in \"sample\" argument",
                               key);
@@ -4884,6 +4892,12 @@ format_SAMPLE(const struct ofpact_sample *a, struct ds *s)
                   colors.param, colors.end, a->collector_set_id,
                   colors.param, colors.end, a->obs_domain_id,
                   colors.param, colors.end, a->obs_point_id);
+
+    if (a->ofpact.raw == NXAST_RAW_SAMPLE2 &&
+        a->snaplen != 0 && a->snaplen != UINT16_MAX) {
+        ds_put_format(s, ",%ssnaplen=%s%"PRIu16,
+                      colors.param, colors.end, a->snaplen);
+    }
     if (a->sampling_port != OFPP_NONE) {
         ds_put_format(s, ",%ssampling_port=%s%"PRIu16,
                       colors.param, colors.end, a->sampling_port);
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index 7d0aa36..f545f9b 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -556,6 +556,16 @@ dpif_sflow_get_probability(const struct dpif_sflow *ds) OVS_EXCLUDED(mutex)
     return probability;
 }
 
+uint16_t
+dpif_sflow_get_header_len(const struct dpif_sflow *ds) OVS_EXCLUDED(mutex)
+{
+    uint16_t header_len;
+    ovs_mutex_lock(&mutex);
+    header_len = ds->options->header_len;
+    ovs_mutex_unlock(&mutex);
+    return header_len;
+}
+
 void
 dpif_sflow_unref(struct dpif_sflow *ds) OVS_EXCLUDED(mutex)
 {
@@ -1223,6 +1233,7 @@ dpif_sflow_cookie_num_outputs(const union user_action_cookie *cookie)
 void
 dpif_sflow_received(struct dpif_sflow *ds, const struct dp_packet *packet,
 		    const struct flow *flow, odp_port_t odp_in_port,
+		    const uint32_t len,
 		    const union user_action_cookie *cookie,
 		    const struct dpif_sflow_actions *sflow_actions)
     OVS_EXCLUDED(mutex)
@@ -1269,11 +1280,10 @@ dpif_sflow_received(struct dpif_sflow *ds, const struct dp_packet *packet,
     header->header_protocol = SFLHEADER_ETHERNET_ISO8023;
     /* The frame_length should include the Ethernet FCS (4 bytes),
      * but it has already been stripped,  so we need to add 4 here. */
-    header->frame_length = dp_packet_size(packet) + 4;
+    header->frame_length = len + 4;
     /* Ethernet FCS stripped off. */
     header->stripped = 4;
-    header->header_length = MIN(dp_packet_size(packet),
-                                sampler->sFlowFsMaximumHeaderSize);
+    header->header_length = MIN(len, sampler->sFlowFsMaximumHeaderSize);
     header->header_bytes = dp_packet_data(packet);
 
     /* Add extended switch element. */
diff --git a/ofproto/ofproto-dpif-sflow.h b/ofproto/ofproto-dpif-sflow.h
index 014e6cc..6b59b84 100644
--- a/ofproto/ofproto-dpif-sflow.h
+++ b/ofproto/ofproto-dpif-sflow.h
@@ -56,6 +56,7 @@ struct dpif_sflow *dpif_sflow_ref(const struct dpif_sflow *);
 void dpif_sflow_unref(struct dpif_sflow *);
 
 uint32_t dpif_sflow_get_probability(const struct dpif_sflow *);
+uint16_t dpif_sflow_get_header_len(const struct dpif_sflow *);
 
 void dpif_sflow_set_options(struct dpif_sflow *,
                             const struct ofproto_sflow_options *);
@@ -75,6 +76,7 @@ void dpif_sflow_read_actions(const struct flow *,
 
 void dpif_sflow_received(struct dpif_sflow *, const struct dp_packet *,
                          const struct flow *, odp_port_t odp_port,
+                         const uint32_t cutlen,
                          const union user_action_cookie *,
 			 const struct dpif_sflow_actions *);
 
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index c83df9e..493291b 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -207,6 +207,7 @@ struct upcall {
     ofp_port_t in_port;            /* OpenFlow in port, or OFPP_NONE. */
     uint16_t mru;                  /* If !0, Maximum receive unit of
                                       fragmented IP packet */
+    uint32_t len;                  /* Original packet length. */
 
     enum dpif_upcall_type type;    /* Datapath type of the upcall. */
     const struct nlattr *userdata; /* Userdata for DPIF_UC_ACTION Upcalls. */
@@ -350,7 +351,7 @@ static enum upcall_type classify_upcall(enum dpif_upcall_type type,
 static int upcall_receive(struct upcall *, const struct dpif_backer *,
                           const struct dp_packet *packet, enum dpif_upcall_type,
                           const struct nlattr *userdata, const struct flow *,
-                          const unsigned int mru,
+                          const unsigned int mru, const uint32_t cutlen,
                           const ovs_u128 *ufid, const unsigned pmd_id);
 static void upcall_uninit(struct upcall *);
 
@@ -746,6 +747,7 @@ recv_upcalls(struct handler *handler)
         struct upcall *upcall = &upcalls[n_upcalls];
         struct flow *flow = &flows[n_upcalls];
         unsigned int mru;
+        uint32_t len;
         int error;
 
         ofpbuf_use_stub(recv_buf, recv_stubs[n_upcalls],
@@ -766,9 +768,14 @@ recv_upcalls(struct handler *handler)
             mru = 0;
         }
 
+        if (dupcall->len) {
+            len = nl_attr_get_u32(dupcall->len);
+        } else {
+            len = 0;
+        }
         error = upcall_receive(upcall, udpif->backer, &dupcall->packet,
                                dupcall->type, dupcall->userdata, flow, mru,
-                               &dupcall->ufid, PMD_ID_NULL);
+                               len, &dupcall->ufid, PMD_ID_NULL);
         if (error) {
             if (error == ENODEV) {
                 /* Received packet on datapath port for which we couldn't
@@ -1009,7 +1016,7 @@ static int
 upcall_receive(struct upcall *upcall, const struct dpif_backer *backer,
                const struct dp_packet *packet, enum dpif_upcall_type type,
                const struct nlattr *userdata, const struct flow *flow,
-               const unsigned int mru,
+               const unsigned int mru, const unsigned int len,
                const ovs_u128 *ufid, const unsigned pmd_id)
 {
     int error;
@@ -1039,6 +1046,7 @@ upcall_receive(struct upcall *upcall, const struct dpif_backer *backer,
     upcall->key = NULL;
     upcall->key_len = 0;
     upcall->mru = mru;
+    upcall->len = len;
 
     upcall->out_tun_key = NULL;
     upcall->actions = NULL;
@@ -1150,7 +1158,8 @@ upcall_cb(const struct dp_packet *packet, const struct flow *flow, ovs_u128 *ufi
     atomic_read_relaxed(&udpif->flow_limit, &flow_limit);
 
     error = upcall_receive(&upcall, udpif->backer, packet, type, userdata,
-                           flow, 0, ufid, pmd_id);
+                           flow, 0, dp_packet_size(packet) + packet->cutlen,
+                           ufid, pmd_id);
     if (error) {
         return error;
     }
@@ -1237,7 +1246,9 @@ process_upcall(struct udpif *udpif, struct upcall *upcall,
                 }
             }
             dpif_sflow_received(upcall->sflow, packet, flow,
-                                flow->in_port.odp_port, &cookie,
+                                flow->in_port.odp_port,
+                                upcall->len,
+                                &cookie,
                                 actions_len > 0 ? &sflow_actions : NULL);
         }
         break;
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 1977b6b..997ad58 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -2604,7 +2604,8 @@ xlate_normal(struct xlate_ctx *ctx)
 
 /* Appends a "sample" action for sFlow or IPFIX to 'ctx->odp_actions'.  The
  * 'probability' is the number of packets out of UINT32_MAX to sample.  The
- * 'cookie' (of length 'cookie_size' bytes) is passed back in the callback for
+ * 'snaplen' is the maximum sampled packet size in bytes.  The 'cookie'
+ * (of length 'cookie_size' bytes) is passed back in the callback for
  * each sampled packet.  'tunnel_out_port', if not ODPP_NONE, is added as the
  * OVS_USERSPACE_ATTR_EGRESS_TUN_PORT attribute.  If 'include_actions', an
  * OVS_USERSPACE_ATTR_ACTIONS attribute is added.  If 'emit_set_tunnel',
@@ -2615,6 +2616,7 @@ xlate_normal(struct xlate_ctx *ctx)
 static size_t
 compose_sample_action(struct xlate_ctx *ctx,
                       const uint32_t probability,
+                      const uint16_t snaplen,
                       const union user_action_cookie *cookie,
                       const size_t cookie_size,
                       const odp_port_t tunnel_out_port,
@@ -2628,6 +2630,21 @@ compose_sample_action(struct xlate_ctx *ctx,
     size_t actions_offset = nl_msg_start_nested(ctx->odp_actions,
                                                 OVS_SAMPLE_ATTR_ACTIONS);
 
+    if (ctx->xbridge->support.trunc) {
+        if (snaplen >= ETH_HEADER_LEN && snaplen < UINT16_MAX) {
+            struct ovs_action_trunc *trunc;
+
+            trunc = nl_msg_put_unspec_uninit(ctx->odp_actions,
+                            OVS_ACTION_ATTR_TRUNC,
+                            sizeof *trunc);
+            trunc->max_len = snaplen;
+        } else if (snaplen != 0 && snaplen < ETH_HEADER_LEN) {
+            static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
+            VLOG_WARN_RL(&rl, "invalid snaplen: %"PRIu16, snaplen);
+        }
+    }
+
     odp_port_t odp_port = ofp_port_to_odp_port(
         ctx->xbridge, ctx->xin->flow.in_port.ofp_port);
     uint32_t pid = dpif_port_get_pid(ctx->xbridge->dpif, odp_port,
@@ -2660,6 +2677,7 @@ compose_sflow_action(struct xlate_ctx *ctx)
 
     union user_action_cookie cookie = { .type = USER_ACTION_COOKIE_SFLOW };
     return compose_sample_action(ctx, dpif_sflow_get_probability(sflow),
+                                 dpif_sflow_get_header_len(sflow),
                                  &cookie, sizeof cookie.sflow, ODPP_NONE,
                                  true);
 }
@@ -2707,6 +2725,7 @@ compose_ipfix_action(struct xlate_ctx *ctx, odp_port_t output_odp_port)
     };
     compose_sample_action(ctx,
                           dpif_ipfix_get_bridge_exporter_probability(ipfix),
+                          UINT16_MAX,
                           &cookie, sizeof cookie.ipfix, tunnel_out_port,
                           false);
 }
@@ -4236,6 +4255,7 @@ xlate_sample_action(struct xlate_ctx *ctx,
     /* Scale the probability from 16-bit to 32-bit while representing
      * the same percentage. */
     uint32_t probability = (os->probability << 16) | os->probability;
+    uint16_t snaplen = os->snaplen;
 
     if (!ctx->xbridge->support.variable_length_userdata) {
         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
@@ -4302,7 +4322,8 @@ xlate_sample_action(struct xlate_ctx *ctx,
             .output_odp_port = output_odp_port,
         }
     };
-    compose_sample_action(ctx, probability, &cookie, sizeof cookie.flow_sample,
+    compose_sample_action(ctx, probability, snaplen,
+                          &cookie, sizeof cookie.flow_sample,
                           tunnel_out_port, false);
 }
 
diff --git a/tests/ofp-actions.at b/tests/ofp-actions.at
index ca4d1ba..a0f8ee2 100644
--- a/tests/ofp-actions.at
+++ b/tests/ofp-actions.at
@@ -127,8 +127,8 @@ 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,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789)
-ffff 0020 00002320 0026 3039 00005BA0 00008707 0000B26E DDD50000 00000000
+# actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,snaplen=100,sampling_port=56789)
+ffff 0020 00002320 0026 3039 00005BA0 00008707 0000B26E DDD50064 00000000
 
 # bad OpenFlow10 actions: OFPBAC_BAD_LEN
 & ofp_actions|WARN|OpenFlow action OFPAT_OUTPUT length 240 exceeds action buffer length 8
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 8287d90..2ff84b0 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -5679,6 +5679,25 @@ AT_SKIP_IF([test $HAVE_IPV6 = no])
 CHECK_SFLOW_SAMPLING_PACKET([[[::1]]])
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - sFlow packet sampling - truncate])
+AT_XFAIL_IF([test "$IS_WIN32" = "yes"])
+OVS_VSWITCHD_START
+add_of_ports br0 1 2
+AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
+
+AT_CHECK([ovs-vsctl -- \
+    --id=@s create sFlow agent=br0 target=\"127.0.0.1:6344\" \
+    header=64 sampling=1 polling=1 -- set bridge br0 sflow=@s
+], [0], [stdout])
+
+AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=2,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,tp_src=8,tp_dst=9"], [0], [stdout])
+AT_CHECK([tail -1 stdout | sed 's/pid=[[0-9]]*/pid=/g'], [0],
+    [Datapath actions: sample(sample=100.0%,actions(trunc(64),userspace(pid=,sFlow(vid=0,pcp=0,output=2147483650),actions))),100,1
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 dnl Test sFlow LAG structures
 AT_SETUP([ofproto-dpif - sFlow packet sampling - LACP structures])
 AT_SKIP_IF([test "$IS_WIN32" = "yes"])
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index 71c4aab..83be273 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -160,7 +160,7 @@ 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,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789)
+actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,snaplen=100,sampling_port=56789)
 actions=ct(nat)
 actions=ct(commit,nat(dst))
 actions=ct(commit,nat(src))
@@ -191,7 +191,7 @@ 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,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789)
+OFPT_FLOW_MOD: ADD actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,snaplen=100,sampling_port=56789)
 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))
@@ -221,7 +221,7 @@ 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,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789)
+actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,snaplen=100,sampling_port=56789)
 ]])
 
 AT_CHECK([ovs-ofctl --protocols OpenFlow11 parse-flows flows.txt
@@ -241,7 +241,7 @@ 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,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789)
+OFPT_FLOW_MOD (OF1.1): ADD actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,snaplen=100,sampling_port=56789)
 ]])
 AT_CLEANUP
 
@@ -264,7 +264,7 @@ ip actions=mod_nw_src:10.1.1.2,mod_nw_dst:192.168.10.1,mod_nw_ttl:1,mod_nw_tos:1
 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,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789)
+actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,snaplen=100,sampling_port=56789)
 ]])
 
 AT_CHECK([ovs-ofctl --protocols OpenFlow12 parse-flows flows.txt
@@ -288,7 +288,7 @@ OFPT_FLOW_MOD (OF1.2): ADD ip actions=set_field:10.1.1.2->ip_src,set_field:192.1
 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,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789)
+OFPT_FLOW_MOD (OF1.2): ADD actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,snaplen=100,sampling_port=56789)
 ]])
 AT_CLEANUP
 
@@ -381,7 +381,7 @@ 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,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789)
+actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,snaplen=100,sampling_port=56789)
 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[])))
@@ -428,7 +428,7 @@ 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,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789)
+NXT_FLOW_MOD: ADD table:255 actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,snaplen=100,sampling_port=56789)
 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]))
@@ -473,7 +473,7 @@ 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,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789)
+actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,snaplen=100,sampling_port=56789)
 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[[]])))
@@ -510,7 +510,7 @@ 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,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789)
+NXT_FLOW_MOD: ADD actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,snaplen=100,sampling_port=56789)
 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]]))
@@ -547,7 +547,7 @@ 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,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789)
+actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,snaplen=100,sampling_port=56789)
 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[])))
@@ -584,7 +584,7 @@ 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,obs_domain_id=34567,obs_point_id=45678,sampling_port=56789)
+NXT_FLOW_MOD: ADD <any> actions=sample(probability=12345,collector_set_id=23456,obs_domain_id=34567,obs_point_id=45678,snaplen=100,sampling_port=56789)
 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/tests/system-traffic.at b/tests/system-traffic.at
index 252ed20..c4681f4 100644
--- a/tests/system-traffic.at
+++ b/tests/system-traffic.at
@@ -497,6 +497,42 @@ n_bytes=100
 OVS_TRAFFIC_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([datapath - truncate and userspace action])
+dnl Demonstrate that when truncate happens at kernel datapath, the
+dnl upcall netlink packet size is no longer the original size.
+OVS_TRAFFIC_VSWITCHD_START()
+
+dnl skip if it is check-userspace
+AT_CHECK([ovs-ofctl add-flow br0 "actions=normal"])
+ADD_NAMESPACES(at_ns0, at_ns1)
+
+ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24")
+ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24")
+
+NS_CHECK_EXEC([at_ns0], [ping -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+dnl setup sflow
+AT_CHECK([ovs-vsctl -- \
+    --id=@s create sFlow agent=br0 target=\"127.0.0.1:6344\" \
+    header=64 sampling=1 polling=1 -- set bridge br0 sflow=@s
+], [0], [stdout])
+
+dnl ofproto/trace
+AT_CHECK([ovs-appctl ofproto/trace br0 "in_port=2,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,tp_src=8,tp_dst=9"], [0], [stdout])
+AT_CHECK([tail -1 stdout | sed 's/pid=[[0-9]]*/pid=/g'], [0],
+    [Datapath actions: sample(sample=100.0%,actions(trunc(64),userspace(pid=,sFlow(vid=0,pcp=0,output=2147483650),actions))),1,2
+])
+
+dnl send ping with 1024 bytes, the sFlow sample will truncate it in datapath
+NS_CHECK_EXEC([at_ns0], [ping -s 1024 -q -c 3 -i 0.3 -w 2 10.1.1.2 | FORMAT_PING], [0], [dnl
+3 packets transmitted, 3 received, 0% packet loss, time 0ms
+])
+
+OVS_TRAFFIC_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([conntrack - controller])
 CHECK_CONNTRACK()
 OVS_TRAFFIC_VSWITCHD_START()
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 94e78d7..05ac277 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -2337,6 +2337,10 @@ port.  When this option is omitted, or specified as \fBNONE\fB, IPFIX
 does not differentiate between ingress packets and egress packets and
 does not export egress tunnel information.  This option was added in
 Open vSwitch 2.5.90.
+.IP "\fBsnaplen=\fIlen\fR"
+Maximum per-packet number of bytes to sample.  The \fIlen\fR should be
+set between \fB14\fR and \fB65535\fR, or \fB0\fR means no-op.  This
+option was added in Open vSwitch 2.5.90.  Defaults to 65535.
 .RE
 .IP
 Refer to \fBovs\-vswitchd.conf.db\fR(5) for more details on
diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
index 32fdf28..55fbd00 100644
--- a/vswitchd/vswitch.ovsschema
+++ b/vswitchd/vswitch.ovsschema
@@ -1,6 +1,6 @@
 {"name": "Open_vSwitch",
  "version": "7.13.0",
- "cksum": "889248633 22774",
+ "cksum": "204479018 22893",
  "tables": {
    "Open_vSwitch": {
      "columns": {
@@ -449,7 +449,10 @@
        "polling": {
          "type": {"key": "integer", "min": 0, "max": 1}},
        "header": {
-         "type": {"key": "integer", "min": 0, "max": 1}},
+         "type": {"key": {"type": "integer",
+                          "minInteger": 14,
+                          "maxInteger": 65535},
+                  "min": 0, "max": 1}},
        "agent": {
          "type": {"key": "string", "min": 0, "max": 1}},
        "external_ids": {
-- 
2.5.0




More information about the dev mailing list