datapath: Fix few mpls issues.
[cascardo/ovs.git] / datapath / flow_netlink.c
index 37b0bdd..0649d2c 100644 (file)
@@ -18,9 +18,6 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include "flow.h"
-#include "datapath.h"
-#include "mpls.h"
 #include <linux/uaccess.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/rculist.h>
 #include <net/geneve.h>
 #include <net/ip.h>
-#include <net/ip_tunnels.h>
 #include <net/ipv6.h>
 #include <net/ndisc.h>
+#include <net/mpls.h>
 
+#include "datapath.h"
+#include "flow.h"
 #include "flow_netlink.h"
 
 static void update_range(struct sw_flow_match *match,
@@ -1665,6 +1664,9 @@ static int validate_set(const struct nlattr *a,
                break;
 
        case OVS_KEY_ATTR_TUNNEL:
+               if (eth_p_mpls(eth_type))
+                       return -EINVAL;
+
                *set_tun = true;
                err = validate_and_copy_set_tun(a, sfa, log);
                if (err)
@@ -1778,6 +1780,7 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr,
                                  __be16 eth_type, __be16 vlan_tci, bool log)
 {
        const struct nlattr *a;
+       bool out_tnl_port = false;
        int rem, err;
 
        if (depth >= SAMPLE_ACTION_DEPTH)
@@ -1820,6 +1823,7 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr,
                case OVS_ACTION_ATTR_OUTPUT:
                        if (nla_get_u32(a) >= DP_MAX_PORTS)
                                return -EINVAL;
+                       out_tnl_port = false;
                        break;
 
                case OVS_ACTION_ATTR_HASH: {
@@ -1854,6 +1858,12 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr,
                case OVS_ACTION_ATTR_PUSH_MPLS: {
                        const struct ovs_action_push_mpls *mpls = nla_data(a);
 
+                       /* Networking stack do not allow simultaneous Tunnel
+                        * and MPLS GSO.
+                        */
+                       if (out_tnl_port)
+                               return -EINVAL;
+
                        if (!eth_p_mpls(mpls->mpls_ethertype))
                                return -EINVAL;
                        /* Prohibit push MPLS other than to a white list
@@ -1888,10 +1898,11 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr,
                        break;
 
                case OVS_ACTION_ATTR_SET:
-                       err = validate_set(a, key, sfa, &skip_copy, eth_type,
-                                          log);
+                       err = validate_set(a, key, sfa,
+                                          &out_tnl_port, eth_type, log);
                        if (err)
                                return err;
+                       skip_copy = out_tnl_port;
                        break;
 
                case OVS_ACTION_ATTR_SAMPLE: