nskb->ip_summed = skb->ip_summed;
nskb->csum = skb->csum;
#endif
-#if defined(CONFIG_XEN) && LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18)
+#if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
/* These fields are copied in skb_clone but not in
* skb_copy or related functions. We need to manually
* copy them over here. */
return dp_output_control(dp, skb, _ODPL_ACTION_NR, arg);
}
+/* Send a copy of this packet up to the sFlow agent, along with extra
+ * information about what happened to it. */
+static void sflow_sample(struct datapath *dp, struct sk_buff *skb,
+ const union odp_action *a, int n_actions, gfp_t gfp)
+{
+ struct odp_sflow_sample_header *hdr;
+ unsigned int actlen = n_actions * sizeof(union odp_action);
+ unsigned int hdrlen = sizeof(struct odp_sflow_sample_header);
+ struct sk_buff *nskb;
+ int i;
+
+ nskb = skb_copy_expand(skb, actlen + hdrlen, 0, gfp);
+ if (!nskb)
+ return;
+
+ memcpy(__skb_push(nskb, actlen), a, actlen);
+ hdr = (struct odp_sflow_sample_header*)__skb_push(nskb, hdrlen);
+ hdr->n_actions = n_actions;
+ hdr->sample_pool = 0;
+ for_each_possible_cpu (i) {
+ const struct dp_stats_percpu *stats;
+ stats = per_cpu_ptr(dp->stats_percpu, i);
+ hdr->sample_pool += stats->sflow_pool;
+ }
+ dp_output_control(dp, nskb, _ODPL_SFLOW_NR, 0);
+}
+
/* Execute a list of actions against 'skb'. */
int execute_actions(struct datapath *dp, struct sk_buff *skb,
struct odp_flow_key *key,
* is slightly obscure just to avoid that. */
int prev_port = -1;
int err;
+
+ if (dp->sflow_probability) {
+ /* Increment sample pool. */
+ int cpu = get_cpu();
+ per_cpu_ptr(dp->stats_percpu, cpu)->sflow_pool++;
+ put_cpu();
+
+ /* Sample packet. */
+ if (dp->sflow_probability == UINT_MAX ||
+ net_random() < dp->sflow_probability)
+ sflow_sample(dp, skb, a, n_actions, gfp);
+ }
+
for (; n_actions > 0; a++, n_actions--) {
WARN_ON_ONCE(skb_shared(skb));
if (prev_port != -1) {