Commit 627c89d0 authored by Sriharsha Basavapatna's avatar Sriharsha Basavapatna Committed by David S. Miller

bnxt_en: flow_offload: offload tunnel decap rules via indirect callbacks

The decap (VXLAN tunnel) flow rules are not getting offloaded with
upstream kernel. This is because TC block callback infrastructure has
been updated to use indirect callbacks to get offloaded rules from
other higher level devices (such as tunnels), instead of ndo_setup_tc().
Since the decap rules are applied to the tunnel devices (e.g, vxlan_sys),
the driver should register for indirect TC callback with tunnel devices
to get the rules for offloading. This patch updates the driver to
register and process indirect TC block callbacks from VXLAN tunnels.
Signed-off-by: default avatarSriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
Signed-off-by: default avatarMichael Chan <michael.chan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 9b9eb518
...@@ -10945,7 +10945,7 @@ static int bnxt_setup_tc_block_cb(enum tc_setup_type type, void *type_data, ...@@ -10945,7 +10945,7 @@ static int bnxt_setup_tc_block_cb(enum tc_setup_type type, void *type_data,
} }
} }
static LIST_HEAD(bnxt_block_cb_list); LIST_HEAD(bnxt_block_cb_list);
static int bnxt_setup_tc(struct net_device *dev, enum tc_setup_type type, static int bnxt_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data) void *type_data)
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
#include <linux/firmware/broadcom/tee_bnxt_fw.h> #include <linux/firmware/broadcom/tee_bnxt_fw.h>
#endif #endif
extern struct list_head bnxt_block_cb_list;
struct page_pool; struct page_pool;
struct tx_bd { struct tx_bd {
...@@ -1244,6 +1246,14 @@ struct bnxt_tc_flow_stats { ...@@ -1244,6 +1246,14 @@ struct bnxt_tc_flow_stats {
u64 bytes; u64 bytes;
}; };
#ifdef CONFIG_BNXT_FLOWER_OFFLOAD
struct bnxt_flower_indr_block_cb_priv {
struct net_device *tunnel_netdev;
struct bnxt *bp;
struct list_head list;
};
#endif
struct bnxt_tc_info { struct bnxt_tc_info {
bool enabled; bool enabled;
...@@ -1821,6 +1831,8 @@ struct bnxt { ...@@ -1821,6 +1831,8 @@ struct bnxt {
u16 *cfa_code_map; /* cfa_code -> vf_idx map */ u16 *cfa_code_map; /* cfa_code -> vf_idx map */
u8 switch_id[8]; u8 switch_id[8];
struct bnxt_tc_info *tc_info; struct bnxt_tc_info *tc_info;
struct list_head tc_indr_block_list;
struct notifier_block tc_netdev_nb;
struct dentry *debugfs_pdev; struct dentry *debugfs_pdev;
struct device *hwmon_dev; struct device *hwmon_dev;
}; };
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <net/tc_act/tc_vlan.h> #include <net/tc_act/tc_vlan.h>
#include <net/tc_act/tc_pedit.h> #include <net/tc_act/tc_pedit.h>
#include <net/tc_act/tc_tunnel_key.h> #include <net/tc_act/tc_tunnel_key.h>
#include <net/vxlan.h>
#include "bnxt_hsi.h" #include "bnxt_hsi.h"
#include "bnxt.h" #include "bnxt.h"
...@@ -1841,6 +1842,147 @@ int bnxt_tc_setup_flower(struct bnxt *bp, u16 src_fid, ...@@ -1841,6 +1842,147 @@ int bnxt_tc_setup_flower(struct bnxt *bp, u16 src_fid,
} }
} }
static int bnxt_tc_setup_indr_block_cb(enum tc_setup_type type,
void *type_data, void *cb_priv)
{
struct bnxt_flower_indr_block_cb_priv *priv = cb_priv;
struct flow_cls_offload *flower = type_data;
struct bnxt *bp = priv->bp;
if (flower->common.chain_index)
return -EOPNOTSUPP;
switch (type) {
case TC_SETUP_CLSFLOWER:
return bnxt_tc_setup_flower(bp, bp->pf.fw_fid, flower);
default:
return -EOPNOTSUPP;
}
}
static struct bnxt_flower_indr_block_cb_priv *
bnxt_tc_indr_block_cb_lookup(struct bnxt *bp, struct net_device *netdev)
{
struct bnxt_flower_indr_block_cb_priv *cb_priv;
/* All callback list access should be protected by RTNL. */
ASSERT_RTNL();
list_for_each_entry(cb_priv, &bp->tc_indr_block_list, list)
if (cb_priv->tunnel_netdev == netdev)
return cb_priv;
return NULL;
}
static void bnxt_tc_setup_indr_rel(void *cb_priv)
{
struct bnxt_flower_indr_block_cb_priv *priv = cb_priv;
list_del(&priv->list);
kfree(priv);
}
static int bnxt_tc_setup_indr_block(struct net_device *netdev, struct bnxt *bp,
struct flow_block_offload *f)
{
struct bnxt_flower_indr_block_cb_priv *cb_priv;
struct flow_block_cb *block_cb;
if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
switch (f->command) {
case FLOW_BLOCK_BIND:
cb_priv = kmalloc(sizeof(*cb_priv), GFP_KERNEL);
if (!cb_priv)
return -ENOMEM;
cb_priv->tunnel_netdev = netdev;
cb_priv->bp = bp;
list_add(&cb_priv->list, &bp->tc_indr_block_list);
block_cb = flow_block_cb_alloc(bnxt_tc_setup_indr_block_cb,
cb_priv, cb_priv,
bnxt_tc_setup_indr_rel);
if (IS_ERR(block_cb)) {
list_del(&cb_priv->list);
kfree(cb_priv);
return PTR_ERR(block_cb);
}
flow_block_cb_add(block_cb, f);
list_add_tail(&block_cb->driver_list, &bnxt_block_cb_list);
break;
case FLOW_BLOCK_UNBIND:
cb_priv = bnxt_tc_indr_block_cb_lookup(bp, netdev);
if (!cb_priv)
return -ENOENT;
block_cb = flow_block_cb_lookup(f->block,
bnxt_tc_setup_indr_block_cb,
cb_priv);
if (!block_cb)
return -ENOENT;
flow_block_cb_remove(block_cb, f);
list_del(&block_cb->driver_list);
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static int bnxt_tc_setup_indr_cb(struct net_device *netdev, void *cb_priv,
enum tc_setup_type type, void *type_data)
{
switch (type) {
case TC_SETUP_BLOCK:
return bnxt_tc_setup_indr_block(netdev, cb_priv, type_data);
default:
return -EOPNOTSUPP;
}
}
static bool bnxt_is_netdev_indr_offload(struct net_device *netdev)
{
return netif_is_vxlan(netdev);
}
static int bnxt_tc_indr_block_event(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct net_device *netdev;
struct bnxt *bp;
int rc;
netdev = netdev_notifier_info_to_dev(ptr);
if (!bnxt_is_netdev_indr_offload(netdev))
return NOTIFY_OK;
bp = container_of(nb, struct bnxt, tc_netdev_nb);
switch (event) {
case NETDEV_REGISTER:
rc = __flow_indr_block_cb_register(netdev, bp,
bnxt_tc_setup_indr_cb,
bp);
if (rc)
netdev_info(bp->dev,
"Failed to register indirect blk: dev: %s",
netdev->name);
break;
case NETDEV_UNREGISTER:
__flow_indr_block_cb_unregister(netdev,
bnxt_tc_setup_indr_cb,
bp);
break;
}
return NOTIFY_DONE;
}
static const struct rhashtable_params bnxt_tc_flow_ht_params = { static const struct rhashtable_params bnxt_tc_flow_ht_params = {
.head_offset = offsetof(struct bnxt_tc_flow_node, node), .head_offset = offsetof(struct bnxt_tc_flow_node, node),
.key_offset = offsetof(struct bnxt_tc_flow_node, cookie), .key_offset = offsetof(struct bnxt_tc_flow_node, cookie),
...@@ -1924,8 +2066,16 @@ int bnxt_init_tc(struct bnxt *bp) ...@@ -1924,8 +2066,16 @@ int bnxt_init_tc(struct bnxt *bp)
bp->dev->hw_features |= NETIF_F_HW_TC; bp->dev->hw_features |= NETIF_F_HW_TC;
bp->dev->features |= NETIF_F_HW_TC; bp->dev->features |= NETIF_F_HW_TC;
bp->tc_info = tc_info; bp->tc_info = tc_info;
/* init indirect block notifications */
INIT_LIST_HEAD(&bp->tc_indr_block_list);
bp->tc_netdev_nb.notifier_call = bnxt_tc_indr_block_event;
rc = register_netdevice_notifier(&bp->tc_netdev_nb);
if (!rc)
return 0; return 0;
rhashtable_destroy(&tc_info->encap_table);
destroy_decap_table: destroy_decap_table:
rhashtable_destroy(&tc_info->decap_table); rhashtable_destroy(&tc_info->decap_table);
destroy_decap_l2_table: destroy_decap_l2_table:
...@@ -1946,6 +2096,7 @@ void bnxt_shutdown_tc(struct bnxt *bp) ...@@ -1946,6 +2096,7 @@ void bnxt_shutdown_tc(struct bnxt *bp)
if (!bnxt_tc_flower_enabled(bp)) if (!bnxt_tc_flower_enabled(bp))
return; return;
unregister_netdevice_notifier(&bp->tc_netdev_nb);
rhashtable_destroy(&tc_info->flow_table); rhashtable_destroy(&tc_info->flow_table);
rhashtable_destroy(&tc_info->l2_table); rhashtable_destroy(&tc_info->l2_table);
rhashtable_destroy(&tc_info->decap_l2_table); rhashtable_destroy(&tc_info->decap_l2_table);
......
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