bridge: Allow specially named "unix:" controllers.
[openvswitch] / datapath / actions.c
index 36437a4baa4fee411a116cd2f578af0885b864bc..a28e98662db314b23486b48d1f321c1b1a7f1aed 100644 (file)
@@ -8,9 +8,12 @@
 
 /* Functions for executing flow actions. */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/skbuff.h>
 #include <linux/in.h>
 #include <linux/ip.h>
+#include <linux/openvswitch.h>
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <linux/in6.h>
@@ -23,8 +26,6 @@
 #include "actions.h"
 #include "checksum.h"
 #include "datapath.h"
-#include "loop_counter.h"
-#include "openvswitch/datapath-protocol.h"
 #include "vlan.h"
 #include "vport.h"
 
@@ -244,13 +245,31 @@ static int do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
        return 0;
 }
 
-static int output_userspace(struct datapath *dp, struct sk_buff *skb, u64 arg)
+static int output_userspace(struct datapath *dp, struct sk_buff *skb,
+                           const struct nlattr *attr)
 {
        struct dp_upcall_info upcall;
+       const struct nlattr *a;
+       int rem;
 
        upcall.cmd = OVS_PACKET_CMD_ACTION;
        upcall.key = &OVS_CB(skb)->flow->key;
-       upcall.userdata = arg;
+       upcall.userdata = NULL;
+       upcall.pid = 0;
+
+       for (a = nla_data(attr), rem = nla_len(attr); rem > 0;
+                a = nla_next(a, &rem)) {
+               switch (nla_type(a)) {
+               case OVS_USERSPACE_ATTR_USERDATA:
+                       upcall.userdata = a;
+                       break;
+
+               case OVS_USERSPACE_ATTR_PID:
+                       upcall.pid = nla_get_u32(a);
+                       break;
+               }
+       }
+
        return dp_upcall(dp, skb, &upcall);
 }
 
@@ -307,7 +326,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
                        break;
 
                case OVS_ACTION_ATTR_USERSPACE:
-                       output_userspace(dp, skb, nla_get_u64(a));
+                       output_userspace(dp, skb, a);
                        break;
 
                case OVS_ACTION_ATTR_SET_TUNNEL:
@@ -380,6 +399,26 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
        return 0;
 }
 
+/* We limit the number of times that we pass into execute_actions()
+ * 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? */
+};
+
+static DEFINE_PER_CPU(struct loop_counter, loop_counters);
+
+static int 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->actions_len = 0;
+       return -ELOOP;
+}
+
 /* Execute a list of actions against 'skb'. */
 int execute_actions(struct datapath *dp, struct sk_buff *skb)
 {
@@ -388,7 +427,7 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb)
        int error;
 
        /* Check whether we've looped too much. */
-       loop = loop_get_counter();
+       loop = &__get_cpu_var(loop_counters);
        if (unlikely(++loop->count > MAX_LOOPS))
                loop->looping = true;
        if (unlikely(loop->looping)) {
@@ -409,7 +448,6 @@ out_loop:
        /* Decrement loop counter. */
        if (!--loop->count)
                loop->looping = false;
-       loop_put_counter();
 
        return error;
 }