Merge branch 'bnxt_en-ntuple-and-rss-updates'

Michael Chan says:

====================
bnxt_en: Ntuple and RSS updates

This patch series adds more ntuple and RSS features following recent
patches to add support for user configured ntuple filters.  Additional
features include L2 ether filters, partial tuple masks, IP filters
besides TCP/UDP, drop action, saving and re-applying user filters
after driver reset, user configured RSS key, and RSS for IPSEC.
====================

Link: https://lore.kernel.org/r/20240205223202.25341-1-michael.chan@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2024-02-09 12:37:44 -08:00
commit 538808694c
4 changed files with 580 additions and 211 deletions

View file

@ -246,6 +246,49 @@ static const u16 bnxt_async_events_arr[] = {
static struct workqueue_struct *bnxt_pf_wq;
#define BNXT_IPV6_MASK_ALL {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
#define BNXT_IPV6_MASK_NONE {{{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}}
const struct bnxt_flow_masks BNXT_FLOW_MASK_NONE = {
.ports = {
.src = 0,
.dst = 0,
},
.addrs = {
.v6addrs = {
.src = BNXT_IPV6_MASK_NONE,
.dst = BNXT_IPV6_MASK_NONE,
},
},
};
const struct bnxt_flow_masks BNXT_FLOW_IPV6_MASK_ALL = {
.ports = {
.src = cpu_to_be16(0xffff),
.dst = cpu_to_be16(0xffff),
},
.addrs = {
.v6addrs = {
.src = BNXT_IPV6_MASK_ALL,
.dst = BNXT_IPV6_MASK_ALL,
},
},
};
const struct bnxt_flow_masks BNXT_FLOW_IPV4_MASK_ALL = {
.ports = {
.src = cpu_to_be16(0xffff),
.dst = cpu_to_be16(0xffff),
},
.addrs = {
.v4addrs = {
.src = cpu_to_be32(0xffffffff),
.dst = cpu_to_be32(0xffffffff),
},
},
};
static bool bnxt_vf_pciid(enum board_idx idx)
{
return (idx == NETXTREME_C_VF || idx == NETXTREME_E_VF ||
@ -4203,9 +4246,23 @@ static void bnxt_init_vnics(struct bnxt *bp)
u8 *key = (void *)vnic->rss_hash_key;
int k;
if (!bp->rss_hash_key_valid &&
!bp->rss_hash_key_updated) {
get_random_bytes(bp->rss_hash_key,
HW_HASH_KEY_SIZE);
bp->rss_hash_key_updated = true;
}
memcpy(vnic->rss_hash_key, bp->rss_hash_key,
HW_HASH_KEY_SIZE);
if (!bp->rss_hash_key_updated)
continue;
bp->rss_hash_key_updated = false;
bp->rss_hash_key_valid = true;
bp->toeplitz_prefix = 0;
get_random_bytes(vnic->rss_hash_key,
HW_HASH_KEY_SIZE);
for (k = 0; k < 8; k++) {
bp->toeplitz_prefix <<= 8;
bp->toeplitz_prefix |= key[k];
@ -4798,6 +4855,44 @@ static void bnxt_clear_ring_indices(struct bnxt *bp)
}
}
void bnxt_insert_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr)
{
u8 type = fltr->type, flags = fltr->flags;
INIT_LIST_HEAD(&fltr->list);
if ((type == BNXT_FLTR_TYPE_L2 && flags & BNXT_ACT_RING_DST) ||
(type == BNXT_FLTR_TYPE_NTUPLE && flags & BNXT_ACT_NO_AGING))
list_add_tail(&fltr->list, &bp->usr_fltr_list);
}
void bnxt_del_one_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr)
{
if (!list_empty(&fltr->list))
list_del_init(&fltr->list);
}
void bnxt_clear_usr_fltrs(struct bnxt *bp, bool all)
{
struct bnxt_filter_base *usr_fltr, *tmp;
list_for_each_entry_safe(usr_fltr, tmp, &bp->usr_fltr_list, list) {
if (!all && usr_fltr->type == BNXT_FLTR_TYPE_L2)
continue;
bnxt_del_one_usr_fltr(bp, usr_fltr);
}
}
static void bnxt_del_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr)
{
hlist_del(&fltr->hash);
bnxt_del_one_usr_fltr(bp, fltr);
if (fltr->flags) {
clear_bit(fltr->sw_id, bp->ntp_fltr_bmap);
bp->ntp_fltr_count--;
}
kfree(fltr);
}
static void bnxt_free_ntp_fltrs(struct bnxt *bp, bool all)
{
int i;
@ -4813,12 +4908,10 @@ 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))
if (!all && ((fltr->base.flags & BNXT_ACT_FUNC_DST) ||
!list_empty(&fltr->base.list)))
continue;
hlist_del(&fltr->base.hash);
clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap);
bp->ntp_fltr_count--;
kfree(fltr);
bnxt_del_fltr(bp, &fltr->base);
}
}
if (!all)
@ -4840,7 +4933,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_MAX_FLTR, GFP_KERNEL);
bp->ntp_fltr_bmap = bitmap_zalloc(bp->max_fltr, GFP_KERNEL);
if (!bp->ntp_fltr_bmap)
rc = -ENOMEM;
@ -4859,14 +4952,10 @@ static void bnxt_free_l2_filters(struct bnxt *bp, bool all)
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))
if (!all && ((fltr->base.flags & BNXT_ACT_FUNC_DST) ||
!list_empty(&fltr->base.list)))
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);
bnxt_del_fltr(bp, &fltr->base);
}
}
}
@ -5342,6 +5431,7 @@ void bnxt_del_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr)
return;
}
hlist_del_rcu(&fltr->base.hash);
bnxt_del_one_usr_fltr(bp, &fltr->base);
if (fltr->base.flags) {
clear_bit(fltr->base.sw_id, bp->ntp_fltr_bmap);
bp->ntp_fltr_count--;
@ -5480,13 +5570,15 @@ static int bnxt_init_l2_filter(struct bnxt *bp, struct bnxt_l2_filter *fltr,
int bit_id;
bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap,
BNXT_MAX_FLTR, 0);
bp->max_fltr, 0);
if (bit_id < 0)
return -ENOMEM;
fltr->base.sw_id = (u16)bit_id;
bp->ntp_fltr_count++;
}
head = &bp->l2_fltr_hash_tbl[idx];
hlist_add_head_rcu(&fltr->base.hash, head);
bnxt_insert_usr_fltr(bp, &fltr->base);
set_bit(BNXT_FLTR_INSERTED, &fltr->base.state);
atomic_set(&fltr->refcnt, 1);
return 0;
@ -5519,6 +5611,40 @@ static struct bnxt_l2_filter *bnxt_alloc_l2_filter(struct bnxt *bp,
return fltr;
}
struct bnxt_l2_filter *bnxt_alloc_new_l2_filter(struct bnxt *bp,
struct bnxt_l2_key *key,
u16 flags)
{
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;
spin_lock_bh(&bp->ntp_fltr_lock);
fltr = __bnxt_lookup_l2_filter(bp, key, idx);
if (fltr) {
fltr = ERR_PTR(-EEXIST);
goto l2_filter_exit;
}
fltr = kzalloc(sizeof(*fltr), GFP_ATOMIC);
if (!fltr) {
fltr = ERR_PTR(-ENOMEM);
goto l2_filter_exit;
}
fltr->base.flags = flags;
rc = bnxt_init_l2_filter(bp, fltr, key, idx);
if (rc) {
spin_unlock_bh(&bp->ntp_fltr_lock);
bnxt_del_l2_filter(bp, fltr);
return ERR_PTR(rc);
}
l2_filter_exit:
spin_unlock_bh(&bp->ntp_fltr_lock);
return fltr;
}
static u16 bnxt_vf_target_id(struct bnxt_pf_info *pf, u16 vf_idx)
{
#ifdef CONFIG_BNXT_SRIOV
@ -5655,6 +5781,7 @@ 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 bnxt_flow_masks *masks = &fltr->fmasks;
struct flow_keys *keys = &fltr->fkeys;
struct bnxt_l2_filter *l2_fltr;
struct bnxt_vnic_info *vnic;
@ -5668,8 +5795,9 @@ int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp,
l2_fltr = fltr->l2_fltr;
req->l2_filter_id = l2_fltr->base.filter_id;
if (bp->fw_cap & BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2) {
if (fltr->base.flags & BNXT_ACT_DROP) {
flags = CFA_NTUPLE_FILTER_ALLOC_REQ_FLAGS_DROP;
} else 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->base.rxq);
} else {
@ -5687,25 +5815,15 @@ int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp,
req->ethertype = htons(ETH_P_IPV6);
req->ip_addr_type =
CFA_NTUPLE_FILTER_ALLOC_REQ_IP_ADDR_TYPE_IPV6;
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);
}
*(struct in6_addr *)&req->src_ipaddr[0] = keys->addrs.v6addrs.src;
*(struct in6_addr *)&req->src_ipaddr_mask[0] = masks->addrs.v6addrs.src;
*(struct in6_addr *)&req->dst_ipaddr[0] = keys->addrs.v6addrs.dst;
*(struct in6_addr *)&req->dst_ipaddr_mask[0] = masks->addrs.v6addrs.dst;
} else {
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);
}
req->src_ipaddr[0] = keys->addrs.v4addrs.src;
req->src_ipaddr_mask[0] = masks->addrs.v4addrs.src;
req->dst_ipaddr[0] = keys->addrs.v4addrs.dst;
req->dst_ipaddr_mask[0] = masks->addrs.v4addrs.dst;
}
if (keys->control.flags & FLOW_DIS_ENCAPSULATION) {
req->enables |= cpu_to_le32(BNXT_NTP_TUNNEL_FLTR_FLAG);
@ -5713,14 +5831,10 @@ int bnxt_hwrm_cfa_ntuple_filter_alloc(struct bnxt *bp,
CFA_NTUPLE_FILTER_ALLOC_REQ_TUNNEL_TYPE_ANYTUNNEL;
}
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);
}
req->src_port = keys->ports.src;
req->src_port_mask = masks->ports.src;
req->dst_port = keys->ports.dst;
req->dst_port_mask = masks->ports.dst;
resp = hwrm_req_hold(bp, req);
rc = hwrm_req_send(bp, req);
@ -5985,10 +6099,13 @@ static void
__bnxt_hwrm_vnic_set_rss(struct bnxt *bp, struct hwrm_vnic_rss_cfg_input *req,
struct bnxt_vnic_info *vnic)
{
if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS)
if (bp->flags & BNXT_FLAG_CHIP_P5_PLUS) {
bnxt_fill_hw_rss_tbl_p5(bp, vnic);
else
if (bp->flags & BNXT_FLAG_CHIP_P7)
req->flags |= VNIC_RSS_CFG_REQ_FLAGS_IPSEC_HASH_TYPE_CFG_SUPPORT;
} else {
bnxt_fill_hw_rss_tbl(bp, vnic);
}
if (bp->rss_hash_delta) {
req->hash_type = cpu_to_le32(bp->rss_hash_delta);
@ -6351,6 +6468,14 @@ static int bnxt_hwrm_vnic_qcaps(struct bnxt *bp)
}
if (flags & VNIC_QCAPS_RESP_FLAGS_HW_TUNNEL_TPA_CAP)
bp->fw_cap |= BNXT_FW_CAP_VNIC_TUNNEL_TPA;
if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_AH_SPI_IPV4_CAP)
bp->rss_cap |= BNXT_RSS_CAP_AH_V4_RSS_CAP;
if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_AH_SPI_IPV6_CAP)
bp->rss_cap |= BNXT_RSS_CAP_AH_V6_RSS_CAP;
if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV4_CAP)
bp->rss_cap |= BNXT_RSS_CAP_ESP_V4_RSS_CAP;
if (flags & VNIC_QCAPS_RESP_FLAGS_RSS_IPSEC_ESP_SPI_IPV6_CAP)
bp->rss_cap |= BNXT_RSS_CAP_ESP_V6_RSS_CAP;
}
hwrm_req_drop(bp, req);
return rc;
@ -8709,6 +8834,13 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
hw_resc->max_vnics = le16_to_cpu(resp->max_vnics);
hw_resc->max_stat_ctxs = le16_to_cpu(resp->max_stat_ctx);
hw_resc->max_encap_records = le32_to_cpu(resp->max_encap_records);
hw_resc->max_decap_records = le32_to_cpu(resp->max_decap_records);
hw_resc->max_tx_em_flows = le32_to_cpu(resp->max_tx_em_flows);
hw_resc->max_tx_wm_flows = le32_to_cpu(resp->max_tx_wm_flows);
hw_resc->max_rx_em_flows = le32_to_cpu(resp->max_rx_em_flows);
hw_resc->max_rx_wm_flows = le32_to_cpu(resp->max_rx_wm_flows);
if (BNXT_PF(bp)) {
struct bnxt_pf_info *pf = &bp->pf;
@ -8717,12 +8849,6 @@ static int __bnxt_hwrm_func_qcaps(struct bnxt *bp)
memcpy(pf->mac_addr, resp->mac_address, ETH_ALEN);
pf->first_vf_id = le16_to_cpu(resp->first_vf_id);
pf->max_vfs = le16_to_cpu(resp->max_vfs);
pf->max_encap_records = le32_to_cpu(resp->max_encap_records);
pf->max_decap_records = le32_to_cpu(resp->max_decap_records);
pf->max_tx_em_flows = le32_to_cpu(resp->max_tx_em_flows);
pf->max_tx_wm_flows = le32_to_cpu(resp->max_tx_wm_flows);
pf->max_rx_em_flows = le32_to_cpu(resp->max_rx_em_flows);
pf->max_rx_wm_flows = le32_to_cpu(resp->max_rx_wm_flows);
bp->flags &= ~BNXT_FLAG_WOL_CAP;
if (flags & FUNC_QCAPS_RESP_FLAGS_WOL_MAGICPKT_SUPPORTED)
bp->flags |= BNXT_FLAG_WOL_CAP;
@ -8825,6 +8951,10 @@ static int bnxt_hwrm_cfa_adv_flow_mgnt_qcaps(struct bnxt *bp)
CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_RFS_RING_TBL_IDX_V2_SUPPORTED)
bp->fw_cap |= BNXT_FW_CAP_CFA_RFS_RING_TBL_IDX_V2;
if (flags &
CFA_ADV_FLOW_MGNT_QCAPS_RESP_FLAGS_NTUPLE_FLOW_RX_EXT_IP_PROTO_SUPPORTED)
bp->fw_cap |= BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO;
hwrm_cfa_adv_qcaps_exit:
hwrm_req_drop(bp, req);
return rc;
@ -11443,6 +11573,42 @@ static int bnxt_reinit_after_abort(struct bnxt *bp)
return rc;
}
static void bnxt_cfg_one_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr)
{
struct bnxt_ntuple_filter *ntp_fltr;
struct bnxt_l2_filter *l2_fltr;
if (list_empty(&fltr->list))
return;
if (fltr->type == BNXT_FLTR_TYPE_NTUPLE) {
ntp_fltr = container_of(fltr, struct bnxt_ntuple_filter, base);
l2_fltr = bp->vnic_info[0].l2_filters[0];
atomic_inc(&l2_fltr->refcnt);
ntp_fltr->l2_fltr = l2_fltr;
if (bnxt_hwrm_cfa_ntuple_filter_alloc(bp, ntp_fltr)) {
bnxt_del_ntp_filter(bp, ntp_fltr);
netdev_err(bp->dev, "restoring previously configured ntuple filter id %d failed\n",
fltr->sw_id);
}
} else if (fltr->type == BNXT_FLTR_TYPE_L2) {
l2_fltr = container_of(fltr, struct bnxt_l2_filter, base);
if (bnxt_hwrm_l2_filter_alloc(bp, l2_fltr)) {
bnxt_del_l2_filter(bp, l2_fltr);
netdev_err(bp->dev, "restoring previously configured l2 filter id %d failed\n",
fltr->sw_id);
}
}
}
static void bnxt_cfg_usr_fltrs(struct bnxt *bp)
{
struct bnxt_filter_base *usr_fltr, *tmp;
list_for_each_entry_safe(usr_fltr, tmp, &bp->usr_fltr_list, list)
bnxt_cfg_one_usr_fltr(bp, usr_fltr);
}
static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
{
int rc = 0;
@ -11529,6 +11695,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
bnxt_vf_reps_open(bp);
bnxt_ptp_init_rtc(bp, true);
bnxt_ptp_cfg_tstamp_filters(bp);
bnxt_cfg_usr_fltrs(bp);
return 0;
open_err_irq:
@ -12270,6 +12437,8 @@ static int bnxt_set_features(struct net_device *dev, netdev_features_t features)
if (features & NETIF_F_NTUPLE)
flags |= BNXT_FLAG_RFS;
else
bnxt_clear_usr_fltrs(bp, true);
changes = flags ^ bp->flags;
if (changes & BNXT_FLAG_TPA) {
@ -13767,6 +13936,7 @@ static int bnxt_change_mac_addr(struct net_device *dev, void *p)
return rc;
eth_hw_addr_set(dev, addr->sa_data);
bnxt_clear_usr_fltrs(bp, true);
if (netif_running(dev)) {
bnxt_close_nic(bp, false, false);
rc = bnxt_open_nic(bp, false, false);
@ -13900,7 +14070,7 @@ int bnxt_insert_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr,
int bit_id;
spin_lock_bh(&bp->ntp_fltr_lock);
bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap, BNXT_MAX_FLTR, 0);
bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap, bp->max_fltr, 0);
if (bit_id < 0) {
spin_unlock_bh(&bp->ntp_fltr_lock);
return -ENOMEM;
@ -13912,6 +14082,7 @@ int bnxt_insert_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr,
head = &bp->ntp_fltr_hash_tbl[idx];
hlist_add_head_rcu(&fltr->base.hash, head);
set_bit(BNXT_FLTR_INSERTED, &fltr->base.state);
bnxt_insert_usr_fltr(bp, &fltr->base);
bp->ntp_fltr_count++;
spin_unlock_bh(&bp->ntp_fltr_lock);
return 0;
@ -13920,45 +14091,39 @@ int bnxt_insert_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr,
static bool bnxt_fltr_match(struct bnxt_ntuple_filter *f1,
struct bnxt_ntuple_filter *f2)
{
struct bnxt_flow_masks *masks1 = &f1->fmasks;
struct bnxt_flow_masks *masks2 = &f2->fmasks;
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 (((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))
if (keys1->addrs.v4addrs.src != keys2->addrs.v4addrs.src ||
masks1->addrs.v4addrs.src != masks2->addrs.v4addrs.src ||
keys1->addrs.v4addrs.dst != keys2->addrs.v4addrs.dst ||
masks1->addrs.v4addrs.dst != masks2->addrs.v4addrs.dst)
return false;
} else {
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))))
if (!ipv6_addr_equal(&keys1->addrs.v6addrs.src,
&keys2->addrs.v6addrs.src) ||
!ipv6_addr_equal(&masks1->addrs.v6addrs.src,
&masks2->addrs.v6addrs.src) ||
!ipv6_addr_equal(&keys1->addrs.v6addrs.dst,
&keys2->addrs.v6addrs.dst) ||
!ipv6_addr_equal(&masks1->addrs.v6addrs.dst,
&masks2->addrs.v6addrs.dst))
return false;
}
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;
return false;
return keys1->ports.src == keys2->ports.src &&
masks1->ports.src == masks2->ports.src &&
keys1->ports.dst == keys2->ports.dst &&
masks1->ports.dst == masks2->ports.dst &&
keys1->control.flags == keys2->control.flags &&
f1->l2_fltr == f2->l2_fltr;
}
struct bnxt_ntuple_filter *
@ -14023,10 +14188,13 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
rc = -EPROTONOSUPPORT;
goto err_free;
}
if (fkeys->basic.n_proto == htons(ETH_P_IPV6) &&
bp->hwrm_spec_code < 0x10601) {
rc = -EPROTONOSUPPORT;
goto err_free;
new_fltr->fmasks = BNXT_FLOW_IPV4_MASK_ALL;
if (fkeys->basic.n_proto == htons(ETH_P_IPV6)) {
if (bp->hwrm_spec_code < 0x10601) {
rc = -EPROTONOSUPPORT;
goto err_free;
}
new_fltr->fmasks = BNXT_FLOW_IPV6_MASK_ALL;
}
flags = fkeys->control.flags;
if (((flags & FLOW_DIS_ENCAPSULATION) &&
@ -14034,9 +14202,7 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
rc = -EPROTONOSUPPORT;
goto err_free;
}
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();
@ -14071,6 +14237,7 @@ void bnxt_del_ntp_filter(struct bnxt *bp, struct bnxt_ntuple_filter *fltr)
return;
}
hlist_del_rcu(&fltr->base.hash);
bnxt_del_one_usr_fltr(bp, &fltr->base);
bp->ntp_fltr_count--;
spin_unlock_bh(&bp->ntp_fltr_lock);
bnxt_del_l2_filter(bp, fltr->l2_fltr);
@ -14670,6 +14837,7 @@ void bnxt_print_device_info(struct bnxt *bp)
static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct bnxt_hw_resc *hw_resc;
struct net_device *dev;
struct bnxt *bp;
int rc, max_irqs;
@ -14828,6 +14996,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
goto init_err_pci_clean;
hw_resc = &bp->hw_resc;
bp->max_fltr = hw_resc->max_rx_em_flows + hw_resc->max_rx_wm_flows +
BNXT_L2_FLTR_MAX_FLTR;
/* Older firmware may not report these filters properly */
if (bp->max_fltr < BNXT_MAX_FLTR)
bp->max_fltr = BNXT_MAX_FLTR;
bnxt_init_l2_fltr_tbl(bp);
bnxt_set_rx_skb_mode(bp, false);
bnxt_set_tpa_flags(bp);
@ -14880,6 +15054,8 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (rc)
goto init_err_dl;
INIT_LIST_HEAD(&bp->usr_fltr_list);
rc = register_netdev(dev);
if (rc)
goto init_err_cleanup;

View file

@ -1281,6 +1281,12 @@ struct bnxt_hw_resc {
u16 max_nqs;
u16 max_irqs;
u16 resv_irqs;
u32 max_encap_records;
u32 max_decap_records;
u32 max_tx_em_flows;
u32 max_tx_wm_flows;
u32 max_rx_em_flows;
u32 max_rx_wm_flows;
};
#if defined(CONFIG_BNXT_SRIOV)
@ -1315,12 +1321,6 @@ struct bnxt_pf_info {
u16 active_vfs;
u16 registered_vfs;
u16 max_vfs;
u32 max_encap_records;
u32 max_decap_records;
u32 max_tx_em_flows;
u32 max_tx_wm_flows;
u32 max_rx_em_flows;
u32 max_rx_wm_flows;
unsigned long *vf_event_bmap;
u16 hwrm_cmd_req_pages;
u8 vf_resv_strategy;
@ -1334,6 +1334,7 @@ struct bnxt_pf_info {
struct bnxt_filter_base {
struct hlist_node hash;
struct list_head list;
__le64 filter_id;
u8 type;
#define BNXT_FLTR_TYPE_NTUPLE 1
@ -1355,19 +1356,21 @@ struct bnxt_filter_base {
struct rcu_head rcu;
};
struct bnxt_flow_masks {
struct flow_dissector_key_ports ports;
struct flow_dissector_key_addrs addrs;
};
extern const struct bnxt_flow_masks BNXT_FLOW_MASK_NONE;
extern const struct bnxt_flow_masks BNXT_FLOW_IPV6_MASK_ALL;
extern const struct bnxt_flow_masks BNXT_FLOW_IPV4_MASK_ALL;
struct bnxt_ntuple_filter {
/* base filter must be the first member */
struct bnxt_filter_base base;
struct flow_keys fkeys;
struct bnxt_flow_masks fmasks;
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;
};
@ -1394,6 +1397,7 @@ struct bnxt_ipv6_tuple {
#define BNXT_L2_KEY_SIZE (sizeof(struct bnxt_l2_key) / 4)
struct bnxt_l2_filter {
/* base filter must be the first member */
struct bnxt_filter_base base;
struct bnxt_l2_key l2_key;
atomic_t refcnt;
@ -2217,6 +2221,14 @@ struct bnxt {
#define BNXT_RSS_CAP_UDP_RSS_CAP BIT(1)
#define BNXT_RSS_CAP_NEW_RSS_CAP BIT(2)
#define BNXT_RSS_CAP_RSS_TCAM BIT(3)
#define BNXT_RSS_CAP_AH_V4_RSS_CAP BIT(4)
#define BNXT_RSS_CAP_AH_V6_RSS_CAP BIT(5)
#define BNXT_RSS_CAP_ESP_V4_RSS_CAP BIT(6)
#define BNXT_RSS_CAP_ESP_V6_RSS_CAP BIT(7)
u8 rss_hash_key[HW_HASH_KEY_SIZE];
u8 rss_hash_key_valid:1;
u8 rss_hash_key_updated:1;
u16 max_mtu;
u8 max_tc;
@ -2301,6 +2313,7 @@ struct bnxt {
#define BNXT_FW_CAP_PRE_RESV_VNICS BIT_ULL(35)
#define BNXT_FW_CAP_BACKING_STORE_V2 BIT_ULL(36)
#define BNXT_FW_CAP_VNIC_TUNNEL_TPA BIT_ULL(37)
#define BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO BIT_ULL(38)
u32 fw_dbg_cap;
@ -2428,6 +2441,7 @@ struct bnxt {
unsigned long *ntp_fltr_bmap;
int ntp_fltr_count;
int max_fltr;
#define BNXT_L2_FLTR_MAX_FLTR 1024
#define BNXT_L2_FLTR_HASH_SIZE 32
@ -2437,6 +2451,8 @@ struct bnxt {
u32 hash_seed;
u64 toeplitz_prefix;
struct list_head usr_fltr_list;
/* To protect link related settings during link changes and
* ethtool settings changes.
*/
@ -2641,10 +2657,16 @@ u32 bnxt_fw_health_readl(struct bnxt *bp, int reg_idx);
void bnxt_set_tpa_flags(struct bnxt *bp);
void bnxt_set_ring_params(struct bnxt *);
int bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode);
void bnxt_insert_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr);
void bnxt_del_one_usr_fltr(struct bnxt *bp, struct bnxt_filter_base *fltr);
void bnxt_clear_usr_fltrs(struct bnxt *bp, bool all);
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);
struct bnxt_l2_filter *bnxt_alloc_new_l2_filter(struct bnxt *bp,
struct bnxt_l2_key *key,
u16 flags);
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,

View file

@ -968,6 +968,7 @@ static int bnxt_set_channels(struct net_device *dev,
return -EINVAL;
}
bnxt_clear_usr_fltrs(bp, true);
if (netif_running(dev)) {
if (BNXT_PF(bp)) {
/* TODO CHIMP_FW: Send message to all VF's
@ -1058,11 +1059,17 @@ static struct bnxt_filter_base *bnxt_get_one_fltr_rcu(struct bnxt *bp,
static int bnxt_grxclsrlall(struct bnxt *bp, struct ethtool_rxnfc *cmd,
u32 *rule_locs)
{
u32 count;
cmd->data = bp->ntp_fltr_count;
rcu_read_lock();
count = bnxt_get_all_fltr_ids_rcu(bp, bp->l2_fltr_hash_tbl,
BNXT_L2_FLTR_HASH_SIZE, rule_locs, 0,
cmd->rule_cnt);
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);
rule_locs, count,
cmd->rule_cnt);
rcu_read_unlock();
return 0;
@ -1074,13 +1081,44 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
(struct ethtool_rx_flow_spec *)&cmd->fs;
struct bnxt_filter_base *fltr_base;
struct bnxt_ntuple_filter *fltr;
struct bnxt_flow_masks *fmasks;
struct flow_keys *fkeys;
int rc = -EINVAL;
if (fs->location >= BNXT_NTP_FLTR_MAX_FLTR)
if (fs->location >= bp->max_fltr)
return rc;
rcu_read_lock();
fltr_base = bnxt_get_one_fltr_rcu(bp, bp->l2_fltr_hash_tbl,
BNXT_L2_FLTR_HASH_SIZE,
fs->location);
if (fltr_base) {
struct ethhdr *h_ether = &fs->h_u.ether_spec;
struct ethhdr *m_ether = &fs->m_u.ether_spec;
struct bnxt_l2_filter *l2_fltr;
struct bnxt_l2_key *l2_key;
l2_fltr = container_of(fltr_base, struct bnxt_l2_filter, base);
l2_key = &l2_fltr->l2_key;
fs->flow_type = ETHER_FLOW;
ether_addr_copy(h_ether->h_dest, l2_key->dst_mac_addr);
eth_broadcast_addr(m_ether->h_dest);
if (l2_key->vlan) {
struct ethtool_flow_ext *m_ext = &fs->m_ext;
struct ethtool_flow_ext *h_ext = &fs->h_ext;
fs->flow_type |= FLOW_EXT;
m_ext->vlan_tci = htons(0xfff);
h_ext->vlan_tci = htons(l2_key->vlan);
}
if (fltr_base->flags & BNXT_ACT_RING_DST)
fs->ring_cookie = fltr_base->rxq;
if (fltr_base->flags & BNXT_ACT_FUNC_DST)
fs->ring_cookie = (u64)(fltr_base->vf_idx + 1) <<
ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF;
rcu_read_unlock();
return 0;
}
fltr_base = bnxt_get_one_fltr_rcu(bp, bp->ntp_fltr_hash_tbl,
BNXT_NTP_FLTR_HASH_SIZE,
fs->location);
@ -1091,59 +1129,74 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
fltr = container_of(fltr_base, struct bnxt_ntuple_filter, base);
fkeys = &fltr->fkeys;
fmasks = &fltr->fmasks;
if (fkeys->basic.n_proto == htons(ETH_P_IP)) {
if (fkeys->basic.ip_proto == IPPROTO_TCP)
if (fkeys->basic.ip_proto == IPPROTO_ICMP ||
fkeys->basic.ip_proto == IPPROTO_RAW) {
fs->flow_type = IP_USER_FLOW;
fs->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
if (fkeys->basic.ip_proto == IPPROTO_ICMP)
fs->h_u.usr_ip4_spec.proto = IPPROTO_ICMP;
else
fs->h_u.usr_ip4_spec.proto = IPPROTO_RAW;
fs->m_u.usr_ip4_spec.proto = BNXT_IP_PROTO_FULL_MASK;
} else if (fkeys->basic.ip_proto == IPPROTO_TCP) {
fs->flow_type = TCP_V4_FLOW;
else if (fkeys->basic.ip_proto == IPPROTO_UDP)
} else if (fkeys->basic.ip_proto == IPPROTO_UDP) {
fs->flow_type = UDP_V4_FLOW;
else
} else {
goto fltr_err;
}
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.ip4src = fkeys->addrs.v4addrs.src;
fs->m_u.tcp_ip4_spec.ip4src = fmasks->addrs.v4addrs.src;
fs->h_u.tcp_ip4_spec.ip4dst = fkeys->addrs.v4addrs.dst;
fs->m_u.tcp_ip4_spec.ip4dst = fmasks->addrs.v4addrs.dst;
if (fs->flow_type == TCP_V4_FLOW ||
fs->flow_type == UDP_V4_FLOW) {
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->m_u.tcp_ip4_spec.psrc = fmasks->ports.src;
fs->h_u.tcp_ip4_spec.pdst = fkeys->ports.dst;
fs->m_u.tcp_ip4_spec.pdst = cpu_to_be16(~0);
fs->m_u.tcp_ip4_spec.pdst = fmasks->ports.dst;
}
} else {
if (fkeys->basic.ip_proto == IPPROTO_TCP)
if (fkeys->basic.ip_proto == IPPROTO_ICMPV6 ||
fkeys->basic.ip_proto == IPPROTO_RAW) {
fs->flow_type = IPV6_USER_FLOW;
if (fkeys->basic.ip_proto == IPPROTO_ICMPV6)
fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_ICMPV6;
else
fs->h_u.usr_ip6_spec.l4_proto = IPPROTO_RAW;
fs->m_u.usr_ip6_spec.l4_proto = BNXT_IP_PROTO_FULL_MASK;
} else if (fkeys->basic.ip_proto == IPPROTO_TCP) {
fs->flow_type = TCP_V6_FLOW;
else if (fkeys->basic.ip_proto == IPPROTO_UDP)
} else if (fkeys->basic.ip_proto == IPPROTO_UDP) {
fs->flow_type = UDP_V6_FLOW;
else
} else {
goto fltr_err;
}
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) {
*(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6src[0] =
fkeys->addrs.v6addrs.src;
*(struct in6_addr *)&fs->m_u.tcp_ip6_spec.ip6src[0] =
fmasks->addrs.v6addrs.src;
*(struct in6_addr *)&fs->h_u.tcp_ip6_spec.ip6dst[0] =
fkeys->addrs.v6addrs.dst;
*(struct in6_addr *)&fs->m_u.tcp_ip6_spec.ip6dst[0] =
fmasks->addrs.v6addrs.dst;
if (fs->flow_type == TCP_V6_FLOW ||
fs->flow_type == UDP_V6_FLOW) {
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->m_u.tcp_ip6_spec.psrc = fmasks->ports.src;
fs->h_u.tcp_ip6_spec.pdst = fkeys->ports.dst;
fs->m_u.tcp_ip6_spec.pdst = cpu_to_be16(~0);
fs->m_u.tcp_ip6_spec.pdst = fmasks->ports.dst;
}
}
fs->ring_cookie = fltr->base.rxq;
if (fltr->base.flags & BNXT_ACT_DROP)
fs->ring_cookie = RX_CLS_FLOW_DISC;
else
fs->ring_cookie = fltr->base.rxq;
rc = 0;
fltr_err:
@ -1152,17 +1205,78 @@ static int bnxt_grxclsrule(struct bnxt *bp, struct ethtool_rxnfc *cmd)
return rc;
}
#define IPV4_ALL_MASK ((__force __be32)~0)
#define L4_PORT_ALL_MASK ((__force __be16)~0)
static bool ipv6_mask_is_full(__be32 mask[4])
static int bnxt_add_l2_cls_rule(struct bnxt *bp,
struct ethtool_rx_flow_spec *fs)
{
return (mask[0] & mask[1] & mask[2] & mask[3]) == IPV4_ALL_MASK;
u32 ring = ethtool_get_flow_spec_ring(fs->ring_cookie);
u8 vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie);
struct ethhdr *h_ether = &fs->h_u.ether_spec;
struct ethhdr *m_ether = &fs->m_u.ether_spec;
struct bnxt_l2_filter *fltr;
struct bnxt_l2_key key;
u16 vnic_id;
u8 flags;
int rc;
if (BNXT_CHIP_P5_PLUS(bp))
return -EOPNOTSUPP;
if (!is_broadcast_ether_addr(m_ether->h_dest))
return -EINVAL;
ether_addr_copy(key.dst_mac_addr, h_ether->h_dest);
key.vlan = 0;
if (fs->flow_type & FLOW_EXT) {
struct ethtool_flow_ext *m_ext = &fs->m_ext;
struct ethtool_flow_ext *h_ext = &fs->h_ext;
if (m_ext->vlan_tci != htons(0xfff) || !h_ext->vlan_tci)
return -EINVAL;
key.vlan = ntohs(h_ext->vlan_tci);
}
if (vf) {
flags = BNXT_ACT_FUNC_DST;
vnic_id = 0xffff;
vf--;
} else {
flags = BNXT_ACT_RING_DST;
vnic_id = bp->vnic_info[ring + 1].fw_vnic_id;
}
fltr = bnxt_alloc_new_l2_filter(bp, &key, flags);
if (IS_ERR(fltr))
return PTR_ERR(fltr);
fltr->base.fw_vnic_id = vnic_id;
fltr->base.rxq = ring;
fltr->base.vf_idx = vf;
rc = bnxt_hwrm_l2_filter_alloc(bp, fltr);
if (rc)
bnxt_del_l2_filter(bp, fltr);
else
fs->location = fltr->base.sw_id;
return rc;
}
static bool ipv6_mask_is_zero(__be32 mask[4])
static bool bnxt_verify_ntuple_ip4_flow(struct ethtool_usrip4_spec *ip_spec,
struct ethtool_usrip4_spec *ip_mask)
{
return !(mask[0] | mask[1] | mask[2] | mask[3]);
if (ip_mask->l4_4_bytes || ip_mask->tos ||
ip_spec->ip_ver != ETH_RX_NFC_IP4 ||
ip_mask->proto != BNXT_IP_PROTO_FULL_MASK ||
(ip_spec->proto != IPPROTO_RAW && ip_spec->proto != IPPROTO_ICMP))
return false;
return true;
}
static bool bnxt_verify_ntuple_ip6_flow(struct ethtool_usrip6_spec *ip_spec,
struct ethtool_usrip6_spec *ip_mask)
{
if (ip_mask->l4_4_bytes || ip_mask->tclass ||
ip_mask->l4_proto != BNXT_IP_PROTO_FULL_MASK ||
(ip_spec->l4_proto != IPPROTO_RAW &&
ip_spec->l4_proto != IPPROTO_ICMPV6))
return false;
return true;
}
static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
@ -1172,6 +1286,7 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
u32 ring = ethtool_get_flow_spec_ring(fs->ring_cookie);
struct bnxt_ntuple_filter *new_fltr, *fltr;
struct bnxt_l2_filter *l2_fltr;
struct bnxt_flow_masks *fmasks;
u32 flow_type = fs->flow_type;
struct flow_keys *fkeys;
u32 idx;
@ -1183,6 +1298,18 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
if ((flow_type & (FLOW_MAC_EXT | FLOW_EXT)) || vf)
return -EOPNOTSUPP;
if (flow_type == IP_USER_FLOW) {
if (!bnxt_verify_ntuple_ip4_flow(&fs->h_u.usr_ip4_spec,
&fs->m_u.usr_ip4_spec))
return -EOPNOTSUPP;
}
if (flow_type == IPV6_USER_FLOW) {
if (!bnxt_verify_ntuple_ip6_flow(&fs->h_u.usr_ip6_spec,
&fs->m_u.usr_ip6_spec))
return -EOPNOTSUPP;
}
new_fltr = kzalloc(sizeof(*new_fltr), GFP_KERNEL);
if (!new_fltr)
return -ENOMEM;
@ -1190,10 +1317,23 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
l2_fltr = bp->vnic_info[0].l2_filters[0];
atomic_inc(&l2_fltr->refcnt);
new_fltr->l2_fltr = l2_fltr;
fmasks = &new_fltr->fmasks;
fkeys = &new_fltr->fkeys;
rc = -EOPNOTSUPP;
switch (flow_type) {
case IP_USER_FLOW: {
struct ethtool_usrip4_spec *ip_spec = &fs->h_u.usr_ip4_spec;
struct ethtool_usrip4_spec *ip_mask = &fs->m_u.usr_ip4_spec;
fkeys->basic.ip_proto = ip_spec->proto;
fkeys->basic.n_proto = htons(ETH_P_IP);
fkeys->addrs.v4addrs.src = ip_spec->ip4src;
fmasks->addrs.v4addrs.src = ip_mask->ip4src;
fkeys->addrs.v4addrs.dst = ip_spec->ip4dst;
fmasks->addrs.v4addrs.dst = ip_mask->ip4dst;
break;
}
case TCP_V4_FLOW:
case UDP_V4_FLOW: {
struct ethtool_tcpip4_spec *ip_spec = &fs->h_u.tcp_ip4_spec;
@ -1203,32 +1343,26 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
if (flow_type == UDP_V4_FLOW)
fkeys->basic.ip_proto = IPPROTO_UDP;
fkeys->basic.n_proto = htons(ETH_P_IP);
fkeys->addrs.v4addrs.src = ip_spec->ip4src;
fmasks->addrs.v4addrs.src = ip_mask->ip4src;
fkeys->addrs.v4addrs.dst = ip_spec->ip4dst;
fmasks->addrs.v4addrs.dst = ip_mask->ip4dst;
fkeys->ports.src = ip_spec->psrc;
fmasks->ports.src = ip_mask->psrc;
fkeys->ports.dst = ip_spec->pdst;
fmasks->ports.dst = ip_mask->pdst;
break;
}
case IPV6_USER_FLOW: {
struct ethtool_usrip6_spec *ip_spec = &fs->h_u.usr_ip6_spec;
struct ethtool_usrip6_spec *ip_mask = &fs->m_u.usr_ip6_spec;
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;
}
fkeys->basic.ip_proto = ip_spec->l4_proto;
fkeys->basic.n_proto = htons(ETH_P_IPV6);
fkeys->addrs.v6addrs.src = *(struct in6_addr *)&ip_spec->ip6src;
fmasks->addrs.v6addrs.src = *(struct in6_addr *)&ip_mask->ip6src;
fkeys->addrs.v6addrs.dst = *(struct in6_addr *)&ip_spec->ip6dst;
fmasks->addrs.v6addrs.dst = *(struct in6_addr *)&ip_mask->ip6dst;
break;
}
case TCP_V6_FLOW:
@ -1241,40 +1375,21 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
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;
}
fkeys->addrs.v6addrs.src = *(struct in6_addr *)&ip_spec->ip6src;
fmasks->addrs.v6addrs.src = *(struct in6_addr *)&ip_mask->ip6src;
fkeys->addrs.v6addrs.dst = *(struct in6_addr *)&ip_spec->ip6dst;
fmasks->addrs.v6addrs.dst = *(struct in6_addr *)&ip_mask->ip6dst;
fkeys->ports.src = ip_spec->psrc;
fmasks->ports.src = ip_mask->psrc;
fkeys->ports.dst = ip_spec->pdst;
fmasks->ports.dst = ip_mask->pdst;
break;
}
default:
rc = -EOPNOTSUPP;
goto ntuple_err;
}
if (!new_fltr->ntuple_flags)
if (!memcmp(&BNXT_FLOW_MASK_NONE, fmasks, sizeof(*fmasks)))
goto ntuple_err;
idx = bnxt_get_ntp_filter_idx(bp, fkeys, NULL);
@ -1287,8 +1402,11 @@ static int bnxt_add_ntuple_cls_rule(struct bnxt *bp,
}
rcu_read_unlock();
new_fltr->base.rxq = ring;
new_fltr->base.flags = BNXT_ACT_NO_AGING;
if (fs->ring_cookie == RX_CLS_FLOW_DISC)
new_fltr->base.flags |= BNXT_ACT_DROP;
else
new_fltr->base.rxq = ring;
__set_bit(BNXT_FLTR_VALID, &new_fltr->base.state);
rc = bnxt_insert_ntp_filter(bp, new_fltr, idx);
if (!rc) {
@ -1321,6 +1439,18 @@ static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd)
if (fs->location != RX_CLS_LOC_ANY)
return -EINVAL;
flow_type = fs->flow_type;
if ((flow_type == IP_USER_FLOW ||
flow_type == IPV6_USER_FLOW) &&
!(bp->fw_cap & BNXT_FW_CAP_CFA_NTUPLE_RX_EXT_IP_PROTO))
return -EOPNOTSUPP;
if (flow_type & (FLOW_MAC_EXT | FLOW_RSS))
return -EINVAL;
flow_type &= ~FLOW_EXT;
if (fs->ring_cookie == RX_CLS_FLOW_DISC && flow_type != ETHER_FLOW)
return bnxt_add_ntuple_cls_rule(bp, fs);
ring = ethtool_get_flow_spec_ring(fs->ring_cookie);
vf = ethtool_get_flow_spec_ring_vf(fs->ring_cookie);
if (BNXT_VF(bp) && vf)
@ -1330,12 +1460,8 @@ static int bnxt_srxclsrlins(struct bnxt *bp, struct ethtool_rxnfc *cmd)
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;
rc = bnxt_add_l2_cls_rule(bp, fs);
else
rc = bnxt_add_ntuple_cls_rule(bp, fs);
return rc;
@ -1346,11 +1472,22 @@ 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;
struct bnxt_ntuple_filter *fltr;
u32 id = fs->location;
rcu_read_lock();
fltr_base = bnxt_get_one_fltr_rcu(bp, bp->l2_fltr_hash_tbl,
BNXT_L2_FLTR_HASH_SIZE, id);
if (fltr_base) {
struct bnxt_l2_filter *l2_fltr;
l2_fltr = container_of(fltr_base, struct bnxt_l2_filter, base);
rcu_read_unlock();
bnxt_hwrm_l2_filter_free(bp, l2_fltr);
bnxt_del_l2_filter(bp, l2_fltr);
return 0;
}
fltr_base = bnxt_get_one_fltr_rcu(bp, bp->ntp_fltr_hash_tbl,
BNXT_NTP_FLTR_HASH_SIZE,
fs->location);
BNXT_NTP_FLTR_HASH_SIZE, id);
if (!fltr_base) {
rcu_read_unlock();
return -ENOENT;
@ -1396,8 +1533,14 @@ static int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
cmd->data |= RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case SCTP_V4_FLOW:
case AH_ESP_V4_FLOW:
if (bp->rss_hash_cfg &
(VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 |
VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4))
cmd->data |= RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case SCTP_V4_FLOW:
case AH_V4_FLOW:
case ESP_V4_FLOW:
case IPV4_FLOW:
@ -1415,8 +1558,14 @@ static int bnxt_grxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
cmd->data |= RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case SCTP_V6_FLOW:
case AH_ESP_V6_FLOW:
if (bp->rss_hash_cfg &
(VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 |
VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6))
cmd->data |= RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough;
case SCTP_V6_FLOW:
case AH_V6_FLOW:
case ESP_V6_FLOW:
case IPV6_FLOW:
@ -1463,6 +1612,24 @@ static int bnxt_srxfh(struct bnxt *bp, struct ethtool_rxnfc *cmd)
rss_hash_cfg &= ~VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
if (tuple == 4)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_UDP_IPV6;
} else if (cmd->flow_type == AH_ESP_V4_FLOW) {
if (tuple == 4 && (!(bp->rss_cap & BNXT_RSS_CAP_AH_V4_RSS_CAP) ||
!(bp->rss_cap & BNXT_RSS_CAP_ESP_V4_RSS_CAP)))
return -EINVAL;
rss_hash_cfg &= ~(VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 |
VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4);
if (tuple == 4)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV4 |
VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV4;
} else if (cmd->flow_type == AH_ESP_V6_FLOW) {
if (tuple == 4 && (!(bp->rss_cap & BNXT_RSS_CAP_AH_V6_RSS_CAP) ||
!(bp->rss_cap & BNXT_RSS_CAP_ESP_V6_RSS_CAP)))
return -EINVAL;
rss_hash_cfg &= ~(VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 |
VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6);
if (tuple == 4)
rss_hash_cfg |= VNIC_RSS_CFG_REQ_HASH_TYPE_AH_SPI_IPV6 |
VNIC_RSS_CFG_REQ_HASH_TYPE_ESP_SPI_IPV6;
} else if (tuple == 4) {
return -EINVAL;
}
@ -1521,7 +1688,7 @@ static int bnxt_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
case ETHTOOL_GRXCLSRLCNT:
cmd->rule_cnt = bp->ntp_fltr_count;
cmd->data = BNXT_NTP_FLTR_MAX_FLTR | RX_CLS_LOC_SPECIAL;
cmd->data = bp->max_fltr | RX_CLS_LOC_SPECIAL;
break;
case ETHTOOL_GRXCLSRLALL:
@ -1619,8 +1786,10 @@ static int bnxt_set_rxfh(struct net_device *dev,
if (rxfh->hfunc && rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
if (rxfh->key)
return -EOPNOTSUPP;
if (rxfh->key) {
memcpy(bp->rss_hash_key, rxfh->key, HW_HASH_KEY_SIZE);
bp->rss_hash_key_updated = true;
}
if (rxfh->indir) {
u32 i, pad, tbl_size = bnxt_get_rxfh_indir_size(dev);
@ -1631,7 +1800,7 @@ static int bnxt_set_rxfh(struct net_device *dev,
if (pad)
memset(&bp->rss_indir_tbl[i], 0, pad * sizeof(u16));
}
bnxt_clear_usr_fltrs(bp, false);
if (netif_running(bp->dev)) {
bnxt_close_nic(bp, false, false);
rc = bnxt_open_nic(bp, false, false);

View file

@ -43,6 +43,8 @@ struct bnxt_led_cfg {
#define BNXT_PXP_REG_LEN 0x3110
#define BNXT_IP_PROTO_FULL_MASK 0xFF
extern const struct ethtool_ops bnxt_ethtool_ops;
u32 bnxt_get_rxfh_indir_size(struct net_device *dev);