@@ -885,6 +885,7 @@ static void ice_lag_link(struct ice_lag *lag)
lag->bonded = true;
lag->role = ICE_LAG_UNSET;
+ netdev_info(lag->netdev, "Shared SR-IOV resources in bond are active\n");
}
/**
@@ -1329,6 +1330,7 @@ ice_lag_chk_comp(struct ice_lag *lag, void *ptr)
struct netdev_notifier_bonding_info *info;
struct netdev_bonding_info *bonding_info;
struct list_head *tmp;
+ struct device *dev;
int count = 0;
if (!lag->primary)
@@ -1341,11 +1343,21 @@ ice_lag_chk_comp(struct ice_lag *lag, void *ptr)
if (event_upper != lag->upper_netdev)
return true;
+ dev = ice_pf_to_dev(lag->pf);
+
+ /* only supporting switchdev mode for SRIOV VF LAG.
+ * primary interface has to be in switchdev mode
+ */
+ if (!ice_is_switchdev_running(lag->pf)) {
+ dev_info(dev, "Primary interface not in switchdev mode - VF LAG disabled\n");
+ return false;
+ }
+
info = (struct netdev_notifier_bonding_info *)ptr;
bonding_info = &info->bonding_info;
lag->bond_mode = bonding_info->master.bond_mode;
if (lag->bond_mode != BOND_MODE_ACTIVEBACKUP) {
- netdev_info(lag->netdev, "Bond Mode not ACTIVE-BACKUP\n");
+ dev_info(dev, "Bond Mode not ACTIVE-BACKUP - VF LAG disabled\n");
return false;
}
@@ -1355,17 +1367,19 @@ ice_lag_chk_comp(struct ice_lag *lag, void *ptr)
struct ice_netdev_priv *peer_np;
struct net_device *peer_netdev;
struct ice_vsi *vsi, *peer_vsi;
+ struct ice_pf *peer_pf;
entry = list_entry(tmp, struct ice_lag_netdev_list, node);
peer_netdev = entry->netdev;
if (!netif_is_ice(peer_netdev)) {
- netdev_info(lag->netdev, "Found non-ice netdev in LAG\n");
+ dev_info(dev, "Found %s non-ice netdev in LAG - VF LAG disabled\n",
+ netdev_name(peer_netdev));
return false;
}
count++;
if (count > 2) {
- netdev_info(lag->netdev, "Found more than two netdevs in LAG\n");
+ dev_info(dev, "Found more than two netdevs in LAG - VF LAG disabled\n");
return false;
}
@@ -1374,7 +1388,8 @@ ice_lag_chk_comp(struct ice_lag *lag, void *ptr)
peer_vsi = peer_np->vsi;
if (lag->pf->pdev->bus != peer_vsi->back->pdev->bus ||
lag->pf->pdev->slot != peer_vsi->back->pdev->slot) {
- netdev_info(lag->netdev, "Found netdev on different device in LAG\n");
+ dev_info(dev, "Found %s on different device in LAG - VF LAG disabled\n",
+ netdev_name(peer_netdev));
return false;
}
@@ -1382,10 +1397,17 @@ ice_lag_chk_comp(struct ice_lag *lag, void *ptr)
peer_dcb_cfg = &peer_vsi->port_info->qos_cfg.local_dcbx_cfg;
if (memcmp(dcb_cfg, peer_dcb_cfg,
sizeof(struct ice_dcbx_cfg))) {
- netdev_info(lag->netdev, "Found netdev with different DCB config in LAG\n");
+ dev_info(dev, "Found %s with different DCB in LAG - VF LAG disabled\n",
+ netdev_name(peer_netdev));
return false;
}
+ peer_pf = peer_vsi->back;
+ if (test_bit(ICE_FLAG_FW_LLDP_AGENT, peer_pf->flags)) {
+ dev_warn(dev, "Found %s with FW LLDP agent active - VF LAG disabled\n",
+ netdev_name(peer_netdev));
+ return false;
+ }
}
return true;
@@ -1457,6 +1479,58 @@ ice_lag_monitor_rdma(struct ice_lag *lag, void *ptr)
ice_set_rdma_cap(pf);
}
+/**
+ * ice_lag_chk_disabled_bond - monitor interfaces entering/leaving disabled bond
+ * @lag: lag info struct
+ * @ptr: opaque data containing event
+ *
+ * as interfaces enter a bond - determine if the bond is currently
+ * SRIOV LAG compliant and flag if not. As interfaces leave the
+ * bond, reset their compliant status.
+ */
+static void ice_lag_chk_disabled_bond(struct ice_lag *lag, void *ptr)
+{
+ struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+ struct netdev_notifier_changeupper_info *info = ptr;
+ struct ice_lag *prim_lag;
+
+ if (netdev != lag->netdev)
+ return;
+
+ if (info->linking) {
+ prim_lag = ice_lag_find_primary(lag);
+ if (prim_lag &&
+ !ice_is_feature_supported(prim_lag->pf, ICE_F_SRIOV_LAG)) {
+ ice_clear_feature_support(lag->pf, ICE_F_SRIOV_LAG);
+ netdev_info(netdev, "Interface added to non-compliant SRIOV LAG aggregate\n");
+ }
+ } else {
+ ice_lag_init_feature_support_flag(lag->pf);
+ }
+}
+
+/**
+ * ice_lag_disable_sriov_bond - set members of bond as not supporting SRIOV LAG
+ * @lag: primary interfaces lag struct
+ */
+static void ice_lag_disable_sriov_bond(struct ice_lag *lag)
+{
+ struct ice_lag_netdev_list *entry;
+ struct ice_netdev_priv *np;
+ struct net_device *netdev;
+ struct list_head *tmp;
+ struct ice_pf *pf;
+
+ list_for_each(tmp, lag->netdev_head) {
+ entry = list_entry(tmp, struct ice_lag_netdev_list, node);
+ netdev = entry->netdev;
+ np = netdev_priv(netdev);
+ pf = np->vsi->back;
+
+ ice_clear_feature_support(pf, ICE_F_SRIOV_LAG);
+ }
+}
+
/**
* ice_lag_process_event - process a task assigned to the lag_wq
* @work: pointer to work_struct
@@ -1478,6 +1552,7 @@ static void ice_lag_process_event(struct work_struct *work)
switch (lag_work->event) {
case NETDEV_CHANGEUPPER:
info = &lag_work->info.changeupper_info;
+ ice_lag_chk_disabled_bond(lag_work->lag, info);
if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG)) {
ice_lag_monitor_link(lag_work->lag, info);
ice_lag_changeupper_event(lag_work->lag, info);
@@ -1489,6 +1564,9 @@ static void ice_lag_process_event(struct work_struct *work)
if (ice_is_feature_supported(pf, ICE_F_SRIOV_LAG)) {
if (!ice_lag_chk_comp(lag_work->lag,
&lag_work->info.bonding_info)) {
+ netdev = lag_work->info.bonding_info.info.dev;
+ ice_lag_disable_sriov_bond(lag_work->lag);
+ ice_lag_unregister(lag_work->lag, netdev);
goto lag_cleanup;
}
ice_lag_monitor_active(lag_work->lag,