datapath: Encapsulate parameters for new vports in new struct vport_parms.
[openvswitch] / datapath / datapath.c
index aa563fb6d43cdca38b814cf63930b59b95f827e6..529d496913ec3c418f611530d729f5e24a7aeed3 100644 (file)
 #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"
 
 #include "compat.h"
 
-
 int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
 EXPORT_SYMBOL(dp_ioctl_hook);
 
@@ -69,23 +69,6 @@ EXPORT_SYMBOL(dp_ioctl_hook);
 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. */
@@ -373,13 +356,14 @@ static int new_dp_port(struct datapath *dp, struct odp_port *odp_port, int port_
 
        vport = vport_locate(odp_port->devname);
        if (!vport) {
-               vport_lock();
+               struct vport_parms parms;
 
-               if (odp_port->flags & ODP_PORT_INTERNAL)
-                       vport = vport_add(odp_port->devname, "internal", NULL);
-               else
-                       vport = vport_add(odp_port->devname, "netdev", NULL);
+               parms.name = odp_port->devname;
+               parms.type = odp_port->flags & ODP_PORT_INTERNAL ? "internal" : "netdev";
+               parms.config = NULL;
 
+               vport_lock();
+               vport = vport_add(&parms);
                vport_unlock();
 
                if (IS_ERR(vport))
@@ -526,14 +510,6 @@ out:
        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)
 {
@@ -581,28 +557,28 @@ 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;
        }
 
        /* Execute actions. */
        execute_actions(dp, skb, &OVS_CB(skb)->flow->key, acts->actions,
-                       acts->n_actions, GFP_ATOMIC);
+                       acts->n_actions);
        stats_counter_off = offsetof(struct dp_stats_percpu, n_hit);
 
        /* 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. */
