From 992d38d2b988a7d71c2416dad9af2b769f51ac25 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 22 Dec 2023 20:21:58 -0800 Subject: [PATCH 01/13] bnxt_en: Refactor bnxt_ntuple_filter structure. This is in preparation to support user defined L2 (ether) filters, which will have many similarities with ntuple filters. Refactor bnxt_ntuple_filter structure to have a bnxt_filter_base structure that can be re-used by the L2 filters. Reviewed-by: Vasundhara Volam Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 39 ++++++++++--------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 25 +++++++++--- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 10 ++--- 3 files changed, 44 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 1f956929191d..bf3b9b2cad76 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4803,8 +4803,8 @@ static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool irq_reinit) struct bnxt_ntuple_filter *fltr; head = &bp->ntp_fltr_hash_tbl[i]; - hlist_for_each_entry_safe(fltr, tmp, head, hash) { - hlist_del(&fltr->hash); + hlist_for_each_entry_safe(fltr, tmp, head, base.hash) { + hlist_del(&fltr->base.hash); kfree(fltr); } } @@ -5301,7 +5301,7 @@ static int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp, if (rc) return rc; - req->ntuple_filter_id = fltr->filter_id; + req->ntuple_filter_id = fltr->base.filter_id; return hwrm_req_send(bp, req); } @@ -5342,9 +5342,9 @@ static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, if (bp->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2) { flags = CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DEST_RFS_RING_IDX; - req->dst_id = cpu_to_le16(fltr->rxq); + req->dst_id = cpu_to_le16(fltr->base.rxq); } else { - vnic = &bp->vnic_info[fltr->rxq + 1]; + vnic = &bp->vnic_info[fltr->base.rxq + 1]; req->dst_id = cpu_to_le16(vnic->fw_vnic_id); } req->flags = cpu_to_le32(flags); @@ -5389,7 +5389,7 @@ static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, resp = hwrm_req_hold(bp, req); rc = hwrm_req_send(bp, req); if (!rc) - fltr->filter_id = resp->ntuple_filter_id; + fltr->base.filter_id = resp->ntuple_filter_id; hwrm_req_drop(bp, req); return rc; } @@ -13653,9 +13653,9 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, idx = skb_get_hash_raw(skb) & BNXT_NTP_FLTR_HASH_MASK; head = &bp->ntp_fltr_hash_tbl[idx]; rcu_read_lock(); - hlist_for_each_entry_rcu(fltr, head, hash) { + hlist_for_each_entry_rcu(fltr, head, base.hash) { if (bnxt_fltr_match(fltr, new_fltr)) { - rc = fltr->sw_id; + rc = fltr->base.sw_id; rcu_read_unlock(); goto err_free; } @@ -13671,17 +13671,18 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, goto err_free; } - new_fltr->sw_id = (u16)bit_id; + new_fltr->base.sw_id = (u16)bit_id; new_fltr->flow_id = flow_id; new_fltr->l2_fltr_idx = l2_idx; - new_fltr->rxq = rxq_index; - hlist_add_head_rcu(&new_fltr->hash, head); + new_fltr->base.rxq = rxq_index; + new_fltr->base.type = BNXT_FLTR_TYPE_NTUPLE; + hlist_add_head_rcu(&new_fltr->base.hash, head); bp->ntp_fltr_count++; spin_unlock_bh(&bp->ntp_fltr_lock); bnxt_queue_sp_work(bp, BNXT_RX_NTP_FLTR_SP_EVENT); - return new_fltr->sw_id; + return new_fltr->base.sw_id; err_free: kfree(new_fltr); @@ -13699,13 +13700,13 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp) int rc; head = &bp->ntp_fltr_hash_tbl[i]; - hlist_for_each_entry_safe(fltr, tmp, head, hash) { + hlist_for_each_entry_safe(fltr, tmp, head, base.hash) { bool del = false; - if (test_bit(BNXT_FLTR_VALID, &fltr->state)) { - if (rps_may_expire_flow(bp->dev, fltr->rxq, + if (test_bit(BNXT_FLTR_VALID, &fltr->base.state)) { + if (rps_may_expire_flow(bp->dev, fltr->base.rxq, fltr->flow_id, - fltr->sw_id)) { + fltr->base.sw_id)) { bnxt_hwrm_cfa_ntuple_filter_free(bp, fltr); del = true; @@ -13716,16 +13717,16 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp) if (rc) del = true; else - set_bit(BNXT_FLTR_VALID, &fltr->state); + set_bit(BNXT_FLTR_VALID, &fltr->base.state); } if (del) { spin_lock_bh(&bp->ntp_fltr_lock); - hlist_del_rcu(&fltr->hash); + hlist_del_rcu(&fltr->base.hash); bp->ntp_fltr_count--; spin_unlock_bh(&bp->ntp_fltr_lock); synchronize_rcu(); - clear_bit(fltr->sw_id, bp->ntp_fltr_bmap); + clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap); kfree(fltr); } } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index d0f3e74fa025..4653abbd2fe4 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1332,21 +1332,34 @@ struct bnxt_pf_info { struct bnxt_vf_info *vf; }; -struct bnxt_ntuple_filter { +struct bnxt_filter_base { struct hlist_node hash; - u8 dst_mac_addr[ETH_ALEN]; - u8 src_mac_addr[ETH_ALEN]; - struct flow_keys fkeys; __le64 filter_id; + u8 type; +#define BNXT_FLTR_TYPE_NTUPLE 1 +#define BNXT_FLTR_TYPE_L2 2 + u8 flags; +#define BNXT_ACT_DROP 1 +#define BNXT_ACT_RING_DST 2 +#define BNXT_ACT_FUNC_DST 4 u16 sw_id; - u8 l2_fltr_idx; u16 rxq; - u32 flow_id; + u16 fw_vnic_id; + u16 vf_idx; unsigned long state; #define BNXT_FLTR_VALID 0 #define BNXT_FLTR_UPDATE 1 }; +struct bnxt_ntuple_filter { + struct bnxt_filter_base base; + u8 dst_mac_addr[ETH_ALEN]; + u8 src_mac_addr[ETH_ALEN]; + struct flow_keys fkeys; + u8 l2_fltr_idx; + u32 flow_id; +}; + struct bnxt_link_info { u8 phy_type; u8 media_type; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 7e49953a93fa..65edad2cfeab 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1024,10 +1024,10 @@ static int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd, head = &bp->ntp_fltr_hash_tbl[i]; rcu_read_lock(); - hlist_for_each_entry_rcu(fltr, head, hash) { + hlist_for_each_entry_rcu(fltr, head, base.hash) { if (j == cmd->rule_cnt) break; - rule_locs[j++] = fltr->sw_id; + rule_locs[j++] = fltr->base.sw_id; } rcu_read_unlock(); if (j == cmd->rule_cnt) @@ -1053,8 +1053,8 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) head = &bp->ntp_fltr_hash_tbl[i]; rcu_read_lock(); - hlist_for_each_entry_rcu(fltr, head, hash) { - if (fltr->sw_id == fs->location) + hlist_for_each_entry_rcu(fltr, head, base.hash) { + if (fltr->base.sw_id == fs->location) goto fltr_found; } rcu_read_unlock(); @@ -1107,7 +1107,7 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0); } - fs->ring_cookie = fltr->rxq; + fs->ring_cookie = fltr->base.rxq; rc = 0; fltr_err: From 1f6e77cb9b328f2ec145e73be97cab6fec838678 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 22 Dec 2023 20:21:59 -0800 Subject: [PATCH 02/13] bnxt_en: Add bnxt_l2_filter hash table. The current driver only has an array of 4 additional L2 unicast addresses to support the netdev uc address list. Generalize and expand this infrastructure with an L2 address hash table so we can support an expanded list of unicast addresses (for bridges, macvlans, OVS, etc). The L2 hash table infrastructure will also allow more generalized n-tuple filter support. This patch creates the bnxt_l2_filter structure and the hash table. This L2 filter structure has the same bnxt_filter_base structure as used in the bnxt_ntuple_filter structure. All currently supported L2 filters will now have an entry in this new table. Note that L2 filters may be created for the VF. VF filters should not be freed when the PF goes down. Add some logic in bnxt_free_l2_filters() to allow keeping the VF filters or to free everything during rmmod. Reviewed-by: Vasundhara Volam Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 175 ++++++++++++++++++++-- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 30 +++- 2 files changed, 191 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index bf3b9b2cad76..8e9a02629450 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4789,7 +4789,7 @@ static void bnxt_clear_ring_indices(struct bnxt *bp) } } -static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool irq_reinit) +static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool all) { #ifdef CONFIG_RFS_ACCEL int i; @@ -4804,14 +4804,19 @@ static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool irq_reinit) head = &bp->ntp_fltr_hash_tbl[i]; hlist_for_each_entry_safe(fltr, tmp, head, base.hash) { + if (!all && (fltr->base.flags & BNXT_ACT_FUNC_DST)) + continue; hlist_del(&fltr->base.hash); + clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap); + bp->ntp_fltr_count--; kfree(fltr); } } - if (irq_reinit) { - bitmap_free(bp->ntp_fltr_bmap); - bp->ntp_fltr_bmap = NULL; - } + if (!all) + return; + + bitmap_free(bp->ntp_fltr_bmap); + bp->ntp_fltr_bmap = NULL; bp->ntp_fltr_count = 0; #endif } @@ -4821,7 +4826,7 @@ static int bnxt_alloc_ntp_fltrs(struct bnxt *bp) #ifdef CONFIG_RFS_ACCEL int i, rc = 0; - if (!(bp->flags & BNXT_FLAG_RFS)) + if (!(bp->flags & BNXT_FLAG_RFS) || bp->ntp_fltr_bmap) return 0; for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) @@ -4839,6 +4844,38 @@ static int bnxt_alloc_ntp_fltrs(struct bnxt *bp) #endif } +static void bnxt_free_l2_filters(struct bnxt *bp, bool all) +{ + int i; + + for (i = 0; i < BNXT_L2_FLTR_HASH_SIZE; i++) { + struct hlist_head *head; + struct hlist_node *tmp; + struct bnxt_l2_filter *fltr; + + head = &bp->l2_fltr_hash_tbl[i]; + hlist_for_each_entry_safe(fltr, tmp, head, base.hash) { + if (!all && (fltr->base.flags & BNXT_ACT_FUNC_DST)) + continue; + hlist_del(&fltr->base.hash); + if (fltr->base.flags) { + clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap); + bp->ntp_fltr_count--; + } + kfree(fltr); + } + } +} + +static void bnxt_init_l2_fltr_tbl(struct bnxt *bp) +{ + int i; + + for (i = 0; i < BNXT_L2_FLTR_HASH_SIZE; i++) + INIT_HLIST_HEAD(&bp->l2_fltr_hash_tbl[i]); + get_random_bytes(&bp->hash_seed, sizeof(bp->hash_seed)); +} + static void bnxt_free_mem(struct bnxt *bp, bool irq_re_init) { bnxt_free_vnic_attributes(bp); @@ -4846,7 +4883,8 @@ static void bnxt_free_mem(struct bnxt *bp, bool irq_re_init) bnxt_free_rx_rings(bp); bnxt_free_cp_rings(bp); bnxt_free_all_cp_arrays(bp); - bnxt_free_ntp_fltrs(bp, irq_re_init); + bnxt_free_ntp_fltrs(bp, false); + bnxt_free_l2_filters(bp, false); if (irq_re_init) { bnxt_free_ring_stats(bp); if (!(bp->phy_flags & BNXT_PHY_FL_PORT_STATS_NO_RESET) || @@ -5290,6 +5328,92 @@ static int bnxt_hwrm_cfa_l2_set_rx_mask(struct bnxt *bp, u16 vnic_id) return hwrm_req_send_silent(bp, req); } +void bnxt_del_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr) +{ + if (!atomic_dec_and_test(&fltr->refcnt)) + return; + spin_lock_bh(&bp->ntp_fltr_lock); + hlist_del_rcu(&fltr->base.hash); + if (fltr->base.flags) { + clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap); + bp->ntp_fltr_count--; + } + spin_unlock_bh(&bp->ntp_fltr_lock); + kfree_rcu(fltr, base.rcu); +} + +static struct bnxt_l2_filter *__bnxt_lookup_l2_filter(struct bnxt *bp, + struct bnxt_l2_key *key, + u32 idx) +{ + struct hlist_head *head = &bp->l2_fltr_hash_tbl[idx]; + struct bnxt_l2_filter *fltr; + + hlist_for_each_entry_rcu(fltr, head, base.hash) { + struct bnxt_l2_key *l2_key = &fltr->l2_key; + + if (ether_addr_equal(l2_key->dst_mac_addr, key->dst_mac_addr) && + l2_key->vlan == key->vlan) + return fltr; + } + return NULL; +} + +static struct bnxt_l2_filter *bnxt_lookup_l2_filter(struct bnxt *bp, + struct bnxt_l2_key *key, + u32 idx) +{ + struct bnxt_l2_filter *fltr = NULL; + + rcu_read_lock(); + fltr = __bnxt_lookup_l2_filter(bp, key, idx); + if (fltr) + atomic_inc(&fltr->refcnt); + rcu_read_unlock(); + return fltr; +} + +static int bnxt_init_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr, + struct bnxt_l2_key *key, u32 idx) +{ + struct hlist_head *head; + + ether_addr_copy(fltr->l2_key.dst_mac_addr, key->dst_mac_addr); + fltr->l2_key.vlan = key->vlan; + fltr->base.type = BNXT_FLTR_TYPE_L2; + head = &bp->l2_fltr_hash_tbl[idx]; + hlist_add_head_rcu(&fltr->base.hash, head); + atomic_set(&fltr->refcnt, 1); + return 0; +} + +static struct bnxt_l2_filter *bnxt_alloc_l2_filter(struct bnxt *bp, + struct bnxt_l2_key *key, + gfp_t gfp) +{ + struct bnxt_l2_filter *fltr; + u32 idx; + int rc; + + idx = jhash2(&key->filter_key, BNXT_L2_KEY_SIZE, bp->hash_seed) & + BNXT_L2_FLTR_HASH_MASK; + fltr = bnxt_lookup_l2_filter(bp, key, idx); + if (fltr) + return fltr; + + fltr = kzalloc(sizeof(*fltr), gfp); + if (!fltr) + return ERR_PTR(-ENOMEM); + spin_lock_bh(&bp->ntp_fltr_lock); + rc = bnxt_init_l2_filter(bp, fltr, key, idx); + spin_unlock_bh(&bp->ntp_fltr_lock); + if (rc) { + bnxt_del_l2_filter(bp, fltr); + fltr = ERR_PTR(rc); + } + return fltr; +} + #ifdef CONFIG_RFS_ACCEL static int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp, struct bnxt_ntuple_filter *fltr) @@ -5330,6 +5454,7 @@ static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, struct hwrm_cfa_ntuple_filter_alloc_output *resp; struct hwrm_cfa_ntuple_filter_alloc_input *req; struct flow_keys *keys = &fltr->fkeys; + struct bnxt_l2_filter *l2_fltr; struct bnxt_vnic_info *vnic; u32 flags = 0; int rc; @@ -5338,7 +5463,9 @@ static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, if (rc) return rc; - req->l2_filter_id = bp->vnic_info[0].fw_l2_filter_id[fltr->l2_fltr_idx]; + l2_fltr = bp->vnic_info[0].l2_filters[fltr->l2_fltr_idx]; + req->l2_filter_id = l2_fltr->base.filter_id; + if (bp->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2) { flags = CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DEST_RFS_RING_IDX; @@ -5400,8 +5527,16 @@ static int bnxt_hwrm_set_vnic_filter(struct bnxt *bp, u16 vnic_id, u16 idx, { struct hwrm_cfa_l2_filter_alloc_output *resp; struct hwrm_cfa_l2_filter_alloc_input *req; + struct bnxt_l2_filter *fltr; + struct bnxt_l2_key key; int rc; + ether_addr_copy(key.dst_mac_addr, mac_addr); + key.vlan = 0; + fltr = bnxt_alloc_l2_filter(bp, &key, GFP_KERNEL); + if (IS_ERR(fltr)) + return PTR_ERR(fltr); + rc = hwrm_req_init(bp, req, HWRM_CFA_L2_FILTER_ALLOC); if (rc) return rc; @@ -5425,9 +5560,13 @@ static int bnxt_hwrm_set_vnic_filter(struct bnxt *bp, u16 vnic_id, u16 idx, resp = hwrm_req_hold(bp, req); rc = hwrm_req_send(bp, req); - if (!rc) - bp->vnic_info[vnic_id].fw_l2_filter_id[idx] = - resp->l2_filter_id; + if (rc) { + bnxt_del_l2_filter(bp, fltr); + } else { + fltr->base.filter_id = resp->l2_filter_id; + set_bit(BNXT_FLTR_VALID, &fltr->base.state); + bp->vnic_info[vnic_id].l2_filters[idx] = fltr; + } hwrm_req_drop(bp, req); return rc; } @@ -5447,9 +5586,13 @@ static int bnxt_hwrm_clear_vnic_filter(struct bnxt *bp) struct bnxt_vnic_info *vnic = &bp->vnic_info[i]; for (j = 0; j < vnic->uc_filter_count; j++) { - req->l2_filter_id = vnic->fw_l2_filter_id[j]; + struct bnxt_l2_filter *fltr; + + fltr = vnic->l2_filters[j]; + req->l2_filter_id = fltr->base.filter_id; rc = hwrm_req_send(bp, req); + bnxt_del_l2_filter(bp, fltr); } vnic->uc_filter_count = 0; } @@ -11759,9 +11902,12 @@ static int bnxt_cfg_rx_mode(struct bnxt *bp) return rc; hwrm_req_hold(bp, req); for (i = 1; i < vnic->uc_filter_count; i++) { - req->l2_filter_id = vnic->fw_l2_filter_id[i]; + struct bnxt_l2_filter *fltr = vnic->l2_filters[i]; + + req->l2_filter_id = fltr->base.filter_id; rc = hwrm_req_send(bp, req); + bnxt_del_l2_filter(bp, fltr); } hwrm_req_drop(bp, req); @@ -13901,6 +14047,8 @@ static void bnxt_remove_one(struct pci_dev *pdev) bnxt_ptp_clear(bp); unregister_netdev(dev); + bnxt_free_l2_filters(bp, true); + bnxt_free_ntp_fltrs(bp, true); clear_bit(BNXT_STATE_IN_FW_RESET, &bp->state); /* Flush any pending tasks */ cancel_work_sync(&bp->sp_task); @@ -14450,6 +14598,7 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) goto init_err_pci_clean; + bnxt_init_l2_fltr_tbl(bp); bnxt_set_rx_skb_mode(bp, false); bnxt_set_tpa_flags(bp); bnxt_set_ring_params(bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 4653abbd2fe4..77c7084e47cd 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1219,7 +1219,7 @@ struct bnxt_vnic_info { u16 fw_rss_cos_lb_ctx[BNXT_MAX_CTX_PER_VNIC]; u16 fw_l2_ctx_id; #define BNXT_MAX_UC_ADDRS 4 - __le64 fw_l2_filter_id[BNXT_MAX_UC_ADDRS]; + struct bnxt_l2_filter *l2_filters[BNXT_MAX_UC_ADDRS]; /* index 0 always dev_addr */ u16 uc_filter_count; u8 *uc_list; @@ -1349,6 +1349,8 @@ struct bnxt_filter_base { unsigned long state; #define BNXT_FLTR_VALID 0 #define BNXT_FLTR_UPDATE 1 + + struct rcu_head rcu; }; struct bnxt_ntuple_filter { @@ -1360,6 +1362,24 @@ struct bnxt_ntuple_filter { u32 flow_id; }; +struct bnxt_l2_key { + union { + struct { + u8 dst_mac_addr[ETH_ALEN]; + u16 vlan; + }; + u32 filter_key; + }; +}; + +#define BNXT_L2_KEY_SIZE (sizeof(struct bnxt_l2_key) / 4) + +struct bnxt_l2_filter { + struct bnxt_filter_base base; + struct bnxt_l2_key l2_key; + atomic_t refcnt; +}; + struct bnxt_link_info { u8 phy_type; u8 media_type; @@ -2388,6 +2408,13 @@ struct bnxt { unsigned long *ntp_fltr_bmap; int ntp_fltr_count; +#define BNXT_L2_FLTR_MAX_FLTR 1024 +#define BNXT_L2_FLTR_HASH_SIZE 32 +#define BNXT_L2_FLTR_HASH_MASK (BNXT_L2_FLTR_HASH_SIZE - 1) + struct hlist_head l2_fltr_hash_tbl[BNXT_L2_FLTR_HASH_SIZE]; + + u32 hash_seed; + /* To protect link related settings during link changes and * ethtool settings changes. */ @@ -2595,6 +2622,7 @@ int bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode); int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp, unsigned long *bmap, int bmap_size, bool async_only); int bnxt_hwrm_func_drv_unrgtr(struct bnxt *bp); +void bnxt_del_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr); int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings); int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id); int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings); From bfeabf7e4615bf3076937be36456906b4597c64c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 22 Dec 2023 20:22:00 -0800 Subject: [PATCH 03/13] bnxt_en: Re-structure the bnxt_ntuple_filter structure. With the new bnxt_l2_filter structure, we can now re-structure the bnxt_ntuple_filter structure to point to the bnxt_l2_filter structure. We eliminate the L2 ether address info from the ntuple filter structure as we can get the information from the L2 filter structure. Note that the source L2 MAC address is no longer used. Reviewed-by: Vasundhara Volam Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 62 ++++++++++++++--------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 4 +- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 8e9a02629450..62e4f35c6f0f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4804,6 +4804,7 @@ static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool all) head = &bp->ntp_fltr_hash_tbl[i]; hlist_for_each_entry_safe(fltr, tmp, head, base.hash) { + bnxt_del_l2_filter(bp, fltr->l2_fltr); if (!all && (fltr->base.flags & BNXT_ACT_FUNC_DST)) continue; hlist_del(&fltr->base.hash); @@ -5373,6 +5374,20 @@ static struct bnxt_l2_filter *bnxt_lookup_l2_filter(struct bnxt *bp, return fltr; } +#ifdef CONFIG_RFS_ACCEL +static struct bnxt_l2_filter * +bnxt_lookup_l2_filter_from_key(struct bnxt *bp, struct bnxt_l2_key *key) +{ + struct bnxt_l2_filter *fltr; + u32 idx; + + idx = jhash2(&key->filter_key, BNXT_L2_KEY_SIZE, bp->hash_seed) & + BNXT_L2_FLTR_HASH_MASK; + fltr = bnxt_lookup_l2_filter(bp, key, idx); + return fltr; +} +#endif + static int bnxt_init_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr, struct bnxt_l2_key *key, u32 idx) { @@ -5432,7 +5447,6 @@ static int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp, #define BNXT_NTP_FLTR_FLAGS \ (CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_L2_FILTER_ID | \ CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_ETHERTYPE | \ - CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_SRC_MACADDR | \ CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_IPADDR_TYPE | \ CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_SRC_IPADDR | \ CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_SRC_IPADDR_MASK | \ @@ -5463,7 +5477,7 @@ static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, if (rc) return rc; - l2_fltr = bp->vnic_info[0].l2_filters[fltr->l2_fltr_idx]; + l2_fltr = fltr->l2_fltr; req->l2_filter_id = l2_fltr->base.filter_id; @@ -5478,7 +5492,6 @@ static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, req->enables = cpu_to_le32(BNXT_NTP_FLTR_FLAGS); req->ethertype = htons(ETH_P_IP); - memcpy(req->src_macaddr, fltr->src_mac_addr, ETH_ALEN); req->ip_addr_type = CFA_NTUPLE_FILTER_ALLOC_REQ_IP_ADDR_TYPE_IPV4; req->ip_protocol = keys->basic.ip_proto; @@ -13730,8 +13743,7 @@ static bool bnxt_fltr_match(struct bnxt_ntuple_filter *f1, if (keys1->ports.ports == keys2->ports.ports && keys1->control.flags == keys2->control.flags && - ether_addr_equal(f1->src_mac_addr, f2->src_mac_addr) && - ether_addr_equal(f1->dst_mac_addr, f2->dst_mac_addr)) + f1->l2_fltr == f2->l2_fltr) return true; return false; @@ -13744,29 +13756,32 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, struct bnxt_ntuple_filter *fltr, *new_fltr; struct flow_keys *fkeys; struct ethhdr *eth = (struct ethhdr *)skb_mac_header(skb); - int rc = 0, idx, bit_id, l2_idx = 0; + struct bnxt_l2_filter *l2_fltr; + int rc = 0, idx, bit_id; struct hlist_head *head; u32 flags; - if (!ether_addr_equal(dev->dev_addr, eth->h_dest)) { - struct bnxt_vnic_info *vnic = &bp->vnic_info[0]; - int off = 0, j; + if (ether_addr_equal(dev->dev_addr, eth->h_dest)) { + l2_fltr = bp->vnic_info[0].l2_filters[0]; + atomic_inc(&l2_fltr->refcnt); + } else { + struct bnxt_l2_key key; - netif_addr_lock_bh(dev); - for (j = 0; j < vnic->uc_filter_count; j++, off += ETH_ALEN) { - if (ether_addr_equal(eth->h_dest, - vnic->uc_list + off)) { - l2_idx = j + 1; - break; - } - } - netif_addr_unlock_bh(dev); - if (!l2_idx) + ether_addr_copy(key.dst_mac_addr, eth->h_dest); + key.vlan = 0; + l2_fltr = bnxt_lookup_l2_filter_from_key(bp, &key); + if (!l2_fltr) return -EINVAL; + if (l2_fltr->base.flags & BNXT_ACT_FUNC_DST) { + bnxt_del_l2_filter(bp, l2_fltr); + return -EINVAL; + } } new_fltr = kzalloc(sizeof(*new_fltr), GFP_ATOMIC); - if (!new_fltr) + if (!new_fltr) { + bnxt_del_l2_filter(bp, l2_fltr); return -ENOMEM; + } fkeys = &new_fltr->fkeys; if (!skb_flow_dissect_flow_keys(skb, fkeys, 0)) { @@ -13793,8 +13808,7 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, goto err_free; } - memcpy(new_fltr->dst_mac_addr, eth->h_dest, ETH_ALEN); - memcpy(new_fltr->src_mac_addr, eth->h_source, ETH_ALEN); + new_fltr->l2_fltr = l2_fltr; idx = skb_get_hash_raw(skb) & BNXT_NTP_FLTR_HASH_MASK; head = &bp->ntp_fltr_hash_tbl[idx]; @@ -13819,9 +13833,9 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, new_fltr->base.sw_id = (u16)bit_id; new_fltr->flow_id = flow_id; - new_fltr->l2_fltr_idx = l2_idx; new_fltr->base.rxq = rxq_index; new_fltr->base.type = BNXT_FLTR_TYPE_NTUPLE; + new_fltr->base.flags = BNXT_ACT_RING_DST; hlist_add_head_rcu(&new_fltr->base.hash, head); bp->ntp_fltr_count++; spin_unlock_bh(&bp->ntp_fltr_lock); @@ -13831,6 +13845,7 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, return new_fltr->base.sw_id; err_free: + bnxt_del_l2_filter(bp, l2_fltr); kfree(new_fltr); return rc; } @@ -13871,6 +13886,7 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp) hlist_del_rcu(&fltr->base.hash); bp->ntp_fltr_count--; spin_unlock_bh(&bp->ntp_fltr_lock); + bnxt_del_l2_filter(bp, fltr->l2_fltr); synchronize_rcu(); clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap); kfree(fltr); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 77c7084e47cd..72e99f2a5c68 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1355,10 +1355,8 @@ struct bnxt_filter_base { struct bnxt_ntuple_filter { struct bnxt_filter_base base; - u8 dst_mac_addr[ETH_ALEN]; - u8 src_mac_addr[ETH_ALEN]; struct flow_keys fkeys; - u8 l2_fltr_idx; + struct bnxt_l2_filter *l2_fltr; u32 flow_id; }; From 96c9bedc755ed1fa6e35d37328ddbcb439c93c4c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 22 Dec 2023 20:22:01 -0800 Subject: [PATCH 04/13] bnxt_en: Refactor L2 filter alloc/free firmware commands. Refactor the L2 filter alloc/free logic so that these filters can be added/deleted by the user. The bp->ntp_fltr_bmap allocated size is also increased to allow enough IDs for L2 filters. Reviewed-by: Vasundhara Volam Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 163 +++++++++++++++------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 3 + 2 files changed, 112 insertions(+), 54 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 62e4f35c6f0f..571f2c443c2e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4834,7 +4834,7 @@ static int bnxt_alloc_ntp_fltrs(struct bnxt *bp) INIT_HLIST_HEAD(&bp->ntp_fltr_hash_tbl[i]); bp->ntp_fltr_count = 0; - bp->ntp_fltr_bmap = bitmap_zalloc(BNXT_NTP_FLTR_MAX_FLTR, GFP_KERNEL); + bp->ntp_fltr_bmap = bitmap_zalloc(BNXT_MAX_FLTR, GFP_KERNEL); if (!bp->ntp_fltr_bmap) rc = -ENOMEM; @@ -5396,6 +5396,15 @@ static int bnxt_init_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr, ether_addr_copy(fltr->l2_key.dst_mac_addr, key->dst_mac_addr); fltr->l2_key.vlan = key->vlan; fltr->base.type = BNXT_FLTR_TYPE_L2; + if (fltr->base.flags) { + int bit_id; + + bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap, + BNXT_MAX_FLTR, 0); + if (bit_id < 0) + return -ENOMEM; + fltr->base.sw_id = (u16)bit_id; + } head = &bp->l2_fltr_hash_tbl[idx]; hlist_add_head_rcu(&fltr->base.hash, head); atomic_set(&fltr->refcnt, 1); @@ -5429,6 +5438,96 @@ static struct bnxt_l2_filter *bnxt_alloc_l2_filter(struct bnxt *bp, return fltr; } +static u16 bnxt_vf_target_id(struct bnxt_pf_info *pf, u16 vf_idx) +{ +#ifdef CONFIG_BNXT_SRIOV + struct bnxt_vf_info *vf = &pf->vf[vf_idx]; + + return vf->fw_fid; +#else + return INVALID_HW_RING_ID; +#endif +} + +int bnxt_hwrm_l2_filter_free(struct bnxt *bp, struct bnxt_l2_filter *fltr) +{ + struct hwrm_cfa_l2_filter_free_input *req; + u16 target_id = 0xffff; + int rc; + + if (fltr->base.flags & BNXT_ACT_FUNC_DST) { + struct bnxt_pf_info *pf = &bp->pf; + + if (fltr->base.vf_idx >= pf->active_vfs) + return -EINVAL; + + target_id = bnxt_vf_target_id(pf, fltr->base.vf_idx); + if (target_id == INVALID_HW_RING_ID) + return -EINVAL; + } + + rc = hwrm_req_init(bp, req, HWRM_CFA_L2_FILTER_FREE); + if (rc) + return rc; + + req->target_id = cpu_to_le16(target_id); + req->l2_filter_id = fltr->base.filter_id; + return hwrm_req_send(bp, req); +} + +int bnxt_hwrm_l2_filter_alloc(struct bnxt *bp, struct bnxt_l2_filter *fltr) +{ + struct hwrm_cfa_l2_filter_alloc_output *resp; + struct hwrm_cfa_l2_filter_alloc_input *req; + u16 target_id = 0xffff; + int rc; + + if (fltr->base.flags & BNXT_ACT_FUNC_DST) { + struct bnxt_pf_info *pf = &bp->pf; + + if (fltr->base.vf_idx >= pf->active_vfs) + return -EINVAL; + + target_id = bnxt_vf_target_id(pf, fltr->base.vf_idx); + } + rc = hwrm_req_init(bp, req, HWRM_CFA_L2_FILTER_ALLOC); + if (rc) + return rc; + + req->target_id = cpu_to_le16(target_id); + req->flags = cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX); + + if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) + req->flags |= + cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_FLAGS_OUTERMOST); + req->dst_id = cpu_to_le16(fltr->base.fw_vnic_id); + req->enables = + cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR | + CFA_L2_FILTER_ALLOC_REQ_ENABLES_DST_ID | + CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR_MASK); + ether_addr_copy(req->l2_addr, fltr->l2_key.dst_mac_addr); + eth_broadcast_addr(req->l2_addr_mask); + + if (fltr->l2_key.vlan) { + req->enables |= + cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_IVLAN | + CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_IVLAN_MASK | + CFA_L2_FILTER_ALLOC_REQ_ENABLES_NUM_VLANS); + req->num_vlans = 1; + req->l2_ivlan = cpu_to_le16(fltr->l2_key.vlan); + req->l2_ivlan_mask = cpu_to_le16(0xfff); + } + + resp = hwrm_req_hold(bp, req); + rc = hwrm_req_send(bp, req); + if (!rc) { + fltr->base.filter_id = resp->l2_filter_id; + set_bit(BNXT_FLTR_VALID, &fltr->base.state); + } + hwrm_req_drop(bp, req); + return rc; +} + #ifdef CONFIG_RFS_ACCEL static int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp, struct bnxt_ntuple_filter *fltr) @@ -5538,8 +5637,6 @@ static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, static int bnxt_hwrm_set_vnic_filter(struct bnxt *bp, u16 vnic_id, u16 idx, const u8 *mac_addr) { - struct hwrm_cfa_l2_filter_alloc_output *resp; - struct hwrm_cfa_l2_filter_alloc_input *req; struct bnxt_l2_filter *fltr; struct bnxt_l2_key key; int rc; @@ -5550,66 +5647,33 @@ static int bnxt_hwrm_set_vnic_filter(struct bnxt *bp, u16 vnic_id, u16 idx, if (IS_ERR(fltr)) return PTR_ERR(fltr); - rc = hwrm_req_init(bp, req, HWRM_CFA_L2_FILTER_ALLOC); + fltr->base.fw_vnic_id = bp->vnic_info[vnic_id].fw_vnic_id; + rc = bnxt_hwrm_l2_filter_alloc(bp, fltr); if (rc) - return rc; - - req->flags = cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_FLAGS_PATH_RX); - if (!BNXT_CHIP_TYPE_NITRO_A0(bp)) - req->flags |= - cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_FLAGS_OUTERMOST); - req->dst_id = cpu_to_le16(bp->vnic_info[vnic_id].fw_vnic_id); - req->enables = - cpu_to_le32(CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR | - CFA_L2_FILTER_ALLOC_REQ_ENABLES_DST_ID | - CFA_L2_FILTER_ALLOC_REQ_ENABLES_L2_ADDR_MASK); - memcpy(req->l2_addr, mac_addr, ETH_ALEN); - req->l2_addr_mask[0] = 0xff; - req->l2_addr_mask[1] = 0xff; - req->l2_addr_mask[2] = 0xff; - req->l2_addr_mask[3] = 0xff; - req->l2_addr_mask[4] = 0xff; - req->l2_addr_mask[5] = 0xff; - - resp = hwrm_req_hold(bp, req); - rc = hwrm_req_send(bp, req); - if (rc) { bnxt_del_l2_filter(bp, fltr); - } else { - fltr->base.filter_id = resp->l2_filter_id; - set_bit(BNXT_FLTR_VALID, &fltr->base.state); + else bp->vnic_info[vnic_id].l2_filters[idx] = fltr; - } - hwrm_req_drop(bp, req); return rc; } static int bnxt_hwrm_clear_vnic_filter(struct bnxt *bp) { - struct hwrm_cfa_l2_filter_free_input *req; u16 i, j, num_of_vnics = 1; /* only vnic 0 supported */ - int rc; + int rc = 0; /* Any associated ntuple filters will also be cleared by firmware. */ - rc = hwrm_req_init(bp, req, HWRM_CFA_L2_FILTER_FREE); - if (rc) - return rc; - hwrm_req_hold(bp, req); for (i = 0; i < num_of_vnics; i++) { struct bnxt_vnic_info *vnic = &bp->vnic_info[i]; for (j = 0; j < vnic->uc_filter_count; j++) { - struct bnxt_l2_filter *fltr; + struct bnxt_l2_filter *fltr = vnic->l2_filters[j]; - fltr = vnic->l2_filters[j]; - req->l2_filter_id = fltr->base.filter_id; - - rc = hwrm_req_send(bp, req); + bnxt_hwrm_l2_filter_free(bp, fltr); bnxt_del_l2_filter(bp, fltr); } vnic->uc_filter_count = 0; } - hwrm_req_drop(bp, req); + return rc; } @@ -11898,7 +11962,6 @@ static int bnxt_cfg_rx_mode(struct bnxt *bp) { struct net_device *dev = bp->dev; struct bnxt_vnic_info *vnic = &bp->vnic_info[0]; - struct hwrm_cfa_l2_filter_free_input *req; struct netdev_hw_addr *ha; int i, off = 0, rc; bool uc_update; @@ -11910,19 +11973,12 @@ static int bnxt_cfg_rx_mode(struct bnxt *bp) if (!uc_update) goto skip_uc; - rc = hwrm_req_init(bp, req, HWRM_CFA_L2_FILTER_FREE); - if (rc) - return rc; - hwrm_req_hold(bp, req); for (i = 1; i < vnic->uc_filter_count; i++) { struct bnxt_l2_filter *fltr = vnic->l2_filters[i]; - req->l2_filter_id = fltr->base.filter_id; - - rc = hwrm_req_send(bp, req); + bnxt_hwrm_l2_filter_free(bp, fltr); bnxt_del_l2_filter(bp, fltr); } - hwrm_req_drop(bp, req); vnic->uc_filter_count = 1; @@ -13823,8 +13879,7 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, rcu_read_unlock(); spin_lock_bh(&bp->ntp_fltr_lock); - bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap, - BNXT_NTP_FLTR_MAX_FLTR, 0); + bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap, BNXT_MAX_FLTR, 0); if (bit_id < 0) { spin_unlock_bh(&bp->ntp_fltr_lock); rc = -ENOMEM; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 72e99f2a5c68..5d67b8299328 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2398,6 +2398,7 @@ struct bnxt { int db_size; #define BNXT_NTP_FLTR_MAX_FLTR 4096 +#define BNXT_MAX_FLTR (BNXT_NTP_FLTR_MAX_FLTR + BNXT_L2_FLTR_MAX_FLTR) #define BNXT_NTP_FLTR_HASH_SIZE 512 #define BNXT_NTP_FLTR_HASH_MASK (BNXT_NTP_FLTR_HASH_SIZE - 1) struct hlist_head ntp_fltr_hash_tbl[BNXT_NTP_FLTR_HASH_SIZE]; @@ -2621,6 +2622,8 @@ int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp, unsigned long *bmap, int bmap_size, bool async_only); int bnxt_hwrm_func_drv_unrgtr(struct bnxt *bp); void bnxt_del_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr); +int bnxt_hwrm_l2_filter_free(struct bnxt *bp, struct bnxt_l2_filter *fltr); +int bnxt_hwrm_l2_filter_alloc(struct bnxt *bp, struct bnxt_l2_filter *fltr); int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings); int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id); int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings); From d3c982851c15ff1c5187a6188710daa7d0db7fe4 Mon Sep 17 00:00:00 2001 From: Pavan Chebbi Date: Fri, 22 Dec 2023 20:22:02 -0800 Subject: [PATCH 05/13] bnxt_en: Add function to calculate Toeplitz hash For ntuple filters added by aRFS, the Toeplitz hash calculated by our NIC is available and is used to store the ntuple filter for quick retrieval. In the next patches, user defined ntuple filter support will be added and we need to calculate the same hash for these filters. The same hash function needs to be used so we can detect duplicates. Add the function bnxt_toeplitz() to calculate the Toeplitz hash for user defined ntuple filters. bnxt_toeplitz() uses the same Toeplitz key and the same key length as the NIC. bnxt_get_ntp_filter_idx() is added to return the hash index. For aRFS, the hash comes from the NIC. For user defined ntuple, we call bnxt_toeplitz() to calculate the hash index. Reviewed-by: Andy Gospodarek Signed-off-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 100 +++++++++++++++++++++- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 11 +++ 2 files changed, 108 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 571f2c443c2e..e9b382832a14 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4199,13 +4199,22 @@ static void bnxt_init_vnics(struct bnxt *bp) vnic->fw_l2_ctx_id = INVALID_HW_RING_ID; if (bp->vnic_info[i].rss_hash_key) { - if (i == 0) + if (!i) { + u8 *key = (void *)vnic->rss_hash_key; + int k; + + bp->toeplitz_prefix = 0; get_random_bytes(vnic->rss_hash_key, HW_HASH_KEY_SIZE); - else + for (k = 0; k < 8; k++) { + bp->toeplitz_prefix <<= 8; + bp->toeplitz_prefix |= key[k]; + } + } else { memcpy(vnic->rss_hash_key, bp->vnic_info[0].rss_hash_key, HW_HASH_KEY_SIZE); + } } } } @@ -5374,6 +5383,79 @@ static struct bnxt_l2_filter *bnxt_lookup_l2_filter(struct bnxt *bp, return fltr; } +#define BNXT_IPV4_4TUPLE(bp, fkeys) \ + (((fkeys)->basic.ip_proto == IPPROTO_TCP && \ + (bp)->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV4) || \ + ((fkeys)->basic.ip_proto == IPPROTO_UDP && \ + (bp)->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV4)) + +#define BNXT_IPV6_4TUPLE(bp, fkeys) \ + (((fkeys)->basic.ip_proto == IPPROTO_TCP && \ + (bp)->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_TCP_IPV6) || \ + ((fkeys)->basic.ip_proto == IPPROTO_UDP && \ + (bp)->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6)) + +static u32 bnxt_get_rss_flow_tuple_len(struct bnxt *bp, struct flow_keys *fkeys) +{ + if (fkeys->basic.n_proto == htons(ETH_P_IP)) { + if (BNXT_IPV4_4TUPLE(bp, fkeys)) + return sizeof(fkeys->addrs.v4addrs) + + sizeof(fkeys->ports); + + if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4) + return sizeof(fkeys->addrs.v4addrs); + } + + if (fkeys->basic.n_proto == htons(ETH_P_IPV6)) { + if (BNXT_IPV6_4TUPLE(bp, fkeys)) + return sizeof(fkeys->addrs.v6addrs) + + sizeof(fkeys->ports); + + if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV6) + return sizeof(fkeys->addrs.v6addrs); + } + + return 0; +} + +static u32 bnxt_toeplitz(struct bnxt *bp, struct flow_keys *fkeys, + const unsigned char *key) +{ + u64 prefix = bp->toeplitz_prefix, hash = 0; + struct bnxt_ipv4_tuple tuple4; + struct bnxt_ipv6_tuple tuple6; + int i, j, len = 0; + u8 *four_tuple; + + len = bnxt_get_rss_flow_tuple_len(bp, fkeys); + if (!len) + return 0; + + if (fkeys->basic.n_proto == htons(ETH_P_IP)) { + tuple4.v4addrs = fkeys->addrs.v4addrs; + tuple4.ports = fkeys->ports; + four_tuple = (unsigned char *)&tuple4; + } else { + tuple6.v6addrs = fkeys->addrs.v6addrs; + tuple6.ports = fkeys->ports; + four_tuple = (unsigned char *)&tuple6; + } + + for (i = 0, j = 8; i < len; i++, j++) { + u8 byte = four_tuple[i]; + int bit; + + for (bit = 0; bit < 8; bit++, prefix <<= 1, byte <<= 1) { + if (byte & 0x80) + hash ^= prefix; + } + prefix |= (j < HW_HASH_KEY_SIZE) ? key[j] : 0; + } + + /* The valid part of the hash is in the upper 32 bits. */ + return (hash >> 32) & BNXT_NTP_FLTR_HASH_MASK; +} + #ifdef CONFIG_RFS_ACCEL static struct bnxt_l2_filter * bnxt_lookup_l2_filter_from_key(struct bnxt *bp, struct bnxt_l2_key *key) @@ -13774,6 +13856,18 @@ static int bnxt_setup_tc(struct net_device *dev, enum tc_setup_type type, } } +static u32 bnxt_get_ntp_filter_idx(struct bnxt *bp, struct flow_keys *fkeys, + const struct sk_buff *skb) +{ + struct bnxt_vnic_info *vnic; + + if (skb) + return skb_get_hash_raw(skb) & BNXT_NTP_FLTR_HASH_MASK; + + vnic = &bp->vnic_info[0]; + return bnxt_toeplitz(bp, fkeys, (void *)vnic->rss_hash_key); +} + #ifdef CONFIG_RFS_ACCEL static bool bnxt_fltr_match(struct bnxt_ntuple_filter *f1, struct bnxt_ntuple_filter *f2) @@ -13866,7 +13960,7 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, new_fltr->l2_fltr = l2_fltr; - idx = skb_get_hash_raw(skb) & BNXT_NTP_FLTR_HASH_MASK; + idx = bnxt_get_ntp_filter_idx(bp, fkeys, skb); head = &bp->ntp_fltr_hash_tbl[idx]; rcu_read_lock(); hlist_for_each_entry_rcu(fltr, head, base.hash) { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 5d67b8299328..3f4e4708f7d8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1370,6 +1370,16 @@ struct bnxt_l2_key { }; }; +struct bnxt_ipv4_tuple { + struct flow_dissector_key_ipv4_addrs v4addrs; + struct flow_dissector_key_ports ports; +}; + +struct bnxt_ipv6_tuple { + struct flow_dissector_key_ipv6_addrs v6addrs; + struct flow_dissector_key_ports ports; +}; + #define BNXT_L2_KEY_SIZE (sizeof(struct bnxt_l2_key) / 4) struct bnxt_l2_filter { @@ -2413,6 +2423,7 @@ struct bnxt { struct hlist_head l2_fltr_hash_tbl[BNXT_L2_FLTR_HASH_SIZE]; u32 hash_seed; + u64 toeplitz_prefix; /* To protect link related settings during link changes and * ethtool settings changes. From cb5bdd292dc01f42dd4ecebda203e2161a901c6f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 22 Dec 2023 20:22:03 -0800 Subject: [PATCH 06/13] bnxt_en: Add bnxt_lookup_ntp_filter_from_idx() function Add the helper function to look up the ntuple filter from the hash index and use it in bnxt_rx_flow_steer(). The helper function will also be used by user defined ntuple filters in the next patches. Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 26 +++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index e9b382832a14..7027391316e5 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -13899,6 +13899,21 @@ static bool bnxt_fltr_match(struct bnxt_ntuple_filter *f1, return false; } +static struct bnxt_ntuple_filter * +bnxt_lookup_ntp_filter_from_idx(struct bnxt *bp, + struct bnxt_ntuple_filter *fltr, u32 idx) +{ + struct bnxt_ntuple_filter *f; + struct hlist_head *head; + + head = &bp->ntp_fltr_hash_tbl[idx]; + hlist_for_each_entry_rcu(f, head, base.hash) { + if (bnxt_fltr_match(f, fltr)) + return f; + } + return NULL; +} + static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, u16 rxq_index, u32 flow_id) { @@ -13963,12 +13978,11 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, idx = bnxt_get_ntp_filter_idx(bp, fkeys, skb); head = &bp->ntp_fltr_hash_tbl[idx]; rcu_read_lock(); - hlist_for_each_entry_rcu(fltr, head, base.hash) { - if (bnxt_fltr_match(fltr, new_fltr)) { - rc = fltr->base.sw_id; - rcu_read_unlock(); - goto err_free; - } + fltr = bnxt_lookup_ntp_filter_from_idx(bp, new_fltr, idx); + if (fltr) { + rcu_read_unlock(); + rc = fltr->base.sw_id; + goto err_free; } rcu_read_unlock(); From ee908d05dd2acd89f5c0625535ef415fd89eb6aa Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 22 Dec 2023 20:22:04 -0800 Subject: [PATCH 07/13] bnxt_en: Add new BNXT_FLTR_INSERTED flag to bnxt_filter_base struct. Change the unused flag to BNXT_FLTR_INSERTED. To prepare for multiple pathways that an ntuple filter can be deleted, we add this flag. These filter structures can be retreived from the RCU hash table but only the caller that sees that the BNXT_FLTR_INSERTED flag is set can delete the filter structure and clear the flag under spinlock. Reviewed-by: Vasundhara Volam Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 10 ++++++++++ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 7027391316e5..0aecf89b4fb9 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5343,6 +5343,10 @@ void bnxt_del_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr) if (!atomic_dec_and_test(&fltr->refcnt)) return; spin_lock_bh(&bp->ntp_fltr_lock); + if (!test_and_clear_bit(BNXT_FLTR_INSERTED, &fltr->base.state)) { + spin_unlock_bh(&bp->ntp_fltr_lock); + return; + } hlist_del_rcu(&fltr->base.hash); if (fltr->base.flags) { clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap); @@ -5489,6 +5493,7 @@ static int bnxt_init_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr, } head = &bp->l2_fltr_hash_tbl[idx]; hlist_add_head_rcu(&fltr->base.hash, head); + set_bit(BNXT_FLTR_INSERTED, &fltr->base.state); atomic_set(&fltr->refcnt, 1); return 0; } @@ -14000,6 +14005,7 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, new_fltr->base.type = BNXT_FLTR_TYPE_NTUPLE; new_fltr->base.flags = BNXT_ACT_RING_DST; hlist_add_head_rcu(&new_fltr->base.hash, head); + set_bit(BNXT_FLTR_INSERTED, &new_fltr->base.state); bp->ntp_fltr_count++; spin_unlock_bh(&bp->ntp_fltr_lock); @@ -14046,6 +14052,10 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp) if (del) { spin_lock_bh(&bp->ntp_fltr_lock); + if (!test_and_clear_bit(BNXT_FLTR_INSERTED, &fltr->base.state)) { + spin_unlock_bh(&bp->ntp_fltr_lock); + continue; + } hlist_del_rcu(&fltr->base.hash); bp->ntp_fltr_count--; spin_unlock_bh(&bp->ntp_fltr_lock); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 3f4e4708f7d8..867cab036e13 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1348,7 +1348,7 @@ struct bnxt_filter_base { u16 vf_idx; unsigned long state; #define BNXT_FLTR_VALID 0 -#define BNXT_FLTR_UPDATE 1 +#define BNXT_FLTR_INSERTED 1 struct rcu_head rcu; }; From 59cde76f33fa4ae5cdc7f51ce87bab9e531ca183 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 22 Dec 2023 20:22:05 -0800 Subject: [PATCH 08/13] bnxt_en: Refactor filter insertion logic in bnxt_rx_flow_steer(). Add a new function bnxt_insert_ntp_filter() to insert the ntuple filter into the hash table and other basic setup. We'll use this function to insert a user defined filter from ethtool. Also, export bnxt_lookup_ntp_filter_from_idx() and bnxt_get_ntp_filter_idx() for similar purposes. All ntuple related functions are now no longer compiled only for CONFIG_RFS_ACCEL Reviewed-by: Vasundhara Volam Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 87 +++++++++-------------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 6 ++ 2 files changed, 41 insertions(+), 52 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 0aecf89b4fb9..097d440339b0 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -4800,7 +4800,6 @@ static void bnxt_clear_ring_indices(struct bnxt *bp) static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool all) { -#ifdef CONFIG_RFS_ACCEL int i; /* Under rtnl_lock and all our NAPIs have been disabled. It's @@ -4828,12 +4827,10 @@ static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool all) bitmap_free(bp->ntp_fltr_bmap); bp->ntp_fltr_bmap = NULL; bp->ntp_fltr_count = 0; -#endif } static int bnxt_alloc_ntp_fltrs(struct bnxt *bp) { -#ifdef CONFIG_RFS_ACCEL int i, rc = 0; if (!(bp->flags & BNXT_FLAG_RFS) || bp->ntp_fltr_bmap) @@ -4849,9 +4846,6 @@ static int bnxt_alloc_ntp_fltrs(struct bnxt *bp) rc = -ENOMEM; return rc; -#else - return 0; -#endif } static void bnxt_free_l2_filters(struct bnxt *bp, bool all) @@ -5615,7 +5609,6 @@ int bnxt_hwrm_l2_filter_alloc(struct bnxt *bp, struct bnxt_l2_filter *fltr) return rc; } -#ifdef CONFIG_RFS_ACCEL static int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp, struct bnxt_ntuple_filter *fltr) { @@ -5719,7 +5712,6 @@ static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, hwrm_req_drop(bp, req); return rc; } -#endif static int bnxt_hwrm_set_vnic_filter(struct bnxt *bp, u16 vnic_id, u16 idx, const u8 *mac_addr) @@ -9677,7 +9669,6 @@ static int bnxt_setup_vnic(struct bnxt *bp, u16 vnic_id) static int bnxt_alloc_rfs_vnics(struct bnxt *bp) { -#ifdef CONFIG_RFS_ACCEL int i, rc = 0; if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) @@ -9706,9 +9697,6 @@ static int bnxt_alloc_rfs_vnics(struct bnxt *bp) break; } return rc; -#else - return 0; -#endif } /* Allow PF, trusted VFs and VFs with default VLAN to be in promiscuous mode */ @@ -10036,7 +10024,6 @@ static int bnxt_setup_int_mode(struct bnxt *bp) return rc; } -#ifdef CONFIG_RFS_ACCEL static unsigned int bnxt_get_max_func_rss_ctxs(struct bnxt *bp) { return bp->hw_resc.max_rsscos_ctxs; @@ -10046,7 +10033,6 @@ static unsigned int bnxt_get_max_func_vnics(struct bnxt *bp) { return bp->hw_resc.max_vnics; } -#endif unsigned int bnxt_get_max_func_stat_ctxs(struct bnxt *bp) { @@ -12160,7 +12146,6 @@ static bool bnxt_rfs_supported(struct bnxt *bp) /* If runtime conditions support RFS */ static bool bnxt_rfs_capable(struct bnxt *bp) { -#ifdef CONFIG_RFS_ACCEL int vnics, max_vnics, max_rss_ctxs; if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) @@ -12196,9 +12181,6 @@ static bool bnxt_rfs_capable(struct bnxt *bp) netdev_warn(bp->dev, "Unable to reserve resources to support NTUPLE filters.\n"); bnxt_hwrm_reserve_rings(bp, 0, 0, 0, 0, 0, 1); return false; -#else - return false; -#endif } static netdev_features_t bnxt_fix_features(struct net_device *dev, @@ -13861,8 +13843,8 @@ static int bnxt_setup_tc(struct net_device *dev, enum tc_setup_type type, } } -static u32 bnxt_get_ntp_filter_idx(struct bnxt *bp, struct flow_keys *fkeys, - const struct sk_buff *skb) +u32 bnxt_get_ntp_filter_idx(struct bnxt *bp, struct flow_keys *fkeys, + const struct sk_buff *skb) { struct bnxt_vnic_info *vnic; @@ -13873,7 +13855,30 @@ static u32 bnxt_get_ntp_filter_idx(struct bnxt *bp, struct flow_keys *fkeys, return bnxt_toeplitz(bp, fkeys, (void *)vnic->rss_hash_key); } -#ifdef CONFIG_RFS_ACCEL +int bnxt_insert_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr, + u32 idx) +{ + struct hlist_head *head; + int bit_id; + + spin_lock_bh(&bp->ntp_fltr_lock); + bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap, BNXT_MAX_FLTR, 0); + if (bit_id < 0) { + spin_unlock_bh(&bp->ntp_fltr_lock); + return -ENOMEM; + } + + fltr->base.sw_id = (u16)bit_id; + fltr->base.type = BNXT_FLTR_TYPE_NTUPLE; + fltr->base.flags |= BNXT_ACT_RING_DST; + head = &bp->ntp_fltr_hash_tbl[idx]; + hlist_add_head_rcu(&fltr->base.hash, head); + set_bit(BNXT_FLTR_INSERTED, &fltr->base.state); + bp->ntp_fltr_count++; + spin_unlock_bh(&bp->ntp_fltr_lock); + return 0; +} + static bool bnxt_fltr_match(struct bnxt_ntuple_filter *f1, struct bnxt_ntuple_filter *f2) { @@ -13904,7 +13909,7 @@ static bool bnxt_fltr_match(struct bnxt_ntuple_filter *f1, return false; } -static struct bnxt_ntuple_filter * +struct bnxt_ntuple_filter * bnxt_lookup_ntp_filter_from_idx(struct bnxt *bp, struct bnxt_ntuple_filter *fltr, u32 idx) { @@ -13919,6 +13924,7 @@ bnxt_lookup_ntp_filter_from_idx(struct bnxt *bp, return NULL; } +#ifdef CONFIG_RFS_ACCEL static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, u16 rxq_index, u32 flow_id) { @@ -13927,8 +13933,7 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, struct flow_keys *fkeys; struct ethhdr *eth = (struct ethhdr *)skb_mac_header(skb); struct bnxt_l2_filter *l2_fltr; - int rc = 0, idx, bit_id; - struct hlist_head *head; + int rc = 0, idx; u32 flags; if (ether_addr_equal(dev->dev_addr, eth->h_dest)) { @@ -13981,7 +13986,6 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, new_fltr->l2_fltr = l2_fltr; idx = bnxt_get_ntp_filter_idx(bp, fkeys, skb); - head = &bp->ntp_fltr_hash_tbl[idx]; rcu_read_lock(); fltr = bnxt_lookup_ntp_filter_from_idx(bp, new_fltr, idx); if (fltr) { @@ -13991,33 +13995,20 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, } rcu_read_unlock(); - spin_lock_bh(&bp->ntp_fltr_lock); - bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap, BNXT_MAX_FLTR, 0); - if (bit_id < 0) { - spin_unlock_bh(&bp->ntp_fltr_lock); - rc = -ENOMEM; - goto err_free; - } - - new_fltr->base.sw_id = (u16)bit_id; new_fltr->flow_id = flow_id; new_fltr->base.rxq = rxq_index; - new_fltr->base.type = BNXT_FLTR_TYPE_NTUPLE; - new_fltr->base.flags = BNXT_ACT_RING_DST; - hlist_add_head_rcu(&new_fltr->base.hash, head); - set_bit(BNXT_FLTR_INSERTED, &new_fltr->base.state); - bp->ntp_fltr_count++; - spin_unlock_bh(&bp->ntp_fltr_lock); - - bnxt_queue_sp_work(bp, BNXT_RX_NTP_FLTR_SP_EVENT); - - return new_fltr->base.sw_id; + rc = bnxt_insert_ntp_filter(bp, new_fltr, idx); + if (!rc) { + bnxt_queue_sp_work(bp, BNXT_RX_NTP_FLTR_SP_EVENT); + return new_fltr->base.sw_id; + } err_free: bnxt_del_l2_filter(bp, l2_fltr); kfree(new_fltr); return rc; } +#endif static void bnxt_cfg_ntp_filters(struct bnxt *bp) { @@ -14070,14 +14061,6 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp) netdev_info(bp->dev, "Receive PF driver unload event!\n"); } -#else - -static void bnxt_cfg_ntp_filters(struct bnxt *bp) -{ -} - -#endif /* CONFIG_RFS_ACCEL */ - static int bnxt_udp_tunnel_set_port(struct net_device *netdev, unsigned int table, unsigned int entry, struct udp_tunnel_info *ti) { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 867cab036e13..73e2fe705caf 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2678,6 +2678,12 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs, int bnxt_fw_init_one(struct bnxt *bp); bool bnxt_hwrm_reset_permitted(struct bnxt *bp); int bnxt_setup_mq_tc(struct net_device *dev, u8 tc); +struct bnxt_ntuple_filter *bnxt_lookup_ntp_filter_from_idx(struct bnxt *bp, + struct bnxt_ntuple_filter *fltr, u32 idx); +u32 bnxt_get_ntp_filter_idx(struct bnxt *bp, struct flow_keys *fkeys, + const struct sk_buff *skb); +int bnxt_insert_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr, + u32 idx); int bnxt_get_max_rings(struct bnxt *, int *, int *, bool); int bnxt_restore_pf_fw_resources(struct bnxt *bp); int bnxt_get_port_parent_id(struct net_device *dev, From 80cfde29ce1fab7f2cedd259e335f3bc725118d2 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 22 Dec 2023 20:22:06 -0800 Subject: [PATCH 09/13] bnxt_en: Refactor the hash table logic for ntuple filters. Generalize the ethtool logic that walks the ntuple hash table now that we have the common bnxt_filter_base structure. This will allow the code to easily extend to cover user defined ntuple or ether filters. Reviewed-by: Vasundhara Volam Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 1 + drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 + .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 87 ++++++++++++------- 3 files changed, 60 insertions(+), 29 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 097d440339b0..1e5bf8b7dd55 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5615,6 +5615,7 @@ static int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp, struct hwrm_cfa_ntuple_filter_free_input *req; int rc; + set_bit(BNXT_FLTR_FW_DELETED, &fltr->base.state); rc = hwrm_req_init(bp, req, HWRM_CFA_NTUPLE_FILTER_FREE); if (rc) return rc; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 73e2fe705caf..f37d98d7962a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1349,6 +1349,7 @@ struct bnxt_filter_base { unsigned long state; #define BNXT_FLTR_VALID 0 #define BNXT_FLTR_INSERTED 1 +#define BNXT_FLTR_FW_DELETED 2 struct rcu_head rcu; }; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 65edad2cfeab..8cc762a12a3e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1012,28 +1012,60 @@ static int bnxt_set_channels(struct net_device *dev, } #ifdef CONFIG_RFS_ACCEL +static u32 bnxt_get_all_fltr_ids_rcu(struct bnxt *bp, struct hlist_head tbl[], + int tbl_size, u32 *ids, u32 start, + u32 id_cnt) +{ + int i, j = start; + + if (j >= id_cnt) + return j; + for (i = 0; i < tbl_size; i++) { + struct hlist_head *head; + struct bnxt_filter_base *fltr; + + head = &tbl[i]; + hlist_for_each_entry_rcu(fltr, head, hash) { + if (!fltr->flags || + test_bit(BNXT_FLTR_FW_DELETED, &fltr->state)) + continue; + ids[j++] = fltr->sw_id; + if (j == id_cnt) + return j; + } + } + return j; +} + +static struct bnxt_filter_base *bnxt_get_one_fltr_rcu(struct bnxt *bp, + struct hlist_head tbl[], + int tbl_size, u32 id) +{ + int i; + + for (i = 0; i < tbl_size; i++) { + struct hlist_head *head; + struct bnxt_filter_base *fltr; + + head = &tbl[i]; + hlist_for_each_entry_rcu(fltr, head, hash) { + if (fltr->flags && fltr->sw_id == id) + return fltr; + } + } + return NULL; +} + static int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd, u32 *rule_locs) { - int i, j = 0; - cmd->data = bp->ntp_fltr_count; - for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) { - struct hlist_head *head; - struct bnxt_ntuple_filter *fltr; + rcu_read_lock(); + cmd->rule_cnt = bnxt_get_all_fltr_ids_rcu(bp, bp->ntp_fltr_hash_tbl, + BNXT_NTP_FLTR_HASH_SIZE, + rule_locs, 0, cmd->rule_cnt); + rcu_read_unlock(); - head = &bp->ntp_fltr_hash_tbl[i]; - rcu_read_lock(); - hlist_for_each_entry_rcu(fltr, head, base.hash) { - if (j == cmd->rule_cnt) - break; - rule_locs[j++] = fltr->base.sw_id; - } - rcu_read_unlock(); - if (j == cmd->rule_cnt) - break; - } - cmd->rule_cnt = j; return 0; } @@ -1041,27 +1073,24 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) { struct ethtool_rx_flow_spec *fs = (struct ethtool_rx_flow_spec *)&cmd->fs; + struct bnxt_filter_base *fltr_base; struct bnxt_ntuple_filter *fltr; struct flow_keys *fkeys; - int i, rc = -EINVAL; + int rc = -EINVAL; if (fs->location >= BNXT_NTP_FLTR_MAX_FLTR) return rc; - for (i = 0; i < BNXT_NTP_FLTR_HASH_SIZE; i++) { - struct hlist_head *head; - - head = &bp->ntp_fltr_hash_tbl[i]; - rcu_read_lock(); - hlist_for_each_entry_rcu(fltr, head, base.hash) { - if (fltr->base.sw_id == fs->location) - goto fltr_found; - } + rcu_read_lock(); + fltr_base = bnxt_get_one_fltr_rcu(bp, bp->ntp_fltr_hash_tbl, + BNXT_NTP_FLTR_HASH_SIZE, + fs->location); + if (!fltr_base) { rcu_read_unlock(); + return rc; } - return rc; + fltr = container_of(fltr_base, struct bnxt_ntuple_filter, base); -fltr_found: fkeys = &fltr->fkeys; if (fkeys->basic.n_proto == htons(ETH_P_IP)) { if (fkeys->basic.ip_proto == IPPROTO_TCP) From 4faeadfd7ed67dc004d292bc3a9557f3c64fae9f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 22 Dec 2023 20:22:07 -0800 Subject: [PATCH 10/13] bnxt_en: Refactor ntuple filter removal logic in bnxt_cfg_ntp_filters(). Refactor the logic into a new function bnxt_del_ntp_filters(). The same call will be used when the user deletes an ntuple filter. The bnxt_hwrm_cfa_ntuple_filter_free() function to call fw to free the ntuple filter is exported so that the ethtool logic can call it. Reviewed-by: Vasundhara Volam Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Reviewed-by: Simon Horman Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 35 ++++++++++++----------- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 3 ++ 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 1e5bf8b7dd55..79a1081c25f5 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5609,8 +5609,8 @@ int bnxt_hwrm_l2_filter_alloc(struct bnxt *bp, struct bnxt_l2_filter *fltr) return rc; } -static int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp, - struct bnxt_ntuple_filter *fltr) +int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp, + struct bnxt_ntuple_filter *fltr) { struct hwrm_cfa_ntuple_filter_free_input *req; int rc; @@ -14011,6 +14011,21 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, } #endif +void bnxt_del_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr) +{ + spin_lock_bh(&bp->ntp_fltr_lock); + if (!test_and_clear_bit(BNXT_FLTR_INSERTED, &fltr->base.state)) { + spin_unlock_bh(&bp->ntp_fltr_lock); + return; + } + hlist_del_rcu(&fltr->base.hash); + bp->ntp_fltr_count--; + spin_unlock_bh(&bp->ntp_fltr_lock); + bnxt_del_l2_filter(bp, fltr->l2_fltr); + clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap); + kfree_rcu(fltr, base.rcu); +} + static void bnxt_cfg_ntp_filters(struct bnxt *bp) { int i; @@ -14042,20 +14057,8 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp) set_bit(BNXT_FLTR_VALID, &fltr->base.state); } - if (del) { - spin_lock_bh(&bp->ntp_fltr_lock); - if (!test_and_clear_bit(BNXT_FLTR_INSERTED, &fltr->base.state)) { - spin_unlock_bh(&bp->ntp_fltr_lock); - continue; - } - hlist_del_rcu(&fltr->base.hash); - bp->ntp_fltr_count--; - spin_unlock_bh(&bp->ntp_fltr_lock); - bnxt_del_l2_filter(bp, fltr->l2_fltr); - synchronize_rcu(); - clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap); - kfree(fltr); - } + if (del) + bnxt_del_ntp_filter(bp, fltr); } } if (test_and_clear_bit(BNXT_HWRM_PF_UNLOAD_SP_EVENT, &bp->sp_event)) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index f37d98d7962a..60f62bc36d2c 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2636,6 +2636,8 @@ int bnxt_hwrm_func_drv_unrgtr(struct bnxt *bp); void bnxt_del_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr); int bnxt_hwrm_l2_filter_free(struct bnxt *bp, struct bnxt_l2_filter *fltr); int bnxt_hwrm_l2_filter_alloc(struct bnxt *bp, struct bnxt_l2_filter *fltr); +int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp, + struct bnxt_ntuple_filter *fltr); int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings); int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id); int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings); @@ -2685,6 +2687,7 @@ u32 bnxt_get_ntp_filter_idx(struct bnxt *bp, struct flow_keys *fkeys, const struct sk_buff *skb); int bnxt_insert_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr, u32 idx); +void bnxt_del_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr); int bnxt_get_max_rings(struct bnxt *, int *, int *, bool); int bnxt_restore_pf_fw_resources(struct bnxt *bp); int bnxt_get_port_parent_id(struct net_device *dev, From 300c191800987a3de3422dad424601d5493041c7 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 22 Dec 2023 20:22:08 -0800 Subject: [PATCH 11/13] bnxt_en: Add ntuple matching flags to the bnxt_ntuple_filter structure. aRFS filters match all 5 tuples. User defined ntuple filters may specify some of the tuples as wildcards. To support that, we add the ntuple_flags to the bnxt_ntuple_filter struct to specify which tuple fields are to be matched. The matching tuple fields will then be passed to the firmware in bnxt_hwrm_cfa_ntuple_filter_alloc() to create the proper filter. Reviewed-by: Vasundhara Volam Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 81 +++++++++++++------ drivers/net/ethernet/broadcom/bnxt/bnxt.h | 10 +++ .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 58 +++++++------ 3 files changed, 99 insertions(+), 50 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 79a1081c25f5..b949ab124dda 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5642,6 +5642,14 @@ int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp, #define BNXT_NTP_TUNNEL_FLTR_FLAG \ CFA_NTUPLE_FILTER_ALLOC_REQ_ENABLES_TUNNEL_TYPE +void bnxt_fill_ipv6_mask(__be32 mask[4]) +{ + int i; + + for (i = 0; i < 4; i++) + mask[i] = cpu_to_be32(~0); +} + static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, struct bnxt_ntuple_filter *fltr) { @@ -5676,24 +5684,28 @@ static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, req->ip_protocol = keys->basic.ip_proto; if (keys->basic.n_proto == htons(ETH_P_IPV6)) { - int i; - req->ethertype = htons(ETH_P_IPV6); req->ip_addr_type = CFA_NTUPLE_FILTER_ALLOC_REQ_IP_ADDR_TYPE_IPV6; - *(struct in6_addr *)&req->src_ipaddr[0] = - keys->addrs.v6addrs.src; - *(struct in6_addr *)&req->dst_ipaddr[0] = - keys->addrs.v6addrs.dst; - for (i = 0; i < 4; i++) { - req->src_ipaddr_mask[i] = cpu_to_be32(0xffffffff); - req->dst_ipaddr_mask[i] = cpu_to_be32(0xffffffff); + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) { + *(struct in6_addr *)&req->src_ipaddr[0] = + keys->addrs.v6addrs.src; + bnxt_fill_ipv6_mask(req->src_ipaddr_mask); + } + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) { + *(struct in6_addr *)&req->dst_ipaddr[0] = + keys->addrs.v6addrs.dst; + bnxt_fill_ipv6_mask(req->dst_ipaddr_mask); } } else { - req->src_ipaddr[0] = keys->addrs.v4addrs.src; - req->src_ipaddr_mask[0] = cpu_to_be32(0xffffffff); - req->dst_ipaddr[0] = keys->addrs.v4addrs.dst; - req->dst_ipaddr_mask[0] = cpu_to_be32(0xffffffff); + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) { + req->src_ipaddr[0] = keys->addrs.v4addrs.src; + req->src_ipaddr_mask[0] = cpu_to_be32(0xffffffff); + } + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) { + req->dst_ipaddr[0] = keys->addrs.v4addrs.dst; + req->dst_ipaddr_mask[0] = cpu_to_be32(0xffffffff); + } } if (keys->control.flags & FLOW_DIS_ENCAPSULATION) { req->enables |= cpu_to_le32(BNXT_NTP_TUNNEL_FLTR_FLAG); @@ -5701,10 +5713,14 @@ static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL; } - req->src_port = keys->ports.src; - req->src_port_mask = cpu_to_be16(0xffff); - req->dst_port = keys->ports.dst; - req->dst_port_mask = cpu_to_be16(0xffff); + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_PORT) { + req->src_port = keys->ports.src; + req->src_port_mask = cpu_to_be16(0xffff); + } + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_PORT) { + req->dst_port = keys->ports.dst; + req->dst_port_mask = cpu_to_be16(0xffff); + } resp = hwrm_req_hold(bp, req); rc = hwrm_req_send(bp, req); @@ -13886,24 +13902,38 @@ static bool bnxt_fltr_match(struct bnxt_ntuple_filter *f1, struct flow_keys *keys1 = &f1->fkeys; struct flow_keys *keys2 = &f2->fkeys; + if (f1->ntuple_flags != f2->ntuple_flags) + return false; + if (keys1->basic.n_proto != keys2->basic.n_proto || keys1->basic.ip_proto != keys2->basic.ip_proto) return false; if (keys1->basic.n_proto == htons(ETH_P_IP)) { - if (keys1->addrs.v4addrs.src != keys2->addrs.v4addrs.src || - keys1->addrs.v4addrs.dst != keys2->addrs.v4addrs.dst) + if (((f1->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) && + keys1->addrs.v4addrs.src != keys2->addrs.v4addrs.src) || + ((f1->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) && + keys1->addrs.v4addrs.dst != keys2->addrs.v4addrs.dst)) return false; } else { - if (memcmp(&keys1->addrs.v6addrs.src, &keys2->addrs.v6addrs.src, - sizeof(keys1->addrs.v6addrs.src)) || - memcmp(&keys1->addrs.v6addrs.dst, &keys2->addrs.v6addrs.dst, - sizeof(keys1->addrs.v6addrs.dst))) + if (((f1->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) && + memcmp(&keys1->addrs.v6addrs.src, + &keys2->addrs.v6addrs.src, + sizeof(keys1->addrs.v6addrs.src))) || + ((f1->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) && + memcmp(&keys1->addrs.v6addrs.dst, + &keys2->addrs.v6addrs.dst, + sizeof(keys1->addrs.v6addrs.dst)))) return false; } - if (keys1->ports.ports == keys2->ports.ports && - keys1->control.flags == keys2->control.flags && + if (((f1->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_PORT) && + keys1->ports.src != keys2->ports.src) || + ((f1->ntuple_flags & BNXT_NTUPLE_MATCH_DST_PORT) && + keys1->ports.dst != keys2->ports.dst)) + return false; + + if (keys1->control.flags == keys2->control.flags && f1->l2_fltr == f2->l2_fltr) return true; @@ -13985,6 +14015,7 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, } new_fltr->l2_fltr = l2_fltr; + new_fltr->ntuple_flags = BNXT_NTUPLE_MATCH_ALL; idx = bnxt_get_ntp_filter_idx(bp, fkeys, skb); rcu_read_lock(); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index 60f62bc36d2c..dc1bc163c82f 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1358,6 +1358,15 @@ struct bnxt_ntuple_filter { struct bnxt_filter_base base; struct flow_keys fkeys; struct bnxt_l2_filter *l2_fltr; + u32 ntuple_flags; +#define BNXT_NTUPLE_MATCH_SRC_IP 1 +#define BNXT_NTUPLE_MATCH_DST_IP 2 +#define BNXT_NTUPLE_MATCH_SRC_PORT 4 +#define BNXT_NTUPLE_MATCH_DST_PORT 8 +#define BNXT_NTUPLE_MATCH_ALL (BNXT_NTUPLE_MATCH_SRC_IP | \ + BNXT_NTUPLE_MATCH_DST_IP | \ + BNXT_NTUPLE_MATCH_SRC_PORT | \ + BNXT_NTUPLE_MATCH_DST_PORT) u32 flow_id; }; @@ -2638,6 +2647,7 @@ int bnxt_hwrm_l2_filter_free(struct bnxt *bp, struct bnxt_l2_filter *fltr); int bnxt_hwrm_l2_filter_alloc(struct bnxt *bp, struct bnxt_l2_filter *fltr); int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp, struct bnxt_ntuple_filter *fltr); +void bnxt_fill_ipv6_mask(__be32 mask[4]); int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings); int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id); int __bnxt_hwrm_get_tx_rings(struct bnxt *bp, u16 fid, int *tx_rings); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 8cc762a12a3e..558dd1f9a18e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1100,20 +1100,23 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) else goto fltr_err; - fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src; - fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0); - - fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst; - fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0); - - fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src; - fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0); - - fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst; - fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0); + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) { + fs->h_u.tcp_ip4_spec.ip4src = fkeys->addrs.v4addrs.src; + fs->m_u.tcp_ip4_spec.ip4src = cpu_to_be32(~0); + } + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) { + fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst; + fs->m_u.tcp_ip4_spec.ip4dst = cpu_to_be32(~0); + } + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_PORT) { + fs->h_u.tcp_ip4_spec.psrc = fkeys->ports.src; + fs->m_u.tcp_ip4_spec.psrc = cpu_to_be16(~0); + } + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_PORT) { + fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst; + fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0); + } } else { - int i; - if (fkeys->basic.ip_proto == IPPROTO_TCP) fs->flow_type = TCP_V6_FLOW; else if (fkeys->basic.ip_proto == IPPROTO_UDP) @@ -1121,19 +1124,24 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) else goto fltr_err; - *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] = - fkeys->addrs.v6addrs.src; - *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] = - fkeys->addrs.v6addrs.dst; - for (i = 0; i < 4; i++) { - fs->m_u.tcp_ip6_spec.ip6src[i] = cpu_to_be32(~0); - fs->m_u.tcp_ip6_spec.ip6dst[i] = cpu_to_be32(~0); + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_IP) { + *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] = + fkeys->addrs.v6addrs.src; + bnxt_fill_ipv6_mask(fs->m_u.tcp_ip6_spec.ip6src); + } + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_IP) { + *(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] = + fkeys->addrs.v6addrs.dst; + bnxt_fill_ipv6_mask(fs->m_u.tcp_ip6_spec.ip6dst); + } + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_SRC_PORT) { + fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src; + fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(~0); + } + if (fltr->ntuple_flags & BNXT_NTUPLE_MATCH_DST_PORT) { + fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst; + fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0); } - fs->h_u.tcp_ip6_spec.psrc = fkeys->ports.src; - fs->m_u.tcp_ip6_spec.psrc = cpu_to_be16(~0); - - fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst; - fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0); } fs->ring_cookie = fltr->base.rxq; From c029bc30b9f6661932ee38e4bba3e8da137a579d Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 22 Dec 2023 20:22:09 -0800 Subject: [PATCH 12/13] bnxt_en: Add support for ntuple filters added from ethtool. Add support for adding user defined ntuple TCP/UDP filters. These filters are similar to aRFS filters except that they don't get aged. Source IP, destination IP, source port, or destination port can be unspecifed as wildcard. At least one of these tuples must be specifed. If a tuple is specified, the full mask must be specified. All ntuple related ethtool functions are now no longer compiled only for CONFIG_RFS_ACCEL. Reviewed-by: Vasundhara Volam Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 6 +- drivers/net/ethernet/broadcom/bnxt/bnxt.h | 3 + .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 199 +++++++++++++++++- 3 files changed, 201 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index b949ab124dda..827821e89c40 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -5650,8 +5650,8 @@ void bnxt_fill_ipv6_mask(__be32 mask[4]) mask[i] = cpu_to_be32(~0); } -static int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, - struct bnxt_ntuple_filter *fltr) +int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, + struct bnxt_ntuple_filter *fltr) { struct hwrm_cfa_ntuple_filter_alloc_output *resp; struct hwrm_cfa_ntuple_filter_alloc_input *req; @@ -14072,6 +14072,8 @@ static void bnxt_cfg_ntp_filters(struct bnxt *bp) bool del = false; if (test_bit(BNXT_FLTR_VALID, &fltr->base.state)) { + if (fltr->base.flags & BNXT_ACT_NO_AGING) + continue; if (rps_may_expire_flow(bp->dev, fltr->base.rxq, fltr->flow_id, fltr->base.sw_id)) { diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index dc1bc163c82f..b8ef1717cb65 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -1342,6 +1342,7 @@ struct bnxt_filter_base { #define BNXT_ACT_DROP 1 #define BNXT_ACT_RING_DST 2 #define BNXT_ACT_FUNC_DST 4 +#define BNXT_ACT_NO_AGING 8 u16 sw_id; u16 rxq; u16 fw_vnic_id; @@ -2647,6 +2648,8 @@ int bnxt_hwrm_l2_filter_free(struct bnxt *bp, struct bnxt_l2_filter *fltr); int bnxt_hwrm_l2_filter_alloc(struct bnxt *bp, struct bnxt_l2_filter *fltr); int bnxt_hwrm_cfa_ntuple_filter_free(struct bnxt *bp, struct bnxt_ntuple_filter *fltr); +int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp, + struct bnxt_ntuple_filter *fltr); void bnxt_fill_ipv6_mask(__be32 mask[4]); int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings); int bnxt_hwrm_vnic_cfg(struct bnxt *bp, u16 vnic_id); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 558dd1f9a18e..c3b9be328b87 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1011,7 +1011,6 @@ static int bnxt_set_channels(struct net_device *dev, return rc; } -#ifdef CONFIG_RFS_ACCEL static u32 bnxt_get_all_fltr_ids_rcu(struct bnxt *bp, struct hlist_head tbl[], int tbl_size, u32 *ids, u32 start, u32 id_cnt) @@ -1152,7 +1151,195 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd) return rc; } -#endif + +#define IPV4_ALL_MASK ((__force __be32)~0) +#define L4_PORT_ALL_MASK ((__force __be16)~0) + +static bool ipv6_mask_is_full(__be32 mask[4]) +{ + return (mask[0] & mask[1] & mask[2] & mask[3]) == IPV4_ALL_MASK; +} + +static bool ipv6_mask_is_zero(__be32 mask[4]) +{ + return !(mask[0] | mask[1] | mask[2] | mask[3]); +} + +static int bnxt_add_ntuple_cls_rule(struct bnxt *bp, + struct ethtool_rx_flow_spec *fs) +{ + u8 vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie); + u32 ring = ethtool_get_flow_spec_ring(fs->ring_cookie); + struct bnxt_ntuple_filter *new_fltr, *fltr; + struct bnxt_l2_filter *l2_fltr; + u32 flow_type = fs->flow_type; + struct flow_keys *fkeys; + u32 idx; + int rc; + + if (!bp->vnic_info) + return -EAGAIN; + + if ((flow_type & (FLOW_MAC_EXT | FLOW_EXT)) || vf) + return -EOPNOTSUPP; + + new_fltr = kzalloc(sizeof(*new_fltr), GFP_KERNEL); + if (!new_fltr) + return -ENOMEM; + + l2_fltr = bp->vnic_info[0].l2_filters[0]; + atomic_inc(&l2_fltr->refcnt); + new_fltr->l2_fltr = l2_fltr; + fkeys = &new_fltr->fkeys; + + rc = -EOPNOTSUPP; + switch (flow_type) { + case TCP_V4_FLOW: + case UDP_V4_FLOW: { + struct ethtool_tcpip4_spec *ip_spec = &fs->h_u.tcp_ip4_spec; + struct ethtool_tcpip4_spec *ip_mask = &fs->m_u.tcp_ip4_spec; + + fkeys->basic.ip_proto = IPPROTO_TCP; + if (flow_type == UDP_V4_FLOW) + fkeys->basic.ip_proto = IPPROTO_UDP; + fkeys->basic.n_proto = htons(ETH_P_IP); + + if (ip_mask->ip4src == IPV4_ALL_MASK) { + fkeys->addrs.v4addrs.src = ip_spec->ip4src; + new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_SRC_IP; + } else if (ip_mask->ip4src) { + goto ntuple_err; + } + if (ip_mask->ip4dst == IPV4_ALL_MASK) { + fkeys->addrs.v4addrs.dst = ip_spec->ip4dst; + new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_DST_IP; + } else if (ip_mask->ip4dst) { + goto ntuple_err; + } + + if (ip_mask->psrc == L4_PORT_ALL_MASK) { + fkeys->ports.src = ip_spec->psrc; + new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_SRC_PORT; + } else if (ip_mask->psrc) { + goto ntuple_err; + } + if (ip_mask->pdst == L4_PORT_ALL_MASK) { + fkeys->ports.dst = ip_spec->pdst; + new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_DST_PORT; + } else if (ip_mask->pdst) { + goto ntuple_err; + } + break; + } + case TCP_V6_FLOW: + case UDP_V6_FLOW: { + struct ethtool_tcpip6_spec *ip_spec = &fs->h_u.tcp_ip6_spec; + struct ethtool_tcpip6_spec *ip_mask = &fs->m_u.tcp_ip6_spec; + + fkeys->basic.ip_proto = IPPROTO_TCP; + if (flow_type == UDP_V6_FLOW) + fkeys->basic.ip_proto = IPPROTO_UDP; + fkeys->basic.n_proto = htons(ETH_P_IPV6); + + if (ipv6_mask_is_full(ip_mask->ip6src)) { + fkeys->addrs.v6addrs.src = + *(struct in6_addr *)&ip_spec->ip6src; + new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_SRC_IP; + } else if (!ipv6_mask_is_zero(ip_mask->ip6src)) { + goto ntuple_err; + } + if (ipv6_mask_is_full(ip_mask->ip6dst)) { + fkeys->addrs.v6addrs.dst = + *(struct in6_addr *)&ip_spec->ip6dst; + new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_DST_IP; + } else if (!ipv6_mask_is_zero(ip_mask->ip6dst)) { + goto ntuple_err; + } + + if (ip_mask->psrc == L4_PORT_ALL_MASK) { + fkeys->ports.src = ip_spec->psrc; + new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_SRC_PORT; + } else if (ip_mask->psrc) { + goto ntuple_err; + } + if (ip_mask->pdst == L4_PORT_ALL_MASK) { + fkeys->ports.dst = ip_spec->pdst; + new_fltr->ntuple_flags |= BNXT_NTUPLE_MATCH_DST_PORT; + } else if (ip_mask->pdst) { + goto ntuple_err; + } + break; + } + default: + rc = -EOPNOTSUPP; + goto ntuple_err; + } + if (!new_fltr->ntuple_flags) + goto ntuple_err; + + idx = bnxt_get_ntp_filter_idx(bp, fkeys, NULL); + rcu_read_lock(); + fltr = bnxt_lookup_ntp_filter_from_idx(bp, new_fltr, idx); + if (fltr) { + rcu_read_unlock(); + rc = -EEXIST; + goto ntuple_err; + } + rcu_read_unlock(); + + new_fltr->base.rxq = ring; + new_fltr->base.flags = BNXT_ACT_NO_AGING; + __set_bit(BNXT_FLTR_VALID, &new_fltr->base.state); + rc = bnxt_insert_ntp_filter(bp, new_fltr, idx); + if (!rc) { + rc = bnxt_hwrm_cfa_ntuple_filter_alloc(bp, new_fltr); + if (rc) { + bnxt_del_ntp_filter(bp, new_fltr); + return rc; + } + fs->location = new_fltr->base.sw_id; + return 0; + } + +ntuple_err: + atomic_dec(&l2_fltr->refcnt); + kfree(new_fltr); + return rc; +} + +static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd) +{ + struct ethtool_rx_flow_spec *fs = &cmd->fs; + u32 ring, flow_type; + int rc; + u8 vf; + + if (!netif_running(bp->dev)) + return -EAGAIN; + if (!(bp->flags & BNXT_FLAG_RFS)) + return -EPERM; + if (fs->location != RX_CLS_LOC_ANY) + return -EINVAL; + + ring = ethtool_get_flow_spec_ring(fs->ring_cookie); + vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie); + if (BNXT_VF(bp) && vf) + return -EINVAL; + if (BNXT_PF(bp) && vf > bp->pf.active_vfs) + return -EINVAL; + if (!vf && ring >= bp->rx_nr_rings) + return -EINVAL; + + flow_type = fs->flow_type; + if (flow_type & (FLOW_MAC_EXT | FLOW_RSS)) + return -EINVAL; + flow_type &= ~FLOW_EXT; + if (flow_type == ETHER_FLOW) + rc = -EOPNOTSUPP; + else + rc = bnxt_add_ntuple_cls_rule(bp, fs); + return rc; +} static u64 get_ethtool_ipv4_rss(struct bnxt *bp) { @@ -1302,14 +1489,13 @@ static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, int rc = 0; switch (cmd->cmd) { -#ifdef CONFIG_RFS_ACCEL case ETHTOOL_GRXRINGS: cmd->data = bp->rx_nr_rings; break; case ETHTOOL_GRXCLSRLCNT: cmd->rule_cnt = bp->ntp_fltr_count; - cmd->data = BNXT_NTP_FLTR_MAX_FLTR; + cmd->data = BNXT_NTP_FLTR_MAX_FLTR | RX_CLS_LOC_SPECIAL; break; case ETHTOOL_GRXCLSRLALL: @@ -1319,7 +1505,6 @@ static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, case ETHTOOL_GRXCLSRULE: rc = bnxt_grxclsrule(bp, cmd); break; -#endif case ETHTOOL_GRXFH: rc = bnxt_grxfh(bp, cmd); @@ -1343,6 +1528,10 @@ static int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) rc = bnxt_srxfh(bp, cmd); break; + case ETHTOOL_SRXCLSRLINS: + rc = bnxt_srxclsrlins(bp, cmd); + break; + default: rc = -EOPNOTSUPP; break; From 8d7ba028aa9ab6570fe233ae026b3609b46f1eb7 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Fri, 22 Dec 2023 20:22:10 -0800 Subject: [PATCH 13/13] bnxt_en: Add support for ntuple filter deletion by ethtool. Add logic to delete a user specified ntuple filter from ethtool. Reviewed-by: Vasundhara Volam Reviewed-by: Andy Gospodarek Reviewed-by: Pavan Chebbi Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnxt/bnxt_ethtool.c | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index c3b9be328b87..5629ba9f4b2e 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -1341,6 +1341,31 @@ static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd) return rc; } +static int bnxt_srxclsrldel(struct bnxt *bp, struct ethtool_rxnfc *cmd) +{ + struct ethtool_rx_flow_spec *fs = &cmd->fs; + struct bnxt_filter_base *fltr_base; + + rcu_read_lock(); + fltr_base = bnxt_get_one_fltr_rcu(bp, bp->ntp_fltr_hash_tbl, + BNXT_NTP_FLTR_HASH_SIZE, + fs->location); + if (fltr_base) { + struct bnxt_ntuple_filter *fltr; + + fltr = container_of(fltr_base, struct bnxt_ntuple_filter, base); + rcu_read_unlock(); + if (!(fltr->base.flags & BNXT_ACT_NO_AGING)) + return -EINVAL; + bnxt_hwrm_cfa_ntuple_filter_free(bp, fltr); + bnxt_del_ntp_filter(bp, fltr); + return 0; + } + + rcu_read_unlock(); + return -ENOENT; +} + static u64 get_ethtool_ipv4_rss(struct bnxt *bp) { if (bp->rss_hash_cfg & VNIC_RSS_CFG_REQ_HASH_TYPE_IPV4) @@ -1532,6 +1557,10 @@ static int bnxt_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) rc = bnxt_srxclsrlins(bp, cmd); break; + case ETHTOOL_SRXCLSRLDEL: + rc = bnxt_srxclsrldel(bp, cmd); + break; + default: rc = -EOPNOTSUPP; break;