Commit abc21095 authored by Yanguo Li's avatar Yanguo Li Committed by David S. Miller

nfp: flower: tunnel neigh support bond offload

Support hardware offload when tunnel neigh out port is bond.
These feature work with the nfp firmware. If the firmware
supports the NFP_FL_FEATS_TUNNEL_NEIGH_LAG feature, nfp driver
write the bond information to the firmware neighbor table or
do nothing for bond. when neighbor MAC changes, nfp driver
need to update the neighbor information too.
Signed-off-by: default avatarYanguo Li <yanguo.li@corigine.com>
Reviewed-by: default avatarLouis Peens <louis.peens@corigine.com>
Signed-off-by: default avatarSimon Horman <simon.horman@corigine.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 04d63e62
......@@ -154,10 +154,11 @@ nfp_fl_lag_find_group_for_master_with_lag(struct nfp_fl_lag *lag,
return NULL;
}
int nfp_flower_lag_populate_pre_action(struct nfp_app *app,
struct net_device *master,
struct nfp_fl_pre_lag *pre_act,
struct netlink_ext_ack *extack)
static int nfp_fl_lag_get_group_info(struct nfp_app *app,
struct net_device *netdev,
__be16 *group_id,
u8 *batch_ver,
u8 *group_inst)
{
struct nfp_flower_priv *priv = app->priv;
struct nfp_fl_lag_group *group = NULL;
......@@ -165,23 +166,52 @@ int nfp_flower_lag_populate_pre_action(struct nfp_app *app,
mutex_lock(&priv->nfp_lag.lock);
group = nfp_fl_lag_find_group_for_master_with_lag(&priv->nfp_lag,
master);
netdev);
if (!group) {
mutex_unlock(&priv->nfp_lag.lock);
NL_SET_ERR_MSG_MOD(extack, "invalid entry: group does not exist for LAG action");
return -ENOENT;
}
pre_act->group_id = cpu_to_be16(group->group_id);
if (group_id)
*group_id = cpu_to_be16(group->group_id);
if (batch_ver) {
temp_vers = cpu_to_be32(priv->nfp_lag.batch_ver <<
NFP_FL_PRE_LAG_VER_OFF);
memcpy(pre_act->lag_version, &temp_vers, 3);
pre_act->instance = group->group_inst;
memcpy(batch_ver, &temp_vers, 3);
}
if (group_inst)
*group_inst = group->group_inst;
mutex_unlock(&priv->nfp_lag.lock);
return 0;
}
int nfp_flower_lag_populate_pre_action(struct nfp_app *app,
struct net_device *master,
struct nfp_fl_pre_lag *pre_act,
struct netlink_ext_ack *extack)
{
if (nfp_fl_lag_get_group_info(app, master, &pre_act->group_id,
pre_act->lag_version,
&pre_act->instance)) {
NL_SET_ERR_MSG_MOD(extack, "invalid entry: group does not exist for LAG action");
return -ENOENT;
}
return 0;
}
void nfp_flower_lag_get_info_from_netdev(struct nfp_app *app,
struct net_device *netdev,
struct nfp_tun_neigh_lag *lag)
{
nfp_fl_lag_get_group_info(app, netdev, NULL,
lag->lag_version, &lag->lag_instance);
}
int nfp_flower_lag_get_output_id(struct nfp_app *app, struct net_device *master)
{
struct nfp_flower_priv *priv = app->priv;
......
......@@ -76,7 +76,9 @@ nfp_flower_get_internal_port_id(struct nfp_app *app, struct net_device *netdev)
u32 nfp_flower_get_port_id_from_netdev(struct nfp_app *app,
struct net_device *netdev)
{
struct nfp_flower_priv *priv = app->priv;
int ext_port;
int gid;
if (nfp_netdev_is_nfp_repr(netdev)) {
return nfp_repr_get_port_id(netdev);
......@@ -86,6 +88,13 @@ u32 nfp_flower_get_port_id_from_netdev(struct nfp_app *app,
return 0;
return nfp_flower_internal_port_get_port_id(ext_port);
} else if (netif_is_lag_master(netdev) &&
priv->flower_ext_feats & NFP_FL_FEATS_TUNNEL_NEIGH_LAG) {
gid = nfp_flower_lag_get_output_id(app, netdev);
if (gid < 0)
return 0;
return (NFP_FL_LAG_OUT | gid);
}
return 0;
......
......@@ -52,6 +52,7 @@ struct nfp_app;
#define NFP_FL_FEATS_QOS_PPS BIT(9)
#define NFP_FL_FEATS_QOS_METER BIT(10)
#define NFP_FL_FEATS_DECAP_V2 BIT(11)
#define NFP_FL_FEATS_TUNNEL_NEIGH_LAG BIT(12)
#define NFP_FL_FEATS_HOST_ACK BIT(31)
#define NFP_FL_ENABLE_FLOW_MERGE BIT(0)
......@@ -69,7 +70,8 @@ struct nfp_app;
NFP_FL_FEATS_VLAN_QINQ | \
NFP_FL_FEATS_QOS_PPS | \
NFP_FL_FEATS_QOS_METER | \
NFP_FL_FEATS_DECAP_V2)
NFP_FL_FEATS_DECAP_V2 | \
NFP_FL_FEATS_TUNNEL_NEIGH_LAG)
struct nfp_fl_mask_id {
struct circ_buf mask_id_free_list;
......@@ -103,6 +105,16 @@ struct nfp_fl_tunnel_offloads {
struct notifier_block neigh_nb;
};
/**
* struct nfp_tun_neigh_lag - lag info
* @lag_version: lag version
* @lag_instance: lag instance
*/
struct nfp_tun_neigh_lag {
u8 lag_version[3];
u8 lag_instance;
};
/**
* struct nfp_tun_neigh - basic neighbour data
* @dst_addr: Destination MAC address
......@@ -133,12 +145,14 @@ struct nfp_tun_neigh_ext {
* @src_ipv4: Source IPv4 address
* @common: Neighbour/route common info
* @ext: Neighbour/route extended info
* @lag: lag port info
*/
struct nfp_tun_neigh_v4 {
__be32 dst_ipv4;
__be32 src_ipv4;
struct nfp_tun_neigh common;
struct nfp_tun_neigh_ext ext;
struct nfp_tun_neigh_lag lag;
};
/**
......@@ -147,12 +161,14 @@ struct nfp_tun_neigh_v4 {
* @src_ipv6: Source IPv6 address
* @common: Neighbour/route common info
* @ext: Neighbour/route extended info
* @lag: lag port info
*/
struct nfp_tun_neigh_v6 {
struct in6_addr dst_ipv6;
struct in6_addr src_ipv6;
struct nfp_tun_neigh common;
struct nfp_tun_neigh_ext ext;
struct nfp_tun_neigh_lag lag;
};
/**
......@@ -647,6 +663,9 @@ int nfp_flower_lag_populate_pre_action(struct nfp_app *app,
struct netlink_ext_ack *extack);
int nfp_flower_lag_get_output_id(struct nfp_app *app,
struct net_device *master);
void nfp_flower_lag_get_info_from_netdev(struct nfp_app *app,
struct net_device *netdev,
struct nfp_tun_neigh_lag *lag);
void nfp_flower_qos_init(struct nfp_app *app);
void nfp_flower_qos_cleanup(struct nfp_app *app);
int nfp_flower_setup_qos_offload(struct nfp_app *app, struct net_device *netdev,
......
......@@ -290,6 +290,11 @@ nfp_flower_xmit_tun_conf(struct nfp_app *app, u8 mtype, u16 plen, void *pdata,
mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6))
plen -= sizeof(struct nfp_tun_neigh_ext);
if (!(priv->flower_ext_feats & NFP_FL_FEATS_TUNNEL_NEIGH_LAG) &&
(mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH ||
mtype == NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6))
plen -= sizeof(struct nfp_tun_neigh_lag);
skb = nfp_flower_cmsg_alloc(app, plen, mtype, flag);
if (!skb)
return -ENOMEM;
......@@ -468,6 +473,7 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
neigh_table_params);
if (!nn_entry && !neigh_invalid) {
struct nfp_tun_neigh_ext *ext;
struct nfp_tun_neigh_lag *lag;
struct nfp_tun_neigh *common;
nn_entry = kzalloc(sizeof(*nn_entry) + neigh_size,
......@@ -488,6 +494,7 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
payload->dst_ipv6 = flowi6->daddr;
common = &payload->common;
ext = &payload->ext;
lag = &payload->lag;
mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6;
} else {
struct flowi4 *flowi4 = (struct flowi4 *)flow;
......@@ -498,6 +505,7 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
payload->dst_ipv4 = flowi4->daddr;
common = &payload->common;
ext = &payload->ext;
lag = &payload->lag;
mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
}
ext->host_ctx = cpu_to_be32(U32_MAX);
......@@ -505,6 +513,9 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
ext->vlan_tci = cpu_to_be16(U16_MAX);
ether_addr_copy(common->src_addr, netdev->dev_addr);
neigh_ha_snapshot(common->dst_addr, neigh, netdev);
if ((port_id & NFP_FL_LAG_OUT) == NFP_FL_LAG_OUT)
nfp_flower_lag_get_info_from_netdev(app, netdev, lag);
common->port_id = cpu_to_be32(port_id);
if (rhashtable_insert_fast(&priv->neigh_table,
......@@ -547,14 +558,39 @@ nfp_tun_write_neigh(struct net_device *netdev, struct nfp_app *app,
if (nn_entry->flow)
list_del(&nn_entry->list_head);
kfree(nn_entry);
} else if (nn_entry && !neigh_invalid && override) {
mtype = is_ipv6 ? NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6 :
NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
} else if (nn_entry && !neigh_invalid) {
struct nfp_tun_neigh *common;
u8 dst_addr[ETH_ALEN];
bool is_mac_change;
if (is_ipv6) {
struct nfp_tun_neigh_v6 *payload;
payload = (struct nfp_tun_neigh_v6 *)nn_entry->payload;
common = &payload->common;
mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH_V6;
} else {
struct nfp_tun_neigh_v4 *payload;
payload = (struct nfp_tun_neigh_v4 *)nn_entry->payload;
common = &payload->common;
mtype = NFP_FLOWER_CMSG_TYPE_TUN_NEIGH;
}
ether_addr_copy(dst_addr, common->dst_addr);
neigh_ha_snapshot(common->dst_addr, neigh, netdev);
is_mac_change = !ether_addr_equal(dst_addr, common->dst_addr);
if (override || is_mac_change) {
if (is_mac_change && nn_entry->flow) {
list_del(&nn_entry->list_head);
nn_entry->flow = NULL;
}
nfp_tun_link_predt_entries(app, nn_entry);
nfp_flower_xmit_tun_conf(app, mtype, neigh_size,
nn_entry->payload,
GFP_ATOMIC);
}
}
spin_unlock_bh(&priv->predt_lock);
return;
......@@ -593,8 +629,7 @@ nfp_tun_neigh_event_handler(struct notifier_block *nb, unsigned long event,
app_priv = container_of(nb, struct nfp_flower_priv, tun.neigh_nb);
app = app_priv->app;
if (!nfp_netdev_is_nfp_repr(n->dev) &&
!nfp_flower_internal_port_can_offload(app, n->dev))
if (!nfp_flower_get_port_id_from_netdev(app, n->dev))
return NOTIFY_DONE;
#if IS_ENABLED(CONFIG_INET)
......
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