aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/team
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/team')
-rw-r--r--drivers/net/team/Kconfig12
-rw-r--r--drivers/net/team/team.c92
-rw-r--r--drivers/net/team/team_mode_loadbalance.c2
3 files changed, 65 insertions, 41 deletions
diff --git a/drivers/net/team/Kconfig b/drivers/net/team/Kconfig
index 2aa9fd7b57df..4d449845dac7 100644
--- a/drivers/net/team/Kconfig
+++ b/drivers/net/team/Kconfig
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
menuconfig NET_TEAM
tristate "Ethernet team driver support"
- ---help---
+ help
This allows one to create virtual interfaces that teams together
multiple ethernet devices.
@@ -18,7 +18,7 @@ if NET_TEAM
config NET_TEAM_MODE_BROADCAST
tristate "Broadcast mode support"
depends on NET_TEAM
- ---help---
+ help
Basic mode where packets are transmitted always by all suitable ports.
All added ports are setup to have team's device address.
@@ -29,7 +29,7 @@ config NET_TEAM_MODE_BROADCAST
config NET_TEAM_MODE_ROUNDROBIN
tristate "Round-robin mode support"
depends on NET_TEAM
- ---help---
+ help
Basic mode where port used for transmitting packets is selected in
round-robin fashion using packet counter.
@@ -41,7 +41,7 @@ config NET_TEAM_MODE_ROUNDROBIN
config NET_TEAM_MODE_RANDOM
tristate "Random mode support"
depends on NET_TEAM
- ---help---
+ help
Basic mode where port used for transmitting packets is selected
randomly.
@@ -53,7 +53,7 @@ config NET_TEAM_MODE_RANDOM
config NET_TEAM_MODE_ACTIVEBACKUP
tristate "Active-backup mode support"
depends on NET_TEAM
- ---help---
+ help
Only one port is active at a time and the rest of ports are used
for backup.
@@ -66,7 +66,7 @@ config NET_TEAM_MODE_ACTIVEBACKUP
config NET_TEAM_MODE_LOADBALANCE
tristate "Load-balance mode support"
depends on NET_TEAM
- ---help---
+ help
This mode provides load balancing functionality. Tx port selection
is done using BPF function set up from userspace (bpf_hash_func
option)
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 4004f98e50d9..62ade69295a9 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -4,6 +4,7 @@
* Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
*/
+#include <linux/ethtool.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
@@ -287,7 +288,7 @@ inst_rollback:
for (i--; i >= 0; i--)
__team_option_inst_del_option(team, dst_opts[i]);
- i = option_count - 1;
+ i = option_count;
alloc_rollback:
for (i--; i >= 0; i--)
kfree(dst_opts[i]);
@@ -468,6 +469,9 @@ static const struct team_mode *team_mode_get(const char *kind)
struct team_mode_item *mitem;
const struct team_mode *mode = NULL;
+ if (!try_module_get(THIS_MODULE))
+ return NULL;
+
spin_lock(&mode_list_lock);
mitem = __find_mode(kind);
if (!mitem) {
@@ -483,6 +487,7 @@ static const struct team_mode *team_mode_get(const char *kind)
}
spin_unlock(&mode_list_lock);
+ module_put(THIS_MODULE);
return mode;
}
@@ -729,6 +734,11 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
port = team_port_get_rcu(skb->dev);
team = port->team;
if (!team_port_enabled(port)) {
+ if (is_link_local_ether_addr(eth_hdr(skb)->h_dest))
+ /* link-local packets are mostly useful when stack receives them
+ * with the link they arrive on.
+ */
+ return RX_HANDLER_PASS;
/* allow exact match delivery for disabled ports */
res = RX_HANDLER_EXACT;
} else {
@@ -739,10 +749,10 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
pcpu_stats = this_cpu_ptr(team->pcpu_stats);
u64_stats_update_begin(&pcpu_stats->syncp);
- pcpu_stats->rx_packets++;
- pcpu_stats->rx_bytes += skb->len;
+ u64_stats_inc(&pcpu_stats->rx_packets);
+ u64_stats_add(&pcpu_stats->rx_bytes, skb->len);
if (skb->pkt_type == PACKET_MULTICAST)
- pcpu_stats->rx_multicast++;
+ u64_stats_inc(&pcpu_stats->rx_multicast);
u64_stats_update_end(&pcpu_stats->syncp);
skb->dev = team->dev;
@@ -971,11 +981,11 @@ static void team_port_disable(struct team *team,
}
#define TEAM_VLAN_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
- NETIF_F_FRAGLIST | NETIF_F_ALL_TSO | \
+ NETIF_F_FRAGLIST | NETIF_F_GSO_SOFTWARE | \
NETIF_F_HIGHDMA | NETIF_F_LRO)
#define TEAM_ENC_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | \
- NETIF_F_RXCSUM | NETIF_F_ALL_TSO)
+ NETIF_F_RXCSUM | NETIF_F_GSO_SOFTWARE)
static void __team_compute_features(struct team *team)
{
@@ -987,7 +997,8 @@ static void __team_compute_features(struct team *team)
unsigned int dst_release_flag = IFF_XMIT_DST_RELEASE |
IFF_XMIT_DST_RELEASE_PERM;
- list_for_each_entry(port, &team->port_list, list) {
+ rcu_read_lock();
+ list_for_each_entry_rcu(port, &team->port_list, list) {
vlan_features = netdev_increment_features(vlan_features,
port->dev->vlan_features,
TEAM_VLAN_FEATURES);
@@ -1001,12 +1012,12 @@ static void __team_compute_features(struct team *team)
if (port->dev->hard_header_len > max_hard_header_len)
max_hard_header_len = port->dev->hard_header_len;
}
+ rcu_read_unlock();
team->dev->vlan_features = vlan_features;
team->dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL |
NETIF_F_HW_VLAN_CTAG_TX |
- NETIF_F_HW_VLAN_STAG_TX |
- NETIF_F_GSO_UDP_L4;
+ NETIF_F_HW_VLAN_STAG_TX;
team->dev->hard_header_len = max_hard_header_len;
team->dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
@@ -1016,9 +1027,7 @@ static void __team_compute_features(struct team *team)
static void team_compute_features(struct team *team)
{
- mutex_lock(&team->lock);
__team_compute_features(team);
- mutex_unlock(&team->lock);
netdev_change_features(team->dev);
}
@@ -1266,10 +1275,12 @@ static int team_port_add(struct team *team, struct net_device *port_dev,
}
}
- netif_addr_lock_bh(dev);
- dev_uc_sync_multiple(port_dev, dev);
- dev_mc_sync_multiple(port_dev, dev);
- netif_addr_unlock_bh(dev);
+ if (dev->flags & IFF_UP) {
+ netif_addr_lock_bh(dev);
+ dev_uc_sync_multiple(port_dev, dev);
+ dev_mc_sync_multiple(port_dev, dev);
+ netif_addr_unlock_bh(dev);
+ }
port->index = -1;
list_add_tail_rcu(&port->list, &team->port_list);
@@ -1340,8 +1351,10 @@ static int team_port_del(struct team *team, struct net_device *port_dev)
netdev_rx_handler_unregister(port_dev);
team_port_disable_netpoll(port);
vlan_vids_del_by_dev(port_dev, dev);
- dev_uc_unsync(port_dev, dev);
- dev_mc_unsync(port_dev, dev);
+ if (dev->flags & IFF_UP) {
+ dev_uc_unsync(port_dev, dev);
+ dev_mc_unsync(port_dev, dev);
+ }
dev_close(port_dev);
team_port_leave(team, port);
@@ -1643,6 +1656,7 @@ static int team_init(struct net_device *dev)
lockdep_register_key(&team->team_lock_key);
__mutex_init(&team->lock, "team->team_lock_key", &team->team_lock_key);
+ netdev_lockdep_set_classes(dev);
return 0;
@@ -1690,6 +1704,14 @@ static int team_open(struct net_device *dev)
static int team_close(struct net_device *dev)
{
+ struct team *team = netdev_priv(dev);
+ struct team_port *port;
+
+ list_for_each_entry(port, &team->port_list, list) {
+ dev_uc_unsync(port->dev, dev);
+ dev_mc_unsync(port->dev, dev);
+ }
+
return 0;
}
@@ -1710,8 +1732,8 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
pcpu_stats = this_cpu_ptr(team->pcpu_stats);
u64_stats_update_begin(&pcpu_stats->syncp);
- pcpu_stats->tx_packets++;
- pcpu_stats->tx_bytes += len;
+ u64_stats_inc(&pcpu_stats->tx_packets);
+ u64_stats_add(&pcpu_stats->tx_bytes, len);
u64_stats_update_end(&pcpu_stats->syncp);
} else {
this_cpu_inc(team->pcpu_stats->tx_dropped);
@@ -1785,7 +1807,7 @@ static int team_set_mac_address(struct net_device *dev, void *p)
if (dev->type == ARPHRD_ETHER && !is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
- memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ dev_addr_set(dev, addr->sa_data);
mutex_lock(&team->lock);
list_for_each_entry(port, &team->port_list, list)
if (team->ops.port_change_dev_addr)
@@ -1844,11 +1866,11 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
p = per_cpu_ptr(team->pcpu_stats, i);
do {
start = u64_stats_fetch_begin_irq(&p->syncp);
- rx_packets = p->rx_packets;
- rx_bytes = p->rx_bytes;
- rx_multicast = p->rx_multicast;
- tx_packets = p->tx_packets;
- tx_bytes = p->tx_bytes;
+ rx_packets = u64_stats_read(&p->rx_packets);
+ rx_bytes = u64_stats_read(&p->rx_bytes);
+ rx_multicast = u64_stats_read(&p->rx_multicast);
+ tx_packets = u64_stats_read(&p->tx_packets);
+ tx_bytes = u64_stats_read(&p->tx_bytes);
} while (u64_stats_fetch_retry_irq(&p->syncp, start));
stats->rx_packets += rx_packets;
@@ -1860,9 +1882,9 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
* rx_dropped, tx_dropped & rx_nohandler are u32,
* updated without syncp protection.
*/
- rx_dropped += p->rx_dropped;
- tx_dropped += p->tx_dropped;
- rx_nohandler += p->rx_nohandler;
+ rx_dropped += READ_ONCE(p->rx_dropped);
+ tx_dropped += READ_ONCE(p->tx_dropped);
+ rx_nohandler += READ_ONCE(p->rx_nohandler);
}
stats->rx_dropped = rx_dropped;
stats->tx_dropped = tx_dropped;
@@ -2060,8 +2082,8 @@ static const struct net_device_ops team_netdev_ops = {
static void team_ethtool_get_drvinfo(struct net_device *dev,
struct ethtool_drvinfo *drvinfo)
{
- strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
- strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
+ strscpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+ strscpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
}
static int team_ethtool_get_link_ksettings(struct net_device *dev,
@@ -2107,6 +2129,7 @@ static void team_setup_by_port(struct net_device *dev,
dev->header_ops = port_dev->header_ops;
dev->type = port_dev->type;
dev->hard_header_len = port_dev->hard_header_len;
+ dev->needed_headroom = port_dev->needed_headroom;
dev->addr_len = port_dev->addr_len;
dev->mtu = port_dev->mtu;
memcpy(dev->broadcast, port_dev->broadcast, port_dev->addr_len);
@@ -2169,7 +2192,7 @@ static void team_setup(struct net_device *dev)
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_FILTER;
- dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4;
+ dev->hw_features |= NETIF_F_GSO_ENCAP_ALL;
dev->features |= dev->hw_features;
dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX;
}
@@ -2790,7 +2813,7 @@ static int team_nl_cmd_port_list_get(struct sk_buff *skb,
return err;
}
-static const struct genl_ops team_nl_ops[] = {
+static const struct genl_small_ops team_nl_ops[] = {
{
.cmd = TEAM_CMD_NOOP,
.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
@@ -2827,8 +2850,9 @@ static struct genl_family team_nl_family __ro_after_init = {
.policy = team_nl_policy,
.netnsok = true,
.module = THIS_MODULE,
- .ops = team_nl_ops,
- .n_ops = ARRAY_SIZE(team_nl_ops),
+ .small_ops = team_nl_ops,
+ .n_small_ops = ARRAY_SIZE(team_nl_ops),
+ .resv_start_op = TEAM_CMD_PORT_LIST_GET + 1,
.mcgrps = team_nl_mcgrps,
.n_mcgrps = ARRAY_SIZE(team_nl_mcgrps),
};
diff --git a/drivers/net/team/team_mode_loadbalance.c b/drivers/net/team/team_mode_loadbalance.c
index 32aef8ac4a14..b095a4b4957b 100644
--- a/drivers/net/team/team_mode_loadbalance.c
+++ b/drivers/net/team/team_mode_loadbalance.c
@@ -197,7 +197,7 @@ static unsigned int lb_get_skb_hash(struct lb_priv *lb_priv,
fp = rcu_dereference_bh(lb_priv->fp);
if (unlikely(!fp))
return 0;
- lhash = BPF_PROG_RUN(fp, skb);
+ lhash = bpf_prog_run(fp, skb);
c = (char *) &lhash;
return c[0] ^ c[1] ^ c[2] ^ c[3];
}