@@ -904,6 +880,7 @@ static int validate_actions(const struct sw_flow_actions *actions)
 
        for (i = 0; i < actions->n_actions; i++) {
                const union odp_action *a = &actions->actions[i];
+
                switch (a->type) {
                case ODPAT_CONTROLLER:
                case ODPAT_STRIP_VLAN:
@@ -925,14 +902,8 @@ static int validate_actions(const struct sw_flow_actions *actions)
                                return -EINVAL;
                        break;
 
-               case ODPAT_SET_VLAN_VID:
-                       if (a->vlan_vid.vlan_vid & htons(~VLAN_VID_MASK))
-                               return -EINVAL;
-                       break;
-
-               case ODPAT_SET_VLAN_PCP:
-                       if (a->vlan_pcp.vlan_pcp
-                           & ~(VLAN_PCP_MASK >> VLAN_PCP_SHIFT))
+               case ODPAT_SET_DL_TCI:
+                       if (a->dl_tci.tci & htons(VLAN_CFI_MASK))
                                return -EINVAL;
                        break;
 
@@ -975,24 +946,15 @@ error:
        return ERR_PTR(error);
 }
 
-static struct timespec get_time_offset(void)
-{
-       struct timespec now_mono, now_jiffies;
-
-       ktime_get_ts(&now_mono);
-       jiffies_to_timespec(jiffies, &now_jiffies);
-       return timespec_sub(now_mono, now_jiffies);
-}
-
-static void get_stats(struct sw_flow *flow, struct odp_flow_stats *stats,
-                     struct timespec time_offset)
+static void get_stats(struct sw_flow *flow, struct odp_flow_stats *stats)
 {
        if (flow->used) {
-               struct timespec flow_ts, used;
+               struct timespec offset_ts, used, now_mono;
 
-               jiffies_to_timespec(flow->used, &flow_ts);
-               set_normalized_timespec(&used, flow_ts.tv_sec + time_offset.tv_sec,
-                                       flow_ts.tv_nsec + time_offset.tv_nsec);
+               ktime_get_ts(&now_mono);
+               jiffies_to_timespec(jiffies - flow->used, &offset_ts);
+               set_normalized_timespec(&used, now_mono.tv_sec - offset_ts.tv_sec,
+                                       now_mono.tv_nsec - offset_ts.tv_nsec);
 
                stats->used_sec = used.tv_sec;
                stats->used_nsec = used.tv_nsec;
@@ -1039,8 +1001,6 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf,
        struct tbl *table;
        int error;
 
-       memset(uf->flow.key.reserved, 0, sizeof uf->flow.key.reserved);
-
        table = rcu_dereference(dp->table);
        flow_node = tbl_lookup(table, &uf->flow.key, flow_hash(&uf->flow.key), flow_cmp);
        if (!flow_node) {
@@ -1109,7 +1069,7 @@ static int do_put_flow(struct datapath *dp, struct odp_flow_put *uf,
 
                /* Fetch stats, then clear them if necessary. */
                spin_lock_bh(&flow->lock);
-               get_stats(flow, stats, get_time_offset());
+               get_stats(flow, stats);
                if (uf->flags & ODPPF_ZERO_STATS)
                        clear_stats(flow);
                spin_unlock_bh(&flow->lock);
@@ -1147,7 +1107,6 @@ static int put_flow(struct datapath *dp, struct odp_flow_put __user *ufp)
 }
 
 static int do_answer_query(struct sw_flow *flow, u32 query_flags,
-                          struct timespec time_offset,
                           struct odp_flow_stats __user *ustats,
                           union odp_action __user *actions,
                           u32 __user *n_actionsp)
@@ -1157,7 +1116,7 @@ static int do_answer_query(struct sw_flow *flow, u32 query_flags,
        u32 n_actions;
 
        spin_lock_bh(&flow->lock);
-       get_stats(flow, &stats, time_offset);
+       get_stats(flow, &stats);
        if (query_flags & ODPFF_ZERO_TCP_FLAGS)
                flow->tcp_flags = 0;
 
@@ -1181,7 +1140,6 @@ static int do_answer_query(struct sw_flow *flow, u32 query_flags,
 }
 
 static int answer_query(struct sw_flow *flow, u32 query_flags,
-                       struct timespec time_offset,
                        struct odp_flow __user *ufp)
 {
        union odp_action *actions;
@@ -1189,7 +1147,7 @@ static int answer_query(struct sw_flow *flow, u32 query_flags,
        if (get_user(actions, &ufp->actions))
                return -EFAULT;
 
-       return do_answer_query(flow, query_flags, time_offset,
+       return do_answer_query(flow, query_flags, 
                               &ufp->stats, actions, &ufp->n_actions);
 }
 
@@ -1199,7 +1157,6 @@ static struct sw_flow *do_del_flow(struct datapath *dp, struct odp_flow_key *key
        struct tbl_node *flow_node;
        int error;
 
-       memset(key->reserved, 0, sizeof key->reserved);
        flow_node = tbl_lookup(table, key, flow_hash(key), flow_cmp);
        if (!flow_node)
                return ERR_PTR(-ENOENT);
@@ -1228,7 +1185,7 @@ static int del_flow(struct datapath *dp, struct odp_flow __user *ufp)
        if (IS_ERR(flow))
                return PTR_ERR(flow);
 
-       error = answer_query(flow, 0, get_time_offset(), ufp);
+       error = answer_query(flow, 0, ufp);
        flow_deferred_free(flow);
        return error;
 }
@@ -1236,11 +1193,8 @@ static int del_flow(struct datapath *dp, struct odp_flow __user *ufp)
 static int do_query_flows(struct datapath *dp, const struct odp_flowvec *flowvec)
 {
        struct tbl *table = rcu_dereference(dp->table);
-       struct timespec time_offset;
        u32 i;
 
-       time_offset = get_time_offset();
-
        for (i = 0; i < flowvec->n_flows; i++) {
                struct odp_flow __user *ufp = &flowvec->flows[i];
                struct odp_flow uf;
@@ -1249,13 +1203,12 @@ static int do_query_flows(struct datapath *dp, const struct odp_flowvec *flowvec
 
                if (copy_from_user(&uf, ufp, sizeof uf))
                        return -EFAULT;
-               memset(uf.key.reserved, 0, sizeof uf.key.reserved);
 
                flow_node = tbl_lookup(table, &uf.key, flow_hash(&uf.key), flow_cmp);
                if (!flow_node)
                        error = put_user(ENOENT, &ufp->stats.error);
                else
-                       error = answer_query(flow_cast(flow_node), uf.flags, time_offset, ufp);
+                       error = answer_query(flow_cast(flow_node), uf.flags, ufp);
                if (error)
                        return -EFAULT;
        }
@@ -1266,7 +1219,6 @@ struct list_flows_cbdata {
        struct odp_flow __user *uflows;
        u32 n_flows;
        u32 listed_flows;
-       struct timespec time_offset;
 };
 
 static int list_flow(struct tbl_node *node, void *cbdata_)
@@ -1278,7 +1230,7 @@ static int list_flow(struct tbl_node *node, void *cbdata_)
 
        if (copy_to_user(&ufp->key, &flow->key, sizeof flow->key))
                return -EFAULT;
-       error = answer_query(flow, 0, cbdata->time_offset, ufp);
+       error = answer_query(flow, 0, ufp);
        if (error)
                return error;
 
@@ -1298,7 +1250,6 @@ static int do_list_flows(struct datapath *dp, const struct odp_flowvec *flowvec)
        cbdata.uflows = flowvec->flows;
        cbdata.n_flows = flowvec->n_flows;
        cbdata.listed_flows = 0;
-       cbdata.time_offset = get_time_offset();
 
        error = tbl_foreach(rcu_dereference(dp->table), list_flow, &cbdata);
        return error ? error : cbdata.listed_flows;
@@ -1379,8 +1330,7 @@ static int do_execute(struct datapath *dp, const struct odp_execute *execute)
                goto error_free_skb;
 
        rcu_read_lock();
-       err = execute_actions(dp, skb, &key, actions->actions,
-                             actions->n_actions, GFP_KERNEL);
+       err = execute_actions(dp, skb, &key, actions->actions, actions->n_actions);
        rcu_read_unlock();
 
        kfree(actions);
@@ -1805,7 +1755,6 @@ static int compat_put_flow(struct datapath *dp, struct compat_odp_flow_put __use
 }
 
 static int compat_answer_query(struct sw_flow *flow, u32 query_flags,
-                              struct timespec time_offset,
                               struct compat_odp_flow __user *ufp)
 {
        compat_uptr_t actions;
@@ -1813,7 +1762,7 @@ static int compat_answer_query(struct sw_flow *flow, u32 query_flags,
        if (get_user(actions, &ufp->actions))
                return -EFAULT;
 
-       return do_answer_query(flow, query_flags, time_offset, &ufp->stats,
+       return do_answer_query(flow, query_flags, &ufp->stats,
                               compat_ptr(actions), &ufp->n_actions);
 }
 
@@ -1830,7 +1779,7 @@ static int compat_del_flow(struct datapath *dp, struct compat_odp_flow __user *u
        if (IS_ERR(flow))
                return PTR_ERR(flow);
 
-       error = compat_answer_query(flow, 0, get_time_offset(), ufp);
+       error = compat_answer_query(flow, 0, ufp);
        flow_deferred_free(flow);
        return error;
 }
@@ -1838,11 +1787,8 @@ static int compat_del_flow(struct datapath *dp, struct compat_odp_flow __user *u
 static int compat_query_flows(struct datapath *dp, struct compat_odp_flow *flows, u32 n_flows)
 {
        struct tbl *table = rcu_dereference(dp->table);
-       struct timespec time_offset;
        u32 i;
 
-       time_offset = get_time_offset();
-
        for (i = 0; i < n_flows; i++) {
                struct compat_odp_flow __user *ufp = &flows[i];
                struct odp_flow uf;
@@ -1851,13 +1797,12 @@ static int compat_query_flows(struct datapath *dp, struct compat_odp_flow *flows
 
                if (compat_get_flow(&uf, ufp))
                        return -EFAULT;
-               memset(uf.key.reserved, 0, sizeof uf.key.reserved);
 
                flow_node = tbl_lookup(table, &uf.key, flow_hash(&uf.key), flow_cmp);
                if (!flow_node)
                        error = put_user(ENOENT, &ufp->stats.error);
                else
-                       error = compat_answer_query(flow_cast(flow_node), uf.flags, time_offset, ufp);
+                       error = compat_answer_query(flow_cast(flow_node), uf.flags, ufp);
                if (error)
                        return -EFAULT;
        }
@@ -1868,7 +1813,6 @@ struct compat_list_flows_cbdata {
        struct compat_odp_flow __user *uflows;
        u32 n_flows;
        u32 listed_flows;
-       struct timespec time_offset;
 };
 
 static int compat_list_flow(struct tbl_node *node, void *cbdata_)
@@ -1880,7 +1824,7 @@ static int compat_list_flow(struct tbl_node *node, void *cbdata_)
 
        if (copy_to_user(&ufp->key, &flow->key, sizeof flow->key))
                return -EFAULT;
-       error = compat_answer_query(flow, 0, cbdata->time_offset, ufp);
+       error = compat_answer_query(flow, 0, ufp);
        if (error)
                return error;
 
@@ -1900,7 +1844,6 @@ static int compat_list_flows(struct datapath *dp, struct compat_odp_flow *flows,
        cbdata.uflows = flows;
        cbdata.n_flows = n_flows;
        cbdata.listed_flows = 0;
-       cbdata.time_offset = get_time_offset();
 
        error = tbl_foreach(rcu_dereference(dp->table), compat_list_flow, &cbdata);
        return error ? error : cbdata.listed_flows;