You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
i40e: store MAC/VLAN filters in a hash with the MAC Address as key
Replace the mac_filter_list with a static size hash table of 8bits. The primary advantage of this is a decrease in latency of operations related to searching for specific MAC filters, including .set_rx_mode. Using a linked list resulted in several locations which were O(n^2). Using a hash table should give us latency growth closer to O(n*log(n)). Change-ID: I5330bd04053b880e670210933e35830b95948ebb Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
This commit is contained in:
committed by
Jeff Kirsher
parent
290d255719
commit
278e7d0b9d
@@ -39,6 +39,7 @@
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/ip.h>
|
||||
@@ -445,6 +446,20 @@ struct i40e_pf {
|
||||
u16 phy_led_val;
|
||||
};
|
||||
|
||||
/**
|
||||
* i40e_mac_to_hkey - Convert a 6-byte MAC Address to a u64 hash key
|
||||
* @macaddr: the MAC Address as the base key
|
||||
*
|
||||
* Simply copies the address and returns it as a u64 for hashing
|
||||
**/
|
||||
static inline u64 i40e_addr_to_hkey(const u8 *macaddr)
|
||||
{
|
||||
u64 key = 0;
|
||||
|
||||
ether_addr_copy((u8 *)&key, macaddr);
|
||||
return key;
|
||||
}
|
||||
|
||||
enum i40e_filter_state {
|
||||
I40E_FILTER_INVALID = 0, /* Invalid state */
|
||||
I40E_FILTER_NEW, /* New, not sent to FW yet */
|
||||
@@ -454,7 +469,7 @@ enum i40e_filter_state {
|
||||
/* There is no 'removed' state; the filter struct is freed */
|
||||
};
|
||||
struct i40e_mac_filter {
|
||||
struct list_head list;
|
||||
struct hlist_node hlist;
|
||||
u8 macaddr[ETH_ALEN];
|
||||
#define I40E_VLAN_ANY -1
|
||||
s16 vlan;
|
||||
@@ -498,9 +513,10 @@ struct i40e_vsi {
|
||||
#define I40E_VSI_FLAG_VEB_OWNER BIT(1)
|
||||
unsigned long flags;
|
||||
|
||||
/* Per VSI lock to protect elements/list (MAC filter) */
|
||||
spinlock_t mac_filter_list_lock;
|
||||
struct list_head mac_filter_list;
|
||||
/* Per VSI lock to protect elements/hash (MAC filter) */
|
||||
spinlock_t mac_filter_hash_lock;
|
||||
/* Fixed size hash table with 2^8 buckets for MAC filters */
|
||||
DECLARE_HASHTABLE(mac_filter_hash, 8);
|
||||
|
||||
/* VSI stats */
|
||||
struct rtnl_link_stats64 net_stats;
|
||||
|
||||
@@ -134,7 +134,7 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
|
||||
struct rtnl_link_stats64 *nstat;
|
||||
struct i40e_mac_filter *f;
|
||||
struct i40e_vsi *vsi;
|
||||
int i;
|
||||
int i, bkt;
|
||||
|
||||
vsi = i40e_dbg_find_vsi(pf, seid);
|
||||
if (!vsi) {
|
||||
@@ -166,7 +166,7 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
|
||||
pf->hw.mac.addr,
|
||||
pf->hw.mac.san_addr,
|
||||
pf->hw.mac.port_addr);
|
||||
list_for_each_entry(f, &vsi->mac_filter_list, list) {
|
||||
hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
|
||||
dev_info(&pf->pdev->dev,
|
||||
" mac_filter_hash: %pM vid=%d, state %s\n",
|
||||
f->macaddr, f->vlan,
|
||||
|
||||
@@ -1522,12 +1522,12 @@ void i40e_fcoe_config_netdev(struct net_device *netdev, struct i40e_vsi *vsi)
|
||||
* same PCI function.
|
||||
*/
|
||||
netdev->dev_port = 1;
|
||||
spin_lock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_lock_bh(&vsi->mac_filter_hash_lock);
|
||||
i40e_add_filter(vsi, hw->mac.san_addr, 0);
|
||||
i40e_add_filter(vsi, (u8[6]) FC_FCOE_FLOGI_MAC, 0);
|
||||
i40e_add_filter(vsi, FIP_ALL_FCOE_MACS, 0);
|
||||
i40e_add_filter(vsi, FIP_ALL_ENODE_MACS, 0);
|
||||
spin_unlock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_unlock_bh(&vsi->mac_filter_hash_lock);
|
||||
|
||||
/* use san mac */
|
||||
ether_addr_copy(netdev->dev_addr, hw->mac.san_addr);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -686,7 +686,7 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
|
||||
if (vf->port_vlan_id)
|
||||
i40e_vsi_add_pvid(vsi, vf->port_vlan_id);
|
||||
|
||||
spin_lock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_lock_bh(&vsi->mac_filter_hash_lock);
|
||||
if (is_valid_ether_addr(vf->default_lan_addr.addr)) {
|
||||
f = i40e_add_filter(vsi, vf->default_lan_addr.addr,
|
||||
vf->port_vlan_id ?
|
||||
@@ -696,7 +696,7 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
|
||||
"Could not add MAC filter %pM for VF %d\n",
|
||||
vf->default_lan_addr.addr, vf->vf_id);
|
||||
}
|
||||
spin_unlock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_unlock_bh(&vsi->mac_filter_hash_lock);
|
||||
i40e_write_rx_ctl(&pf->hw, I40E_VFQF_HENA1(0, vf->vf_id),
|
||||
(u32)hena);
|
||||
i40e_write_rx_ctl(&pf->hw, I40E_VFQF_HENA1(1, vf->vf_id),
|
||||
@@ -1449,9 +1449,9 @@ static void i40e_vc_reset_vf_msg(struct i40e_vf *vf)
|
||||
static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
|
||||
{
|
||||
struct i40e_mac_filter *f;
|
||||
int num_vlans = 0;
|
||||
int num_vlans = 0, bkt;
|
||||
|
||||
list_for_each_entry(f, &vsi->mac_filter_list, list) {
|
||||
hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
|
||||
if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID)
|
||||
num_vlans++;
|
||||
}
|
||||
@@ -1481,6 +1481,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf,
|
||||
struct i40e_vsi *vsi;
|
||||
bool alluni = false;
|
||||
int aq_err = 0;
|
||||
int bkt;
|
||||
|
||||
vsi = i40e_find_vsi_from_id(pf, info->vsi_id);
|
||||
if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) ||
|
||||
@@ -1507,7 +1508,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf,
|
||||
vf->port_vlan_id,
|
||||
NULL);
|
||||
} else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
|
||||
list_for_each_entry(f, &vsi->mac_filter_list, list) {
|
||||
hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
|
||||
if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID)
|
||||
continue;
|
||||
aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw,
|
||||
@@ -1557,7 +1558,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf,
|
||||
vf->port_vlan_id,
|
||||
NULL);
|
||||
} else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
|
||||
list_for_each_entry(f, &vsi->mac_filter_list, list) {
|
||||
hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
|
||||
aq_ret = 0;
|
||||
if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID) {
|
||||
aq_ret =
|
||||
@@ -1927,7 +1928,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
|
||||
/* Lock once, because all function inside for loop accesses VSI's
|
||||
* MAC filter list which needs to be protected using same lock.
|
||||
*/
|
||||
spin_lock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_lock_bh(&vsi->mac_filter_hash_lock);
|
||||
|
||||
/* add new addresses to the list */
|
||||
for (i = 0; i < al->num_elements; i++) {
|
||||
@@ -1946,13 +1947,13 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
|
||||
"Unable to add MAC filter %pM for VF %d\n",
|
||||
al->list[i].addr, vf->vf_id);
|
||||
ret = I40E_ERR_PARAM;
|
||||
spin_unlock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_unlock_bh(&vsi->mac_filter_hash_lock);
|
||||
goto error_param;
|
||||
} else {
|
||||
vf->num_mac++;
|
||||
}
|
||||
}
|
||||
spin_unlock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_unlock_bh(&vsi->mac_filter_hash_lock);
|
||||
|
||||
/* program the updated filter list */
|
||||
ret = i40e_sync_vsi_filters(vsi);
|
||||
@@ -2001,18 +2002,18 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
|
||||
}
|
||||
vsi = pf->vsi[vf->lan_vsi_idx];
|
||||
|
||||
spin_lock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_lock_bh(&vsi->mac_filter_hash_lock);
|
||||
/* delete addresses from the list */
|
||||
for (i = 0; i < al->num_elements; i++)
|
||||
if (i40e_del_mac_all_vlan(vsi, al->list[i].addr)) {
|
||||
ret = I40E_ERR_INVALID_MAC_ADDR;
|
||||
spin_unlock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_unlock_bh(&vsi->mac_filter_hash_lock);
|
||||
goto error_param;
|
||||
} else {
|
||||
vf->num_mac--;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_unlock_bh(&vsi->mac_filter_hash_lock);
|
||||
|
||||
/* program the updated filter list */
|
||||
ret = i40e_sync_vsi_filters(vsi);
|
||||
@@ -2687,6 +2688,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
|
||||
struct i40e_mac_filter *f;
|
||||
struct i40e_vf *vf;
|
||||
int ret = 0;
|
||||
int bkt;
|
||||
|
||||
/* validate the request */
|
||||
if (vf_id >= pf->num_alloc_vfs) {
|
||||
@@ -2713,9 +2715,9 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
|
||||
}
|
||||
|
||||
/* Lock once because below invoked function add/del_filter requires
|
||||
* mac_filter_list_lock to be held
|
||||
* mac_filter_hash_lock to be held
|
||||
*/
|
||||
spin_lock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_lock_bh(&vsi->mac_filter_hash_lock);
|
||||
|
||||
/* delete the temporary mac address */
|
||||
if (!is_zero_ether_addr(vf->default_lan_addr.addr))
|
||||
@@ -2725,10 +2727,10 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
|
||||
/* Delete all the filters for this VSI - we're going to kill it
|
||||
* anyway.
|
||||
*/
|
||||
list_for_each_entry(f, &vsi->mac_filter_list, list)
|
||||
hash_for_each(vsi->mac_filter_hash, bkt, f, hlist)
|
||||
i40e_del_filter(vsi, f->macaddr, f->vlan);
|
||||
|
||||
spin_unlock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_unlock_bh(&vsi->mac_filter_hash_lock);
|
||||
|
||||
dev_info(&pf->pdev->dev, "Setting MAC %pM on VF %d\n", mac, vf_id);
|
||||
/* program mac filter */
|
||||
@@ -2800,9 +2802,9 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
|
||||
/* duplicate request, so just return success */
|
||||
goto error_pvid;
|
||||
|
||||
spin_lock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_lock_bh(&vsi->mac_filter_hash_lock);
|
||||
is_vsi_in_vlan = i40e_is_vsi_in_vlan(vsi);
|
||||
spin_unlock_bh(&vsi->mac_filter_list_lock);
|
||||
spin_unlock_bh(&vsi->mac_filter_hash_lock);
|
||||
|
||||
if (le16_to_cpu(vsi->info.pvid) == 0 && is_vsi_in_vlan) {
|
||||
dev_err(&pf->pdev->dev,
|
||||
|
||||
Reference in New Issue
Block a user