@@ -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
---------------------
@@ -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;
@@ -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,
@@ -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. */
@@ -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);
@@ -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. */
@@ -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 *);
@@ -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;
@@ -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);
}
@@ -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
@@ -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"])
@@ -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]))
@@ -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()
@@ -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
@@ -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": {
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@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(-)