Commit b1711d43 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'nfp-add-flow-steering-support'

Louis Peens says:

====================
nfp: add flow-steering support

This short series adds flow steering support for the nfp driver.
The first patch adds the part to communicate with ethtool but
stubs out the HW offload parts. The second patch implements the
HW communication and offloads flow steering.

After this series the user can now use 'ethtool -N/-n' to configure
and display rx classification rules.
====================

Link: https://lore.kernel.org/r/20231117071114.10667-1-louis.peens@corigine.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 21612f52 c38fb3dc
......@@ -621,6 +621,9 @@ struct nfp_net_dp {
* @mbox_amsg.lock: Protect message list
* @mbox_amsg.list: List of message to process
* @mbox_amsg.work: Work to process message asynchronously
* @fs: Flow steering
* @fs.count: Flow count
* @fs.list: List of flows
* @app_priv: APP private data for this vNIC
*/
struct nfp_net {
......@@ -728,9 +731,39 @@ struct nfp_net {
struct work_struct work;
} mbox_amsg;
struct {
u16 count;
struct list_head list;
} fs;
void *app_priv;
};
struct nfp_fs_entry {
struct list_head node;
u32 flow_type;
u32 loc;
struct {
union {
struct {
__be32 sip4;
__be32 dip4;
};
struct {
__be32 sip6[4];
__be32 dip6[4];
};
};
union {
__be16 l3_proto;
u8 l4_proto;
};
__be16 sport;
__be16 dport;
} key, msk;
u64 action;
};
struct nfp_mbox_amsg_entry {
struct list_head list;
int (*cfg)(struct nfp_net *nn, struct nfp_mbox_amsg_entry *entry);
......@@ -987,6 +1020,9 @@ struct nfp_net_dp *nfp_net_clone_dp(struct nfp_net *nn);
int nfp_net_ring_reconfig(struct nfp_net *nn, struct nfp_net_dp *new,
struct netlink_ext_ack *extack);
int nfp_net_fs_add_hw(struct nfp_net *nn, struct nfp_fs_entry *entry);
int nfp_net_fs_del_hw(struct nfp_net *nn, struct nfp_fs_entry *entry);
#ifdef CONFIG_NFP_DEBUG
void nfp_net_debugfs_create(void);
void nfp_net_debugfs_destroy(void);
......
......@@ -1763,6 +1763,186 @@ nfp_net_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
return nfp_net_mbox_reconfig_and_unlock(nn, cmd);
}
static void
nfp_net_fs_fill_v4(struct nfp_net *nn, struct nfp_fs_entry *entry, u32 op, u32 *addr)
{
unsigned int i;
union {
struct {
__be16 loc;
u8 k_proto, m_proto;
__be32 k_sip, m_sip, k_dip, m_dip;
__be16 k_sport, m_sport, k_dport, m_dport;
};
__be32 val[7];
} v4_rule;
nn_writel(nn, *addr, op);
*addr += sizeof(u32);
v4_rule.loc = cpu_to_be16(entry->loc);
v4_rule.k_proto = entry->key.l4_proto;
v4_rule.m_proto = entry->msk.l4_proto;
v4_rule.k_sip = entry->key.sip4;
v4_rule.m_sip = entry->msk.sip4;
v4_rule.k_dip = entry->key.dip4;
v4_rule.m_dip = entry->msk.dip4;
v4_rule.k_sport = entry->key.sport;
v4_rule.m_sport = entry->msk.sport;
v4_rule.k_dport = entry->key.dport;
v4_rule.m_dport = entry->msk.dport;
for (i = 0; i < ARRAY_SIZE(v4_rule.val); i++, *addr += sizeof(__be32))
nn_writel(nn, *addr, be32_to_cpu(v4_rule.val[i]));
}
static void
nfp_net_fs_fill_v6(struct nfp_net *nn, struct nfp_fs_entry *entry, u32 op, u32 *addr)
{
unsigned int i;
union {
struct {
__be16 loc;
u8 k_proto, m_proto;
__be32 k_sip[4], m_sip[4], k_dip[4], m_dip[4];
__be16 k_sport, m_sport, k_dport, m_dport;
};
__be32 val[19];
} v6_rule;
nn_writel(nn, *addr, op);
*addr += sizeof(u32);
v6_rule.loc = cpu_to_be16(entry->loc);
v6_rule.k_proto = entry->key.l4_proto;
v6_rule.m_proto = entry->msk.l4_proto;
for (i = 0; i < 4; i++) {
v6_rule.k_sip[i] = entry->key.sip6[i];
v6_rule.m_sip[i] = entry->msk.sip6[i];
v6_rule.k_dip[i] = entry->key.dip6[i];
v6_rule.m_dip[i] = entry->msk.dip6[i];
}
v6_rule.k_sport = entry->key.sport;
v6_rule.m_sport = entry->msk.sport;
v6_rule.k_dport = entry->key.dport;
v6_rule.m_dport = entry->msk.dport;
for (i = 0; i < ARRAY_SIZE(v6_rule.val); i++, *addr += sizeof(__be32))
nn_writel(nn, *addr, be32_to_cpu(v6_rule.val[i]));
}
#define NFP_FS_QUEUE_ID GENMASK(22, 16)
#define NFP_FS_ACT GENMASK(15, 0)
#define NFP_FS_ACT_DROP BIT(0)
#define NFP_FS_ACT_Q BIT(1)
static void
nfp_net_fs_fill_act(struct nfp_net *nn, struct nfp_fs_entry *entry, u32 addr)
{
u32 action = 0; /* 0 means default passthrough */
if (entry->action == RX_CLS_FLOW_DISC)
action = NFP_FS_ACT_DROP;
else if (!(entry->flow_type & FLOW_RSS))
action = FIELD_PREP(NFP_FS_QUEUE_ID, entry->action) | NFP_FS_ACT_Q;
nn_writel(nn, addr, action);
}
int nfp_net_fs_add_hw(struct nfp_net *nn, struct nfp_fs_entry *entry)
{
u32 addr = nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL;
int err;
err = nfp_net_mbox_lock(nn, NFP_NET_CFG_FS_SZ);
if (err)
return err;
switch (entry->flow_type & ~FLOW_RSS) {
case TCP_V4_FLOW:
case UDP_V4_FLOW:
case SCTP_V4_FLOW:
case IPV4_USER_FLOW:
nfp_net_fs_fill_v4(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_ADD_V4, &addr);
break;
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
case IPV6_USER_FLOW:
nfp_net_fs_fill_v6(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_ADD_V6, &addr);
break;
case ETHER_FLOW:
nn_writel(nn, addr, NFP_NET_CFG_MBOX_CMD_FS_ADD_ETHTYPE);
addr += sizeof(u32);
nn_writew(nn, addr, be16_to_cpu(entry->key.l3_proto));
addr += sizeof(u32);
break;
}
nfp_net_fs_fill_act(nn, entry, addr);
err = nfp_net_mbox_reconfig_and_unlock(nn, NFP_NET_CFG_MBOX_CMD_FLOW_STEER);
if (err) {
nn_err(nn, "Add new fs rule failed with %d\n", err);
return -EIO;
}
return 0;
}
int nfp_net_fs_del_hw(struct nfp_net *nn, struct nfp_fs_entry *entry)
{
u32 addr = nn->tlv_caps.mbox_off + NFP_NET_CFG_MBOX_SIMPLE_VAL;
int err;
err = nfp_net_mbox_lock(nn, NFP_NET_CFG_FS_SZ);
if (err)
return err;
switch (entry->flow_type & ~FLOW_RSS) {
case TCP_V4_FLOW:
case UDP_V4_FLOW:
case SCTP_V4_FLOW:
case IPV4_USER_FLOW:
nfp_net_fs_fill_v4(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_DEL_V4, &addr);
break;
case TCP_V6_FLOW:
case UDP_V6_FLOW:
case SCTP_V6_FLOW:
case IPV6_USER_FLOW:
nfp_net_fs_fill_v6(nn, entry, NFP_NET_CFG_MBOX_CMD_FS_DEL_V6, &addr);
break;
case ETHER_FLOW:
nn_writel(nn, addr, NFP_NET_CFG_MBOX_CMD_FS_DEL_ETHTYPE);
addr += sizeof(u32);
nn_writew(nn, addr, be16_to_cpu(entry->key.l3_proto));
addr += sizeof(u32);
break;
}
nfp_net_fs_fill_act(nn, entry, addr);
err = nfp_net_mbox_reconfig_and_unlock(nn, NFP_NET_CFG_MBOX_CMD_FLOW_STEER);
if (err) {
nn_err(nn, "Delete fs rule failed with %d\n", err);
return -EIO;
}
return 0;
}
static void nfp_net_fs_clean(struct nfp_net *nn)
{
struct nfp_fs_entry *entry, *tmp;
list_for_each_entry_safe(entry, tmp, &nn->fs.list, node) {
nfp_net_fs_del_hw(nn, entry);
list_del(&entry->node);
kfree(entry);
}
}
static void nfp_net_stat64(struct net_device *netdev,
struct rtnl_link_stats64 *stats)
{
......@@ -2740,6 +2920,8 @@ int nfp_net_init(struct nfp_net *nn)
INIT_LIST_HEAD(&nn->mbox_amsg.list);
INIT_WORK(&nn->mbox_amsg.work, nfp_net_mbox_amsg_work);
INIT_LIST_HEAD(&nn->fs.list);
return register_netdev(nn->dp.netdev);
err_clean_mbox:
......@@ -2759,6 +2941,7 @@ void nfp_net_clean(struct nfp_net *nn)
unregister_netdev(nn->dp.netdev);
nfp_net_ipsec_clean(nn);
nfp_ccm_mbox_clean(nn);
nfp_net_fs_clean(nn);
flush_work(&nn->mbox_amsg.work);
nfp_net_reconfig_wait_posted(nn);
}
......@@ -269,6 +269,7 @@
#define NFP_NET_CFG_CTRL_IPSEC (0x1 << 1) /* IPsec offload */
#define NFP_NET_CFG_CTRL_MCAST_FILTER (0x1 << 2) /* Multicast Filter */
#define NFP_NET_CFG_CTRL_FREELIST_EN (0x1 << 6) /* Freelist enable flag bit */
#define NFP_NET_CFG_CTRL_FLOW_STEER (0x1 << 8) /* Flow steering */
#define NFP_NET_CFG_CAP_WORD1 0x00a4
......@@ -418,6 +419,8 @@
#define NFP_NET_CFG_MBOX_CMD_MULTICAST_ADD 8
#define NFP_NET_CFG_MBOX_CMD_MULTICAST_DEL 9
#define NFP_NET_CFG_MBOX_CMD_FLOW_STEER 10
/* VLAN filtering using general use mailbox
* %NFP_NET_CFG_VLAN_FILTER: Base address of VLAN filter mailbox
* %NFP_NET_CFG_VLAN_FILTER_VID: VLAN ID to filter
......@@ -440,6 +443,18 @@
#define NFP_NET_CFG_MULTICAST_MAC_LO (NFP_NET_CFG_MULTICAST + 6)
#define NFP_NET_CFG_MULTICAST_SZ 0x0006
/* Max size of FS rules in bytes */
#define NFP_NET_CFG_FS_SZ 0x0054
/* Sub commands for FS */
enum {
NFP_NET_CFG_MBOX_CMD_FS_ADD_V4,
NFP_NET_CFG_MBOX_CMD_FS_DEL_V4,
NFP_NET_CFG_MBOX_CMD_FS_ADD_V6,
NFP_NET_CFG_MBOX_CMD_FS_DEL_V6,
NFP_NET_CFG_MBOX_CMD_FS_ADD_ETHTYPE,
NFP_NET_CFG_MBOX_CMD_FS_DEL_ETHTYPE,
};
/* TLV capabilities
* %NFP_NET_CFG_TLV_TYPE: Offset of type within the TLV
* %NFP_NET_CFG_TLV_TYPE_REQUIRED: Driver must be able to parse the TLV
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment