+/* Compose SAMPLE action for sFlow. */
+static size_t
+compose_sflow_action(const struct ofproto_dpif *ofproto,
+ struct ofpbuf *odp_actions,
+ const struct flow *flow,
+ uint32_t odp_port)
+{
+ uint32_t port_ifindex;
+ uint32_t probability;
+ struct user_action_cookie *cookie;
+ size_t sample_offset, actions_offset;
+ int user_cookie_offset, n_output;
+
+ if (!ofproto->sflow || flow->in_port == OFPP_NONE) {
+ return 0;
+ }
+
+ if (odp_port == OVSP_NONE) {
+ port_ifindex = 0;
+ n_output = 0;
+ } else {
+ port_ifindex = dpif_sflow_odp_port_to_ifindex(ofproto->sflow, odp_port);
+ n_output = 1;
+ }
+
+ sample_offset = nl_msg_start_nested(odp_actions, OVS_ACTION_ATTR_SAMPLE);
+
+ /* Number of packets out of UINT_MAX to sample. */
+ probability = dpif_sflow_get_probability(ofproto->sflow);
+ nl_msg_put_u32(odp_actions, OVS_SAMPLE_ATTR_PROBABILITY, probability);
+
+ actions_offset = nl_msg_start_nested(odp_actions, OVS_SAMPLE_ATTR_ACTIONS);
+
+ cookie = nl_msg_put_unspec_uninit(odp_actions, OVS_ACTION_ATTR_USERSPACE,
+ sizeof(*cookie));
+ cookie->type = USER_ACTION_COOKIE_SFLOW;
+ cookie->data = port_ifindex;
+ cookie->n_output = n_output;
+ cookie->vlan_tci = 0;
+ user_cookie_offset = (char *) cookie - (char *) odp_actions->data;
+
+ nl_msg_end_nested(odp_actions, actions_offset);
+ nl_msg_end_nested(odp_actions, sample_offset);
+ return user_cookie_offset;
+}
+
+/* SAMPLE action must be first action in any given list of actions.
+ * At this point we do not have all information required to build it. So try to
+ * build sample action as complete as possible. */
+static void
+add_sflow_action(struct action_xlate_ctx *ctx)
+{
+ ctx->user_cookie_offset = compose_sflow_action(ctx->ofproto,
+ ctx->odp_actions,
+ &ctx->flow, OVSP_NONE);
+ ctx->sflow_odp_port = 0;
+ ctx->sflow_n_outputs = 0;
+}
+
+/* Fix SAMPLE action according to data collected while composing ODP actions.
+ * We need to fix SAMPLE actions OVS_SAMPLE_ATTR_ACTIONS attribute, i.e. nested
+ * USERSPACE action's user-cookie which is required for sflow. */
+static void
+fix_sflow_action(struct action_xlate_ctx *ctx)
+{
+ const struct flow *base = &ctx->base_flow;
+ struct user_action_cookie *cookie;
+
+ if (!ctx->user_cookie_offset) {
+ return;
+ }
+
+ cookie = ofpbuf_at(ctx->odp_actions, ctx->user_cookie_offset,
+ sizeof(*cookie));
+ assert(cookie != NULL);
+ assert(cookie->type == USER_ACTION_COOKIE_SFLOW);
+
+ if (ctx->sflow_n_outputs) {
+ cookie->data = dpif_sflow_odp_port_to_ifindex(ctx->ofproto->sflow,
+ ctx->sflow_odp_port);
+ }
+ if (ctx->sflow_n_outputs >= 255) {
+ cookie->n_output = 255;
+ } else {
+ cookie->n_output = ctx->sflow_n_outputs;
+ }
+ cookie->vlan_tci = base->vlan_tci;
+}
+