mlx5: count all link events

mlx5 devices were observed generating MLX5_PORT_CHANGE_SUBTYPE_ACTIVE
events without an intervening MLX5_PORT_CHANGE_SUBTYPE_DOWN. This
breaks link flap detection based on Linux carrier state transition
count as netif_carrier_on() does nothing if carrier is already on.
Make sure we count such events.

netif_carrier_event() increments the counters and fires the linkwatch
events. The latter is not necessary for the use case but seems like
the right thing to do.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
This commit is contained in:
Jakub Kicinski 2021-05-19 10:18:25 -07:00 committed by Saeed Mahameed
parent 270d47dc1f
commit 490dcecabb
3 changed files with 24 additions and 2 deletions

View File

@ -91,12 +91,16 @@ void mlx5e_update_carrier(struct mlx5e_priv *priv)
{ {
struct mlx5_core_dev *mdev = priv->mdev; struct mlx5_core_dev *mdev = priv->mdev;
u8 port_state; u8 port_state;
bool up;
port_state = mlx5_query_vport_state(mdev, port_state = mlx5_query_vport_state(mdev,
MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT, MLX5_VPORT_STATE_OP_MOD_VNIC_VPORT,
0); 0);
if (port_state == VPORT_STATE_UP) { up = port_state == VPORT_STATE_UP;
if (up == netif_carrier_ok(priv->netdev))
netif_carrier_event(priv->netdev);
if (up) {
netdev_info(priv->netdev, "Link up\n"); netdev_info(priv->netdev, "Link up\n");
netif_carrier_on(priv->netdev); netif_carrier_on(priv->netdev);
} else { } else {

View File

@ -4187,8 +4187,8 @@ unsigned long dev_trans_start(struct net_device *dev);
void __netdev_watchdog_up(struct net_device *dev); void __netdev_watchdog_up(struct net_device *dev);
void netif_carrier_on(struct net_device *dev); void netif_carrier_on(struct net_device *dev);
void netif_carrier_off(struct net_device *dev); void netif_carrier_off(struct net_device *dev);
void netif_carrier_event(struct net_device *dev);
/** /**
* netif_dormant_on - mark device as dormant. * netif_dormant_on - mark device as dormant.

View File

@ -540,6 +540,24 @@ void netif_carrier_off(struct net_device *dev)
} }
EXPORT_SYMBOL(netif_carrier_off); EXPORT_SYMBOL(netif_carrier_off);
/**
* netif_carrier_event - report carrier state event
* @dev: network device
*
* Device has detected a carrier event but the carrier state wasn't changed.
* Use in drivers when querying carrier state asynchronously, to avoid missing
* events (link flaps) if link recovers before it's queried.
*/
void netif_carrier_event(struct net_device *dev)
{
if (dev->reg_state == NETREG_UNINITIALIZED)
return;
atomic_inc(&dev->carrier_up_count);
atomic_inc(&dev->carrier_down_count);
linkwatch_fire_event(dev);
}
EXPORT_SYMBOL_GPL(netif_carrier_event);
/* "NOOP" scheduler: the best scheduler, recommended for all interfaces /* "NOOP" scheduler: the best scheduler, recommended for all interfaces
under all circumstances. It is difficult to invent anything faster or under all circumstances. It is difficult to invent anything faster or
cheaper. cheaper.