hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/drivers/net/team/team.c
....@@ -1,11 +1,7 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * drivers/net/team/team.c - Network team device driver
34 * Copyright (c) 2011 Jiri Pirko <jpirko@redhat.com>
4
- *
5
- * This program is free software; you can redistribute it and/or modify
6
- * it under the terms of the GNU General Public License as published by
7
- * the Free Software Foundation; either version 2 of the License, or
8
- * (at your option) any later version.
95 */
106
117 #include <linux/kernel.h>
....@@ -28,7 +24,6 @@
2824 #include <net/genetlink.h>
2925 #include <net/netlink.h>
3026 #include <net/sch_generic.h>
31
-#include <net/switchdev.h>
3227 #include <generated/utsrelease.h>
3328 #include <linux/if_team.h>
3429
....@@ -39,13 +34,11 @@
3934 * Helpers
4035 **********/
4136
42
-#define team_port_exists(dev) (dev->priv_flags & IFF_TEAM_PORT)
43
-
4437 static struct team_port *team_port_get_rtnl(const struct net_device *dev)
4538 {
4639 struct team_port *port = rtnl_dereference(dev->rx_handler_data);
4740
48
- return team_port_exists(dev) ? port : NULL;
41
+ return netif_is_team_port(dev) ? port : NULL;
4942 }
5043
5144 /*
....@@ -59,7 +52,7 @@
5952
6053 memcpy(addr.__data, dev_addr, port_dev->addr_len);
6154 addr.ss_family = port_dev->type;
62
- return dev_set_mac_address(port_dev, (struct sockaddr *)&addr);
55
+ return dev_set_mac_address(port_dev, (struct sockaddr *)&addr, NULL);
6356 }
6457
6558 static int team_port_set_orig_dev_addr(struct team_port *port)
....@@ -1097,10 +1090,7 @@
10971090 return;
10981091 port->np = NULL;
10991092
1100
- /* Wait for transmitting packets to finish before freeing. */
1101
- synchronize_rcu_bh();
1102
- __netpoll_cleanup(np);
1103
- kfree(np);
1093
+ __netpoll_free(np);
11041094 }
11051095 #else
11061096 static int team_port_enable_netpoll(struct team_port *port)
....@@ -1153,7 +1143,7 @@
11531143 return -EINVAL;
11541144 }
11551145
1156
- if (team_port_exists(port_dev)) {
1146
+ if (netif_is_team_port(port_dev)) {
11571147 NL_SET_ERR_MSG(extack, "Device is already a port of a team device");
11581148 netdev_err(dev, "Device %s is already a port "
11591149 "of a team device\n", portname);
....@@ -1217,7 +1207,7 @@
12171207 goto err_port_enter;
12181208 }
12191209
1220
- err = dev_open(port_dev);
1210
+ err = dev_open(port_dev, extack);
12211211 if (err) {
12221212 netdev_dbg(dev, "Device %s opening failed\n",
12231213 portname);
....@@ -1280,10 +1270,12 @@
12801270 }
12811271 }
12821272
1283
- netif_addr_lock_bh(dev);
1284
- dev_uc_sync_multiple(port_dev, dev);
1285
- dev_mc_sync_multiple(port_dev, dev);
1286
- netif_addr_unlock_bh(dev);
1273
+ if (dev->flags & IFF_UP) {
1274
+ netif_addr_lock_bh(dev);
1275
+ dev_uc_sync_multiple(port_dev, dev);
1276
+ dev_mc_sync_multiple(port_dev, dev);
1277
+ netif_addr_unlock_bh(dev);
1278
+ }
12871279
12881280 port->index = -1;
12891281 list_add_tail_rcu(&port->list, &team->port_list);
....@@ -1354,8 +1346,10 @@
13541346 netdev_rx_handler_unregister(port_dev);
13551347 team_port_disable_netpoll(port);
13561348 vlan_vids_del_by_dev(port_dev, dev);
1357
- dev_uc_unsync(port_dev, dev);
1358
- dev_mc_unsync(port_dev, dev);
1349
+ if (dev->flags & IFF_UP) {
1350
+ dev_uc_unsync(port_dev, dev);
1351
+ dev_mc_unsync(port_dev, dev);
1352
+ }
13591353 dev_close(port_dev);
13601354 team_port_leave(team, port);
13611355
....@@ -1629,8 +1623,8 @@
16291623 int err;
16301624
16311625 team->dev = dev;
1632
- mutex_init(&team->lock);
16331626 team_set_no_mode(team);
1627
+ team->notifier_ctx = false;
16341628
16351629 team->pcpu_stats = netdev_alloc_pcpu_stats(struct team_pcpu_stats);
16361630 if (!team->pcpu_stats)
....@@ -1656,6 +1650,8 @@
16561650 goto err_options_register;
16571651 netif_carrier_off(dev);
16581652
1653
+ lockdep_register_key(&team->team_lock_key);
1654
+ __mutex_init(&team->lock, "team->team_lock_key", &team->team_lock_key);
16591655 netdev_lockdep_set_classes(dev);
16601656
16611657 return 0;
....@@ -1687,6 +1683,7 @@
16871683 team_queue_override_fini(team);
16881684 mutex_unlock(&team->lock);
16891685 netdev_change_features(dev);
1686
+ lockdep_unregister_key(&team->team_lock_key);
16901687 }
16911688
16921689 static void team_destructor(struct net_device *dev)
....@@ -1703,6 +1700,14 @@
17031700
17041701 static int team_close(struct net_device *dev)
17051702 {
1703
+ struct team *team = netdev_priv(dev);
1704
+ struct team_port *port;
1705
+
1706
+ list_for_each_entry(port, &team->port_list, list) {
1707
+ dev_uc_unsync(port->dev, dev);
1708
+ dev_mc_unsync(port->dev, dev);
1709
+ }
1710
+
17061711 return 0;
17071712 }
17081713
....@@ -1734,8 +1739,7 @@
17341739 }
17351740
17361741 static u16 team_select_queue(struct net_device *dev, struct sk_buff *skb,
1737
- struct net_device *sb_dev,
1738
- select_queue_fallback_t fallback)
1742
+ struct net_device *sb_dev)
17391743 {
17401744 /*
17411745 * This helper function exists to help dev_pick_tx get the correct
....@@ -1991,8 +1995,15 @@
19911995 err = team_port_del(team, port_dev);
19921996 mutex_unlock(&team->lock);
19931997
1994
- if (!err)
1995
- netdev_change_features(dev);
1998
+ if (err)
1999
+ return err;
2000
+
2001
+ if (netif_is_team_master(port_dev)) {
2002
+ lockdep_unregister_key(&team->team_lock_key);
2003
+ lockdep_register_key(&team->team_lock_key);
2004
+ lockdep_set_class(&team->lock, &team->team_lock_key);
2005
+ }
2006
+ netdev_change_features(dev);
19962007
19972008 return err;
19982009 }
....@@ -2071,9 +2082,37 @@
20712082 strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
20722083 }
20732084
2085
+static int team_ethtool_get_link_ksettings(struct net_device *dev,
2086
+ struct ethtool_link_ksettings *cmd)
2087
+{
2088
+ struct team *team= netdev_priv(dev);
2089
+ unsigned long speed = 0;
2090
+ struct team_port *port;
2091
+
2092
+ cmd->base.duplex = DUPLEX_UNKNOWN;
2093
+ cmd->base.port = PORT_OTHER;
2094
+
2095
+ rcu_read_lock();
2096
+ list_for_each_entry_rcu(port, &team->port_list, list) {
2097
+ if (team_port_txable(port)) {
2098
+ if (port->state.speed != SPEED_UNKNOWN)
2099
+ speed += port->state.speed;
2100
+ if (cmd->base.duplex == DUPLEX_UNKNOWN &&
2101
+ port->state.duplex != DUPLEX_UNKNOWN)
2102
+ cmd->base.duplex = port->state.duplex;
2103
+ }
2104
+ }
2105
+ rcu_read_unlock();
2106
+
2107
+ cmd->base.speed = speed ? : SPEED_UNKNOWN;
2108
+
2109
+ return 0;
2110
+}
2111
+
20742112 static const struct ethtool_ops team_ethtool_ops = {
20752113 .get_drvinfo = team_ethtool_get_drvinfo,
20762114 .get_link = ethtool_op_get_link,
2115
+ .get_link_ksettings = team_ethtool_get_link_ksettings,
20772116 };
20782117
20792118 /***********************
....@@ -2083,7 +2122,12 @@
20832122 static void team_setup_by_port(struct net_device *dev,
20842123 struct net_device *port_dev)
20852124 {
2086
- dev->header_ops = port_dev->header_ops;
2125
+ struct team *team = netdev_priv(dev);
2126
+
2127
+ if (port_dev->type == ARPHRD_ETHER)
2128
+ dev->header_ops = team->header_ops_cache;
2129
+ else
2130
+ dev->header_ops = port_dev->header_ops;
20872131 dev->type = port_dev->type;
20882132 dev->hard_header_len = port_dev->hard_header_len;
20892133 dev->needed_headroom = port_dev->needed_headroom;
....@@ -2091,6 +2135,15 @@
20912135 dev->mtu = port_dev->mtu;
20922136 memcpy(dev->broadcast, port_dev->broadcast, port_dev->addr_len);
20932137 eth_hw_addr_inherit(dev, port_dev);
2138
+
2139
+ if (port_dev->flags & IFF_POINTOPOINT) {
2140
+ dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
2141
+ dev->flags |= (IFF_POINTOPOINT | IFF_NOARP);
2142
+ } else if ((port_dev->flags & (IFF_BROADCAST | IFF_MULTICAST)) ==
2143
+ (IFF_BROADCAST | IFF_MULTICAST)) {
2144
+ dev->flags |= (IFF_BROADCAST | IFF_MULTICAST);
2145
+ dev->flags &= ~(IFF_POINTOPOINT | IFF_NOARP);
2146
+ }
20942147 }
20952148
20962149 static int team_dev_type_check_change(struct net_device *dev,
....@@ -2121,8 +2174,11 @@
21212174
21222175 static void team_setup(struct net_device *dev)
21232176 {
2177
+ struct team *team = netdev_priv(dev);
2178
+
21242179 ether_setup(dev);
21252180 dev->max_mtu = ETH_MAX_MTU;
2181
+ team->header_ops_cache = dev->header_ops;
21262182
21272183 dev->netdev_ops = &team_netdev_ops;
21282184 dev->ethtool_ops = &team_ethtool_ops;
....@@ -2147,7 +2203,9 @@
21472203
21482204 dev->hw_features = TEAM_VLAN_FEATURES |
21492205 NETIF_F_HW_VLAN_CTAG_RX |
2150
- NETIF_F_HW_VLAN_CTAG_FILTER;
2206
+ NETIF_F_HW_VLAN_CTAG_FILTER |
2207
+ NETIF_F_HW_VLAN_STAG_RX |
2208
+ NETIF_F_HW_VLAN_STAG_FILTER;
21512209
21522210 dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4;
21532211 dev->features |= dev->hw_features;
....@@ -2306,7 +2364,7 @@
23062364 if (err)
23072365 return err;
23082366
2309
- option_item = nla_nest_start(skb, TEAM_ATTR_ITEM_OPTION);
2367
+ option_item = nla_nest_start_noflag(skb, TEAM_ATTR_ITEM_OPTION);
23102368 if (!option_item)
23112369 return -EMSGSIZE;
23122370
....@@ -2420,7 +2478,7 @@
24202478
24212479 if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex))
24222480 goto nla_put_failure;
2423
- option_list = nla_nest_start(skb, TEAM_ATTR_LIST_OPTION);
2481
+ option_list = nla_nest_start_noflag(skb, TEAM_ATTR_LIST_OPTION);
24242482 if (!option_list)
24252483 goto nla_put_failure;
24262484
....@@ -2526,9 +2584,11 @@
25262584 err = -EINVAL;
25272585 goto team_put;
25282586 }
2529
- err = nla_parse_nested(opt_attrs, TEAM_ATTR_OPTION_MAX,
2530
- nl_option, team_nl_option_policy,
2531
- info->extack);
2587
+ err = nla_parse_nested_deprecated(opt_attrs,
2588
+ TEAM_ATTR_OPTION_MAX,
2589
+ nl_option,
2590
+ team_nl_option_policy,
2591
+ info->extack);
25322592 if (err)
25332593 goto team_put;
25342594 if (!opt_attrs[TEAM_ATTR_OPTION_NAME] ||
....@@ -2642,7 +2702,7 @@
26422702 {
26432703 struct nlattr *port_item;
26442704
2645
- port_item = nla_nest_start(skb, TEAM_ATTR_ITEM_PORT);
2705
+ port_item = nla_nest_start_noflag(skb, TEAM_ATTR_ITEM_PORT);
26462706 if (!port_item)
26472707 goto nest_cancel;
26482708 if (nla_put_u32(skb, TEAM_ATTR_PORT_IFINDEX, port->dev->ifindex))
....@@ -2697,7 +2757,7 @@
26972757
26982758 if (nla_put_u32(skb, TEAM_ATTR_TEAM_IFINDEX, team->dev->ifindex))
26992759 goto nla_put_failure;
2700
- port_list = nla_nest_start(skb, TEAM_ATTR_LIST_PORT);
2760
+ port_list = nla_nest_start_noflag(skb, TEAM_ATTR_LIST_PORT);
27012761 if (!port_list)
27022762 goto nla_put_failure;
27032763
....@@ -2768,28 +2828,28 @@
27682828 return err;
27692829 }
27702830
2771
-static const struct genl_ops team_nl_ops[] = {
2831
+static const struct genl_small_ops team_nl_ops[] = {
27722832 {
27732833 .cmd = TEAM_CMD_NOOP,
2834
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
27742835 .doit = team_nl_cmd_noop,
2775
- .policy = team_nl_policy,
27762836 },
27772837 {
27782838 .cmd = TEAM_CMD_OPTIONS_SET,
2839
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
27792840 .doit = team_nl_cmd_options_set,
2780
- .policy = team_nl_policy,
27812841 .flags = GENL_ADMIN_PERM,
27822842 },
27832843 {
27842844 .cmd = TEAM_CMD_OPTIONS_GET,
2845
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
27852846 .doit = team_nl_cmd_options_get,
2786
- .policy = team_nl_policy,
27872847 .flags = GENL_ADMIN_PERM,
27882848 },
27892849 {
27902850 .cmd = TEAM_CMD_PORT_LIST_GET,
2851
+ .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
27912852 .doit = team_nl_cmd_port_list_get,
2792
- .policy = team_nl_policy,
27932853 .flags = GENL_ADMIN_PERM,
27942854 },
27952855 };
....@@ -2802,10 +2862,11 @@
28022862 .name = TEAM_GENL_NAME,
28032863 .version = TEAM_GENL_VERSION,
28042864 .maxattr = TEAM_ATTR_MAX,
2865
+ .policy = team_nl_policy,
28052866 .netnsok = true,
28062867 .module = THIS_MODULE,
2807
- .ops = team_nl_ops,
2808
- .n_ops = ARRAY_SIZE(team_nl_ops),
2868
+ .small_ops = team_nl_ops,
2869
+ .n_small_ops = ARRAY_SIZE(team_nl_ops),
28092870 .mcgrps = team_nl_mcgrps,
28102871 .n_mcgrps = ARRAY_SIZE(team_nl_mcgrps),
28112872 };
....@@ -2975,7 +3036,11 @@
29753036 team_del_slave(port->team->dev, dev);
29763037 break;
29773038 case NETDEV_FEAT_CHANGE:
2978
- team_compute_features(port->team);
3039
+ if (!port->team->notifier_ctx) {
3040
+ port->team->notifier_ctx = true;
3041
+ team_compute_features(port->team);
3042
+ port->team->notifier_ctx = false;
3043
+ }
29793044 break;
29803045 case NETDEV_PRECHANGEMTU:
29813046 /* Forbid to change mtu of underlaying device */