aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-02-27 14:46:28 -0500
committerDavid S. Miller <davem@davemloft.net>2018-02-27 14:46:28 -0500
commit431c7ec3b3bac0136c61dd38814d51519db6eee6 (patch)
tree69f007862fe11de8dadd24a81e0023e05450b979
parent63d638012e78ed2eb7bf484c30d2cc3263c3b5a1 (diff)
parent8f08a528de5eaded034c5480588722e7dc167540 (diff)
Merge branch 'mlxsw-Offloading-encapsulated-SPAN'
Jiri Pirko says: ==================== mlxsw: Offloading encapsulated SPAN Petr says: This patch series introduces support for mirroring with GRE encapsulation. It offloads tc action mirred mirror from a mlxsw port to either a gretap or an ip6gretap netdevice. Spectrum hardware needs to know all the details of the requested encapsulation: source and destination MAC and IP addresses, details of VLAN tagging, etc. The only variables are the encapsulated packet itself, and TOS field, which may be inherited. To that end, mlxsw driver resolves the route that encapsulated packets would take, queries the corresponding neighbor, and with that configuration in hand, configures the mirroring in the hardware. The driver also hooks into event handlers for netdevice changes, FIB and neighbor events, and reconsiders the configuration on each such change. When the new configuration differs from the currently-offloaded one, the existing offload is removed and replaced with a new one. It is possible to mirror to {ip6,}gretap from a matchall rule as well as from a flower match. ** Note that with this patch set, mlxsw build depends on NET_IPGRE and IPV6_GRE. Current limitations: - There has to be a route that directs packets to an mlxsw port. We intend to extend the logic to support other netdevice types in the future, but the eventual egress netdevice will have to be an mlxsw port in any case. - Offload reconfiguration due to changes in netdevice configuration creates a window of time where packets are not mirrored. Under some circumstances this can be prevented by configuring an unused port analyzer and migrating mirrors over to that. However that's currently not implemented. - Remote address of a tunnel device needs to be set, there may not be a GRE key, checksumming or sequence numbers, and TTL needs to be fixed (non-inherit). These are hard requirements imposed by the underlying hardware. - TOS of a tunnel device needs to be "inherit". The hardware supports a fixed TOS, but that's currently not implemented. The series start with two patches, #1 and #2, that publish one function and add support for querying IPv6 tunnel parameters. In patches #3 and #4, we introduce helpers to GRE and tunneling code that we will use later in the patchset from the SPAN code. Patches #5 and #6 introduce support for encapsulated SPAN in reg.h. The following seven patches, #7-#13, then prepare the SPAN codebase for introduction of mirroring to netdevices that don't correspond to front panel ports. Then #14 and #15 pull all this together to implement mirroring to {ip6,}gretap netdevices. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/Kconfig4
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c19
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h9
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/reg.h145
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.c50
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum.h2
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c9
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c33
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c45
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h8
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c522
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h41
-rw-r--r--include/net/gre.h3
-rw-r--r--include/net/ip_tunnels.h16
-rw-r--r--net/ipv4/ip_gre.c6
-rw-r--r--net/ipv4/ip_tunnel.c40
-rw-r--r--net/ipv6/ip6_gre.c6
18 files changed, 808 insertions, 157 deletions
diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
index d56eea310509..93d97b4676eb 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
@@ -78,6 +78,10 @@ config MLXSW_SPECTRUM
78 depends on IPV6 || IPV6=n 78 depends on IPV6 || IPV6=n
79 select PARMAN 79 select PARMAN
80 select MLXFW 80 select MLXFW
81 depends on NET_IPGRE
82 depends on !(MLXSW_CORE=y && NET_IPGRE=m)
83 depends on IPV6_GRE
84 depends on !(MLXSW_CORE=y && IPV6_GRE=m)
81 default m 85 default m
82 ---help--- 86 ---help---
83 This driver supports Mellanox Technologies Spectrum Ethernet 87 This driver supports Mellanox Technologies Spectrum Ethernet
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
index b698fb481b2e..ba338428ffd1 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c 2 * drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved. 3 * Copyright (c) 2017, 2018 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2017 Jiri Pirko <jiri@mellanox.com> 4 * Copyright (c) 2017 Jiri Pirko <jiri@mellanox.com>
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
@@ -838,7 +838,6 @@ struct mlxsw_afa_mirror {
838 struct mlxsw_afa_resource resource; 838 struct mlxsw_afa_resource resource;
839 int span_id; 839 int span_id;
840 u8 local_in_port; 840 u8 local_in_port;
841 u8 local_out_port;
842 bool ingress; 841 bool ingress;
843}; 842};
844 843
@@ -848,7 +847,7 @@ mlxsw_afa_mirror_destroy(struct mlxsw_afa_block *block,
848{ 847{
849 block->afa->ops->mirror_del(block->afa->ops_priv, 848 block->afa->ops->mirror_del(block->afa->ops_priv,
850 mirror->local_in_port, 849 mirror->local_in_port,
851 mirror->local_out_port, 850 mirror->span_id,
852 mirror->ingress); 851 mirror->ingress);
853 kfree(mirror); 852 kfree(mirror);
854} 853}
@@ -864,9 +863,8 @@ mlxsw_afa_mirror_destructor(struct mlxsw_afa_block *block,
864} 863}
865 864
866static struct mlxsw_afa_mirror * 865static struct mlxsw_afa_mirror *
867mlxsw_afa_mirror_create(struct mlxsw_afa_block *block, 866mlxsw_afa_mirror_create(struct mlxsw_afa_block *block, u8 local_in_port,
868 u8 local_in_port, u8 local_out_port, 867 const struct net_device *out_dev, bool ingress)
869 bool ingress)
870{ 868{
871 struct mlxsw_afa_mirror *mirror; 869 struct mlxsw_afa_mirror *mirror;
872 int err; 870 int err;
@@ -876,13 +874,12 @@ mlxsw_afa_mirror_create(struct mlxsw_afa_block *block,
876 return ERR_PTR(-ENOMEM); 874 return ERR_PTR(-ENOMEM);
877 875
878 err = block->afa->ops->mirror_add(block->afa->ops_priv, 876 err = block->afa->ops->mirror_add(block->afa->ops_priv,
879 local_in_port, local_out_port, 877 local_in_port, out_dev,
880 ingress, &mirror->span_id); 878 ingress, &mirror->span_id);
881 if (err) 879 if (err)
882 goto err_mirror_add; 880 goto err_mirror_add;
883 881
884 mirror->ingress = ingress; 882 mirror->ingress = ingress;
885 mirror->local_out_port = local_out_port;
886 mirror->local_in_port = local_in_port; 883 mirror->local_in_port = local_in_port;
887 mirror->resource.destructor = mlxsw_afa_mirror_destructor; 884 mirror->resource.destructor = mlxsw_afa_mirror_destructor;
888 mlxsw_afa_resource_add(block, &mirror->resource); 885 mlxsw_afa_resource_add(block, &mirror->resource);
@@ -909,13 +906,13 @@ mlxsw_afa_block_append_allocated_mirror(struct mlxsw_afa_block *block,
909} 906}
910 907
911int 908int
912mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block, 909mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block, u8 local_in_port,
913 u8 local_in_port, u8 local_out_port, bool ingress) 910 const struct net_device *out_dev, bool ingress)
914{ 911{
915 struct mlxsw_afa_mirror *mirror; 912 struct mlxsw_afa_mirror *mirror;
916 int err; 913 int err;
917 914
918 mirror = mlxsw_afa_mirror_create(block, local_in_port, local_out_port, 915 mirror = mlxsw_afa_mirror_create(block, local_in_port, out_dev,
919 ingress); 916 ingress);
920 if (IS_ERR(mirror)) 917 if (IS_ERR(mirror))
921 return PTR_ERR(mirror); 918 return PTR_ERR(mirror);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h
index 43132293475c..6dd601703c99 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.h
@@ -36,6 +36,7 @@
36#define _MLXSW_CORE_ACL_FLEX_ACTIONS_H 36#define _MLXSW_CORE_ACL_FLEX_ACTIONS_H
37 37
38#include <linux/types.h> 38#include <linux/types.h>
39#include <linux/netdevice.h>
39 40
40struct mlxsw_afa; 41struct mlxsw_afa;
41struct mlxsw_afa_block; 42struct mlxsw_afa_block;
@@ -48,9 +49,10 @@ struct mlxsw_afa_ops {
48 void (*kvdl_fwd_entry_del)(void *priv, u32 kvdl_index); 49 void (*kvdl_fwd_entry_del)(void *priv, u32 kvdl_index);
49 int (*counter_index_get)(void *priv, unsigned int *p_counter_index); 50 int (*counter_index_get)(void *priv, unsigned int *p_counter_index);
50 void (*counter_index_put)(void *priv, unsigned int counter_index); 51 void (*counter_index_put)(void *priv, unsigned int counter_index);
51 int (*mirror_add)(void *priv, u8 locol_in_port, u8 local_out_port, 52 int (*mirror_add)(void *priv, u8 local_in_port,
53 const struct net_device *out_dev,
52 bool ingress, int *p_span_id); 54 bool ingress, int *p_span_id);
53 void (*mirror_del)(void *priv, u8 locol_in_port, u8 local_out_port, 55 void (*mirror_del)(void *priv, u8 local_in_port, int span_id,
54 bool ingress); 56 bool ingress);
55}; 57};
56 58
@@ -70,7 +72,8 @@ int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block, u16 trap_id);
70int mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block *block, 72int mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block *block,
71 u16 trap_id); 73 u16 trap_id);
72int mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block, 74int mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block,
73 u8 local_in_port, u8 local_out_port, 75 u8 local_in_port,
76 const struct net_device *out_dev,
74 bool ingress); 77 bool ingress);
75int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block, 78int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block,
76 u8 local_port, bool in_port); 79 u8 local_port, bool in_port);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index 0e08be41c8e0..cb5f77f09f8e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -1,11 +1,11 @@
1/* 1/*
2 * drivers/net/ethernet/mellanox/mlxsw/reg.h 2 * drivers/net/ethernet/mellanox/mlxsw/reg.h
3 * Copyright (c) 2015-2017 Mellanox Technologies. All rights reserved. 3 * Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2015-2016 Ido Schimmel <idosch@mellanox.com> 4 * Copyright (c) 2015-2016 Ido Schimmel <idosch@mellanox.com>
5 * Copyright (c) 2015 Elad Raz <eladr@mellanox.com> 5 * Copyright (c) 2015 Elad Raz <eladr@mellanox.com>
6 * Copyright (c) 2015-2017 Jiri Pirko <jiri@mellanox.com> 6 * Copyright (c) 2015-2017 Jiri Pirko <jiri@mellanox.com>
7 * Copyright (c) 2016 Yotam Gigi <yotamg@mellanox.com> 7 * Copyright (c) 2016 Yotam Gigi <yotamg@mellanox.com>
8 * Copyright (c) 2017 Petr Machata <petrm@mellanox.com> 8 * Copyright (c) 2017-2018 Petr Machata <petrm@mellanox.com>
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met: 11 * modification, are permitted provided that the following conditions are met:
@@ -6772,8 +6772,104 @@ MLXSW_ITEM32(reg, mpat, qos, 0x04, 26, 1);
6772 */ 6772 */
6773MLXSW_ITEM32(reg, mpat, be, 0x04, 25, 1); 6773MLXSW_ITEM32(reg, mpat, be, 0x04, 25, 1);
6774 6774
6775enum mlxsw_reg_mpat_span_type {
6776 /* Local SPAN Ethernet.
6777 * The original packet is not encapsulated.
6778 */
6779 MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH = 0x0,
6780
6781 /* Encapsulated Remote SPAN Ethernet L3 GRE.
6782 * The packet is encapsulated with GRE header.
6783 */
6784 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3 = 0x3,
6785};
6786
6787/* reg_mpat_span_type
6788 * SPAN type.
6789 * Access: RW
6790 */
6791MLXSW_ITEM32(reg, mpat, span_type, 0x04, 0, 4);
6792
6793/* Remote SPAN - Ethernet VLAN
6794 * - - - - - - - - - - - - - -
6795 */
6796
6797/* reg_mpat_eth_rspan_vid
6798 * Encapsulation header VLAN ID.
6799 * Access: RW
6800 */
6801MLXSW_ITEM32(reg, mpat, eth_rspan_vid, 0x18, 0, 12);
6802
6803/* Encapsulated Remote SPAN - Ethernet L2
6804 * - - - - - - - - - - - - - - - - - - -
6805 */
6806
6807enum mlxsw_reg_mpat_eth_rspan_version {
6808 MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER = 15,
6809};
6810
6811/* reg_mpat_eth_rspan_version
6812 * RSPAN mirror header version.
6813 * Access: RW
6814 */
6815MLXSW_ITEM32(reg, mpat, eth_rspan_version, 0x10, 18, 4);
6816
6817/* reg_mpat_eth_rspan_mac
6818 * Destination MAC address.
6819 * Access: RW
6820 */
6821MLXSW_ITEM_BUF(reg, mpat, eth_rspan_mac, 0x12, 6);
6822
6823/* reg_mpat_eth_rspan_tp
6824 * Tag Packet. Indicates whether the mirroring header should be VLAN tagged.
6825 * Access: RW
6826 */
6827MLXSW_ITEM32(reg, mpat, eth_rspan_tp, 0x18, 16, 1);
6828
6829/* Encapsulated Remote SPAN - Ethernet L3
6830 * - - - - - - - - - - - - - - - - - - -
6831 */
6832
6833enum mlxsw_reg_mpat_eth_rspan_protocol {
6834 MLXSW_REG_MPAT_ETH_RSPAN_PROTOCOL_IPV4,
6835 MLXSW_REG_MPAT_ETH_RSPAN_PROTOCOL_IPV6,
6836};
6837
6838/* reg_mpat_eth_rspan_protocol
6839 * SPAN encapsulation protocol.
6840 * Access: RW
6841 */
6842MLXSW_ITEM32(reg, mpat, eth_rspan_protocol, 0x18, 24, 4);
6843
6844/* reg_mpat_eth_rspan_ttl
6845 * Encapsulation header Time-to-Live/HopLimit.
6846 * Access: RW
6847 */
6848MLXSW_ITEM32(reg, mpat, eth_rspan_ttl, 0x1C, 4, 8);
6849
6850/* reg_mpat_eth_rspan_smac
6851 * Source MAC address
6852 * Access: RW
6853 */
6854MLXSW_ITEM_BUF(reg, mpat, eth_rspan_smac, 0x22, 6);
6855
6856/* reg_mpat_eth_rspan_dip*
6857 * Destination IP address. The IP version is configured by protocol.
6858 * Access: RW
6859 */
6860MLXSW_ITEM32(reg, mpat, eth_rspan_dip4, 0x4C, 0, 32);
6861MLXSW_ITEM_BUF(reg, mpat, eth_rspan_dip6, 0x40, 16);
6862
6863/* reg_mpat_eth_rspan_sip*
6864 * Source IP address. The IP version is configured by protocol.
6865 * Access: RW
6866 */
6867MLXSW_ITEM32(reg, mpat, eth_rspan_sip4, 0x5C, 0, 32);
6868MLXSW_ITEM_BUF(reg, mpat, eth_rspan_sip6, 0x50, 16);
6869
6775static inline void mlxsw_reg_mpat_pack(char *payload, u8 pa_id, 6870static inline void mlxsw_reg_mpat_pack(char *payload, u8 pa_id,
6776 u16 system_port, bool e) 6871 u16 system_port, bool e,
6872 enum mlxsw_reg_mpat_span_type span_type)
6777{ 6873{
6778 MLXSW_REG_ZERO(mpat, payload); 6874 MLXSW_REG_ZERO(mpat, payload);
6779 mlxsw_reg_mpat_pa_id_set(payload, pa_id); 6875 mlxsw_reg_mpat_pa_id_set(payload, pa_id);
@@ -6781,6 +6877,49 @@ static inline void mlxsw_reg_mpat_pack(char *payload, u8 pa_id,
6781 mlxsw_reg_mpat_e_set(payload, e); 6877 mlxsw_reg_mpat_e_set(payload, e);
6782 mlxsw_reg_mpat_qos_set(payload, 1); 6878 mlxsw_reg_mpat_qos_set(payload, 1);
6783 mlxsw_reg_mpat_be_set(payload, 1); 6879 mlxsw_reg_mpat_be_set(payload, 1);
6880 mlxsw_reg_mpat_span_type_set(payload, span_type);
6881}
6882
6883static inline void mlxsw_reg_mpat_eth_rspan_pack(char *payload, u16 vid)
6884{
6885 mlxsw_reg_mpat_eth_rspan_vid_set(payload, vid);
6886}
6887
6888static inline void
6889mlxsw_reg_mpat_eth_rspan_l2_pack(char *payload,
6890 enum mlxsw_reg_mpat_eth_rspan_version version,
6891 const char *mac,
6892 bool tp)
6893{
6894 mlxsw_reg_mpat_eth_rspan_version_set(payload, version);
6895 mlxsw_reg_mpat_eth_rspan_mac_memcpy_to(payload, mac);
6896 mlxsw_reg_mpat_eth_rspan_tp_set(payload, tp);
6897}
6898
6899static inline void
6900mlxsw_reg_mpat_eth_rspan_l3_ipv4_pack(char *payload, u8 ttl,
6901 const char *smac,
6902 u32 sip, u32 dip)
6903{
6904 mlxsw_reg_mpat_eth_rspan_ttl_set(payload, ttl);
6905 mlxsw_reg_mpat_eth_rspan_smac_memcpy_to(payload, smac);
6906 mlxsw_reg_mpat_eth_rspan_protocol_set(payload,
6907 MLXSW_REG_MPAT_ETH_RSPAN_PROTOCOL_IPV4);
6908 mlxsw_reg_mpat_eth_rspan_sip4_set(payload, sip);
6909 mlxsw_reg_mpat_eth_rspan_dip4_set(payload, dip);
6910}
6911
6912static inline void
6913mlxsw_reg_mpat_eth_rspan_l3_ipv6_pack(char *payload, u8 ttl,
6914 const char *smac,
6915 struct in6_addr sip, struct in6_addr dip)
6916{
6917 mlxsw_reg_mpat_eth_rspan_ttl_set(payload, ttl);
6918 mlxsw_reg_mpat_eth_rspan_smac_memcpy_to(payload, smac);
6919 mlxsw_reg_mpat_eth_rspan_protocol_set(payload,
6920 MLXSW_REG_MPAT_ETH_RSPAN_PROTOCOL_IPV6);
6921 mlxsw_reg_mpat_eth_rspan_sip6_memcpy_to(payload, (void *)&sip);
6922 mlxsw_reg_mpat_eth_rspan_dip6_memcpy_to(payload, (void *)&dip);
6784} 6923}
6785 6924
6786/* MPAR - Monitoring Port Analyzer Register 6925/* MPAR - Monitoring Port Analyzer Register
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
index bfde93910f82..8d2d140d7910 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * drivers/net/ethernet/mellanox/mlxsw/spectrum.c 2 * drivers/net/ethernet/mellanox/mlxsw/spectrum.c
3 * Copyright (c) 2015-2017 Mellanox Technologies. All rights reserved. 3 * Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2015-2017 Jiri Pirko <jiri@mellanox.com> 4 * Copyright (c) 2015-2017 Jiri Pirko <jiri@mellanox.com>
5 * Copyright (c) 2015 Ido Schimmel <idosch@mellanox.com> 5 * Copyright (c) 2015 Ido Schimmel <idosch@mellanox.com>
6 * Copyright (c) 2015 Elad Raz <eladr@mellanox.com> 6 * Copyright (c) 2015 Elad Raz <eladr@mellanox.com>
@@ -1258,7 +1258,6 @@ mlxsw_sp_port_add_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,
1258 bool ingress) 1258 bool ingress)
1259{ 1259{
1260 enum mlxsw_sp_span_type span_type; 1260 enum mlxsw_sp_span_type span_type;
1261 struct mlxsw_sp_port *to_port;
1262 struct net_device *to_dev; 1261 struct net_device *to_dev;
1263 1262
1264 to_dev = tcf_mirred_dev(a); 1263 to_dev = tcf_mirred_dev(a);
@@ -1267,17 +1266,10 @@ mlxsw_sp_port_add_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,
1267 return -EINVAL; 1266 return -EINVAL;
1268 } 1267 }
1269 1268
1270 if (!mlxsw_sp_port_dev_check(to_dev)) {
1271 netdev_err(mlxsw_sp_port->dev, "Cannot mirror to a non-spectrum port");
1272 return -EOPNOTSUPP;
1273 }
1274 to_port = netdev_priv(to_dev);
1275
1276 mirror->to_local_port = to_port->local_port;
1277 mirror->ingress = ingress; 1269 mirror->ingress = ingress;
1278 span_type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS; 1270 span_type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
1279 return mlxsw_sp_span_mirror_add(mlxsw_sp_port, to_port, span_type, 1271 return mlxsw_sp_span_mirror_add(mlxsw_sp_port, to_dev, span_type,
1280 true); 1272 true, &mirror->span_id);
1281} 1273}
1282 1274
1283static void 1275static void
@@ -1288,7 +1280,7 @@ mlxsw_sp_port_del_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,
1288 1280
1289 span_type = mirror->ingress ? 1281 span_type = mirror->ingress ?
1290 MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS; 1282 MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
1291 mlxsw_sp_span_mirror_del(mlxsw_sp_port, mirror->to_local_port, 1283 mlxsw_sp_span_mirror_del(mlxsw_sp_port, mirror->span_id,
1292 span_type, true); 1284 span_type, true);
1293} 1285}
1294 1286
@@ -3675,14 +3667,24 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
3675 goto err_afa_init; 3667 goto err_afa_init;
3676 } 3668 }
3677 3669
3670 err = mlxsw_sp_span_init(mlxsw_sp);
3671 if (err) {
3672 dev_err(mlxsw_sp->bus_info->dev, "Failed to init span system\n");
3673 goto err_span_init;
3674 }
3675
3676 /* Initialize router after SPAN is initialized, so that the FIB and
3677 * neighbor event handlers can issue SPAN respin.
3678 */
3678 err = mlxsw_sp_router_init(mlxsw_sp); 3679 err = mlxsw_sp_router_init(mlxsw_sp);
3679 if (err) { 3680 if (err) {
3680 dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n"); 3681 dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n");
3681 goto err_router_init; 3682 goto err_router_init;
3682 } 3683 }
3683 3684
3684 /* Initialize netdevice notifier after router is initialized, so that 3685 /* Initialize netdevice notifier after router and SPAN is initialized,
3685 * the event handler can use router structures. 3686 * so that the event handler can use router structures and call SPAN
3687 * respin.
3686 */ 3688 */
3687 mlxsw_sp->netdevice_nb.notifier_call = mlxsw_sp_netdevice_event; 3689 mlxsw_sp->netdevice_nb.notifier_call = mlxsw_sp_netdevice_event;
3688 err = register_netdevice_notifier(&mlxsw_sp->netdevice_nb); 3690 err = register_netdevice_notifier(&mlxsw_sp->netdevice_nb);
@@ -3691,12 +3693,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
3691 goto err_netdev_notifier; 3693 goto err_netdev_notifier;
3692 } 3694 }
3693 3695
3694 err = mlxsw_sp_span_init(mlxsw_sp);
3695 if (err) {
3696 dev_err(mlxsw_sp->bus_info->dev, "Failed to init span system\n");
3697 goto err_span_init;
3698 }
3699
3700 err = mlxsw_sp_acl_init(mlxsw_sp); 3696 err = mlxsw_sp_acl_init(mlxsw_sp);
3701 if (err) { 3697 if (err) {
3702 dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL\n"); 3698 dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL\n");
@@ -3722,12 +3718,12 @@ err_ports_create:
3722err_dpipe_init: 3718err_dpipe_init:
3723 mlxsw_sp_acl_fini(mlxsw_sp); 3719 mlxsw_sp_acl_fini(mlxsw_sp);
3724err_acl_init: 3720err_acl_init:
3725 mlxsw_sp_span_fini(mlxsw_sp);
3726err_span_init:
3727 unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb); 3721 unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb);
3728err_netdev_notifier: 3722err_netdev_notifier:
3729 mlxsw_sp_router_fini(mlxsw_sp); 3723 mlxsw_sp_router_fini(mlxsw_sp);
3730err_router_init: 3724err_router_init:
3725 mlxsw_sp_span_fini(mlxsw_sp);
3726err_span_init:
3731 mlxsw_sp_afa_fini(mlxsw_sp); 3727 mlxsw_sp_afa_fini(mlxsw_sp);
3732err_afa_init: 3728err_afa_init:
3733 mlxsw_sp_counter_pool_fini(mlxsw_sp); 3729 mlxsw_sp_counter_pool_fini(mlxsw_sp);
@@ -3753,9 +3749,9 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
3753 mlxsw_sp_ports_remove(mlxsw_sp); 3749 mlxsw_sp_ports_remove(mlxsw_sp);
3754 mlxsw_sp_dpipe_fini(mlxsw_sp); 3750 mlxsw_sp_dpipe_fini(mlxsw_sp);
3755 mlxsw_sp_acl_fini(mlxsw_sp); 3751 mlxsw_sp_acl_fini(mlxsw_sp);
3756 mlxsw_sp_span_fini(mlxsw_sp);
3757 unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb); 3752 unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb);
3758 mlxsw_sp_router_fini(mlxsw_sp); 3753 mlxsw_sp_router_fini(mlxsw_sp);
3754 mlxsw_sp_span_fini(mlxsw_sp);
3759 mlxsw_sp_afa_fini(mlxsw_sp); 3755 mlxsw_sp_afa_fini(mlxsw_sp);
3760 mlxsw_sp_counter_pool_fini(mlxsw_sp); 3756 mlxsw_sp_counter_pool_fini(mlxsw_sp);
3761 mlxsw_sp_switchdev_fini(mlxsw_sp); 3757 mlxsw_sp_switchdev_fini(mlxsw_sp);
@@ -4639,10 +4635,18 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *nb,
4639 unsigned long event, void *ptr) 4635 unsigned long event, void *ptr)
4640{ 4636{
4641 struct net_device *dev = netdev_notifier_info_to_dev(ptr); 4637 struct net_device *dev = netdev_notifier_info_to_dev(ptr);
4638 struct mlxsw_sp_span_entry *span_entry;
4642 struct mlxsw_sp *mlxsw_sp; 4639 struct mlxsw_sp *mlxsw_sp;
4643 int err = 0; 4640 int err = 0;
4644 4641
4645 mlxsw_sp = container_of(nb, struct mlxsw_sp, netdevice_nb); 4642 mlxsw_sp = container_of(nb, struct mlxsw_sp, netdevice_nb);
4643 if (event == NETDEV_UNREGISTER) {
4644 span_entry = mlxsw_sp_span_entry_find_by_port(mlxsw_sp, dev);
4645 if (span_entry)
4646 mlxsw_sp_span_entry_invalidate(mlxsw_sp, span_entry);
4647 }
4648 mlxsw_sp_span_respin(mlxsw_sp);
4649
4646 if (mlxsw_sp_netdev_is_ipip_ol(mlxsw_sp, dev)) 4650 if (mlxsw_sp_netdev_is_ipip_ol(mlxsw_sp, dev))
4647 err = mlxsw_sp_netdevice_ipip_ol_event(mlxsw_sp, dev, 4651 err = mlxsw_sp_netdevice_ipip_ol_event(mlxsw_sp, dev,
4648 event, ptr); 4652 event, ptr);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
index 675e03a892ed..2673310f92da 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -124,7 +124,7 @@ enum mlxsw_sp_port_mall_action_type {
124}; 124};
125 125
126struct mlxsw_sp_port_mall_mirror_tc_entry { 126struct mlxsw_sp_port_mall_mirror_tc_entry {
127 u8 to_local_port; 127 int span_id;
128 bool ingress; 128 bool ingress;
129}; 129};
130 130
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
index 0897a5435cc2..21ed27ae51e3 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
@@ -572,7 +572,6 @@ int mlxsw_sp_acl_rulei_act_mirror(struct mlxsw_sp *mlxsw_sp,
572 struct net_device *out_dev) 572 struct net_device *out_dev)
573{ 573{
574 struct mlxsw_sp_acl_block_binding *binding; 574 struct mlxsw_sp_acl_block_binding *binding;
575 struct mlxsw_sp_port *out_port;
576 struct mlxsw_sp_port *in_port; 575 struct mlxsw_sp_port *in_port;
577 576
578 if (!list_is_singular(&block->binding_list)) 577 if (!list_is_singular(&block->binding_list))
@@ -581,16 +580,10 @@ int mlxsw_sp_acl_rulei_act_mirror(struct mlxsw_sp *mlxsw_sp,
581 binding = list_first_entry(&block->binding_list, 580 binding = list_first_entry(&block->binding_list,
582 struct mlxsw_sp_acl_block_binding, list); 581 struct mlxsw_sp_acl_block_binding, list);
583 in_port = binding->mlxsw_sp_port; 582 in_port = binding->mlxsw_sp_port;
584 if (!mlxsw_sp_port_dev_check(out_dev))
585 return -EINVAL;
586
587 out_port = netdev_priv(out_dev);
588 if (out_port->mlxsw_sp != mlxsw_sp)
589 return -EINVAL;
590 583
591 return mlxsw_afa_block_append_mirror(rulei->act_block, 584 return mlxsw_afa_block_append_mirror(rulei->act_block,
592 in_port->local_port, 585 in_port->local_port,
593 out_port->local_port, 586 out_dev,
594 binding->ingress); 587 binding->ingress);
595} 588}
596 589
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c
index f7e61cecc42b..510ce48d87f7 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c
@@ -1,6 +1,6 @@
1/* 1/*
2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c 2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_flex_actions.c
3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved. 3 * Copyright (c) 2017, 2018 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2017 Jiri Pirko <jiri@mellanox.com> 4 * Copyright (c) 2017 Jiri Pirko <jiri@mellanox.com>
5 * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com> 5 * Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
6 * 6 *
@@ -126,40 +126,23 @@ mlxsw_sp_act_counter_index_put(void *priv, unsigned int counter_index)
126} 126}
127 127
128static int 128static int
129mlxsw_sp_act_mirror_add(void *priv, u8 local_in_port, u8 local_out_port, 129mlxsw_sp_act_mirror_add(void *priv, u8 local_in_port,
130 const struct net_device *out_dev,
130 bool ingress, int *p_span_id) 131 bool ingress, int *p_span_id)
131{ 132{
132 struct mlxsw_sp_port *in_port, *out_port; 133 struct mlxsw_sp_port *in_port;
133 struct mlxsw_sp_span_entry *span_entry;
134 struct mlxsw_sp *mlxsw_sp = priv; 134 struct mlxsw_sp *mlxsw_sp = priv;
135 enum mlxsw_sp_span_type type; 135 enum mlxsw_sp_span_type type;
136 int err;
137 136
138 type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS; 137 type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
139 out_port = mlxsw_sp->ports[local_out_port];
140 in_port = mlxsw_sp->ports[local_in_port]; 138 in_port = mlxsw_sp->ports[local_in_port];
141 139
142 err = mlxsw_sp_span_mirror_add(in_port, out_port, type, false); 140 return mlxsw_sp_span_mirror_add(in_port, out_dev, type,
143 if (err) 141 false, p_span_id);
144 return err;
145
146 span_entry = mlxsw_sp_span_entry_find(mlxsw_sp, local_out_port);
147 if (!span_entry) {
148 err = -ENOENT;
149 goto err_span_entry_find;
150 }
151
152 *p_span_id = span_entry->id;
153 return 0;
154
155err_span_entry_find:
156 mlxsw_sp_span_mirror_del(in_port, local_out_port, type, false);
157 return err;
158} 142}
159 143
160static void 144static void
161mlxsw_sp_act_mirror_del(void *priv, u8 local_in_port, u8 local_out_port, 145mlxsw_sp_act_mirror_del(void *priv, u8 local_in_port, int span_id, bool ingress)
162 bool ingress)
163{ 146{
164 struct mlxsw_sp *mlxsw_sp = priv; 147 struct mlxsw_sp *mlxsw_sp = priv;
165 struct mlxsw_sp_port *in_port; 148 struct mlxsw_sp_port *in_port;
@@ -168,7 +151,7 @@ mlxsw_sp_act_mirror_del(void *priv, u8 local_in_port, u8 local_out_port,
168 type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS; 151 type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
169 in_port = mlxsw_sp->ports[local_in_port]; 152 in_port = mlxsw_sp->ports[local_in_port];
170 153
171 mlxsw_sp_span_mirror_del(in_port, local_out_port, type, false); 154 mlxsw_sp_span_mirror_del(in_port, span_id, type, false);
172} 155}
173 156
174static const struct mlxsw_afa_ops mlxsw_sp_act_afa_ops = { 157static const struct mlxsw_afa_ops mlxsw_sp_act_afa_ops = {
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
index a1c4b1e63f8d..98d896c14b87 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c 2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.c
3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved. 3 * Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2017 Petr Machata <petrm@mellanox.com> 4 * Copyright (c) 2017-2018 Petr Machata <petrm@mellanox.com>
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met: 7 * modification, are permitted provided that the following conditions are met:
@@ -33,6 +33,7 @@
33 */ 33 */
34 34
35#include <net/ip_tunnels.h> 35#include <net/ip_tunnels.h>
36#include <net/ip6_tunnel.h>
36 37
37#include "spectrum_ipip.h" 38#include "spectrum_ipip.h"
38 39
@@ -44,6 +45,14 @@ mlxsw_sp_ipip_netdev_parms4(const struct net_device *ol_dev)
44 return tun->parms; 45 return tun->parms;
45} 46}
46 47
48struct __ip6_tnl_parm
49mlxsw_sp_ipip_netdev_parms6(const struct net_device *ol_dev)
50{
51 struct ip6_tnl *tun = netdev_priv(ol_dev);
52
53 return tun->parms;
54}
55
47static bool mlxsw_sp_ipip_parms4_has_ikey(struct ip_tunnel_parm parms) 56static bool mlxsw_sp_ipip_parms4_has_ikey(struct ip_tunnel_parm parms)
48{ 57{
49 return !!(parms.i_flags & TUNNEL_KEY); 58 return !!(parms.i_flags & TUNNEL_KEY);
@@ -73,23 +82,37 @@ mlxsw_sp_ipip_parms4_saddr(struct ip_tunnel_parm parms)
73} 82}
74 83
75static union mlxsw_sp_l3addr 84static union mlxsw_sp_l3addr
85mlxsw_sp_ipip_parms6_saddr(struct __ip6_tnl_parm parms)
86{
87 return (union mlxsw_sp_l3addr) { .addr6 = parms.laddr };
88}
89
90static union mlxsw_sp_l3addr
76mlxsw_sp_ipip_parms4_daddr(struct ip_tunnel_parm parms) 91mlxsw_sp_ipip_parms4_daddr(struct ip_tunnel_parm parms)
77{ 92{
78 return (union mlxsw_sp_l3addr) { .addr4 = parms.iph.daddr }; 93 return (union mlxsw_sp_l3addr) { .addr4 = parms.iph.daddr };
79} 94}
80 95
96static union mlxsw_sp_l3addr
97mlxsw_sp_ipip_parms6_daddr(struct __ip6_tnl_parm parms)
98{
99 return (union mlxsw_sp_l3addr) { .addr6 = parms.raddr };
100}
101
81union mlxsw_sp_l3addr 102union mlxsw_sp_l3addr
82mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto, 103mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto,
83 const struct net_device *ol_dev) 104 const struct net_device *ol_dev)
84{ 105{
85 struct ip_tunnel_parm parms4; 106 struct ip_tunnel_parm parms4;
107 struct __ip6_tnl_parm parms6;
86 108
87 switch (proto) { 109 switch (proto) {
88 case MLXSW_SP_L3_PROTO_IPV4: 110 case MLXSW_SP_L3_PROTO_IPV4:
89 parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); 111 parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
90 return mlxsw_sp_ipip_parms4_saddr(parms4); 112 return mlxsw_sp_ipip_parms4_saddr(parms4);
91 case MLXSW_SP_L3_PROTO_IPV6: 113 case MLXSW_SP_L3_PROTO_IPV6:
92 break; 114 parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev);
115 return mlxsw_sp_ipip_parms6_saddr(parms6);
93 } 116 }
94 117
95 WARN_ON(1); 118 WARN_ON(1);
@@ -109,19 +132,28 @@ mlxsw_sp_ipip_netdev_daddr(enum mlxsw_sp_l3proto proto,
109 const struct net_device *ol_dev) 132 const struct net_device *ol_dev)
110{ 133{
111 struct ip_tunnel_parm parms4; 134 struct ip_tunnel_parm parms4;
135 struct __ip6_tnl_parm parms6;
112 136
113 switch (proto) { 137 switch (proto) {
114 case MLXSW_SP_L3_PROTO_IPV4: 138 case MLXSW_SP_L3_PROTO_IPV4:
115 parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev); 139 parms4 = mlxsw_sp_ipip_netdev_parms4(ol_dev);
116 return mlxsw_sp_ipip_parms4_daddr(parms4); 140 return mlxsw_sp_ipip_parms4_daddr(parms4);
117 case MLXSW_SP_L3_PROTO_IPV6: 141 case MLXSW_SP_L3_PROTO_IPV6:
118 break; 142 parms6 = mlxsw_sp_ipip_netdev_parms6(ol_dev);
143 return mlxsw_sp_ipip_parms6_daddr(parms6);
119 } 144 }
120 145
121 WARN_ON(1); 146 WARN_ON(1);
122 return (union mlxsw_sp_l3addr) {0}; 147 return (union mlxsw_sp_l3addr) {0};
123} 148}
124 149
150bool mlxsw_sp_l3addr_is_zero(union mlxsw_sp_l3addr addr)
151{
152 union mlxsw_sp_l3addr naddr = {0};
153
154 return !memcmp(&addr, &naddr, sizeof(naddr));
155}
156
125static int 157static int
126mlxsw_sp_ipip_nexthop_update_gre4(struct mlxsw_sp *mlxsw_sp, u32 adj_index, 158mlxsw_sp_ipip_nexthop_update_gre4(struct mlxsw_sp *mlxsw_sp, u32 adj_index,
127 struct mlxsw_sp_ipip_entry *ipip_entry) 159 struct mlxsw_sp_ipip_entry *ipip_entry)
@@ -215,15 +247,14 @@ static bool mlxsw_sp_ipip_tunnel_complete(enum mlxsw_sp_l3proto proto,
215{ 247{
216 union mlxsw_sp_l3addr saddr = mlxsw_sp_ipip_netdev_saddr(proto, ol_dev); 248 union mlxsw_sp_l3addr saddr = mlxsw_sp_ipip_netdev_saddr(proto, ol_dev);
217 union mlxsw_sp_l3addr daddr = mlxsw_sp_ipip_netdev_daddr(proto, ol_dev); 249 union mlxsw_sp_l3addr daddr = mlxsw_sp_ipip_netdev_daddr(proto, ol_dev);
218 union mlxsw_sp_l3addr naddr = {0};
219 250
220 /* Tunnels with unset local or remote address are valid in Linux and 251 /* Tunnels with unset local or remote address are valid in Linux and
221 * used for lightweight tunnels (LWT) and Non-Broadcast Multi-Access 252 * used for lightweight tunnels (LWT) and Non-Broadcast Multi-Access
222 * (NBMA) tunnels. In principle these can be offloaded, but the driver 253 * (NBMA) tunnels. In principle these can be offloaded, but the driver
223 * currently doesn't support this. So punt. 254 * currently doesn't support this. So punt.
224 */ 255 */
225 return memcmp(&saddr, &naddr, sizeof(naddr)) && 256 return !mlxsw_sp_l3addr_is_zero(saddr) &&
226 memcmp(&daddr, &naddr, sizeof(naddr)); 257 !mlxsw_sp_l3addr_is_zero(daddr);
227} 258}
228 259
229static bool mlxsw_sp_ipip_can_offload_gre4(const struct mlxsw_sp *mlxsw_sp, 260static bool mlxsw_sp_ipip_can_offload_gre4(const struct mlxsw_sp *mlxsw_sp,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h
index a4ff5737eccc..6909d867bb59 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h 2 * drivers/net/ethernet/mellanox/mlxsw/spectrum_ipip.h
3 * Copyright (c) 2017 Mellanox Technologies. All rights reserved. 3 * Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2017 Petr Machata <petrm@mellanox.com> 4 * Copyright (c) 2017-2018 Petr Machata <petrm@mellanox.com>
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met: 7 * modification, are permitted provided that the following conditions are met:
@@ -41,11 +41,15 @@
41 41
42struct ip_tunnel_parm 42struct ip_tunnel_parm
43mlxsw_sp_ipip_netdev_parms4(const struct net_device *ol_dev); 43mlxsw_sp_ipip_netdev_parms4(const struct net_device *ol_dev);
44struct __ip6_tnl_parm
45mlxsw_sp_ipip_netdev_parms6(const struct net_device *ol_dev);
44 46
45union mlxsw_sp_l3addr 47union mlxsw_sp_l3addr
46mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto, 48mlxsw_sp_ipip_netdev_saddr(enum mlxsw_sp_l3proto proto,
47 const struct net_device *ol_dev); 49 const struct net_device *ol_dev);
48 50
51bool mlxsw_sp_l3addr_is_zero(union mlxsw_sp_l3addr addr);
52
49enum mlxsw_sp_ipip_type { 53enum mlxsw_sp_ipip_type {
50 MLXSW_SP_IPIP_TYPE_GRE4, 54 MLXSW_SP_IPIP_TYPE_GRE4,
51 MLXSW_SP_IPIP_TYPE_MAX, 55 MLXSW_SP_IPIP_TYPE_MAX,
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
index 05146970c19c..69f16c605b9d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c
@@ -70,6 +70,7 @@
70#include "spectrum_mr.h" 70#include "spectrum_mr.h"
71#include "spectrum_mr_tcam.h" 71#include "spectrum_mr_tcam.h"
72#include "spectrum_router.h" 72#include "spectrum_router.h"
73#include "spectrum_span.h"
73 74
74struct mlxsw_sp_fib; 75struct mlxsw_sp_fib;
75struct mlxsw_sp_vr; 76struct mlxsw_sp_vr;
@@ -2330,6 +2331,8 @@ static void mlxsw_sp_router_neigh_event_work(struct work_struct *work)
2330 read_unlock_bh(&n->lock); 2331 read_unlock_bh(&n->lock);
2331 2332
2332 rtnl_lock(); 2333 rtnl_lock();
2334 mlxsw_sp_span_respin(mlxsw_sp);
2335
2333 entry_connected = nud_state & NUD_VALID && !dead; 2336 entry_connected = nud_state & NUD_VALID && !dead;
2334 neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n); 2337 neigh_entry = mlxsw_sp_neigh_entry_lookup(mlxsw_sp, n);
2335 if (!entry_connected && !neigh_entry) 2338 if (!entry_connected && !neigh_entry)
@@ -5589,6 +5592,8 @@ static void mlxsw_sp_router_fib4_event_work(struct work_struct *work)
5589 5592
5590 /* Protect internal structures from changes */ 5593 /* Protect internal structures from changes */
5591 rtnl_lock(); 5594 rtnl_lock();
5595 mlxsw_sp_span_respin(mlxsw_sp);
5596
5592 switch (fib_work->event) { 5597 switch (fib_work->event) {
5593 case FIB_EVENT_ENTRY_REPLACE: /* fall through */ 5598 case FIB_EVENT_ENTRY_REPLACE: /* fall through */
5594 case FIB_EVENT_ENTRY_APPEND: /* fall through */ 5599 case FIB_EVENT_ENTRY_APPEND: /* fall through */
@@ -5631,6 +5636,8 @@ static void mlxsw_sp_router_fib6_event_work(struct work_struct *work)
5631 int err; 5636 int err;
5632 5637
5633 rtnl_lock(); 5638 rtnl_lock();
5639 mlxsw_sp_span_respin(mlxsw_sp);
5640
5634 switch (fib_work->event) { 5641 switch (fib_work->event) {
5635 case FIB_EVENT_ENTRY_REPLACE: /* fall through */ 5642 case FIB_EVENT_ENTRY_REPLACE: /* fall through */
5636 case FIB_EVENT_ENTRY_ADD: 5643 case FIB_EVENT_ENTRY_ADD:
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
index c3bec37d71ed..f537e1de11d9 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * drivers/net/ethernet/mellanox/mlxsw/mlxsw_span.c 2 * drivers/net/ethernet/mellanox/mlxsw/mlxsw_span.c
3 * Copyright (c) 2018 Mellanox Technologies. All rights reserved. 3 * Copyright (c) 2018 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2018 Petr Machata <petrm@mellanox.com>
4 * 5 *
5 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met: 7 * modification, are permitted provided that the following conditions are met:
@@ -32,9 +33,14 @@
32 */ 33 */
33 34
34#include <linux/list.h> 35#include <linux/list.h>
36#include <net/arp.h>
37#include <net/gre.h>
38#include <net/ndisc.h>
39#include <net/ip6_tunnel.h>
35 40
36#include "spectrum.h" 41#include "spectrum.h"
37#include "spectrum_span.h" 42#include "spectrum_span.h"
43#include "spectrum_ipip.h"
38 44
39int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp) 45int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp)
40{ 46{
@@ -51,8 +57,12 @@ int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp)
51 if (!mlxsw_sp->span.entries) 57 if (!mlxsw_sp->span.entries)
52 return -ENOMEM; 58 return -ENOMEM;
53 59
54 for (i = 0; i < mlxsw_sp->span.entries_count; i++) 60 for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
55 INIT_LIST_HEAD(&mlxsw_sp->span.entries[i].bound_ports_list); 61 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
62
63 INIT_LIST_HEAD(&curr->bound_ports_list);
64 curr->id = i;
65 }
56 66
57 return 0; 67 return 0;
58} 68}
@@ -69,80 +79,460 @@ void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp)
69 kfree(mlxsw_sp->span.entries); 79 kfree(mlxsw_sp->span.entries);
70} 80}
71 81
72static struct mlxsw_sp_span_entry * 82static int
73mlxsw_sp_span_entry_create(struct mlxsw_sp_port *port) 83mlxsw_sp_span_entry_phys_parms(const struct net_device *to_dev,
84 struct mlxsw_sp_span_parms *sparmsp)
74{ 85{
75 struct mlxsw_sp *mlxsw_sp = port->mlxsw_sp; 86 sparmsp->dest_port = netdev_priv(to_dev);
76 struct mlxsw_sp_span_entry *span_entry; 87 return 0;
88}
89
90static int
91mlxsw_sp_span_entry_phys_configure(struct mlxsw_sp_span_entry *span_entry,
92 struct mlxsw_sp_span_parms sparms)
93{
94 struct mlxsw_sp_port *dest_port = sparms.dest_port;
95 struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp;
96 u8 local_port = dest_port->local_port;
97 char mpat_pl[MLXSW_REG_MPAT_LEN];
98 int pa_id = span_entry->id;
99
100 /* Create a new port analayzer entry for local_port. */
101 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true,
102 MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH);
103
104 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
105}
106
107static void
108mlxsw_sp_span_entry_deconfigure_common(struct mlxsw_sp_span_entry *span_entry,
109 enum mlxsw_reg_mpat_span_type span_type)
110{
111 struct mlxsw_sp_port *dest_port = span_entry->parms.dest_port;
112 struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp;
113 u8 local_port = dest_port->local_port;
114 char mpat_pl[MLXSW_REG_MPAT_LEN];
115 int pa_id = span_entry->id;
116
117 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, false, span_type);
118 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
119}
120
121static void
122mlxsw_sp_span_entry_phys_deconfigure(struct mlxsw_sp_span_entry *span_entry)
123{
124 mlxsw_sp_span_entry_deconfigure_common(span_entry,
125 MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH);
126}
127
128static const
129struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_phys = {
130 .can_handle = mlxsw_sp_port_dev_check,
131 .parms = mlxsw_sp_span_entry_phys_parms,
132 .configure = mlxsw_sp_span_entry_phys_configure,
133 .deconfigure = mlxsw_sp_span_entry_phys_deconfigure,
134};
135
136static struct net_device *
137mlxsw_sp_span_gretap4_route(const struct net_device *to_dev,
138 __be32 *saddrp, __be32 *daddrp)
139{
140 struct ip_tunnel *tun = netdev_priv(to_dev);
141 struct net_device *dev = NULL;
142 struct ip_tunnel_parm parms;
143 struct rtable *rt = NULL;
144 struct flowi4 fl4;
145
146 /* We assume "dev" stays valid after rt is put. */
147 ASSERT_RTNL();
148
149 parms = mlxsw_sp_ipip_netdev_parms4(to_dev);
150 ip_tunnel_init_flow(&fl4, parms.iph.protocol, *daddrp, *saddrp,
151 0, 0, parms.link, tun->fwmark);
152
153 rt = ip_route_output_key(tun->net, &fl4);
154 if (IS_ERR(rt))
155 return NULL;
156
157 if (rt->rt_type != RTN_UNICAST)
158 goto out;
159
160 dev = rt->dst.dev;
161 *saddrp = fl4.saddr;
162 *daddrp = rt->rt_gateway;
163
164out:
165 ip_rt_put(rt);
166 return dev;
167}
168
169static int mlxsw_sp_span_dmac(struct neigh_table *tbl,
170 const void *pkey,
171 struct net_device *l3edev,
172 unsigned char dmac[ETH_ALEN])
173{
174 struct neighbour *neigh = neigh_lookup(tbl, pkey, l3edev);
175 int err = 0;
176
177 if (!neigh) {
178 neigh = neigh_create(tbl, pkey, l3edev);
179 if (IS_ERR(neigh))
180 return PTR_ERR(neigh);
181 }
182
183 neigh_event_send(neigh, NULL);
184
185 read_lock_bh(&neigh->lock);
186 if ((neigh->nud_state & NUD_VALID) && !neigh->dead)
187 memcpy(dmac, neigh->ha, ETH_ALEN);
188 else
189 err = -ENOENT;
190 read_unlock_bh(&neigh->lock);
191
192 neigh_release(neigh);
193 return err;
194}
195
196static int
197mlxsw_sp_span_entry_unoffloadable(struct mlxsw_sp_span_parms *sparmsp)
198{
199 sparmsp->dest_port = NULL;
200 return 0;
201}
202
203static int
204mlxsw_sp_span_entry_tunnel_parms_common(struct net_device *l3edev,
205 union mlxsw_sp_l3addr saddr,
206 union mlxsw_sp_l3addr daddr,
207 union mlxsw_sp_l3addr gw,
208 __u8 ttl,
209 struct neigh_table *tbl,
210 struct mlxsw_sp_span_parms *sparmsp)
211{
212 unsigned char dmac[ETH_ALEN];
213
214 if (mlxsw_sp_l3addr_is_zero(gw))
215 gw = daddr;
216
217 if (!l3edev || !mlxsw_sp_port_dev_check(l3edev) ||
218 mlxsw_sp_span_dmac(tbl, &gw, l3edev, dmac))
219 return mlxsw_sp_span_entry_unoffloadable(sparmsp);
220
221 sparmsp->dest_port = netdev_priv(l3edev);
222 sparmsp->ttl = ttl;
223 memcpy(sparmsp->dmac, dmac, ETH_ALEN);
224 memcpy(sparmsp->smac, l3edev->dev_addr, ETH_ALEN);
225 sparmsp->saddr = saddr;
226 sparmsp->daddr = daddr;
227 return 0;
228}
229
230static int
231mlxsw_sp_span_entry_gretap4_parms(const struct net_device *to_dev,
232 struct mlxsw_sp_span_parms *sparmsp)
233{
234 struct ip_tunnel_parm tparm = mlxsw_sp_ipip_netdev_parms4(to_dev);
235 union mlxsw_sp_l3addr saddr = { .addr4 = tparm.iph.saddr };
236 union mlxsw_sp_l3addr daddr = { .addr4 = tparm.iph.daddr };
237 bool inherit_tos = tparm.iph.tos & 0x1;
238 bool inherit_ttl = !tparm.iph.ttl;
239 union mlxsw_sp_l3addr gw = daddr;
240 struct net_device *l3edev;
241
242 if (!(to_dev->flags & IFF_UP) ||
243 /* Reject tunnels with GRE keys, checksums, etc. */
244 tparm.i_flags || tparm.o_flags ||
245 /* Require a fixed TTL and a TOS copied from the mirrored packet. */
246 inherit_ttl || !inherit_tos ||
247 /* A destination address may not be "any". */
248 mlxsw_sp_l3addr_is_zero(daddr))
249 return mlxsw_sp_span_entry_unoffloadable(sparmsp);
250
251 l3edev = mlxsw_sp_span_gretap4_route(to_dev, &saddr.addr4, &gw.addr4);
252 return mlxsw_sp_span_entry_tunnel_parms_common(l3edev, saddr, daddr, gw,
253 tparm.iph.ttl,
254 &arp_tbl, sparmsp);
255}
256
257static int
258mlxsw_sp_span_entry_gretap4_configure(struct mlxsw_sp_span_entry *span_entry,
259 struct mlxsw_sp_span_parms sparms)
260{
261 struct mlxsw_sp_port *dest_port = sparms.dest_port;
262 struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp;
263 u8 local_port = dest_port->local_port;
264 char mpat_pl[MLXSW_REG_MPAT_LEN];
265 int pa_id = span_entry->id;
266
267 /* Create a new port analayzer entry for local_port. */
268 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true,
269 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3);
270 mlxsw_reg_mpat_eth_rspan_l2_pack(mpat_pl,
271 MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER,
272 sparms.dmac, false);
273 mlxsw_reg_mpat_eth_rspan_l3_ipv4_pack(mpat_pl,
274 sparms.ttl, sparms.smac,
275 be32_to_cpu(sparms.saddr.addr4),
276 be32_to_cpu(sparms.daddr.addr4));
277
278 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
279}
280
281static void
282mlxsw_sp_span_entry_gretap4_deconfigure(struct mlxsw_sp_span_entry *span_entry)
283{
284 mlxsw_sp_span_entry_deconfigure_common(span_entry,
285 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3);
286}
287
288static const struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_gretap4 = {
289 .can_handle = is_gretap_dev,
290 .parms = mlxsw_sp_span_entry_gretap4_parms,
291 .configure = mlxsw_sp_span_entry_gretap4_configure,
292 .deconfigure = mlxsw_sp_span_entry_gretap4_deconfigure,
293};
294
295static struct net_device *
296mlxsw_sp_span_gretap6_route(const struct net_device *to_dev,
297 struct in6_addr *saddrp,
298 struct in6_addr *daddrp)
299{
300 struct ip6_tnl *t = netdev_priv(to_dev);
301 struct flowi6 fl6 = t->fl.u.ip6;
302 struct net_device *dev = NULL;
303 struct dst_entry *dst;
304 struct rt6_info *rt6;
305
306 /* We assume "dev" stays valid after dst is released. */
307 ASSERT_RTNL();
308
309 fl6.flowi6_mark = t->parms.fwmark;
310 if (!ip6_tnl_xmit_ctl(t, &fl6.saddr, &fl6.daddr))
311 return NULL;
312
313 dst = ip6_route_output(t->net, NULL, &fl6);
314 if (!dst || dst->error)
315 goto out;
316
317 rt6 = container_of(dst, struct rt6_info, dst);
318
319 dev = dst->dev;
320 *saddrp = fl6.saddr;
321 *daddrp = rt6->rt6i_gateway;
322
323out:
324 dst_release(dst);
325 return dev;
326}
327
328static int
329mlxsw_sp_span_entry_gretap6_parms(const struct net_device *to_dev,
330 struct mlxsw_sp_span_parms *sparmsp)
331{
332 struct __ip6_tnl_parm tparm = mlxsw_sp_ipip_netdev_parms6(to_dev);
333 bool inherit_tos = tparm.flags & IP6_TNL_F_USE_ORIG_TCLASS;
334 union mlxsw_sp_l3addr saddr = { .addr6 = tparm.laddr };
335 union mlxsw_sp_l3addr daddr = { .addr6 = tparm.raddr };
336 bool inherit_ttl = !tparm.hop_limit;
337 union mlxsw_sp_l3addr gw = daddr;
338 struct net_device *l3edev;
339
340 if (!(to_dev->flags & IFF_UP) ||
341 /* Reject tunnels with GRE keys, checksums, etc. */
342 tparm.i_flags || tparm.o_flags ||
343 /* Require a fixed TTL and a TOS copied from the mirrored packet. */
344 inherit_ttl || !inherit_tos ||
345 /* A destination address may not be "any". */
346 mlxsw_sp_l3addr_is_zero(daddr))
347 return mlxsw_sp_span_entry_unoffloadable(sparmsp);
348
349 l3edev = mlxsw_sp_span_gretap6_route(to_dev, &saddr.addr6, &gw.addr6);
350 return mlxsw_sp_span_entry_tunnel_parms_common(l3edev, saddr, daddr, gw,
351 tparm.hop_limit,
352 &nd_tbl, sparmsp);
353}
354
355static int
356mlxsw_sp_span_entry_gretap6_configure(struct mlxsw_sp_span_entry *span_entry,
357 struct mlxsw_sp_span_parms sparms)
358{
359 struct mlxsw_sp_port *dest_port = sparms.dest_port;
360 struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp;
361 u8 local_port = dest_port->local_port;
77 char mpat_pl[MLXSW_REG_MPAT_LEN]; 362 char mpat_pl[MLXSW_REG_MPAT_LEN];
78 u8 local_port = port->local_port; 363 int pa_id = span_entry->id;
79 int index; 364
365 /* Create a new port analayzer entry for local_port. */
366 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true,
367 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3);
368 mlxsw_reg_mpat_eth_rspan_l2_pack(mpat_pl,
369 MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER,
370 sparms.dmac, false);
371 mlxsw_reg_mpat_eth_rspan_l3_ipv6_pack(mpat_pl, sparms.ttl, sparms.smac,
372 sparms.saddr.addr6,
373 sparms.daddr.addr6);
374
375 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
376}
377
378static void
379mlxsw_sp_span_entry_gretap6_deconfigure(struct mlxsw_sp_span_entry *span_entry)
380{
381 mlxsw_sp_span_entry_deconfigure_common(span_entry,
382 MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3);
383}
384
385static const
386struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_gretap6 = {
387 .can_handle = is_ip6gretap_dev,
388 .parms = mlxsw_sp_span_entry_gretap6_parms,
389 .configure = mlxsw_sp_span_entry_gretap6_configure,
390 .deconfigure = mlxsw_sp_span_entry_gretap6_deconfigure,
391};
392
393static const
394struct mlxsw_sp_span_entry_ops *const mlxsw_sp_span_entry_types[] = {
395 &mlxsw_sp_span_entry_ops_phys,
396 &mlxsw_sp_span_entry_ops_gretap4,
397 &mlxsw_sp_span_entry_ops_gretap6,
398};
399
400static int
401mlxsw_sp_span_entry_nop_parms(const struct net_device *to_dev,
402 struct mlxsw_sp_span_parms *sparmsp)
403{
404 return mlxsw_sp_span_entry_unoffloadable(sparmsp);
405}
406
407static int
408mlxsw_sp_span_entry_nop_configure(struct mlxsw_sp_span_entry *span_entry,
409 struct mlxsw_sp_span_parms sparms)
410{
411 return 0;
412}
413
414static void
415mlxsw_sp_span_entry_nop_deconfigure(struct mlxsw_sp_span_entry *span_entry)
416{
417}
418
419static const struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_nop = {
420 .parms = mlxsw_sp_span_entry_nop_parms,
421 .configure = mlxsw_sp_span_entry_nop_configure,
422 .deconfigure = mlxsw_sp_span_entry_nop_deconfigure,
423};
424
425static void
426mlxsw_sp_span_entry_configure(struct mlxsw_sp *mlxsw_sp,
427 struct mlxsw_sp_span_entry *span_entry,
428 struct mlxsw_sp_span_parms sparms)
429{
430 if (sparms.dest_port) {
431 if (sparms.dest_port->mlxsw_sp != mlxsw_sp) {
432 netdev_err(span_entry->to_dev, "Cannot mirror to %s, which belongs to a different mlxsw instance",
433 sparms.dest_port->dev->name);
434 sparms.dest_port = NULL;
435 } else if (span_entry->ops->configure(span_entry, sparms)) {
436 netdev_err(span_entry->to_dev, "Failed to offload mirror to %s",
437 sparms.dest_port->dev->name);
438 sparms.dest_port = NULL;
439 }
440 }
441
442 span_entry->parms = sparms;
443}
444
445static void
446mlxsw_sp_span_entry_deconfigure(struct mlxsw_sp_span_entry *span_entry)
447{
448 if (span_entry->parms.dest_port)
449 span_entry->ops->deconfigure(span_entry);
450}
451
452static struct mlxsw_sp_span_entry *
453mlxsw_sp_span_entry_create(struct mlxsw_sp *mlxsw_sp,
454 const struct net_device *to_dev,
455 const struct mlxsw_sp_span_entry_ops *ops,
456 struct mlxsw_sp_span_parms sparms)
457{
458 struct mlxsw_sp_span_entry *span_entry = NULL;
80 int i; 459 int i;
81 int err;
82 460
83 /* find a free entry to use */ 461 /* find a free entry to use */
84 index = -1;
85 for (i = 0; i < mlxsw_sp->span.entries_count; i++) { 462 for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
86 if (!mlxsw_sp->span.entries[i].ref_count) { 463 if (!mlxsw_sp->span.entries[i].ref_count) {
87 index = i;
88 span_entry = &mlxsw_sp->span.entries[i]; 464 span_entry = &mlxsw_sp->span.entries[i];
89 break; 465 break;
90 } 466 }
91 } 467 }
92 if (index < 0) 468 if (!span_entry)
93 return NULL;
94
95 /* create a new port analayzer entry for local_port */
96 mlxsw_reg_mpat_pack(mpat_pl, index, local_port, true);
97 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
98 if (err)
99 return NULL; 469 return NULL;
100 470
101 span_entry->id = index; 471 span_entry->ops = ops;
102 span_entry->ref_count = 1; 472 span_entry->ref_count = 1;
103 span_entry->local_port = local_port; 473 span_entry->to_dev = to_dev;
474 mlxsw_sp_span_entry_configure(mlxsw_sp, span_entry, sparms);
475
104 return span_entry; 476 return span_entry;
105} 477}
106 478
107static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp *mlxsw_sp, 479static void mlxsw_sp_span_entry_destroy(struct mlxsw_sp_span_entry *span_entry)
108 struct mlxsw_sp_span_entry *span_entry)
109{ 480{
110 u8 local_port = span_entry->local_port; 481 mlxsw_sp_span_entry_deconfigure(span_entry);
111 char mpat_pl[MLXSW_REG_MPAT_LEN];
112 int pa_id = span_entry->id;
113
114 mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, false);
115 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
116} 482}
117 483
118struct mlxsw_sp_span_entry * 484struct mlxsw_sp_span_entry *
119mlxsw_sp_span_entry_find(struct mlxsw_sp *mlxsw_sp, u8 local_port) 485mlxsw_sp_span_entry_find_by_port(struct mlxsw_sp *mlxsw_sp,
486 const struct net_device *to_dev)
120{ 487{
121 int i; 488 int i;
122 489
123 for (i = 0; i < mlxsw_sp->span.entries_count; i++) { 490 for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
124 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i]; 491 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
125 492
126 if (curr->ref_count && curr->local_port == local_port) 493 if (curr->ref_count && curr->to_dev == to_dev)
127 return curr; 494 return curr;
128 } 495 }
129 return NULL; 496 return NULL;
130} 497}
131 498
499void mlxsw_sp_span_entry_invalidate(struct mlxsw_sp *mlxsw_sp,
500 struct mlxsw_sp_span_entry *span_entry)
501{
502 mlxsw_sp_span_entry_deconfigure(span_entry);
503 span_entry->ops = &mlxsw_sp_span_entry_ops_nop;
504}
505
132static struct mlxsw_sp_span_entry * 506static struct mlxsw_sp_span_entry *
133mlxsw_sp_span_entry_get(struct mlxsw_sp_port *port) 507mlxsw_sp_span_entry_find_by_id(struct mlxsw_sp *mlxsw_sp, int span_id)
508{
509 int i;
510
511 for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
512 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
513
514 if (curr->ref_count && curr->id == span_id)
515 return curr;
516 }
517 return NULL;
518}
519
520static struct mlxsw_sp_span_entry *
521mlxsw_sp_span_entry_get(struct mlxsw_sp *mlxsw_sp,
522 const struct net_device *to_dev,
523 const struct mlxsw_sp_span_entry_ops *ops,
524 struct mlxsw_sp_span_parms sparms)
134{ 525{
135 struct mlxsw_sp_span_entry *span_entry; 526 struct mlxsw_sp_span_entry *span_entry;
136 527
137 span_entry = mlxsw_sp_span_entry_find(port->mlxsw_sp, 528 span_entry = mlxsw_sp_span_entry_find_by_port(mlxsw_sp, to_dev);
138 port->local_port);
139 if (span_entry) { 529 if (span_entry) {
140 /* Already exists, just take a reference */ 530 /* Already exists, just take a reference */
141 span_entry->ref_count++; 531 span_entry->ref_count++;
142 return span_entry; 532 return span_entry;
143 } 533 }
144 534
145 return mlxsw_sp_span_entry_create(port); 535 return mlxsw_sp_span_entry_create(mlxsw_sp, to_dev, ops, sparms);
146} 536}
147 537
148static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp, 538static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp,
@@ -150,7 +540,7 @@ static int mlxsw_sp_span_entry_put(struct mlxsw_sp *mlxsw_sp,
150{ 540{
151 WARN_ON(!span_entry->ref_count); 541 WARN_ON(!span_entry->ref_count);
152 if (--span_entry->ref_count == 0) 542 if (--span_entry->ref_count == 0)
153 mlxsw_sp_span_entry_destroy(mlxsw_sp, span_entry); 543 mlxsw_sp_span_entry_destroy(span_entry);
154 return 0; 544 return 0;
155} 545}
156 546
@@ -312,15 +702,41 @@ mlxsw_sp_span_inspected_port_del(struct mlxsw_sp_port *port,
312 kfree(inspected_port); 702 kfree(inspected_port);
313} 703}
314 704
705static const struct mlxsw_sp_span_entry_ops *
706mlxsw_sp_span_entry_ops(struct mlxsw_sp *mlxsw_sp,
707 const struct net_device *to_dev)
708{
709 size_t i;
710
711 for (i = 0; i < ARRAY_SIZE(mlxsw_sp_span_entry_types); ++i)
712 if (mlxsw_sp_span_entry_types[i]->can_handle(to_dev))
713 return mlxsw_sp_span_entry_types[i];
714
715 return NULL;
716}
717
315int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, 718int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from,
316 struct mlxsw_sp_port *to, 719 const struct net_device *to_dev,
317 enum mlxsw_sp_span_type type, bool bind) 720 enum mlxsw_sp_span_type type, bool bind,
721 int *p_span_id)
318{ 722{
319 struct mlxsw_sp *mlxsw_sp = from->mlxsw_sp; 723 struct mlxsw_sp *mlxsw_sp = from->mlxsw_sp;
724 const struct mlxsw_sp_span_entry_ops *ops;
725 struct mlxsw_sp_span_parms sparms = {0};
320 struct mlxsw_sp_span_entry *span_entry; 726 struct mlxsw_sp_span_entry *span_entry;
321 int err; 727 int err;
322 728
323 span_entry = mlxsw_sp_span_entry_get(to); 729 ops = mlxsw_sp_span_entry_ops(mlxsw_sp, to_dev);
730 if (!ops) {
731 netdev_err(to_dev, "Cannot mirror to %s", to_dev->name);
732 return -EOPNOTSUPP;
733 }
734
735 err = ops->parms(to_dev, &sparms);
736 if (err)
737 return err;
738
739 span_entry = mlxsw_sp_span_entry_get(mlxsw_sp, to_dev, ops, sparms);
324 if (!span_entry) 740 if (!span_entry)
325 return -ENOENT; 741 return -ENOENT;
326 742
@@ -331,6 +747,7 @@ int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from,
331 if (err) 747 if (err)
332 goto err_port_bind; 748 goto err_port_bind;
333 749
750 *p_span_id = span_entry->id;
334 return 0; 751 return 0;
335 752
336err_port_bind: 753err_port_bind:
@@ -338,13 +755,12 @@ err_port_bind:
338 return err; 755 return err;
339} 756}
340 757
341void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, u8 destination_port, 758void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, int span_id,
342 enum mlxsw_sp_span_type type, bool bind) 759 enum mlxsw_sp_span_type type, bool bind)
343{ 760{
344 struct mlxsw_sp_span_entry *span_entry; 761 struct mlxsw_sp_span_entry *span_entry;
345 762
346 span_entry = mlxsw_sp_span_entry_find(from->mlxsw_sp, 763 span_entry = mlxsw_sp_span_entry_find_by_id(from->mlxsw_sp, span_id);
347 destination_port);
348 if (!span_entry) { 764 if (!span_entry) {
349 netdev_err(from->dev, "no span entry found\n"); 765 netdev_err(from->dev, "no span entry found\n");
350 return; 766 return;
@@ -354,3 +770,27 @@ void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, u8 destination_port,
354 span_entry->id); 770 span_entry->id);
355 mlxsw_sp_span_inspected_port_del(from, span_entry, type, bind); 771 mlxsw_sp_span_inspected_port_del(from, span_entry, type, bind);
356} 772}
773
774void mlxsw_sp_span_respin(struct mlxsw_sp *mlxsw_sp)
775{
776 int i;
777 int err;
778
779 ASSERT_RTNL();
780 for (i = 0; i < mlxsw_sp->span.entries_count; i++) {
781 struct mlxsw_sp_span_entry *curr = &mlxsw_sp->span.entries[i];
782 struct mlxsw_sp_span_parms sparms = {0};
783
784 if (!curr->ref_count)
785 continue;
786
787 err = curr->ops->parms(curr->to_dev, &sparms);
788 if (err)
789 continue;
790
791 if (memcmp(&sparms, &curr->parms, sizeof(sparms))) {
792 mlxsw_sp_span_entry_deconfigure(curr);
793 mlxsw_sp_span_entry_configure(mlxsw_sp, curr, sparms);
794 }
795 }
796}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h
index 069050e385ff..948aceb512c5 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h
@@ -35,6 +35,9 @@
35#define _MLXSW_SPECTRUM_SPAN_H 35#define _MLXSW_SPECTRUM_SPAN_H
36 36
37#include <linux/types.h> 37#include <linux/types.h>
38#include <linux/if_ether.h>
39
40#include "spectrum_router.h"
38 41
39struct mlxsw_sp; 42struct mlxsw_sp;
40struct mlxsw_sp_port; 43struct mlxsw_sp_port;
@@ -50,23 +53,51 @@ struct mlxsw_sp_span_inspected_port {
50 u8 local_port; 53 u8 local_port;
51}; 54};
52 55
56struct mlxsw_sp_span_parms {
57 struct mlxsw_sp_port *dest_port; /* NULL for unoffloaded SPAN. */
58 unsigned int ttl;
59 unsigned char dmac[ETH_ALEN];
60 unsigned char smac[ETH_ALEN];
61 union mlxsw_sp_l3addr daddr;
62 union mlxsw_sp_l3addr saddr;
63};
64
65struct mlxsw_sp_span_entry_ops;
66
53struct mlxsw_sp_span_entry { 67struct mlxsw_sp_span_entry {
54 u8 local_port; 68 const struct net_device *to_dev;
69 const struct mlxsw_sp_span_entry_ops *ops;
70 struct mlxsw_sp_span_parms parms;
55 struct list_head bound_ports_list; 71 struct list_head bound_ports_list;
56 int ref_count; 72 int ref_count;
57 int id; 73 int id;
58}; 74};
59 75
76struct mlxsw_sp_span_entry_ops {
77 bool (*can_handle)(const struct net_device *to_dev);
78 int (*parms)(const struct net_device *to_dev,
79 struct mlxsw_sp_span_parms *sparmsp);
80 int (*configure)(struct mlxsw_sp_span_entry *span_entry,
81 struct mlxsw_sp_span_parms sparms);
82 void (*deconfigure)(struct mlxsw_sp_span_entry *span_entry);
83};
84
60int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp); 85int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp);
61void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp); 86void mlxsw_sp_span_fini(struct mlxsw_sp *mlxsw_sp);
87void mlxsw_sp_span_respin(struct mlxsw_sp *mlxsw_sp);
62 88
63int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from, 89int mlxsw_sp_span_mirror_add(struct mlxsw_sp_port *from,
64 struct mlxsw_sp_port *to, 90 const struct net_device *to_dev,
65 enum mlxsw_sp_span_type type, bool bind); 91 enum mlxsw_sp_span_type type,
66void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, u8 destination_port, 92 bool bind, int *p_span_id);
93void mlxsw_sp_span_mirror_del(struct mlxsw_sp_port *from, int span_id,
67 enum mlxsw_sp_span_type type, bool bind); 94 enum mlxsw_sp_span_type type, bool bind);
68struct mlxsw_sp_span_entry * 95struct mlxsw_sp_span_entry *
69mlxsw_sp_span_entry_find(struct mlxsw_sp *mlxsw_sp, u8 local_port); 96mlxsw_sp_span_entry_find_by_port(struct mlxsw_sp *mlxsw_sp,
97 const struct net_device *to_dev);
98
99void mlxsw_sp_span_entry_invalidate(struct mlxsw_sp *mlxsw_sp,
100 struct mlxsw_sp_span_entry *span_entry);
70 101
71int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu); 102int mlxsw_sp_span_port_mtu_update(struct mlxsw_sp_port *port, u16 mtu);
72 103
diff --git a/include/net/gre.h b/include/net/gre.h
index f90585decbce..797142eee9cd 100644
--- a/include/net/gre.h
+++ b/include/net/gre.h
@@ -37,6 +37,9 @@ struct net_device *gretap_fb_dev_create(struct net *net, const char *name,
37int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, 37int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
38 bool *csum_err, __be16 proto, int nhs); 38 bool *csum_err, __be16 proto, int nhs);
39 39
40bool is_gretap_dev(const struct net_device *dev);
41bool is_ip6gretap_dev(const struct net_device *dev);
42
40static inline int gre_calc_hlen(__be16 o_flags) 43static inline int gre_calc_hlen(__be16 o_flags)
41{ 44{
42 int addend = 4; 45 int addend = 4;
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index 1f16773cfd76..cbe5addb9293 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -254,6 +254,22 @@ static inline __be32 tunnel_id_to_key32(__be64 tun_id)
254 254
255#ifdef CONFIG_INET 255#ifdef CONFIG_INET
256 256
257static inline void ip_tunnel_init_flow(struct flowi4 *fl4,
258 int proto,
259 __be32 daddr, __be32 saddr,
260 __be32 key, __u8 tos, int oif,
261 __u32 mark)
262{
263 memset(fl4, 0, sizeof(*fl4));
264 fl4->flowi4_oif = oif;
265 fl4->daddr = daddr;
266 fl4->saddr = saddr;
267 fl4->flowi4_tos = tos;
268 fl4->flowi4_proto = proto;
269 fl4->fl4_gre_key = key;
270 fl4->flowi4_mark = mark;
271}
272
257int ip_tunnel_init(struct net_device *dev); 273int ip_tunnel_init(struct net_device *dev);
258void ip_tunnel_uninit(struct net_device *dev); 274void ip_tunnel_uninit(struct net_device *dev);
259void ip_tunnel_dellink(struct net_device *dev, struct list_head *head); 275void ip_tunnel_dellink(struct net_device *dev, struct list_head *head);
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index e496afa47709..0fe1d69b5df4 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -1323,6 +1323,12 @@ static void ipgre_tap_setup(struct net_device *dev)
1323 ip_tunnel_setup(dev, gre_tap_net_id); 1323 ip_tunnel_setup(dev, gre_tap_net_id);
1324} 1324}
1325 1325
1326bool is_gretap_dev(const struct net_device *dev)
1327{
1328 return dev->netdev_ops == &gre_tap_netdev_ops;
1329}
1330EXPORT_SYMBOL_GPL(is_gretap_dev);
1331
1326static int ipgre_newlink(struct net *src_net, struct net_device *dev, 1332static int ipgre_newlink(struct net *src_net, struct net_device *dev,
1327 struct nlattr *tb[], struct nlattr *data[], 1333 struct nlattr *tb[], struct nlattr *data[],
1328 struct netlink_ext_ack *extack) 1334 struct netlink_ext_ack *extack)
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index d786a8441bce..b2117d89bc83 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -290,22 +290,6 @@ failed:
290 return ERR_PTR(err); 290 return ERR_PTR(err);
291} 291}
292 292
293static inline void init_tunnel_flow(struct flowi4 *fl4,
294 int proto,
295 __be32 daddr, __be32 saddr,
296 __be32 key, __u8 tos, int oif,
297 __u32 mark)
298{
299 memset(fl4, 0, sizeof(*fl4));
300 fl4->flowi4_oif = oif;
301 fl4->daddr = daddr;
302 fl4->saddr = saddr;
303 fl4->flowi4_tos = tos;
304 fl4->flowi4_proto = proto;
305 fl4->fl4_gre_key = key;
306 fl4->flowi4_mark = mark;
307}
308
309static int ip_tunnel_bind_dev(struct net_device *dev) 293static int ip_tunnel_bind_dev(struct net_device *dev)
310{ 294{
311 struct net_device *tdev = NULL; 295 struct net_device *tdev = NULL;
@@ -322,10 +306,10 @@ static int ip_tunnel_bind_dev(struct net_device *dev)
322 struct flowi4 fl4; 306 struct flowi4 fl4;
323 struct rtable *rt; 307 struct rtable *rt;
324 308
325 init_tunnel_flow(&fl4, iph->protocol, iph->daddr, 309 ip_tunnel_init_flow(&fl4, iph->protocol, iph->daddr,
326 iph->saddr, tunnel->parms.o_key, 310 iph->saddr, tunnel->parms.o_key,
327 RT_TOS(iph->tos), tunnel->parms.link, 311 RT_TOS(iph->tos), tunnel->parms.link,
328 tunnel->fwmark); 312 tunnel->fwmark);
329 rt = ip_route_output_key(tunnel->net, &fl4); 313 rt = ip_route_output_key(tunnel->net, &fl4);
330 314
331 if (!IS_ERR(rt)) { 315 if (!IS_ERR(rt)) {
@@ -581,8 +565,8 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, u8 proto)
581 else if (skb->protocol == htons(ETH_P_IPV6)) 565 else if (skb->protocol == htons(ETH_P_IPV6))
582 tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph); 566 tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph);
583 } 567 }
584 init_tunnel_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src, 0, 568 ip_tunnel_init_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src, 0,
585 RT_TOS(tos), tunnel->parms.link, tunnel->fwmark); 569 RT_TOS(tos), tunnel->parms.link, tunnel->fwmark);
586 if (tunnel->encap.type != TUNNEL_ENCAP_NONE) 570 if (tunnel->encap.type != TUNNEL_ENCAP_NONE)
587 goto tx_error; 571 goto tx_error;
588 rt = ip_route_output_key(tunnel->net, &fl4); 572 rt = ip_route_output_key(tunnel->net, &fl4);
@@ -711,14 +695,14 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
711 } 695 }
712 696
713 if (tunnel->fwmark) { 697 if (tunnel->fwmark) {
714 init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, 698 ip_tunnel_init_flow(&fl4, protocol, dst, tnl_params->saddr,
715 tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link, 699 tunnel->parms.o_key, RT_TOS(tos),
716 tunnel->fwmark); 700 tunnel->parms.link, tunnel->fwmark);
717 } 701 }
718 else { 702 else {
719 init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, 703 ip_tunnel_init_flow(&fl4, protocol, dst, tnl_params->saddr,
720 tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link, 704 tunnel->parms.o_key, RT_TOS(tos),
721 skb->mark); 705 tunnel->parms.link, skb->mark);
722 } 706 }
723 707
724 if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) 708 if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0)
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 3026662a6413..4f150a394387 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -1785,6 +1785,12 @@ static void ip6gre_tap_setup(struct net_device *dev)
1785 netif_keep_dst(dev); 1785 netif_keep_dst(dev);
1786} 1786}
1787 1787
1788bool is_ip6gretap_dev(const struct net_device *dev)
1789{
1790 return dev->netdev_ops == &ip6gre_tap_netdev_ops;
1791}
1792EXPORT_SYMBOL_GPL(is_ip6gretap_dev);
1793
1788static bool ip6gre_netlink_encap_parms(struct nlattr *data[], 1794static bool ip6gre_netlink_encap_parms(struct nlattr *data[],
1789 struct ip_tunnel_encap *ipencap) 1795 struct ip_tunnel_encap *ipencap)
1790{ 1796{