diff options
-rw-r--r-- | drivers/net/bonding/bond_main.c | 100 |
1 files changed, 87 insertions, 13 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index f13d413ad26c..47ab4ccd6fc1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -419,6 +419,41 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev, #ifdef CONFIG_XFRM_OFFLOAD /** + * bond_ipsec_dev - Get active device for IPsec offload + * @xs: pointer to transformer state struct + * + * Context: caller must hold rcu_read_lock. + * + * Return: the device for ipsec offload, or NULL if not exist. + **/ +static struct net_device *bond_ipsec_dev(struct xfrm_state *xs) +{ + struct net_device *bond_dev = xs->xso.dev; + struct bonding *bond; + struct slave *slave; + + if (!bond_dev) + return NULL; + + bond = netdev_priv(bond_dev); + if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) + return NULL; + + slave = rcu_dereference(bond->curr_active_slave); + if (!slave) + return NULL; + + if (!xs->xso.real_dev) + return NULL; + + if (xs->xso.real_dev != slave->dev) + pr_warn_ratelimited("%s: (slave %s): not same with IPsec offload real dev %s\n", + bond_dev->name, slave->dev->name, xs->xso.real_dev->name); + + return slave->dev; +} + +/** * bond_ipsec_add_sa - program device with a security association * @xs: pointer to transformer state struct * @extack: extack point to fill failure reason @@ -640,23 +675,12 @@ out: **/ static bool bond_ipsec_offload_ok(struct sk_buff *skb, struct xfrm_state *xs) { - struct net_device *bond_dev = xs->xso.dev; struct net_device *real_dev; - struct slave *curr_active; - struct bonding *bond; bool ok = false; - bond = netdev_priv(bond_dev); rcu_read_lock(); - curr_active = rcu_dereference(bond->curr_active_slave); - if (!curr_active) - goto out; - real_dev = curr_active->dev; - - if (BOND_MODE(bond) != BOND_MODE_ACTIVEBACKUP) - goto out; - - if (!xs->xso.real_dev) + real_dev = bond_ipsec_dev(xs); + if (!real_dev) goto out; if (!real_dev->xfrmdev_ops || @@ -670,11 +694,61 @@ out: return ok; } +/** + * bond_advance_esn_state - ESN support for IPSec HW offload + * @xs: pointer to transformer state struct + **/ +static void bond_advance_esn_state(struct xfrm_state *xs) +{ + struct net_device *real_dev; + + rcu_read_lock(); + real_dev = bond_ipsec_dev(xs); + if (!real_dev) + goto out; + + if (!real_dev->xfrmdev_ops || + !real_dev->xfrmdev_ops->xdo_dev_state_advance_esn) { + pr_warn_ratelimited("%s: %s doesn't support xdo_dev_state_advance_esn\n", __func__, real_dev->name); + goto out; + } + + real_dev->xfrmdev_ops->xdo_dev_state_advance_esn(xs); +out: + rcu_read_unlock(); +} + +/** + * bond_xfrm_update_stats - Update xfrm state + * @xs: pointer to transformer state struct + **/ +static void bond_xfrm_update_stats(struct xfrm_state *xs) +{ + struct net_device *real_dev; + + rcu_read_lock(); + real_dev = bond_ipsec_dev(xs); + if (!real_dev) + goto out; + + if (!real_dev->xfrmdev_ops || + !real_dev->xfrmdev_ops->xdo_dev_state_update_stats) { + pr_warn_ratelimited("%s: %s doesn't support xdo_dev_state_update_stats\n", __func__, real_dev->name); + goto out; + } + + real_dev->xfrmdev_ops->xdo_dev_state_update_stats(xs); +out: + rcu_read_unlock(); +} + static const struct xfrmdev_ops bond_xfrmdev_ops = { .xdo_dev_state_add = bond_ipsec_add_sa, .xdo_dev_state_delete = bond_ipsec_del_sa, .xdo_dev_state_free = bond_ipsec_free_sa, .xdo_dev_offload_ok = bond_ipsec_offload_ok, + .xdo_dev_state_advance_esn = bond_advance_esn_state, + .xdo_dev_state_update_stats = bond_xfrm_update_stats, }; #endif /* CONFIG_XFRM_OFFLOAD */ |