From: Jiri Pirko <redacted>
Petr says:
This patch series introduces to mlxsw driver support for offloading
IP-in-IP tunnels in general, and for (subset of) GRE in particular.
This patchset supports two ways of configuring GRE:
- So called "hierarchical configuration", where the GRE device has a bound
dummy device, which is in a different VRF. The VRF with host traffic is
called "overlay", the one with encapsulated traffic is called "underlay".
- So called "flat configuration", where the GRE device doesn't have a bound
device, and overlay and underlay are both in the same VRF (possibly the
default one).
Two routes are then interesting: a route that directs traffic to a GRE
device (which would typically be in overlay VRF, but could be in another
one), and a local route for the tunnel's local address (in underlay).
Handling of these two route types is then introduced as patches to support,
respectively, IPv4 and IPv6 encapsulation and IPv4 decapsulation.
The encap and decap routes then reference a loopback device, a new type of
RIF introduced by this patchset for the specific use of offloading tunnels.
The encap and decap code is abstract with respect to the particulars of
individual L3 tunnel types. This patchset introduces support for GRE
tunnels in particular.
Limitations:
- Each tunnel needs to have a different local address (within a given VRF).
When two tunnels are used that are in conflict, FIB abort is triggered
and the driver ceases offloading FIBs. Full handling of such
configurations needs special setup in the hardware, such that the tunnels
that share an address are dispatched correctly according to their key (or
lack thereof). That's currently not implemented, and to keep things
deterministic, the driver triggers FIB abort.
- A next hop that uses an incompletely-specified tunnel (e.g. such that are
used for LWT) is not offloaded, but doesn't trigger FIB abort like the
above. If such routes end up being in a de facto conflict with other
tunnels, then if there already is an offload for that address, the
traffic for the conflicting tunnel will end up mismatching the
configuration of the offloaded tunnel, and thus gets to slow path through
an error trap.
- GRE checksumming and sequence numbers are not supported and TTL and TOS
need to be set to inherit. Tunnels with a different configuration are not
offloaded and their traffic is trapping to slow path.
Note in particular that TOS of inherit is not the default configuration
and needs to be explicitly specified when the tunnel is created.
- The only feature that is not graciously handled is that if a change is
made to the tunnel, e.g. through "ip tunnel change", such changes are not
reflected in the driver. There is currently no notification mechanism for
these changes. Introduction of this mechanism and its leverage in the
driver will be subject of follow-up work. For now this limitation can be
worked around by removing and re-adding the encap route.
---
v1->v2:
-fix order of patch 5
Petr Machata (21):
mlxsw: reg: Update RITR to support loopback device
mlxsw: reg: Update RATR to support IP-in-IP tunnels
mlxsw: reg: Move enum mlxsw_reg_ratr_trap_id
mlxsw: reg: Add mlxsw_reg_ralue_act_ip2me_tun_pack()
mlxsw: reg: Add Routing Tunnel Decap Properties Register
mlxsw: reg: Extract mlxsw_reg_ritr_mac_pack()
mlxsw: reg: Give mlxsw_reg_ratr_pack a type parameter
mlxsw: spectrum_router: Publish mlxsw_sp_l3proto
mlxsw: spectrum_router: Add mlxsw_sp_ipip_ops
mlxsw: spectrum_router: Support FID-less RIFs
mlxsw: spectrum_router: Introduce loopback RIFs
mlxsw: spectrum_router: Extract mlxsw_sp_fi_is_gateway()
mlxsw: spectrum_router: Extract mlxsw_sp_rt6_is_gateway()
mlxsw: spectrum_router: Make nexthops typed
mlxsw: spectrum_router: Support IPv4 overlay encap
mlxsw: spectrum_router: Support IPv6 overlay encap
mlxsw: spectrum_router: Support IPv4 underlay decap
mlxsw: spectrum_router: Use existing decap route
mlxsw: spectrum: Register for IPIP_DECAP_ERROR trap
mlxsw: spectrum_router: Add loopback accessors
mlxsw: spectrum_router: Support GRE tunnels
drivers/net/ethernet/mellanox/mlxsw/Makefile | 4 +-
drivers/net/ethernet/mellanox/mlxsw/reg.h | 311 ++++++-
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 1 +
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 +
.../net/ethernet/mellanox/mlxsw/spectrum_ipip.c | 214 +++++
.../net/ethernet/mellanox/mlxsw/spectrum_ipip.h | 79 ++
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 947 +++++++++++++++++++--
.../net/ethernet/mellanox/mlxsw/spectrum_router.h | 28 +
drivers/net/ethernet/mellanox/mlxsw/trap.h | 1 +
9 files changed, 1485 insertions(+), 101 deletions(-)
create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h
--
2.9.3
From: Petr Machata <redacted>
Update the register so that loopback RIFs can be created and loopback
properties specified.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/reg.h | 88 +++++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)
@@ -4129,6 +4131,67 @@ MLXSW_ITEM32(reg, ritr, sp_if_system_port, 0x08, 0, 16);*/MLXSW_ITEM32(reg,ritr,sp_if_vid,0x18,0,12);+/* Loopback Interface */++enummlxsw_reg_ritr_loopback_protocol{+/* IPinIP IPv4 underlay Unicast */+MLXSW_REG_RITR_LOOPBACK_PROTOCOL_IPIP_IPV4,+/* IPinIP IPv6 underlay Unicast */+MLXSW_REG_RITR_LOOPBACK_PROTOCOL_IPIP_IPV6,+};++/* reg_ritr_loopback_protocol+*Access:RW+*/+MLXSW_ITEM32(reg,ritr,loopback_protocol,0x08,28,4);++enummlxsw_reg_ritr_loopback_ipip_type{+/* Tunnel is IPinIP. */+MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_IP,+/* Tunnel is GRE, no key. */+MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP,+/* Tunnel is GRE, with a key. */+MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP,+};++/* reg_ritr_loopback_ipip_type+*Encapsulationtype.+*Access:RW+*/+MLXSW_ITEM32(reg,ritr,loopback_ipip_type,0x10,24,4);++enummlxsw_reg_ritr_loopback_ipip_options{+/* The key is defined by gre_key. */+MLXSW_REG_RITR_LOOPBACK_IPIP_OPTIONS_GRE_KEY_PRESET,+};++/* reg_ritr_loopback_ipip_options+*Access:RW+*/+MLXSW_ITEM32(reg,ritr,loopback_ipip_options,0x10,20,4);++/* reg_ritr_loopback_ipip_uvr+*UnderlayVirtualRouterID.+*Rangeis0..cap_max_virtual_routers-1.+*ReservedforSpectrum-2.+*Access:RW+*/+MLXSW_ITEM32(reg,ritr,loopback_ipip_uvr,0x10,0,16);++/* reg_ritr_loopback_ipip_usip*+*EncapsulationUnderlaysourceIP.+*Access:RW+*/+MLXSW_ITEM_BUF(reg,ritr,loopback_ipip_usip6,0x18,16);+MLXSW_ITEM32(reg,ritr,loopback_ipip_usip4,0x24,0,32);++/* reg_ritr_loopback_ipip_gre_key+*GREKey.+*Reservedwhenipip_typeisnotIP_IN_GRE_KEY_IN_IP.+*Access:RW+*/+MLXSW_ITEM32(reg,ritr,loopback_ipip_gre_key,0x28,0,32);+/* Shared between ingress/egress */enummlxsw_reg_ritr_counter_set_type{/* No Count. */
From: Petr Machata <redacted>
So far, adjacencies have always been of type Ethernet (with value of 0),
and thus there was no need to explicitly support RATR type. However to
support IP-in-IP adjacencies, this type and a suite of IP-in-IP-specific
attributes need to be added.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/reg.h | 66 +++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
From: Petr Machata <redacted>
This enum is used with reg_ratr_trap_id, so move it next to the register
definition.
While at it, drop the enumerator initializers.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/reg.h | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
From: Petr Machata <redacted>
To implement IP-in-IP decapsulation, Spectrum uses LPM entries of type
IP2ME with tunnel validity bit and tunnel pointer set. The necessary
register fields are already available, so add a function to pack the
RALUE as appropriate.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/reg.h | 9 +++++++++
1 file changed, 9 insertions(+)
From: Petr Machata <redacted>
The RTDP register is used for configuring the tunnel decap properties of
NVE and IPinIP.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/reg.h | 129 ++++++++++++++++++++++++++++++
1 file changed, 129 insertions(+)
@@ -5463,6 +5464,133 @@ static inline void mlxsw_reg_rauhtd_ent_ipv6_unpack(char *payload,mlxsw_reg_rauhtd_ipv6_ent_dip_memcpy_from(payload,rec_index,p_dip);}+/* RTDP - Routing Tunnel Decap Properties Register+*-----------------------------------------------+*TheRTDPregisterisusedforconfiguringthetunneldecappropertiesofNVE+*andIPinIP.+*/+#define MLXSW_REG_RTDP_ID 0x8020+#define MLXSW_REG_RTDP_LEN 0x44++MLXSW_REG_DEFINE(rtdp,MLXSW_REG_RTDP_ID,MLXSW_REG_RTDP_LEN);++enummlxsw_reg_rtdp_type{+MLXSW_REG_RTDP_TYPE_NVE,+MLXSW_REG_RTDP_TYPE_IPIP,+};++/* reg_rtdp_type+*TypeoftheRTDPentryasperenummlxsw_reg_rtdp_type.+*Access:RW+*/+MLXSW_ITEM32(reg,rtdp,type,0x00,28,4);++/* reg_rtdp_tunnel_index+*IndextotheDecapentry.+*ForSpectrum,IndextoKVDLinear.+*Access:Index+*/+MLXSW_ITEM32(reg,rtdp,tunnel_index,0x00,0,24);++/* IPinIP */++/* reg_rtdp_ipip_irif+*IngressRouterInterfacefortheoverlayrouter+*Access:RW+*/+MLXSW_ITEM32(reg,rtdp,ipip_irif,0x04,16,16);++enummlxsw_reg_rtdp_ipip_sip_check{+/* No sip checks. */+MLXSW_REG_RTDP_IPIP_SIP_CHECK_NO,+/* Filter packet if underlay is not IPv4 or if underlay SIP does not+*equalipv4_usip.+*/+MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV4,+/* Filter packet if underlay is not IPv6 or if underlay SIP does not+*equalipv6_usip.+*/+MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV6=3,+};++/* reg_rtdp_ipip_sip_check+*SIPchecktoperform.Ifdecapsulationfailedduetotheseconfigurations+*thentrap_idisIPIP_DECAP_ERROR.+*Access:RW+*/+MLXSW_ITEM32(reg,rtdp,ipip_sip_check,0x04,0,3);++/* If set, allow decapsulation of IPinIP (without GRE). */+#define MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_IPIP BIT(0)+/* If set, allow decapsulation of IPinGREinIP without a key. */+#define MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE BIT(1)+/* If set, allow decapsulation of IPinGREinIP with a key. */+#define MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY BIT(2)++/* reg_rtdp_ipip_type_check+*FlagsasperMLXSW_REG_RTDP_IPIP_TYPE_CHECK_*.Ifdecapsulationfaileddueto+*theseconfigurationsthentrap_idisIPIP_DECAP_ERROR.+*Access:RW+*/+MLXSW_ITEM32(reg,rtdp,ipip_type_check,0x08,24,3);++/* reg_rtdp_ipip_gre_key_check+*WhetherGREkeyshouldbechecked.Whencheckisenabled:+*-ApacketreceivedasIPinIP(withoutGRE)willalwayspass.+*-ApacketreceivedasIPinGREinIPwithoutakeywillnotpassthecheck.+*-ApacketreceivedasIPinGREinIPwithakeywillpassthecheckonlyifthe+*keyinthepacketisequaltoexpected_gre_key.+*IfdecapsulationfailedduetoGREkeythentrap_idisIPIP_DECAP_ERROR.+*Access:RW+*/+MLXSW_ITEM32(reg,rtdp,ipip_gre_key_check,0x08,23,1);++/* reg_rtdp_ipip_ipv4_usip+*UnderlayIPv4addressforipv4sourceaddresscheck.+*Reservedwhensip_checkisnot'1'.+*Access:RW+*/+MLXSW_ITEM32(reg,rtdp,ipip_ipv4_usip,0x0C,0,32);++/* reg_rtdp_ipip_ipv6_usip_ptr+*Thisfieldisvalidwhensip_checkis"sipv6 check explicitly".Thisisa+*pointertotheIPv6DIPwhichisconfiguredbyRIPS.ForSpectrum,theindex+*istotheKVDlinear.+*Reservedwhensip_checkisnotMLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV6.+*Access:RW+*/+MLXSW_ITEM32(reg,rtdp,ipip_ipv6_usip_ptr,0x10,0,24);++/* reg_rtdp_ipip_expected_gre_key+*GREkeyforchecking.+*Reservedwhengre_key_checkis'0'.+*Access:RW+*/+MLXSW_ITEM32(reg,rtdp,ipip_expected_gre_key,0x14,0,32);++staticinlinevoidmlxsw_reg_rtdp_pack(char*payload,+enummlxsw_reg_rtdp_typetype,+u32tunnel_index)+{+MLXSW_REG_ZERO(rtdp,payload);+mlxsw_reg_rtdp_type_set(payload,type);+mlxsw_reg_rtdp_tunnel_index_set(payload,tunnel_index);+}++staticinlinevoid+mlxsw_reg_rtdp_ipip4_pack(char*payload,u16irif,+enummlxsw_reg_rtdp_ipip_sip_checksip_check,+unsignedinttype_check,boolgre_key_check,+u32ipv4_usip,u32expected_gre_key)+{+mlxsw_reg_rtdp_ipip_irif_set(payload,irif);+mlxsw_reg_rtdp_ipip_sip_check_set(payload,sip_check);+mlxsw_reg_rtdp_ipip_type_check_set(payload,type_check);+mlxsw_reg_rtdp_ipip_gre_key_check_set(payload,gre_key_check);+mlxsw_reg_rtdp_ipip_ipv4_usip_set(payload,ipv4_usip);+mlxsw_reg_rtdp_ipip_expected_gre_key_set(payload,expected_gre_key);+}+/* MFCR - Management Fan Control Register*--------------------------------------*ThisregistercontrolsthesettingsoftheFanSpeedPWMmechanism.
From: Petr Machata <redacted>
Unlike other interface types, loopback RIFs do not have MAC address. So
drop the corresponding argument from mlxsw_reg_ritr_pack() and move it
to a new function. Call that from callers of mlxsw_reg_ritr_pack.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/reg.h | 7 +++++--
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 7 ++++---
2 files changed, 9 insertions(+), 5 deletions(-)
From: Petr Machata <redacted>
To support IPIP, the driver needs to be able to construct an IPIP
adjacency. Change mlxsw_reg_ratr_pack to take an adjacency type as an
argument. Adjust the one existing caller.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/reg.h | 2 ++
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 3 ++-
2 files changed, 4 insertions(+), 1 deletion(-)
From: Petr Machata <redacted>
The spectrum_ipip module that will be introduced in the follow-up
patches needs to know the data type.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 5 -----
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h | 5 +++++
2 files changed, 5 insertions(+), 5 deletions(-)
@@ -405,11 +405,6 @@ struct mlxsw_sp_rt6 {structrt6_info*rt;};-enummlxsw_sp_l3proto{-MLXSW_SP_L3_PROTO_IPV4,-MLXSW_SP_L3_PROTO_IPV6,-};-structmlxsw_sp_lpm_tree{u8id;/* tree ID */unsignedintref_count;
From: Petr Machata <redacted>
Details of individual tunnel types are kept in an array of
mlxsw_sp_ipip_ops objects. Follow-up patches will use the list to
determine whether a constructed RIF should be a loopback, and to decide
whether a next hop references a tunnel.
The list is currently empty, follow-up patches will add support for GRE.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/Makefile | 4 +-
.../net/ethernet/mellanox/mlxsw/spectrum_ipip.c | 38 ++++++++++++++++
.../net/ethernet/mellanox/mlxsw/spectrum_ipip.h | 51 ++++++++++++++++++++++
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 19 ++++++++
4 files changed, 110 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
create mode 100644 drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h
From: Petr Machata <redacted>
Loopback RIFs, which will be introduced in a follow-up patch, differ
from other RIFs in that they do not have a FID associated with them.
To support this, demote FID allocation from mlxsw_sp_rif_create to
configure op of the existing RIF types, and likewise the FID release
from mlxsw_sp_rif_destroy to deconfigure op.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 85 ++++++++++++++++------
1 file changed, 63 insertions(+), 22 deletions(-)
@@ -4520,12 +4515,11 @@ void mlxsw_sp_rif_destroy(struct mlxsw_sp_rif *rif)vr->rif_count--;mlxsw_sp->router->rifs[rif->rif_index]=NULL;-mlxsw_sp_fid_rif_set(fid,NULL);mlxsw_sp_rif_counters_free(rif);-mlxsw_sp_rif_fdb_op(mlxsw_sp,rif->dev->dev_addr,-mlxsw_sp_fid_index(fid),false);ops->deconfigure(rif);-mlxsw_sp_fid_put(fid);+if(fid)+/* Loopback RIFs are not associated with a FID. */+mlxsw_sp_fid_put(fid);kfree(rif);mlxsw_sp_vr_put(vr);}
From: Petr Machata <redacted>
When offloading L3 tunnels, an adjacency entry is created that loops the
packet back into the underlay router. Loopback interfaces then hold the
corresponding information and are created for IP-in-IP netdevices.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 1 +
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 152 ++++++++++++++++++++-
.../net/ethernet/mellanox/mlxsw/spectrum_router.h | 13 ++
3 files changed, 164 insertions(+), 2 deletions(-)
@@ -4374,7 +4425,10 @@ mlxsw_sp_dev_rif_type(const struct mlxsw_sp *mlxsw_sp,{enummlxsw_sp_fid_typetype;-/* RIF type is derived from the type of the underlying FID */+if(mlxsw_sp_netdev_ipip_type(mlxsw_sp,dev,NULL))+returnMLXSW_SP_RIF_TYPE_IPIP_LB;++/* Otherwise RIF type is derived from the type of the underlying FID. */if(is_vlan_dev(dev)&&netif_is_bridge_master(vlan_dev_real_dev(dev)))type=MLXSW_SP_FID_TYPE_8021Q;elseif(netif_is_bridge_master(dev)&&br_vlan_enabled(dev))
From: Petr Machata <redacted>
For IPv4 IP-in-IP offload, routes that direct traffic to IP-in-IP
devices need to be considered gateway routes as well. That involves a
bit more logic, so extract the current test to a separate function,
where the logic can be later added.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
From: Petr Machata <redacted>
IPv6 counterpart of the previous patch: introduce a function to
determine whether a given route is a gateway route.
The new function takes a mlxsw_sp argument which follow-up patches will
use. Thus mlxsw_sp_fib6_entry_type_set() got that argument as well.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
@@ -3705,7 +3711,8 @@ mlxsw_sp_fib6_entry_nexthop_del(struct mlxsw_sp *mlxsw_sp,mlxsw_sp_rt6_destroy(mlxsw_sp_rt6);}-staticvoidmlxsw_sp_fib6_entry_type_set(structmlxsw_sp_fib_entry*fib_entry,+staticvoidmlxsw_sp_fib6_entry_type_set(structmlxsw_sp*mlxsw_sp,+structmlxsw_sp_fib_entry*fib_entry,conststructrt6_info*rt){/* Packets hitting RTF_REJECT routes need to be discarded by the
From: Petr Machata <redacted>
In the router, some next hops may reference an encapsulating netdevice,
such as GRE or IPIP. To properly offload these next hops, mlxsw needs to
keep track of whether a given next hop is a regular Ethernet entry, or
an IP-in-IP tunneling entry.
To facilitate this book-keeping, add a type field to struct
mlxsw_sp_nexthop. There is, as of this patch, only one next hop type:
MLXSW_SP_NEXTHOP_TYPE_ETH. Follow-up patches will introduce the IP-in-IP
variant.
There are several places where next hops are initialized in the IPv4
path. Instead of replicating the logic at every one of them, factor it
out to a function mlxsw_sp_nexthop4_type_init(). The corresponding fini
is actually protocol-neutral, so put it to mlxsw_sp_nexthop_type_fini(),
but create a corresponding protocoled _fini function that dispatches to
the protocol-neutral one.
The IPv6 path is simpler, but for symmetry with IPv4, create the same
suite of functions with corresponding logic.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 138 ++++++++++++++-------
1 file changed, 95 insertions(+), 43 deletions(-)
@@ -1676,7 +1680,10 @@ struct mlxsw_sp_nexthop {update:1;/* set indicates that MAC of this neigh should be*updatedinHW*/-structmlxsw_sp_neigh_entry*neigh_entry;+enummlxsw_sp_nexthop_typetype;+union{+structmlxsw_sp_neigh_entry*neigh_entry;+};};structmlxsw_sp_nexthop_group{
@@ -1964,9 +1971,9 @@ static int mlxsw_sp_nexthop_mac_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index,}staticint-mlxsw_sp_nexthop_group_mac_update(structmlxsw_sp*mlxsw_sp,-structmlxsw_sp_nexthop_group*nh_grp,-boolreallocate)+mlxsw_sp_nexthop_group_update(structmlxsw_sp*mlxsw_sp,+structmlxsw_sp_nexthop_group*nh_grp,+boolreallocate){u32adj_index=nh_grp->adj_index;/* base */structmlxsw_sp_nexthop*nh;
@@ -2071,8 +2082,7 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,/* Nothing was added or removed, so no need to reallocate. Just*updateMAConexistingadjacencyindexes.*/-err=mlxsw_sp_nexthop_group_mac_update(mlxsw_sp,nh_grp,-false);+err=mlxsw_sp_nexthop_group_update(mlxsw_sp,nh_grp,false);if(err){dev_warn(mlxsw_sp->bus_info->dev,"Failed to update neigh MAC in adjacency table.\n");gotoset_trap;
@@ -2099,7 +2109,7 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp,nh_grp->adj_index_valid=1;nh_grp->adj_index=adj_index;nh_grp->ecmp_size=ecmp_size;-err=mlxsw_sp_nexthop_group_mac_update(mlxsw_sp,nh_grp,true);+err=mlxsw_sp_nexthop_group_update(mlxsw_sp,nh_grp,true);if(err){dev_warn(mlxsw_sp->bus_info->dev,"Failed to update neigh MAC in adjacency table.\n");gotoset_trap;
From: Petr Machata <redacted>
This introduces some common code for tracking of offloaded IP-in-IP
tunnels, and support for offloading IPv4 overlay encapsulating routes in
particular. A follow-up patch will introduce IPv6 overlay as well.
Offloaded tunnels are kept in a linked list of mlxsw_sp_ipip_entry
objects hooked up in mlxsw_sp_router. A network device that represents
the tunnel is used as a key to look up the corresponding IPIP entry.
Note that in the future, more general keying mechanism will be needed,
because parts of the tunnel information can be provided by the route.
IPIP entries are reference counted, because several next hops may end up
using the same tunnel, and we only want to offload it once.
Encapsulation path hooks into next hop handling. Routes that forward to
a tunnel are now considered gateway routes, thus giving them the same
treatment that other remote routes get. An IPIP next hop type is
introduced.
Details of individual tunnel types are kept in an array of
mlxsw_sp_ipip_ops objects. If a tunnel type doesn't match any of the
known tunnel types, the next-hop is not considered an IPIP next hop.
The list of IPIP tunnel types is currently empty, follow-up patches will
add support for GRE. Traffic to IPIP tunnel types that are not
explicitly recognized by the driver traps and is handled in slow path.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
.../net/ethernet/mellanox/mlxsw/spectrum_ipip.h | 20 ++
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 238 ++++++++++++++++++++-
2 files changed, 257 insertions(+), 1 deletion(-)
@@ -41,9 +41,29 @@ enum mlxsw_sp_ipip_type {MLXSW_SP_IPIP_TYPE_MAX,};+structmlxsw_sp_ipip_entry{+enummlxsw_sp_ipip_typeipipt;+structnet_device*ol_dev;/* Overlay. */+structmlxsw_sp_rif_ipip_lb*ol_lb;+unsignedintref_count;/* Number of next hops using the tunnel. */+structlist_headipip_list_node;+};+structmlxsw_sp_ipip_ops{intdev_type;enummlxsw_sp_l3protoul_proto;/* Underlay. */++int(*nexthop_update)(structmlxsw_sp*mlxsw_sp,u32adj_index,+structmlxsw_sp_ipip_entry*ipip_entry);++bool(*can_offload)(conststructmlxsw_sp*mlxsw_sp,+conststructnet_device*ol_dev,+enummlxsw_sp_l3protool_proto);++/* Return a configuration for creating an overlay loopback RIF. */+structmlxsw_sp_rif_ipip_lb_config+(*ol_loopback_config)(structmlxsw_sp*mlxsw_sp,+conststructnet_device*ol_dev);};externconststructmlxsw_sp_ipip_ops*mlxsw_sp_ipip_ops_arr[];
@@ -915,6 +916,170 @@ static u32 mlxsw_sp_ipip_dev_ul_tb_id(const struct net_device *ol_dev)returnl3mdev_fib_table(ol_dev)?:RT_TABLE_MAIN;}+staticstructmlxsw_sp_rif*+mlxsw_sp_rif_create(structmlxsw_sp*mlxsw_sp,+conststructmlxsw_sp_rif_params*params);++staticstructmlxsw_sp_rif_ipip_lb*+mlxsw_sp_ipip_ol_ipip_lb_create(structmlxsw_sp*mlxsw_sp,+enummlxsw_sp_ipip_typeipipt,+structnet_device*ol_dev)+{+structmlxsw_sp_rif_params_ipip_lblb_params;+conststructmlxsw_sp_ipip_ops*ipip_ops;+structmlxsw_sp_rif*rif;++ipip_ops=mlxsw_sp->router->ipip_ops_arr[ipipt];+lb_params=(structmlxsw_sp_rif_params_ipip_lb){+.common.dev=ol_dev,+.common.lag=false,+.lb_config=ipip_ops->ol_loopback_config(mlxsw_sp,ol_dev),+};++rif=mlxsw_sp_rif_create(mlxsw_sp,&lb_params.common);+if(IS_ERR(rif))+returnERR_CAST(rif);+returncontainer_of(rif,structmlxsw_sp_rif_ipip_lb,common);+}++staticstructmlxsw_sp_ipip_entry*+mlxsw_sp_ipip_entry_alloc(structmlxsw_sp*mlxsw_sp,+enummlxsw_sp_ipip_typeipipt,+structnet_device*ol_dev)+{+structmlxsw_sp_ipip_entry*ipip_entry;+structmlxsw_sp_ipip_entry*ret=NULL;++ipip_entry=kzalloc(sizeof(*ipip_entry),GFP_KERNEL);+if(!ipip_entry)+returnERR_PTR(-ENOMEM);++ipip_entry->ol_lb=mlxsw_sp_ipip_ol_ipip_lb_create(mlxsw_sp,ipipt,+ol_dev);+if(IS_ERR(ipip_entry->ol_lb)){+ret=ERR_CAST(ipip_entry->ol_lb);+gotoerr_ol_ipip_lb_create;+}++ipip_entry->ipipt=ipipt;+ipip_entry->ol_dev=ol_dev;++returnipip_entry;++err_ol_ipip_lb_create:+kfree(ipip_entry);+returnret;+}++staticvoid+mlxsw_sp_ipip_entry_destroy(structmlxsw_sp_ipip_entry*ipip_entry)+{+WARN_ON(ipip_entry->ref_count>0);+mlxsw_sp_rif_destroy(&ipip_entry->ol_lb->common);+kfree(ipip_entry);+}++static__be32+mlxsw_sp_ipip_netdev_saddr4(conststructnet_device*ol_dev)+{+structip_tunnel*tun=netdev_priv(ol_dev);++returntun->parms.iph.saddr;+}++unionmlxsw_sp_l3addr+mlxsw_sp_ipip_netdev_saddr(enummlxsw_sp_l3protoproto,+conststructnet_device*ol_dev)+{+switch(proto){+caseMLXSW_SP_L3_PROTO_IPV4:+return(unionmlxsw_sp_l3addr){+.addr4=mlxsw_sp_ipip_netdev_saddr4(ol_dev),+};+caseMLXSW_SP_L3_PROTO_IPV6:+break;+};++WARN_ON(1);+return(unionmlxsw_sp_l3addr){+.addr4=0,+};+}++staticboolmlxsw_sp_l3addr_eq(constunionmlxsw_sp_l3addr*addr1,+constunionmlxsw_sp_l3addr*addr2)+{+return!memcmp(addr1,addr2,sizeof(*addr1));+}++staticbool+mlxsw_sp_ipip_entry_saddr_matches(structmlxsw_sp*mlxsw_sp,+constenummlxsw_sp_l3protoul_proto,+unionmlxsw_sp_l3addrsaddr,+u32ul_tb_id,+structmlxsw_sp_ipip_entry*ipip_entry)+{+u32tun_ul_tb_id=mlxsw_sp_ipip_dev_ul_tb_id(ipip_entry->ol_dev);+enummlxsw_sp_ipip_typeipipt=ipip_entry->ipipt;+unionmlxsw_sp_l3addrtun_saddr;++if(mlxsw_sp->router->ipip_ops_arr[ipipt]->ul_proto!=ul_proto)+returnfalse;++tun_saddr=mlxsw_sp_ipip_netdev_saddr(ul_proto,ipip_entry->ol_dev);+returntun_ul_tb_id==ul_tb_id&&+mlxsw_sp_l3addr_eq(&tun_saddr,&saddr);+}++staticstructmlxsw_sp_ipip_entry*+mlxsw_sp_ipip_entry_get(structmlxsw_sp*mlxsw_sp,+enummlxsw_sp_ipip_typeipipt,+structnet_device*ol_dev)+{+u32ul_tb_id=mlxsw_sp_ipip_dev_ul_tb_id(ol_dev);+structmlxsw_sp_router*router=mlxsw_sp->router;+structmlxsw_sp_ipip_entry*ipip_entry;+enummlxsw_sp_l3protoul_proto;+unionmlxsw_sp_l3addrsaddr;++list_for_each_entry(ipip_entry,&mlxsw_sp->router->ipip_list,+ipip_list_node){+if(ipip_entry->ol_dev==ol_dev)+gotoinc_ref_count;++/* The configuration where several tunnels have the same local+*addressinthesameunderlaytableneedsspecialtreatmentin+*theHW.Thatiscurrentlynotimplementedinthedriver.+*/+ul_proto=router->ipip_ops_arr[ipip_entry->ipipt]->ul_proto;+saddr=mlxsw_sp_ipip_netdev_saddr(ul_proto,ol_dev);+if(mlxsw_sp_ipip_entry_saddr_matches(mlxsw_sp,ul_proto,saddr,+ul_tb_id,ipip_entry))+returnERR_PTR(-EEXIST);+}++ipip_entry=mlxsw_sp_ipip_entry_alloc(mlxsw_sp,ipipt,ol_dev);+if(IS_ERR(ipip_entry))+returnipip_entry;++list_add_tail(&ipip_entry->ipip_list_node,+&mlxsw_sp->router->ipip_list);++inc_ref_count:+++ipip_entry->ref_count;+returnipip_entry;+}++staticvoid+mlxsw_sp_ipip_entry_put(structmlxsw_sp*mlxsw_sp,+structmlxsw_sp_ipip_entry*ipip_entry)+{+if(--ipip_entry->ref_count==0){+list_del(&ipip_entry->ipip_list_node);+mlxsw_sp_ipip_entry_destroy(ipip_entry);+}+}+structmlxsw_sp_neigh_key{structneighbour*n;};
From: Petr Machata <redacted>
Unlike encapsulation, which is represented by a next hop forwarding to
an IPIP tunnel, decapsulation is a type of local route. It is created
for local routes whose prefix corresponds to the local address of one of
offloaded IPIP tunnels. When the tunnel is removed (i.e. all the encap
next hops are removed), the decap offload is migrated back to a trap for
resolution in slow path.
This patch assumes that decap route is already present when encap route
is added. A follow-up patch will fix this issue.
Note that this patch only supports IPv4 underlay. Support for IPv6
underlay will be subject to follow-up work apart from this patchset.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
.../net/ethernet/mellanox/mlxsw/spectrum_ipip.h | 7 +
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 141 ++++++++++++++++++++-
.../net/ethernet/mellanox/mlxsw/spectrum_router.h | 3 +
3 files changed, 146 insertions(+), 5 deletions(-)
@@ -46,6 +47,7 @@ struct mlxsw_sp_ipip_entry {structnet_device*ol_dev;/* Overlay. */structmlxsw_sp_rif_ipip_lb*ol_lb;unsignedintref_count;/* Number of next hops using the tunnel. */+structmlxsw_sp_fib_entry*decap_fib_entry;structlist_headipip_list_node;};
@@ -381,6 +381,14 @@ enum mlxsw_sp_fib_entry_type {MLXSW_SP_FIB_ENTRY_TYPE_REMOTE,MLXSW_SP_FIB_ENTRY_TYPE_LOCAL,MLXSW_SP_FIB_ENTRY_TYPE_TRAP,++/* This is a special case of local delivery, where a packet should be+*decapsulatedonreception.NotethatthereisnocorrespondingENCAP,+*becausethat'satypeofnexthop,notofFIBentry.(Therecanbe+*severalnexthopsinaREMOTEentry,andsomeofthemmaybe+*encapsulatingentries.)+*/+MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP,};structmlxsw_sp_nexthop_group;
@@ -1031,6 +1045,48 @@ mlxsw_sp_ipip_entry_saddr_matches(struct mlxsw_sp *mlxsw_sp,mlxsw_sp_l3addr_eq(&tun_saddr,&saddr);}+staticint+mlxsw_sp_fib_entry_decap_init(structmlxsw_sp*mlxsw_sp,+structmlxsw_sp_fib_entry*fib_entry,+structmlxsw_sp_ipip_entry*ipip_entry)+{+u32tunnel_index;+interr;++err=mlxsw_sp_kvdl_alloc(mlxsw_sp,1,&tunnel_index);+if(err)+returnerr;++ipip_entry->decap_fib_entry=fib_entry;+fib_entry->decap.ipip_entry=ipip_entry;+fib_entry->decap.tunnel_index=tunnel_index;+return0;+}++staticvoidmlxsw_sp_fib_entry_decap_fini(structmlxsw_sp*mlxsw_sp,+structmlxsw_sp_fib_entry*fib_entry)+{+/* Unlink this node from the IPIP entry that it's the decap entry of. */+fib_entry->decap.ipip_entry->decap_fib_entry=NULL;+fib_entry->decap.ipip_entry=NULL;+mlxsw_sp_kvdl_free(mlxsw_sp,fib_entry->decap.tunnel_index);+}++staticintmlxsw_sp_fib_entry_update(structmlxsw_sp*mlxsw_sp,+structmlxsw_sp_fib_entry*fib_entry);++staticvoid+mlxsw_sp_ipip_entry_demote_decap(structmlxsw_sp*mlxsw_sp,+structmlxsw_sp_ipip_entry*ipip_entry)+{+structmlxsw_sp_fib_entry*fib_entry=ipip_entry->decap_fib_entry;++mlxsw_sp_fib_entry_decap_fini(mlxsw_sp,fib_entry);+fib_entry->type=MLXSW_SP_FIB_ENTRY_TYPE_TRAP;++mlxsw_sp_fib_entry_update(mlxsw_sp,fib_entry);+}+staticstructmlxsw_sp_ipip_entry*mlxsw_sp_ipip_entry_get(structmlxsw_sp*mlxsw_sp,enummlxsw_sp_ipip_typeipipt,
@@ -1076,10 +1132,51 @@ mlxsw_sp_ipip_entry_put(struct mlxsw_sp *mlxsw_sp,{if(--ipip_entry->ref_count==0){list_del(&ipip_entry->ipip_list_node);+if(ipip_entry->decap_fib_entry)+mlxsw_sp_ipip_entry_demote_decap(mlxsw_sp,ipip_entry);mlxsw_sp_ipip_entry_destroy(ipip_entry);}}+staticbool+mlxsw_sp_ipip_entry_matches_decap(structmlxsw_sp*mlxsw_sp,+conststructnet_device*ul_dev,+enummlxsw_sp_l3protoul_proto,+unionmlxsw_sp_l3addrul_dip,+structmlxsw_sp_ipip_entry*ipip_entry)+{+u32ul_tb_id=l3mdev_fib_table(ul_dev)?:RT_TABLE_MAIN;+enummlxsw_sp_ipip_typeipipt=ipip_entry->ipipt;+structnet_device*ipip_ul_dev;++if(mlxsw_sp->router->ipip_ops_arr[ipipt]->ul_proto!=ul_proto)+returnfalse;++ipip_ul_dev=__mlxsw_sp_ipip_netdev_ul_dev_get(ipip_entry->ol_dev);+returnmlxsw_sp_ipip_entry_saddr_matches(mlxsw_sp,ul_proto,ul_dip,+ul_tb_id,ipip_entry)&&+(!ipip_ul_dev||ipip_ul_dev==ul_dev);+}++/* Given decap parameters, find the corresponding IPIP entry. */+staticstructmlxsw_sp_ipip_entry*+mlxsw_sp_ipip_entry_find_by_decap(structmlxsw_sp*mlxsw_sp,+conststructnet_device*ul_dev,+enummlxsw_sp_l3protoul_proto,+unionmlxsw_sp_l3addrul_dip)+{+structmlxsw_sp_ipip_entry*ipip_entry;++list_for_each_entry(ipip_entry,&mlxsw_sp->router->ipip_list,+ipip_list_node)+if(mlxsw_sp_ipip_entry_matches_decap(mlxsw_sp,ul_dev,+ul_proto,ul_dip,+ipip_entry))+returnipip_entry;++returnNULL;+}+structmlxsw_sp_neigh_key{structneighbour*n;};
@@ -3015,6 +3112,22 @@ static int mlxsw_sp_fib_entry_op_trap(struct mlxsw_sp *mlxsw_sp,returnmlxsw_reg_write(mlxsw_sp->core,MLXSW_REG(ralue),ralue_pl);}+staticint+mlxsw_sp_fib_entry_op_ipip_decap(structmlxsw_sp*mlxsw_sp,+structmlxsw_sp_fib_entry*fib_entry,+enummlxsw_reg_ralue_opop)+{+structmlxsw_sp_ipip_entry*ipip_entry=fib_entry->decap.ipip_entry;+conststructmlxsw_sp_ipip_ops*ipip_ops;++if(WARN_ON(!ipip_entry))+return-EINVAL;++ipip_ops=mlxsw_sp->router->ipip_ops_arr[ipip_entry->ipipt];+returnipip_ops->fib_entry_op(mlxsw_sp,ipip_entry,op,+fib_entry->decap.tunnel_index);+}+staticint__mlxsw_sp_fib_entry_op(structmlxsw_sp*mlxsw_sp,structmlxsw_sp_fib_entry*fib_entry,enummlxsw_reg_ralue_opop)
@@ -3026,6 +3139,9 @@ static int __mlxsw_sp_fib_entry_op(struct mlxsw_sp *mlxsw_sp,returnmlxsw_sp_fib_entry_op_local(mlxsw_sp,fib_entry,op);caseMLXSW_SP_FIB_ENTRY_TYPE_TRAP:returnmlxsw_sp_fib_entry_op_trap(mlxsw_sp,fib_entry,op);+caseMLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP:+returnmlxsw_sp_fib_entry_op_ipip_decap(mlxsw_sp,+fib_entry,op);}return-EINVAL;}
@@ -3060,11 +3176,23 @@ mlxsw_sp_fib4_entry_type_set(struct mlxsw_sp *mlxsw_sp,conststructfib_entry_notifier_info*fen_info,structmlxsw_sp_fib_entry*fib_entry){+unionmlxsw_sp_l3addrdip={.addr4=htonl(fen_info->dst)};+structnet_device*dev=fen_info->fi->fib_dev;+structmlxsw_sp_ipip_entry*ipip_entry;structfib_info*fi=fen_info->fi;switch(fen_info->type){-caseRTN_BROADCAST:/* fall through */caseRTN_LOCAL:+ipip_entry=mlxsw_sp_ipip_entry_find_by_decap(mlxsw_sp,dev,+MLXSW_SP_L3_PROTO_IPV4,dip);+if(ipip_entry){+fib_entry->type=MLXSW_SP_FIB_ENTRY_TYPE_IPIP_DECAP;+returnmlxsw_sp_fib_entry_decap_init(mlxsw_sp,+fib_entry,+ipip_entry);+}+/* fall through */+caseRTN_BROADCAST:fib_entry->type=MLXSW_SP_FIB_ENTRY_TYPE_TRAP;return0;caseRTN_UNREACHABLE:/* fall through */
From: Petr Machata <redacted>
The local route that points at IPIP's underlay device (decap route) can
be present long before the GRE device. Thus when an encap route is
added, it's necessary to look inside the underlay FIB if the decap route
is already present. If so, the current trap offload needs to be
withdrawn and replaced with a decap offload.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
.../net/ethernet/mellanox/mlxsw/spectrum_router.c | 80 ++++++++++++++++++++--
1 file changed, 76 insertions(+), 4 deletions(-)
From: Petr Machata <redacted>
These traps are generated for packets that fail checks for source IP,
encapsulation type, or GRE key. Trap these packets to CPU for follow-up
handling by the kernel, which will send ICMP destination unreachable
responses.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 1 +
drivers/net/ethernet/mellanox/mlxsw/trap.h | 1 +
2 files changed, 2 insertions(+)
From: Petr Machata <redacted>
struct mlxsw_sp_rif is a router-private structure, and therefore
everything related to it is as well: parameters, and derived RIF types
including loopbacks. IPIP module needs access to some details of
loopback interfaces, but exporting all the RIF shebang would create too
large an interface.
So instead export just the bare minimum necessary: accessors for RIF
index and underlay VRF ID.
Signed-off-by: Petr Machata <redacted>
Reviewed-by: Ido Schimmel <redacted>
Signed-off-by: Jiri Pirko <redacted>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 10 ++++++++++
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.h | 3 +++
2 files changed, 13 insertions(+)
@@ -32,7 +32,183 @@*POSSIBILITYOFSUCHDAMAGE.*/+#include<net/ip_tunnels.h>+#include"spectrum_ipip.h"+staticbool+mlxsw_sp_ipip_netdev_has_ikey(conststructnet_device*ol_dev)+{+structip_tunnel*tun=netdev_priv(ol_dev);++return!!(tun->parms.i_flags&TUNNEL_KEY);+}++staticbool+mlxsw_sp_ipip_netdev_has_okey(conststructnet_device*ol_dev)+{+structip_tunnel*tun=netdev_priv(ol_dev);++return!!(tun->parms.o_flags&TUNNEL_KEY);+}++staticu32mlxsw_sp_ipip_netdev_ikey(conststructnet_device*ol_dev)+{+structip_tunnel*tun=netdev_priv(ol_dev);++returnmlxsw_sp_ipip_netdev_has_ikey(ol_dev)?+be32_to_cpu(tun->parms.i_key):0;+}++staticu32mlxsw_sp_ipip_netdev_okey(conststructnet_device*ol_dev)+{+structip_tunnel*tun=netdev_priv(ol_dev);++returnmlxsw_sp_ipip_netdev_has_okey(ol_dev)?+be32_to_cpu(tun->parms.o_key):0;+}++staticint+mlxsw_sp_ipip_nexthop_update_gre4(structmlxsw_sp*mlxsw_sp,u32adj_index,+structmlxsw_sp_ipip_entry*ipip_entry)+{+u16rif_index=mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);+__be32daddr4=mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev);+charratr_pl[MLXSW_REG_RATR_LEN];++mlxsw_reg_ratr_pack(ratr_pl,MLXSW_REG_RATR_OP_WRITE_WRITE_ENTRY,+true,MLXSW_REG_RATR_TYPE_IPIP,+adj_index,rif_index);+mlxsw_reg_ratr_ipip4_entry_pack(ratr_pl,be32_to_cpu(daddr4));++returnmlxsw_reg_write(mlxsw_sp->core,MLXSW_REG(ratr),ratr_pl);+}++staticint+mlxsw_sp_ipip_fib_entry_op_gre4_rtdp(structmlxsw_sp*mlxsw_sp,+u32tunnel_index,+structmlxsw_sp_ipip_entry*ipip_entry)+{+boolhas_ikey=mlxsw_sp_ipip_netdev_has_ikey(ipip_entry->ol_dev);+u16rif_index=mlxsw_sp_ipip_lb_rif_index(ipip_entry->ol_lb);+u32ikey=mlxsw_sp_ipip_netdev_ikey(ipip_entry->ol_dev);+charrtdp_pl[MLXSW_REG_RTDP_LEN];+unsignedinttype_check;+u32daddr4;++mlxsw_reg_rtdp_pack(rtdp_pl,MLXSW_REG_RTDP_TYPE_IPIP,tunnel_index);++type_check=has_ikey?+MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE_KEY:+MLXSW_REG_RTDP_IPIP_TYPE_CHECK_ALLOW_GRE;++/* Linux demuxes tunnels based on packet SIP (which must match tunnel+*remoteIP).Thusconfiguredecapsothatitfiltersoutpacketsthat+*arenotIPv4orhavethewrongSIP.IPIP_DECAP_ERRORtrapis+*generatedforpacketsthatfailthiscriterion.Linuxthenhandles+*suchpacketsinslowpathandgeneratesICMPdestinationunreachable.+*/+daddr4=be32_to_cpu(mlxsw_sp_ipip_netdev_daddr4(ipip_entry->ol_dev));+mlxsw_reg_rtdp_ipip4_pack(rtdp_pl,rif_index,+MLXSW_REG_RTDP_IPIP_SIP_CHECK_FILTER_IPV4,+type_check,has_ikey,daddr4,ikey);++returnmlxsw_reg_write(mlxsw_sp->core,MLXSW_REG(rtdp),rtdp_pl);+}++staticint+mlxsw_sp_ipip_fib_entry_op_gre4_ralue(structmlxsw_sp*mlxsw_sp,+u32dip,u8prefix_len,u16ul_vr_id,+enummlxsw_reg_ralue_opop,+u32tunnel_index)+{+charralue_pl[MLXSW_REG_RALUE_LEN];++mlxsw_reg_ralue_pack4(ralue_pl,MLXSW_REG_RALXX_PROTOCOL_IPV4,op,+ul_vr_id,prefix_len,dip);+mlxsw_reg_ralue_act_ip2me_tun_pack(ralue_pl,tunnel_index);+returnmlxsw_reg_write(mlxsw_sp->core,MLXSW_REG(ralue),ralue_pl);+}++staticintmlxsw_sp_ipip_fib_entry_op_gre4(structmlxsw_sp*mlxsw_sp,+structmlxsw_sp_ipip_entry*ipip_entry,+enummlxsw_reg_ralue_opop,+u32tunnel_index)+{+u16ul_vr_id=mlxsw_sp_ipip_lb_ul_vr_id(ipip_entry->ol_lb);+__be32dip;+interr;++err=mlxsw_sp_ipip_fib_entry_op_gre4_rtdp(mlxsw_sp,tunnel_index,+ipip_entry);+if(err)+returnerr;++dip=mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4,+ipip_entry->ol_dev).addr4;+returnmlxsw_sp_ipip_fib_entry_op_gre4_ralue(mlxsw_sp,be32_to_cpu(dip),+32,ul_vr_id,op,+tunnel_index);+}++staticboolmlxsw_sp_ipip_tunnel_complete(enummlxsw_sp_l3protoproto,+conststructnet_device*ol_dev)+{+unionmlxsw_sp_l3addrsaddr=mlxsw_sp_ipip_netdev_saddr(proto,ol_dev);+unionmlxsw_sp_l3addrdaddr=mlxsw_sp_ipip_netdev_daddr(proto,ol_dev);+unionmlxsw_sp_l3addrnaddr={0};++/* Tunnels with unset local or remote address are valid in Linux and+*usedforlightweighttunnels(LWT)andNon-BroadcastMulti-Access+*(NBMA)tunnels.Inprinciplethesecanbeoffloaded,butthedriver+*currentlydoesn'tsupportthis.Sopunt.+*/+returnmemcmp(&saddr,&naddr,sizeof(naddr))&&+memcmp(&daddr,&naddr,sizeof(naddr));+}++staticboolmlxsw_sp_ipip_can_offload_gre4(conststructmlxsw_sp*mlxsw_sp,+conststructnet_device*ol_dev,+enummlxsw_sp_l3protool_proto)+{+structip_tunnel*tunnel=netdev_priv(ol_dev);+__be16okflags=TUNNEL_KEY;/* We can't offload any other features. */+boolinherit_ttl=tunnel->parms.iph.ttl==0;+boolinherit_tos=tunnel->parms.iph.tos&0x1;++return(tunnel->parms.i_flags&~okflags)==0&&+(tunnel->parms.o_flags&~okflags)==0&&+inherit_ttl&&inherit_tos&&+mlxsw_sp_ipip_tunnel_complete(MLXSW_SP_L3_PROTO_IPV4,ol_dev);+}++staticstructmlxsw_sp_rif_ipip_lb_config+mlxsw_sp_ipip_ol_loopback_config_gre4(structmlxsw_sp*mlxsw_sp,+conststructnet_device*ol_dev)+{+enummlxsw_reg_ritr_loopback_ipip_typelb_ipipt;++lb_ipipt=mlxsw_sp_ipip_netdev_has_okey(ol_dev)?+MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_KEY_IN_IP:+MLXSW_REG_RITR_LOOPBACK_IPIP_TYPE_IP_IN_GRE_IN_IP;+return(structmlxsw_sp_rif_ipip_lb_config){+.lb_ipipt=lb_ipipt,+.okey=mlxsw_sp_ipip_netdev_okey(ol_dev),+.ul_protocol=MLXSW_SP_L3_PROTO_IPV4,+.saddr=mlxsw_sp_ipip_netdev_saddr(MLXSW_SP_L3_PROTO_IPV4,+ol_dev),+};+}++staticconststructmlxsw_sp_ipip_opsmlxsw_sp_ipip_gre4_ops={+.dev_type=ARPHRD_IPGRE,+.ul_proto=MLXSW_SP_L3_PROTO_IPV4,+.nexthop_update=mlxsw_sp_ipip_nexthop_update_gre4,+.fib_entry_op=mlxsw_sp_ipip_fib_entry_op_gre4,+.can_offload=mlxsw_sp_ipip_can_offload_gre4,+.ol_loopback_config=mlxsw_sp_ipip_ol_loopback_config_gre4,+};+conststructmlxsw_sp_ipip_ops*mlxsw_sp_ipip_ops_arr[]={+[MLXSW_SP_IPIP_TYPE_GRE4]=&mlxsw_sp_ipip_gre4_ops,};
From: Jiri Pirko <redacted>
Petr says:
This patch series introduces to mlxsw driver support for offloading
IP-in-IP tunnels in general, and for (subset of) GRE in particular.