diff options
Diffstat (limited to 'drivers/net/ipvlan/ipvlan_main.c')
-rw-r--r-- | drivers/net/ipvlan/ipvlan_main.c | 75 |
1 files changed, 51 insertions, 24 deletions
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index f195f278a83a..54c94a69c2bb 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -2,6 +2,8 @@ /* Copyright (c) 2014 Mahesh Bandewar <maheshb@google.com> */ +#include <linux/ethtool.h> + #include "ipvlan.h" static int ipvlan_set_port_mode(struct ipvl_port *port, u16 nval, @@ -98,20 +100,28 @@ static void ipvlan_port_destroy(struct net_device *dev) netdev_rx_handler_unregister(dev); cancel_work_sync(&port->wq); while ((skb = __skb_dequeue(&port->backlog)) != NULL) { - if (skb->dev) - dev_put(skb->dev); + dev_put(skb->dev); kfree_skb(skb); } ida_destroy(&port->ida); kfree(port); } +#define IPVLAN_ALWAYS_ON_OFLOADS \ + (NETIF_F_SG | NETIF_F_HW_CSUM | \ + NETIF_F_GSO_ROBUST | NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ENCAP_ALL) + +#define IPVLAN_ALWAYS_ON \ + (IPVLAN_ALWAYS_ON_OFLOADS | NETIF_F_LLTX | NETIF_F_VLAN_CHALLENGED) + #define IPVLAN_FEATURES \ - (NETIF_F_SG | NETIF_F_CSUM_MASK | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ + (NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ NETIF_F_GSO | NETIF_F_ALL_TSO | NETIF_F_GSO_ROBUST | \ NETIF_F_GRO | NETIF_F_RXCSUM | \ NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER) + /* NETIF_F_GSO_ENCAP_ALL NETIF_F_GSO_SOFTWARE Newly added */ + #define IPVLAN_STATE_MASK \ ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT)) @@ -125,12 +135,15 @@ static int ipvlan_init(struct net_device *dev) dev->state = (dev->state & ~IPVLAN_STATE_MASK) | (phy_dev->state & IPVLAN_STATE_MASK); dev->features = phy_dev->features & IPVLAN_FEATURES; - dev->features |= NETIF_F_LLTX | NETIF_F_VLAN_CHALLENGED; + dev->features |= IPVLAN_ALWAYS_ON; + dev->vlan_features = phy_dev->vlan_features & IPVLAN_FEATURES; + dev->vlan_features |= IPVLAN_ALWAYS_ON_OFLOADS; dev->hw_enc_features |= dev->features; - dev->gso_max_size = phy_dev->gso_max_size; - dev->gso_max_segs = phy_dev->gso_max_segs; + netif_inherit_tso_max(dev, phy_dev); dev->hard_header_len = phy_dev->hard_header_len; + netdev_lockdep_set_classes(dev); + ipvlan->pcpu_stats = netdev_alloc_pcpu_stats(struct ipvl_pcpu_stats); if (!ipvlan->pcpu_stats) return -ENOMEM; @@ -211,8 +224,8 @@ static netdev_tx_t ipvlan_start_xmit(struct sk_buff *skb, pcptr = this_cpu_ptr(ipvlan->pcpu_stats); u64_stats_update_begin(&pcptr->syncp); - pcptr->tx_pkts++; - pcptr->tx_bytes += skblen; + u64_stats_inc(&pcptr->tx_pkts); + u64_stats_add(&pcptr->tx_bytes, skblen); u64_stats_update_end(&pcptr->syncp); } else { this_cpu_inc(ipvlan->pcpu_stats->tx_drps); @@ -225,7 +238,14 @@ static netdev_features_t ipvlan_fix_features(struct net_device *dev, { struct ipvl_dev *ipvlan = netdev_priv(dev); - return features & (ipvlan->sfeatures | ~IPVLAN_FEATURES); + features |= NETIF_F_ALL_FOR_ALL; + features &= (ipvlan->sfeatures | ~IPVLAN_FEATURES); + features = netdev_increment_features(ipvlan->phy_dev->features, + features, features); + features |= IPVLAN_ALWAYS_ON; + features &= (IPVLAN_FEATURES | IPVLAN_ALWAYS_ON); + + return features; } static void ipvlan_change_rx_flags(struct net_device *dev, int change) @@ -280,11 +300,11 @@ static void ipvlan_get_stats64(struct net_device *dev, pcptr = per_cpu_ptr(ipvlan->pcpu_stats, idx); do { strt= u64_stats_fetch_begin_irq(&pcptr->syncp); - rx_pkts = pcptr->rx_pkts; - rx_bytes = pcptr->rx_bytes; - rx_mcast = pcptr->rx_mcast; - tx_pkts = pcptr->tx_pkts; - tx_bytes = pcptr->tx_bytes; + rx_pkts = u64_stats_read(&pcptr->rx_pkts); + rx_bytes = u64_stats_read(&pcptr->rx_bytes); + rx_mcast = u64_stats_read(&pcptr->rx_mcast); + tx_pkts = u64_stats_read(&pcptr->tx_pkts); + tx_bytes = u64_stats_read(&pcptr->tx_bytes); } while (u64_stats_fetch_retry_irq(&pcptr->syncp, strt)); @@ -295,8 +315,8 @@ static void ipvlan_get_stats64(struct net_device *dev, s->tx_bytes += tx_bytes; /* u32 values are updated without syncp protection. */ - rx_errs += pcptr->rx_errs; - tx_drps += pcptr->tx_drps; + rx_errs += READ_ONCE(pcptr->rx_errs); + tx_drps += READ_ONCE(pcptr->tx_drps); } s->rx_errors = rx_errs; s->rx_dropped = rx_errs; @@ -388,8 +408,8 @@ static int ipvlan_ethtool_get_link_ksettings(struct net_device *dev, static void ipvlan_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) { - strlcpy(drvinfo->driver, IPVLAN_DRV, sizeof(drvinfo->driver)); - strlcpy(drvinfo->version, IPV_DRV_VER, sizeof(drvinfo->version)); + strscpy(drvinfo->driver, IPVLAN_DRV, sizeof(drvinfo->driver)); + strscpy(drvinfo->version, IPV_DRV_VER, sizeof(drvinfo->version)); } static u32 ipvlan_ethtool_get_msglevel(struct net_device *dev) @@ -557,7 +577,7 @@ int ipvlan_link_new(struct net *src_net, struct net_device *dev, * world but keep using the physical-dev address for the outgoing * packets. */ - memcpy(dev->dev_addr, phy_dev->dev_addr, ETH_ALEN); + eth_hw_addr_set(dev, phy_dev->dev_addr); dev->priv_flags |= IFF_NO_RX_HANDLER; @@ -664,6 +684,13 @@ static const struct nla_policy ipvlan_nl_policy[IFLA_IPVLAN_MAX + 1] = [IFLA_IPVLAN_FLAGS] = { .type = NLA_U16 }, }; +static struct net *ipvlan_get_link_net(const struct net_device *dev) +{ + struct ipvl_dev *ipvlan = netdev_priv(dev); + + return dev_net(ipvlan->phy_dev); +} + static struct rtnl_link_ops ipvlan_link_ops = { .kind = "ipvlan", .priv_size = sizeof(struct ipvl_dev), @@ -671,6 +698,7 @@ static struct rtnl_link_ops ipvlan_link_ops = { .setup = ipvlan_link_setup, .newlink = ipvlan_link_new, .dellink = ipvlan_link_delete, + .get_link_net = ipvlan_get_link_net, }; int ipvlan_link_register(struct rtnl_link_ops *ops) @@ -702,6 +730,7 @@ static int ipvlan_device_event(struct notifier_block *unused, port = ipvlan_port_get_rtnl(dev); switch (event) { + case NETDEV_UP: case NETDEV_CHANGE: list_for_each_entry(ipvlan, &port->ipvlans, pnode) netif_stacked_transfer_operstate(ipvlan->phy_dev, @@ -732,10 +761,8 @@ static int ipvlan_device_event(struct notifier_block *unused, case NETDEV_FEAT_CHANGE: list_for_each_entry(ipvlan, &port->ipvlans, pnode) { - ipvlan->dev->features = dev->features & IPVLAN_FEATURES; - ipvlan->dev->gso_max_size = dev->gso_max_size; - ipvlan->dev->gso_max_segs = dev->gso_max_segs; - netdev_features_change(ipvlan->dev); + netif_inherit_tso_max(ipvlan->dev, dev); + netdev_update_features(ipvlan->dev); } break; @@ -757,7 +784,7 @@ static int ipvlan_device_event(struct notifier_block *unused, case NETDEV_CHANGEADDR: list_for_each_entry(ipvlan, &port->ipvlans, pnode) { - ether_addr_copy(ipvlan->dev->dev_addr, dev->dev_addr); + eth_hw_addr_set(ipvlan->dev, dev->dev_addr); call_netdevice_notifiers(NETDEV_CHANGEADDR, ipvlan->dev); } break; |