--- zzzz-none-000/linux-3.10.107/drivers/net/veth.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/net/veth.c 2021-02-04 17:41:59.000000000 +0000 @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -149,10 +150,10 @@ unsigned int start; do { - start = u64_stats_fetch_begin_bh(&stats->syncp); + start = u64_stats_fetch_begin_irq(&stats->syncp); packets = stats->packets; bytes = stats->bytes; - } while (u64_stats_fetch_retry_bh(&stats->syncp, start)); + } while (u64_stats_fetch_retry_irq(&stats->syncp, start)); result->packets += packets; result->bytes += bytes; } @@ -182,6 +183,11 @@ return tot; } +/* fake multicast ability */ +static void veth_set_multicast_list(struct net_device *dev) +{ +} + static int veth_open(struct net_device *dev) { struct veth_priv *priv = netdev_priv(dev); @@ -224,10 +230,9 @@ static int veth_dev_init(struct net_device *dev) { - dev->vstats = alloc_percpu(struct pcpu_vstats); + dev->vstats = netdev_alloc_pcpu_stats(struct pcpu_vstats); if (!dev->vstats) return -ENOMEM; - return 0; } @@ -237,6 +242,35 @@ free_netdev(dev); } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void veth_poll_controller(struct net_device *dev) +{ + /* veth only receives frames when its peer sends one + * Since it's a synchronous operation, we are guaranteed + * never to have pending data when we poll for it so + * there is nothing to do here. + * + * We need this though so netpoll recognizes us as an interface that + * supports polling, which enables bridge devices in virt setups to + * still use netconsole + */ +} +#endif /* CONFIG_NET_POLL_CONTROLLER */ + +static int veth_get_iflink(const struct net_device *dev) +{ + struct veth_priv *priv = netdev_priv(dev); + struct net_device *peer; + int iflink; + + rcu_read_lock(); + peer = rcu_dereference(priv->peer); + iflink = peer ? peer->ifindex : 0; + rcu_read_unlock(); + + return iflink; +} + static const struct net_device_ops veth_netdev_ops = { .ndo_init = veth_dev_init, .ndo_open = veth_open, @@ -244,11 +278,19 @@ .ndo_start_xmit = veth_xmit, .ndo_change_mtu = veth_change_mtu, .ndo_get_stats64 = veth_get_stats64, + .ndo_set_rx_mode = veth_set_multicast_list, .ndo_set_mac_address = eth_mac_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = veth_poll_controller, +#endif + .ndo_get_iflink = veth_get_iflink, + .ndo_features_check = passthru_features_check, }; #define VETH_FEATURES (NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \ NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_HIGHDMA | \ + NETIF_F_GSO_GRE | NETIF_F_GSO_UDP_TUNNEL | \ + NETIF_F_GSO_IPIP | NETIF_F_GSO_SIT | NETIF_F_UFO | \ NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | \ NETIF_F_HW_VLAN_STAG_TX | NETIF_F_HW_VLAN_STAG_RX ) @@ -258,14 +300,21 @@ dev->priv_flags &= ~IFF_TX_SKB_SHARING; dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + dev->priv_flags |= IFF_NO_QUEUE; dev->netdev_ops = &veth_netdev_ops; dev->ethtool_ops = &veth_ethtool_ops; dev->features |= NETIF_F_LLTX; dev->features |= VETH_FEATURES; + dev->vlan_features = dev->features & + ~(NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_STAG_TX | + NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_HW_VLAN_STAG_RX); dev->destructor = veth_dev_free; dev->hw_features = VETH_FEATURES; + dev->hw_enc_features = VETH_FEATURES; } /* @@ -297,6 +346,7 @@ struct veth_priv *priv; char ifname[IFNAMSIZ]; struct nlattr *peer_tb[IFLA_MAX + 1], **tbp; + unsigned char name_assign_type; struct ifinfomsg *ifmp; struct net *net; @@ -308,10 +358,9 @@ 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), - ifla_policy); + err = rtnl_nla_parse_ifla(peer_tb, + nla_data(nla_peer) + sizeof(struct ifinfomsg), + nla_len(nla_peer) - sizeof(struct ifinfomsg)); if (err < 0) return err; @@ -325,16 +374,20 @@ tbp = tb; } - if (tbp[IFLA_IFNAME]) + if (tbp[IFLA_IFNAME]) { nla_strlcpy(ifname, tbp[IFLA_IFNAME], IFNAMSIZ); - else + name_assign_type = NET_NAME_USER; + } else { snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); + name_assign_type = NET_NAME_ENUM; + } net = rtnl_link_get_net(src_net, tbp); if (IS_ERR(net)) return PTR_ERR(net); - peer = rtnl_create_link(net, ifname, &veth_link_ops, tbp); + peer = rtnl_create_link(net, ifname, name_assign_type, + &veth_link_ops, tbp); if (IS_ERR(peer)) { put_net(net); return PTR_ERR(peer); @@ -373,12 +426,6 @@ else snprintf(dev->name, IFNAMSIZ, DRV_NAME "%%d"); - if (strchr(dev->name, '%')) { - err = dev_alloc_name(dev, dev->name); - if (err < 0) - goto err_alloc_name; - } - err = register_netdevice(dev); if (err < 0) goto err_register_dev; @@ -398,7 +445,6 @@ err_register_dev: /* nothing to do */ -err_alloc_name: err_configure_peer: unregister_netdevice(peer); return err; @@ -434,6 +480,14 @@ [VETH_INFO_PEER] = { .len = sizeof(struct ifinfomsg) }, }; +static struct net *veth_get_link_net(const struct net_device *dev) +{ + struct veth_priv *priv = netdev_priv(dev); + struct net_device *peer = rtnl_dereference(priv->peer); + + return peer ? dev_net(peer) : dev_net(dev); +} + static struct rtnl_link_ops veth_link_ops = { .kind = DRV_NAME, .priv_size = sizeof(struct veth_priv), @@ -443,6 +497,7 @@ .dellink = veth_dellink, .policy = veth_policy, .maxtype = VETH_INFO_MAX, + .get_link_net = veth_get_link_net, }; /*