dp_sysfs_dp.c \
dp_sysfs_if.c \
flow.c \
+ loop_counter.c \
table.c \
tunnel.c \
vport.c \
datapath.h \
dp_sysfs.h \
flow.h \
+ loop_counter.h \
odp-compat.h \
table.h \
tunnel.h \
#include "datapath.h"
#include "actions.h"
#include "flow.h"
+#include "loop_counter.h"
#include "odp-compat.h"
#include "table.h"
#include "vport-internal_dev.h"
static struct datapath *dps[ODP_MAX];
static DEFINE_MUTEX(dp_mutex);
-/* We limit the number of times that we pass into dp_process_received_packet()
- * to avoid blowing out the stack in the event that we have a loop. */
-struct loop_counter {
- int count; /* Count. */
- bool looping; /* Loop detected? */
-};
-
-#define DP_MAX_LOOPS 5
-
-/* We use a separate counter for each CPU for both interrupt and non-interrupt
- * context in order to keep the limit deterministic for a given packet. */
-struct percpu_loop_counters {
- struct loop_counter counters[2];
-};
-
-static DEFINE_PER_CPU(struct percpu_loop_counters, dp_loop_counters);
-
static int new_dp_port(struct datapath *, struct odp_port *, int port_no);
/* Must be called with rcu_read_lock or dp_mutex. */
return err;
}
-static void suppress_loop(struct datapath *dp, struct sw_flow_actions *actions)
-{
- if (net_ratelimit())
- pr_warn("%s: flow looped %d times, dropping\n",
- dp_name(dp), DP_MAX_LOOPS);
- actions->n_actions = 0;
-}
-
/* Must be called with rcu_read_lock. */
void dp_process_received_packet(struct dp_port *p, struct sk_buff *skb)
{
acts = rcu_dereference(OVS_CB(skb)->flow->sf_acts);
/* Check whether we've looped too much. */
- loop = &get_cpu_var(dp_loop_counters).counters[!!in_interrupt()];
- if (unlikely(++loop->count > DP_MAX_LOOPS))
+ loop = loop_get_counter();
+ if (unlikely(++loop->count > MAX_LOOPS))
loop->looping = true;
if (unlikely(loop->looping)) {
- suppress_loop(dp, acts);
+ loop_suppress(dp, acts);
goto out_loop;
}
/* Check whether sub-actions looped too much. */
if (unlikely(loop->looping))
- suppress_loop(dp, acts);
+ loop_suppress(dp, acts);
out_loop:
/* Decrement loop counter. */
if (!--loop->count)
loop->looping = false;
- put_cpu_var(dp_loop_counters);
+ loop_put_counter();
out:
/* Update datapath statistics. */
--- /dev/null
+/*
+ * Distributed under the terms of the GNU GPL version 2.
+ * Copyright (c) 2010 Nicira Networks.
+ *
+ * Significant portions of this file may be copied from parts of the Linux
+ * kernel, by Linus Torvalds and others.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/hardirq.h>
+#include <linux/kernel.h>
+#include <linux/percpu.h>
+#include <linux/sched.h>
+
+#include "loop_counter.h"
+
+void loop_suppress(struct datapath *dp, struct sw_flow_actions *actions)
+{
+ if (net_ratelimit())
+ pr_warn("%s: flow looped %d times, dropping\n",
+ dp_name(dp), MAX_LOOPS);
+ actions->n_actions = 0;
+}
+
+#ifndef CONFIG_PREEMPT_RT
+
+/* We use a separate counter for each CPU for both interrupt and non-interrupt
+ * context in order to keep the limit deterministic for a given packet.
+ */
+struct percpu_loop_counters {
+ struct loop_counter counters[2];
+};
+
+static DEFINE_PER_CPU(struct percpu_loop_counters, loop_counters);
+
+struct loop_counter *loop_get_counter(void)
+{
+ return &get_cpu_var(loop_counters).counters[!!in_interrupt()];
+}
+
+void loop_put_counter(void)
+{
+ put_cpu_var(loop_counters);
+}
+
+#else /* !CONFIG_PREEMPT_RT */
+
+struct loop_counter *loop_get_counter(void)
+{
+ WARN_ON(in_interrupt());
+
+ /* Only two bits of the extra_flags field in struct task_struct are
+ * used and it's an unsigned int. We hijack the most significant bits
+ * to be our counter structure. On RT kernels softirqs always run in
+ * process context so we are guaranteed to have a valid task_struct.
+ */
+
+#ifdef __LITTLE_ENDIAN
+ return (void *)(¤t->extra_flags + 1) -
+ sizeof(struct loop_counter);
+#elif __BIG_ENDIAN
+ return (struct loop_counter *)¤t->extra_flags;
+#else
+#error "Please fix <asm/byteorder.h>."
+#endif
+}
+
+void loop_put_counter(void) { }
+
+#endif /* CONFIG_PREEMPT_RT */
--- /dev/null
+/*
+ * Copyright (c) 2010 Nicira Networks.
+ * Distributed under the terms of the GNU GPL version 2.
+ *
+ * Significant portions of this file may be copied from parts of the Linux
+ * kernel, by Linus Torvalds and others.
+ */
+
+#ifndef LOOP_COUNTER_H
+#define LOOP_COUNTER_H 1
+
+#include "datapath.h"
+#include "flow.h"
+
+/* We limit the number of times that we pass into dp_process_received_packet()
+ * to avoid blowing out the stack in the event that we have a loop. */
+#define MAX_LOOPS 5
+
+struct loop_counter {
+ u8 count; /* Count. */
+ bool looping; /* Loop detected? */
+};
+
+struct loop_counter *loop_get_counter(void);
+void loop_put_counter(void);
+void loop_suppress(struct datapath *, struct sw_flow_actions *);
+
+#endif /* loop_counter.h */