mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
sfc: neighbour lookup for TC encap action offload
For each neighbour we're interested in, create a struct efx_neigh_binder object which has a list of all the encap_actions using it. When we receive a neighbouring update (through the netevent notifier), find the corresponding efx_neigh_binder and update all its users. Since the actual generation of encap headers is still only a stub, the resulting rules still get left on fallback actions. Signed-off-by: Edward Cree <ecree.xilinx@gmail.com> Reviewed-by: Simon Horman <simon.horman@corigine.com> Reviewed-by: Pieter Jansen van Vuuren <pieter.jansen-van-vuuren@amd.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
f1363154c4
commit
7e5e7d8000
@@ -24,6 +24,7 @@
|
||||
#include "rx_common.h"
|
||||
#include "ef100_sriov.h"
|
||||
#include "tc_bindings.h"
|
||||
#include "tc_encap_actions.h"
|
||||
#include "efx_devlink.h"
|
||||
|
||||
static void ef100_update_name(struct efx_nic *efx)
|
||||
@@ -300,14 +301,38 @@ int ef100_netdev_event(struct notifier_block *this,
|
||||
{
|
||||
struct efx_nic *efx = container_of(this, struct efx_nic, netdev_notifier);
|
||||
struct net_device *net_dev = netdev_notifier_info_to_dev(ptr);
|
||||
struct ef100_nic_data *nic_data = efx->nic_data;
|
||||
int err;
|
||||
|
||||
if (efx->net_dev == net_dev &&
|
||||
(event == NETDEV_CHANGENAME || event == NETDEV_REGISTER))
|
||||
ef100_update_name(efx);
|
||||
|
||||
if (!nic_data->grp_mae)
|
||||
return NOTIFY_DONE;
|
||||
err = efx_tc_netdev_event(efx, event, net_dev);
|
||||
if (err & NOTIFY_STOP_MASK)
|
||||
return err;
|
||||
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
static int ef100_netevent_event(struct notifier_block *this,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct efx_nic *efx = container_of(this, struct efx_nic, netevent_notifier);
|
||||
struct ef100_nic_data *nic_data = efx->nic_data;
|
||||
int err;
|
||||
|
||||
if (!nic_data->grp_mae)
|
||||
return NOTIFY_DONE;
|
||||
err = efx_tc_netevent_event(efx, event, ptr);
|
||||
if (err & NOTIFY_STOP_MASK)
|
||||
return err;
|
||||
|
||||
return NOTIFY_DONE;
|
||||
};
|
||||
|
||||
static int ef100_register_netdev(struct efx_nic *efx)
|
||||
{
|
||||
struct net_device *net_dev = efx->net_dev;
|
||||
@@ -367,6 +392,7 @@ void ef100_remove_netdev(struct efx_probe_data *probe_data)
|
||||
rtnl_unlock();
|
||||
|
||||
unregister_netdevice_notifier(&efx->netdev_notifier);
|
||||
unregister_netevent_notifier(&efx->netevent_notifier);
|
||||
#if defined(CONFIG_SFC_SRIOV)
|
||||
if (!efx->type->is_vf)
|
||||
efx_ef100_pci_sriov_disable(efx, true);
|
||||
@@ -487,6 +513,14 @@ int ef100_probe_netdev(struct efx_probe_data *probe_data)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
efx->netevent_notifier.notifier_call = ef100_netevent_event;
|
||||
rc = register_netevent_notifier(&efx->netevent_notifier);
|
||||
if (rc) {
|
||||
netif_err(efx, probe, efx->net_dev,
|
||||
"Failed to register netevent notifier, rc=%d\n", rc);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
efx_probe_devlink_unlock(efx);
|
||||
return rc;
|
||||
fail:
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <net/busy_poll.h>
|
||||
#include <net/xdp.h>
|
||||
#include <net/netevent.h>
|
||||
|
||||
#include "enum.h"
|
||||
#include "bitfield.h"
|
||||
@@ -996,6 +997,7 @@ struct efx_mae;
|
||||
* @xdp_rxq_info_failed: Have any of the rx queues failed to initialise their
|
||||
* xdp_rxq_info structures?
|
||||
* @netdev_notifier: Netdevice notifier.
|
||||
* @netevent_notifier: Netevent notifier (for neighbour updates).
|
||||
* @tc: state for TC offload (EF100).
|
||||
* @devlink: reference to devlink structure owned by this device
|
||||
* @dl_port: devlink port associated with the PF
|
||||
@@ -1183,6 +1185,7 @@ struct efx_nic {
|
||||
bool xdp_rxq_info_failed;
|
||||
|
||||
struct notifier_block netdev_notifier;
|
||||
struct notifier_block netevent_notifier;
|
||||
struct efx_tc_state *tc;
|
||||
|
||||
struct devlink *devlink;
|
||||
|
||||
@@ -34,8 +34,8 @@ enum efx_encap_type efx_tc_indr_netdev_type(struct net_device *net_dev)
|
||||
* May return NULL for the PF (us), or an error pointer for a device that
|
||||
* isn't supported as a TC offload endpoint
|
||||
*/
|
||||
static struct efx_rep *efx_tc_flower_lookup_efv(struct efx_nic *efx,
|
||||
struct net_device *dev)
|
||||
struct efx_rep *efx_tc_flower_lookup_efv(struct efx_nic *efx,
|
||||
struct net_device *dev)
|
||||
{
|
||||
struct efx_rep *efv;
|
||||
|
||||
@@ -71,7 +71,7 @@ static s64 efx_tc_flower_internal_mport(struct efx_nic *efx, struct efx_rep *efv
|
||||
}
|
||||
|
||||
/* Convert a driver-internal vport ID into an external device (wire or VF) */
|
||||
static s64 efx_tc_flower_external_mport(struct efx_nic *efx, struct efx_rep *efv)
|
||||
s64 efx_tc_flower_external_mport(struct efx_nic *efx, struct efx_rep *efv)
|
||||
{
|
||||
u32 mport;
|
||||
|
||||
@@ -112,8 +112,10 @@ static void efx_tc_free_action_set(struct efx_nic *efx,
|
||||
}
|
||||
if (act->count)
|
||||
efx_tc_flower_put_counter_index(efx, act->count);
|
||||
if (act->encap_md)
|
||||
if (act->encap_md) {
|
||||
list_del(&act->encap_user);
|
||||
efx_tc_flower_release_encap_md(efx, act->encap_md);
|
||||
}
|
||||
kfree(act);
|
||||
}
|
||||
|
||||
@@ -1115,6 +1117,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx,
|
||||
goto release;
|
||||
}
|
||||
act->encap_md = encap;
|
||||
list_add_tail(&act->encap_user, &encap->users);
|
||||
act->dest_mport = encap->dest_mport;
|
||||
act->deliver = 1;
|
||||
rc = efx_mae_alloc_action_set(efx, act);
|
||||
@@ -1123,6 +1126,7 @@ static int efx_tc_flower_replace(struct efx_nic *efx,
|
||||
goto release;
|
||||
}
|
||||
list_add_tail(&act->list, &rule->acts.list);
|
||||
act->user = &rule->acts;
|
||||
act = NULL;
|
||||
if (fa->id == FLOW_ACTION_REDIRECT)
|
||||
break; /* end of the line */
|
||||
|
||||
@@ -36,6 +36,8 @@ struct efx_tc_action_set {
|
||||
__be16 vlan_proto[2]; /* Ethertypes for vlan_push */
|
||||
struct efx_tc_counter_index *count;
|
||||
struct efx_tc_encap_action *encap_md; /* entry in tc_encap_ht table */
|
||||
struct list_head encap_user; /* entry on encap_md->users list */
|
||||
struct efx_tc_action_set_list *user; /* Only populated if encap_md */
|
||||
u32 dest_mport;
|
||||
u32 fw_id; /* index of this entry in firmware actions table */
|
||||
struct list_head list;
|
||||
@@ -151,6 +153,7 @@ enum efx_tc_rule_prios {
|
||||
* @encap_ht: Hashtable of TC encap actions
|
||||
* @encap_match_ht: Hashtable of TC encap matches
|
||||
* @match_action_ht: Hashtable of TC match-action rules
|
||||
* @neigh_ht: Hashtable of neighbour watches (&struct efx_neigh_binder)
|
||||
* @reps_mport_id: MAE port allocated for representor RX
|
||||
* @reps_filter_uc: VNIC filter for representor unicast RX (promisc)
|
||||
* @reps_filter_mc: VNIC filter for representor multicast RX (allmulti)
|
||||
@@ -181,6 +184,7 @@ struct efx_tc_state {
|
||||
struct rhashtable encap_ht;
|
||||
struct rhashtable encap_match_ht;
|
||||
struct rhashtable match_action_ht;
|
||||
struct rhashtable neigh_ht;
|
||||
u32 reps_mport_id, reps_mport_vport_id;
|
||||
s32 reps_filter_uc, reps_filter_mc;
|
||||
bool flush_counters;
|
||||
@@ -201,6 +205,9 @@ struct efx_tc_state {
|
||||
struct efx_rep;
|
||||
|
||||
enum efx_encap_type efx_tc_indr_netdev_type(struct net_device *net_dev);
|
||||
struct efx_rep *efx_tc_flower_lookup_efv(struct efx_nic *efx,
|
||||
struct net_device *dev);
|
||||
s64 efx_tc_flower_external_mport(struct efx_nic *efx, struct efx_rep *efv);
|
||||
int efx_tc_configure_default_rule_rep(struct efx_rep *efv);
|
||||
void efx_tc_deconfigure_default_rule(struct efx_nic *efx,
|
||||
struct efx_tc_flow_rule *rule);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "tc_bindings.h"
|
||||
#include "tc.h"
|
||||
#include "tc_encap_actions.h"
|
||||
|
||||
struct efx_tc_block_binding {
|
||||
struct list_head list;
|
||||
@@ -226,3 +227,15 @@ int efx_tc_setup(struct net_device *net_dev, enum tc_setup_type type,
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
int efx_tc_netdev_event(struct efx_nic *efx, unsigned long event,
|
||||
struct net_device *net_dev)
|
||||
{
|
||||
if (efx->type->is_vf)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (event == NETDEV_UNREGISTER)
|
||||
efx_tc_unregister_egdev(efx, net_dev);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
@@ -26,4 +26,6 @@ int efx_tc_indr_setup_cb(struct net_device *net_dev, struct Qdisc *sch,
|
||||
void *cb_priv, enum tc_setup_type type,
|
||||
void *type_data, void *data,
|
||||
void (*cleanup)(struct flow_block_cb *block_cb));
|
||||
int efx_tc_netdev_event(struct efx_nic *efx, unsigned long event,
|
||||
struct net_device *net_dev);
|
||||
#endif /* EFX_TC_BINDINGS_H */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,54 @@
|
||||
#include <linux/refcount.h>
|
||||
#include <net/tc_act/tc_tunnel_key.h>
|
||||
|
||||
/**
|
||||
* struct efx_neigh_binder - driver state for a neighbour entry
|
||||
* @net: the network namespace in which this neigh resides
|
||||
* @dst_ip: the IPv4 destination address resolved by this neigh
|
||||
* @dst_ip6: the IPv6 destination address resolved by this neigh
|
||||
* @ha: the hardware (Ethernet) address of the neighbour
|
||||
* @n_valid: true if the neighbour is in NUD_VALID state
|
||||
* @lock: protects @ha and @n_valid
|
||||
* @ttl: Time To Live associated with the route used
|
||||
* @dying: set when egdev is going away, to skip further updates
|
||||
* @egdev: egress device from the route lookup. Holds a reference
|
||||
* @dev_tracker: reference tracker entry for @egdev
|
||||
* @ns_tracker: reference tracker entry for @ns
|
||||
* @ref: counts encap actions referencing this entry
|
||||
* @used: jiffies of last time traffic hit any encap action using this.
|
||||
* When counter reads update this, a new neighbour event is sent to
|
||||
* indicate that the neighbour entry is still in use.
|
||||
* @users: list of &struct efx_tc_encap_action
|
||||
* @linkage: entry in efx->neigh_ht (keys are @net, @dst_ip, @dst_ip6).
|
||||
* @work: processes neighbour state changes, updates the encap actions
|
||||
* @efx: owning NIC instance.
|
||||
*
|
||||
* Associates a neighbour entry with the encap actions that are
|
||||
* interested in it, allowing the latter to be updated when the
|
||||
* neighbour details change.
|
||||
* Whichever of @dst_ip and @dst_ip6 is not in use will be all-zeroes,
|
||||
* this distinguishes IPv4 from IPv6 entries.
|
||||
*/
|
||||
struct efx_neigh_binder {
|
||||
struct net *net;
|
||||
__be32 dst_ip;
|
||||
struct in6_addr dst_ip6;
|
||||
char ha[ETH_ALEN];
|
||||
bool n_valid;
|
||||
rwlock_t lock;
|
||||
u8 ttl;
|
||||
bool dying;
|
||||
struct net_device *egdev;
|
||||
netdevice_tracker dev_tracker;
|
||||
netns_tracker ns_tracker;
|
||||
refcount_t ref;
|
||||
unsigned long used;
|
||||
struct list_head users;
|
||||
struct rhash_head linkage;
|
||||
struct work_struct work;
|
||||
struct efx_nic *efx;
|
||||
};
|
||||
|
||||
/* This limit is arbitrary; current hardware (SN1022) handles encap headers
|
||||
* of up to 126 bytes, but that limit is not enshrined in the MCDI protocol.
|
||||
*/
|
||||
@@ -24,7 +72,11 @@ struct efx_tc_encap_action {
|
||||
struct ip_tunnel_key key; /* 52 bytes */
|
||||
u32 dest_mport; /* is copied into struct efx_tc_action_set */
|
||||
u8 encap_hdr_len;
|
||||
bool n_valid;
|
||||
u8 encap_hdr[EFX_TC_MAX_ENCAP_HDR];
|
||||
struct efx_neigh_binder *neigh;
|
||||
struct list_head list; /* entry on neigh->users list */
|
||||
struct list_head users; /* action sets using this encap_md */
|
||||
struct rhash_head linkage; /* efx->tc_encap_ht */
|
||||
refcount_t ref;
|
||||
u32 fw_id; /* index of this entry in firmware encap table */
|
||||
@@ -44,4 +96,8 @@ struct efx_tc_encap_action *efx_tc_flower_create_encap_md(
|
||||
void efx_tc_flower_release_encap_md(struct efx_nic *efx,
|
||||
struct efx_tc_encap_action *encap);
|
||||
|
||||
void efx_tc_unregister_egdev(struct efx_nic *efx, struct net_device *net_dev);
|
||||
int efx_tc_netevent_event(struct efx_nic *efx, unsigned long event,
|
||||
void *ptr);
|
||||
|
||||
#endif /* EFX_TC_ENCAP_ACTIONS_H */
|
||||
|
||||
Reference in New Issue
Block a user