diff --git a/Documentation/networking/dsa/dsa.rst b/Documentation/networking/dsa/dsa.rst index a8d15dd2b42b72eef0f9cbe55b7f431033b1be2a..e9517af5fe02ebcf5fdb3f86153930955e77d9bf 100644 --- a/Documentation/networking/dsa/dsa.rst +++ b/Documentation/networking/dsa/dsa.rst @@ -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 ================================== diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 960948290001eed4d07a8d20327e9158659adc45..c310c7c1cef7f21538d248926aab6303cecf68b0 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -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; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index b0571ab4e5a755cdce7cd7c4477d4ca7ff866309..f77e9eeb1a620cf0cb4ee5185ae8d8b474e93e97 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -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; diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 3cd13e1bc6a7009255a3aea0cf668c0142ae0022..f9ab1fb219ec73f861e707651896aeca56fcc4c1 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -61,7 +61,6 @@ #include #include #include -#include #include #include #include @@ -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); }