Commit 8d9dbce4 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'automatically-manage-dsa-master-interface-state'

Vladimir Oltean says:

====================
Automatically manage DSA master interface state

This patch series adds code that makes DSA open the master interface
automatically whenever one user interface gets opened, either by the
user, or by various networking subsystems: netconsole, nfsroot.
With that in place, we can remove some of the places in the network
stack where DSA-specific code was sprinkled.
====================

Link: https://lore.kernel.org/r/20210205133713.4172846-1-vladimir.oltean@nxp.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 78936acc 46acf7bd
......@@ -273,10 +273,6 @@ will not make us go through the switch tagging protocol transmit function, so
the Ethernet switch on the other end, expecting a tag will typically drop this
frame.
Slave network devices check that the master network device is UP before allowing
you to administratively bring UP these slave network devices. A common
configuration mistake is forgetting to bring UP the master network device first.
Interactions with other subsystems
==================================
......
......@@ -29,7 +29,6 @@
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/if_vlan.h>
#include <net/dsa.h>
#include <net/tcp.h>
#include <net/udp.h>
#include <net/addrconf.h>
......@@ -658,15 +657,15 @@ EXPORT_SYMBOL_GPL(__netpoll_setup);
int netpoll_setup(struct netpoll *np)
{
struct net_device *ndev = NULL, *dev = NULL;
struct net *net = current->nsproxy->net_ns;
struct net_device *ndev = NULL;
struct in_device *in_dev;
int err;
rtnl_lock();
if (np->dev_name[0])
if (np->dev_name[0]) {
struct net *net = current->nsproxy->net_ns;
ndev = __dev_get_by_name(net, np->dev_name);
}
if (!ndev) {
np_err(np, "%s doesn't exist, aborting\n", np->dev_name);
err = -ENODEV;
......@@ -674,19 +673,6 @@ int netpoll_setup(struct netpoll *np)
}
dev_hold(ndev);
/* bring up DSA management network devices up first */
for_each_netdev(net, dev) {
if (!netdev_uses_dsa(dev))
continue;
err = dev_change_flags(dev, dev->flags | IFF_UP, NULL);
if (err < 0) {
np_err(np, "%s failed to open %s\n",
np->dev_name, dev->name);
goto put;
}
}
if (netdev_master_upper_dev_get(ndev)) {
np_err(np, "%s is a slave device, aborting\n", np->dev_name);
err = -EBUSY;
......
......@@ -68,8 +68,11 @@ static int dsa_slave_open(struct net_device *dev)
struct dsa_port *dp = dsa_slave_to_port(dev);
int err;
if (!(master->flags & IFF_UP))
return -ENETDOWN;
err = dev_open(master, NULL);
if (err < 0) {
netdev_err(dev, "failed to open master %s\n", master->name);
goto out;
}
if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) {
err = dev_uc_add(master, dev->dev_addr);
......@@ -2078,6 +2081,30 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
err = dsa_port_lag_change(dp, info->lower_state_info);
return notifier_from_errno(err);
}
case NETDEV_GOING_DOWN: {
struct dsa_port *dp, *cpu_dp;
struct dsa_switch_tree *dst;
LIST_HEAD(close_list);
if (!netdev_uses_dsa(dev))
return NOTIFY_DONE;
cpu_dp = dev->dsa_ptr;
dst = cpu_dp->ds->dst;
list_for_each_entry(dp, &dst->ports, list) {
if (!dsa_is_user_port(dp->ds, dp->index))
continue;
list_add(&dp->slave->close_list, &close_list);
}
dev_close_many(&close_list, true);
return NOTIFY_OK;
}
default:
break;
}
return NOTIFY_DONE;
......
......@@ -61,7 +61,6 @@
#include <linux/export.h>
#include <net/net_namespace.h>
#include <net/arp.h>
#include <net/dsa.h>
#include <net/ip.h>
#include <net/ipconfig.h>
#include <net/route.h>
......@@ -218,9 +217,9 @@ static int __init ic_open_devs(void)
last = &ic_first_dev;
rtnl_lock();
/* bring loopback and DSA master network devices up first */
/* bring loopback device up first */
for_each_netdev(&init_net, dev) {
if (!(dev->flags & IFF_LOOPBACK) && !netdev_uses_dsa(dev))
if (!(dev->flags & IFF_LOOPBACK))
continue;
if (dev_change_flags(dev, dev->flags | IFF_UP, NULL) < 0)
pr_err("IP-Config: Failed to open %s\n", dev->name);
......@@ -305,6 +304,9 @@ static int __init ic_open_devs(void)
return 0;
}
/* Close all network interfaces except the one we've autoconfigured, and its
* lowers, in case it's a stacked virtual interface.
*/
static void __init ic_close_devs(void)
{
struct ic_device *d, *next;
......@@ -313,9 +315,20 @@ static void __init ic_close_devs(void)
rtnl_lock();
next = ic_first_dev;
while ((d = next)) {
bool bring_down = (d != ic_dev);
struct net_device *lower_dev;
struct list_head *iter;
next = d->next;
dev = d->dev;
if (d != ic_dev && !netdev_uses_dsa(dev)) {
netdev_for_each_lower_dev(ic_dev->dev, lower_dev, iter) {
if (dev == lower_dev) {
bring_down = false;
break;
}
}
if (bring_down) {
pr_debug("IP-Config: Downing %s\n", dev->name);
dev_change_flags(dev, d->flags, NULL);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment