On Wed,  3 Feb 2021 18:08:21 +0200 Vladimir Oltean wrote:
> From: Vladimir Oltean <vladimir.olt...@nxp.com>
> 
> This is not fixing any actual bug that I know of, but having a DSA
> interface that is up even when its lower (master) interface is down is
> one of those things that just do not sound right.
> 
> Yes, DSA checks if the master is up before actually bringing the
> user interface up, but nobody prevents bringing the master interface
> down immediately afterwards... Then the user ports would attempt
> dev_queue_xmit on an interface that is down, and wonder what's wrong.
> 
> This patch prevents that from happening. NETDEV_GOING_DOWN is the
> notification emitted _before_ the master actually goes down, and we are
> protected by the rtnl_mutex, so all is well.
> 
> $ ip link set eno2 down
> [  763.672211] mscc_felix 0000:00:00.5 swp0: Link is Down
> [  763.880137] mscc_felix 0000:00:00.5 swp1: Link is Down
> [  764.078773] mscc_felix 0000:00:00.5 swp2: Link is Down
> [  764.197106] mscc_felix 0000:00:00.5 swp3: Link is Down
> [  764.299384] fsl_enetc 0000:00:00.2 eno2: Link is Down
> 
> For those of you reading this because you were doing switch testing
> such as latency measurements for autonomously forwarded traffic, and you
> needed a controlled environment with no extra packets sent by the
> network stack, this patch breaks that, because now the user ports go
> down too, which may shut down the PHY etc. But please don't do it like
> that, just do instead:
> 
> tc qdisc add dev eno2 clsact
> tc filter add dev eno2 egress flower action drop
> 
> Signed-off-by: Vladimir Oltean <vladimir.olt...@nxp.com>
> Reviewed-by: Andrew Lunn <and...@lunn.ch>
> Reviewed-by: Florian Fainelli <f.faine...@gmail.com>
> ---
> Changes in v2:
> Fix typo: !dsa_is_user_port -> dsa_is_user_port.
> 
>  net/dsa/slave.c | 30 ++++++++++++++++++++++++++++++
>  1 file changed, 30 insertions(+)
> 
> diff --git a/net/dsa/slave.c b/net/dsa/slave.c
> index 4616bd7c8684..aa7bd223073c 100644
> --- a/net/dsa/slave.c
> +++ b/net/dsa/slave.c
> @@ -2084,6 +2084,36 @@ 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;
> +             int err = 0;
> +
> +             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)) {
> +                             struct net_device *slave = dp->slave;
> +
> +                             if (!(slave->flags & IFF_UP))
> +                                     continue;
> +
> +                             err = dev_change_flags(slave,
> +                                                    slave->flags & ~IFF_UP,
> +                                                    NULL);
> +                             if (err)
> +                                     break;
> +                     }
> +             }

Perhaps:

                LIST_HEAD(close_list);

                list_for_each_entry(dp, &dst->ports, list)
                        list_add(&slave->close_list, &close_list);

                dev_close_many(&close_list, true);

                return NOTIFY_OK;

But we can keep as is if you prefer.

> +             return notifier_from_errno(err);
> +     }
> +     default:
> +             break;
>       }
>  
>       return NOTIFY_DONE;

Reply via email to