bonding: add xdp_features support
[linux-block.git] / drivers / net / bonding / bond_main.c
index 7a7d584f378a5ae441d41ab5c804a31601ec9453..3fed888629f7b5d08fede3187fb5639d74185c13 100644 (file)
@@ -1789,6 +1789,26 @@ static void bond_ether_setup(struct net_device *bond_dev)
        bond_dev->priv_flags &= ~IFF_TX_SKB_SHARING;
 }
 
+void bond_xdp_set_features(struct net_device *bond_dev)
+{
+       struct bonding *bond = netdev_priv(bond_dev);
+       xdp_features_t val = NETDEV_XDP_ACT_MASK;
+       struct list_head *iter;
+       struct slave *slave;
+
+       ASSERT_RTNL();
+
+       if (!bond_xdp_check(bond)) {
+               xdp_clear_features_flag(bond_dev);
+               return;
+       }
+
+       bond_for_each_slave(bond, slave, iter)
+               val &= slave->dev->xdp_features;
+
+       xdp_set_features_flag(bond_dev, val);
+}
+
 /* enslave device <slave> to bond device <master> */
 int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
                 struct netlink_ext_ack *extack)
@@ -2236,6 +2256,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev,
                        bpf_prog_inc(bond->xdp_prog);
        }
 
+       bond_xdp_set_features(bond_dev);
+
        slave_info(bond_dev, slave_dev, "Enslaving as %s interface with %s link\n",
                   bond_is_active_slave(new_slave) ? "an active" : "a backup",
                   new_slave->link != BOND_LINK_DOWN ? "an up" : "a down");
@@ -2483,6 +2505,7 @@ static int __bond_release_one(struct net_device *bond_dev,
        if (!netif_is_bond_master(slave_dev))
                slave_dev->priv_flags &= ~IFF_BONDING;
 
+       bond_xdp_set_features(bond_dev);
        kobject_put(&slave->kobj);
 
        return 0;
@@ -3930,6 +3953,9 @@ static int bond_slave_netdev_event(unsigned long event,
                /* Propagate to master device */
                call_netdevice_notifiers(event, slave->bond->dev);
                break;
+       case NETDEV_XDP_FEAT_CHANGE:
+               bond_xdp_set_features(bond_dev);
+               break;
        default:
                break;
        }
@@ -5697,9 +5723,13 @@ static int bond_ethtool_get_ts_info(struct net_device *bond_dev,
                                    struct ethtool_ts_info *info)
 {
        struct bonding *bond = netdev_priv(bond_dev);
+       struct ethtool_ts_info ts_info;
        const struct ethtool_ops *ops;
        struct net_device *real_dev;
+       bool sw_tx_support = false;
        struct phy_device *phydev;
+       struct list_head *iter;
+       struct slave *slave;
        int ret = 0;
 
        rcu_read_lock();
@@ -5718,10 +5748,36 @@ static int bond_ethtool_get_ts_info(struct net_device *bond_dev,
                        ret = ops->get_ts_info(real_dev, info);
                        goto out;
                }
+       } else {
+               /* Check if all slaves support software tx timestamping */
+               rcu_read_lock();
+               bond_for_each_slave_rcu(bond, slave, iter) {
+                       ret = -1;
+                       ops = slave->dev->ethtool_ops;
+                       phydev = slave->dev->phydev;
+
+                       if (phy_has_tsinfo(phydev))
+                               ret = phy_ts_info(phydev, &ts_info);
+                       else if (ops->get_ts_info)
+                               ret = ops->get_ts_info(slave->dev, &ts_info);
+
+                       if (!ret && (ts_info.so_timestamping & SOF_TIMESTAMPING_TX_SOFTWARE)) {
+                               sw_tx_support = true;
+                               continue;
+                       }
+
+                       sw_tx_support = false;
+                       break;
+               }
+               rcu_read_unlock();
        }
 
+       ret = 0;
        info->so_timestamping = SOF_TIMESTAMPING_RX_SOFTWARE |
                                SOF_TIMESTAMPING_SOFTWARE;
+       if (sw_tx_support)
+               info->so_timestamping |= SOF_TIMESTAMPING_TX_SOFTWARE;
+
        info->phc_index = -1;
 
 out:
@@ -5844,6 +5900,9 @@ void bond_setup(struct net_device *bond_dev)
        if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP)
                bond_dev->features |= BOND_XFRM_FEATURES;
 #endif /* CONFIG_XFRM_OFFLOAD */
+
+       if (bond_xdp_check(bond))
+               bond_dev->xdp_features = NETDEV_XDP_ACT_MASK;
 }
 
 /* Destroy a bonding device.