*/
#include <linux/netdevice.h>
+#include <linux/slab.h>
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
struct veth_priv {
struct net_device *peer;
- struct veth_net_stats *stats;
+ struct veth_net_stats __percpu *stats;
unsigned ip_summed;
};
struct net_device *rcv = NULL;
struct veth_priv *priv, *rcv_priv;
struct veth_net_stats *stats, *rcv_stats;
- int length, cpu;
+ int length;
priv = netdev_priv(dev);
rcv = priv->peer;
rcv_priv = netdev_priv(rcv);
- cpu = smp_processor_id();
- stats = per_cpu_ptr(priv->stats, cpu);
- rcv_stats = per_cpu_ptr(rcv_priv->stats, cpu);
+ stats = this_cpu_ptr(priv->stats);
+ rcv_stats = this_cpu_ptr(rcv_priv->stats);
if (!(rcv->flags & IFF_UP))
goto tx_drop;
static struct net_device_stats *veth_get_stats(struct net_device *dev)
{
struct veth_priv *priv;
- struct net_device_stats *dev_stats;
int cpu;
- struct veth_net_stats *stats;
+ struct veth_net_stats *stats, total = {0};
priv = netdev_priv(dev);
- dev_stats = &dev->stats;
- dev_stats->rx_packets = 0;
- dev_stats->tx_packets = 0;
- dev_stats->rx_bytes = 0;
- dev_stats->tx_bytes = 0;
- dev_stats->tx_dropped = 0;
- dev_stats->rx_dropped = 0;
-
- for_each_online_cpu(cpu) {
+ for_each_possible_cpu(cpu) {
stats = per_cpu_ptr(priv->stats, cpu);
- dev_stats->rx_packets += stats->rx_packets;
- dev_stats->tx_packets += stats->tx_packets;
- dev_stats->rx_bytes += stats->rx_bytes;
- dev_stats->tx_bytes += stats->tx_bytes;
- dev_stats->tx_dropped += stats->tx_dropped;
- dev_stats->rx_dropped += stats->rx_dropped;
+ total.rx_packets += stats->rx_packets;
+ total.tx_packets += stats->tx_packets;
+ total.rx_bytes += stats->rx_bytes;
+ total.tx_bytes += stats->tx_bytes;
+ total.tx_dropped += stats->tx_dropped;
+ total.rx_dropped += stats->rx_dropped;
}
-
- return dev_stats;
+ dev->stats.rx_packets = total.rx_packets;
+ dev->stats.tx_packets = total.tx_packets;
+ dev->stats.rx_bytes = total.rx_bytes;
+ dev->stats.tx_bytes = total.tx_bytes;
+ dev->stats.tx_dropped = total.tx_dropped;
+ dev->stats.rx_dropped = total.rx_dropped;
+
+ return &dev->stats;
}
static int veth_open(struct net_device *dev)
static int veth_dev_init(struct net_device *dev)
{
- struct veth_net_stats *stats;
+ struct veth_net_stats __percpu *stats;
struct veth_priv *priv;
stats = alloc_percpu(struct veth_net_stats);
struct veth_priv *priv;
char ifname[IFNAMSIZ];
struct nlattr *peer_tb[IFLA_MAX + 1], **tbp;
+ struct ifinfomsg *ifmp;
struct net *net;
/*
* create and register peer first
- *
- * struct ifinfomsg is at the head of VETH_INFO_PEER, but we
- * skip it since no info from it is useful yet
*/
-
if (data != NULL && data[VETH_INFO_PEER] != NULL) {
struct nlattr *nla_peer;
nla_peer = data[VETH_INFO_PEER];
+ ifmp = nla_data(nla_peer);
err = nla_parse(peer_tb, IFLA_MAX,
nla_data(nla_peer) + sizeof(struct ifinfomsg),
nla_len(nla_peer) - sizeof(struct ifinfomsg),
return err;
tbp = peer_tb;
- } else
+ } else {
+ ifmp = NULL;
tbp = tb;
+ }
if (tbp[IFLA_IFNAME])
nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ);
netif_carrier_off(peer);
+ err = rtnl_configure_link(peer, ifmp);
+ if (err < 0)
+ goto err_configure_peer;
+
/*
* register dev last
*
err_register_dev:
/* nothing to do */
err_alloc_name:
+err_configure_peer:
unregister_netdevice(peer);
return err;