struct mlx5e_rep_bond_metadata { struct list_head list; /* link to global list of rep_bond_metadata */ struct mlx5_eswitch *esw; /* private of uplink holding rep bond metadata list */ struct net_device *lag_dev;
u32 metadata_reg_c_0;
struct list_head slaves_list; /* slaves list */ int slaves;
};
/* This must be called under rtnl_lock */ int mlx5e_rep_bond_enslave(struct mlx5_eswitch *esw, struct net_device *netdev, struct net_device *lag_dev)
{ struct mlx5e_rep_bond_slave_entry *s_entry; struct mlx5e_rep_bond_metadata *mdata; struct mlx5e_rep_priv *rpriv; struct mlx5e_priv *priv; int err;
ASSERT_RTNL();
rpriv = mlx5_eswitch_get_uplink_priv(esw, REP_ETH);
mdata = mlx5e_lookup_rep_bond_metadata(&rpriv->uplink_priv, lag_dev); if (!mdata) { /* First netdev becomes slave, no metadata presents the lag_dev. Create one */
mdata = kzalloc(sizeof(*mdata), GFP_KERNEL); if (!mdata) return -ENOMEM;
s_entry = mlx5e_lookup_rep_bond_slave_entry(mdata, netdev); if (!s_entry) return;
priv = netdev_priv(netdev);
rpriv = priv->ppriv;
/* Reset bond_metadata to zero first then reset all ingress/egress * acls and rx rules of unslave representor's vport
*/
mlx5_esw_acl_ingress_vport_metadata_update(esw, rpriv->rep->vport, 0);
mlx5_esw_acl_egress_vport_unbond(esw, rpriv->rep->vport);
mlx5e_rep_bond_update(priv, false);
netdev_dbg(netdev, "lag_dev(%s)'s slave vport(%d) is txable(%d)\n",
lag_dev->name, fwd_vport_num, net_lag_port_dev_txable(netdev));
/* Point everyone's egress acl to the vport of the active representor */
netdev_for_each_lower_dev(lag_dev, dev, iter) {
priv = netdev_priv(dev);
rpriv = priv->ppriv;
acl_vport_num = rpriv->rep->vport; if (acl_vport_num != fwd_vport_num) { /* Only single rx_rule for unique bond_metadata should be * present, delete it if it's saved as passive vport's * rx_rule with destination as passive vport's root_ft
*/
mlx5e_rep_bond_update(priv, true);
err = mlx5_esw_acl_egress_vport_bond(priv->mdev->priv.eswitch,
fwd_vport_num,
acl_vport_num); if (err)
netdev_warn(dev, "configure slave vport(%d) egress fwd, err(%d)",
acl_vport_num, err);
}
}
/* Insert new rx_rule for unique bond_metadata, save it as active vport's * rx_rule with new destination as active vport's root_ft
*/
err = mlx5e_rep_bond_update(netdev_priv(netdev), false); if (err)
netdev_warn(netdev, "configure active slave vport(%d) rx_rule, err(%d)",
fwd_vport_num, err);
}
if (info->linking)
mlx5e_rep_bond_enslave(priv->mdev->priv.eswitch, netdev, lag_dev); else
mlx5e_rep_bond_unslave(priv->mdev->priv.eswitch, netdev, lag_dev);
}
/* Bond device of representors and netdev events are used here in specific way * to support eswitch vports bonding and to perform failover of eswitch vport * by modifying the vport's egress acl of lower dev representors. Thus this * also change the traditional behavior of lower dev under bond device. * All non-representor netdevs or representors of other vendors as lower dev * of bond device are not supported.
*/ staticint mlx5e_rep_esw_bond_netevent(struct notifier_block *nb, unsignedlong event, void *ptr)
{ struct net_device *netdev = netdev_notifier_info_to_dev(ptr); struct mlx5e_rep_priv *rpriv; struct mlx5e_rep_bond *bond; struct mlx5e_priv *priv;
if (!mlx5e_rep_is_lag_netdev(netdev)) return NOTIFY_DONE;
bond = container_of(nb, struct mlx5e_rep_bond, nb);
priv = netdev_priv(netdev);
rpriv = mlx5_eswitch_get_uplink_priv(priv->mdev->priv.eswitch, REP_ETH); /* Verify VF representor is on the same device of the bond handling the netevent. */ if (rpriv->uplink_priv.bond != bond) return NOTIFY_DONE;
switch (event) { case NETDEV_CHANGELOWERSTATE:
mlx5e_rep_changelowerstate_event(netdev, ptr); break; case NETDEV_CHANGEUPPER:
mlx5e_rep_changeupper_event(netdev, ptr); break;
} return NOTIFY_DONE;
}
/* If HW support eswitch vports bonding, register a specific notifier to * handle it when two or more representors are bonded
*/ int mlx5e_rep_bond_init(struct mlx5e_rep_priv *rpriv)
{ struct mlx5_rep_uplink_priv *uplink_priv = &rpriv->uplink_priv; struct net_device *netdev = rpriv->netdev; struct mlx5e_priv *priv; int ret = 0;
priv = netdev_priv(netdev); if (!mlx5_esw_acl_egress_fwd2vport_supported(priv->mdev->priv.eswitch)) goto out;
uplink_priv->bond = kvzalloc(sizeof(*uplink_priv->bond), GFP_KERNEL); if (!uplink_priv->bond) {
ret = -ENOMEM; goto out;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.