proc-net-compat: Stub out on non-Linux.
[openvswitch] / datapath / vport-internal_dev.c
index 6d52db0f3881dd86ecdd547479d9998c6009c68a..d8e57fef85daa122ed9645219e3c8b0ef9fcf7a9 100644 (file)
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/percpu.h>
-#include <linux/preempt.h>
 #include <linux/rcupdate.h>
 #include <linux/skbuff.h>
-#include <linux/workqueue.h>
 
 #include "datapath.h"
+#include "openvswitch/internal_dev.h"
+#include "vport-generic.h"
 #include "vport-internal_dev.h"
 #include "vport-netdev.h"
 
@@ -32,6 +32,12 @@ struct internal_dev {
 
        struct net_device_stats stats;
        struct pcpu_lstats *lstats;
+
+       /* This is warty support for XAPI, which does not support summing bond
+        * device statistics itself.  'extra_stats' can be set by userspace via
+        * the DP_DEV_SET_STATS ioctl and, if they are, then they are added to
+        * the real device stats. */
+       struct pcpu_lstats extra_stats;
 };
 
 struct vport_ops internal_vport_ops;
@@ -48,7 +54,10 @@ static struct net_device_stats *internal_dev_get_stats(struct net_device *netdev
        int i;
 
        stats = &internal_dev->stats;
-       memset(stats, 0, sizeof(struct net_device_stats));
+       stats->rx_bytes = internal_dev->extra_stats.rx_bytes;
+       stats->rx_packets = internal_dev->extra_stats.rx_packets;
+       stats->tx_bytes = internal_dev->extra_stats.tx_bytes;
+       stats->tx_packets = internal_dev->extra_stats.tx_packets;
        for_each_possible_cpu(i) {
                const struct pcpu_lstats *lb_stats;
 
@@ -71,8 +80,7 @@ static int internal_dev_mac_addr(struct net_device *dev, void *p)
        return 0;
 }
 
-/* Not reentrant (because it is called with BHs disabled), but may be called
- * simultaneously on different CPUs. */
+/* Called with rcu_read_lock and bottom-halves disabled. */
 static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        struct internal_dev *internal_dev = internal_dev_priv(netdev);
@@ -89,9 +97,9 @@ static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev)
        lb_stats->tx_bytes += skb->len;
 
        skb_reset_mac_header(skb);
-       rcu_read_lock_bh();
+       compute_ip_summed(skb, true);
+
        vport_receive(vport, skb);
-       rcu_read_unlock_bh();
 
        return 0;
 }
@@ -119,11 +127,14 @@ static void internal_dev_getinfo(struct net_device *netdev,
 }
 
 static struct ethtool_ops internal_dev_ethtool_ops = {
-       .get_drvinfo = internal_dev_getinfo,
-       .get_link = ethtool_op_get_link,
-       .get_sg = ethtool_op_get_sg,
-       .get_tx_csum = ethtool_op_get_tx_csum,
-       .get_tso = ethtool_op_get_tso,
+       .get_drvinfo    = internal_dev_getinfo,
+       .get_link       = ethtool_op_get_link,
+       .get_sg         = ethtool_op_get_sg,
+       .set_sg         = ethtool_op_set_sg,
+       .get_tx_csum    = ethtool_op_get_tx_csum,
+       .set_tx_csum    = ethtool_op_set_tx_hw_csum,
+       .get_tso        = ethtool_op_get_tso,
+       .set_tso        = ethtool_op_set_tso,
 };
 
 static int internal_dev_change_mtu(struct net_device *netdev, int new_mtu)
@@ -134,13 +145,7 @@ static int internal_dev_change_mtu(struct net_device *netdev, int new_mtu)
                return -EINVAL;
 
        if (dp_port) {
-               int min_mtu;
-
-               mutex_lock(&dp_port->dp->mutex);
-               min_mtu = dp_min_mtu(dp_port->dp);
-               mutex_unlock(&dp_port->dp->mutex);
-
-               if (new_mtu > min_mtu)
+               if (new_mtu > dp_min_mtu(dp_port->dp))
                        return -EINVAL;
        }
 
@@ -169,6 +174,22 @@ static void internal_dev_free(struct net_device *netdev)
 
 static int internal_dev_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
+       struct internal_dev *internal_dev = internal_dev_priv(dev);
+
+       if (cmd == INTERNAL_DEV_SET_STATS) {
+               struct internal_dev_stats stats;
+
+               if (copy_from_user(&stats, ifr->ifr_data, sizeof(stats)))
+                       return -EFAULT;
+
+               internal_dev->extra_stats.rx_bytes = stats.rx_bytes;
+               internal_dev->extra_stats.rx_packets = stats.rx_packets;
+               internal_dev->extra_stats.tx_bytes = stats.tx_bytes;
+               internal_dev->extra_stats.tx_packets = stats.tx_packets;
+
+               return 0;
+       }
+
        if (dp_ioctl_hook)
                return dp_ioctl_hook(dev, ifr, cmd);
        return -EOPNOTSUPP;
@@ -210,9 +231,10 @@ do_setup(struct net_device *netdev)
        netdev->tx_queue_len = 0;
 
        netdev->flags = IFF_BROADCAST | IFF_MULTICAST;
-       netdev->features = NETIF_F_LLTX; /* XXX other features? */
+       netdev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_HIGHDMA
+                               | NETIF_F_HW_CSUM | NETIF_F_TSO;
 
-       vport_gen_ether_addr(netdev->dev_addr);
+       vport_gen_rand_ether_addr(netdev->dev_addr);
 }
 
 static struct vport *
@@ -314,11 +336,11 @@ internal_dev_recv(struct vport *vport, struct sk_buff *skb)
                netif_rx_ni(skb);
        netdev->last_rx = jiffies;
 
-       preempt_disable();
+       local_bh_disable();
        lb_stats = per_cpu_ptr(internal_dev->lstats, smp_processor_id());
        lb_stats->rx_packets++;
        lb_stats->rx_bytes += len;
-       preempt_enable();
+       local_bh_enable();
 
        return len;
 }