Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 431c7ec3 authored by David S. Miller's avatar David S. Miller
Browse files

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 63d63801 8f08a528
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -78,6 +78,10 @@ config MLXSW_SPECTRUM
	depends on IPV6 || IPV6=n
	select PARMAN
	select MLXFW
	depends on NET_IPGRE
	depends on !(MLXSW_CORE=y && NET_IPGRE=m)
	depends on IPV6_GRE
	depends on !(MLXSW_CORE=y && IPV6_GRE=m)
	default m
	---help---
	  This driver supports Mellanox Technologies Spectrum Ethernet
+8 −11
Original line number Diff line number Diff line
/*
 * drivers/net/ethernet/mellanox/mlxsw/core_acl_flex_actions.c
 * Copyright (c) 2017 Mellanox Technologies. All rights reserved.
 * Copyright (c) 2017, 2018 Mellanox Technologies. All rights reserved.
 * Copyright (c) 2017 Jiri Pirko <jiri@mellanox.com>
 *
 * Redistribution and use in source and binary forms, with or without
@@ -838,7 +838,6 @@ struct mlxsw_afa_mirror {
	struct mlxsw_afa_resource resource;
	int span_id;
	u8 local_in_port;
	u8 local_out_port;
	bool ingress;
};

@@ -848,7 +847,7 @@ mlxsw_afa_mirror_destroy(struct mlxsw_afa_block *block,
{
	block->afa->ops->mirror_del(block->afa->ops_priv,
				    mirror->local_in_port,
				    mirror->local_out_port,
				    mirror->span_id,
				    mirror->ingress);
	kfree(mirror);
}
@@ -864,9 +863,8 @@ mlxsw_afa_mirror_destructor(struct mlxsw_afa_block *block,
}

static struct mlxsw_afa_mirror *
mlxsw_afa_mirror_create(struct mlxsw_afa_block *block,
			u8 local_in_port, u8 local_out_port,
			bool ingress)
mlxsw_afa_mirror_create(struct mlxsw_afa_block *block, u8 local_in_port,
			const struct net_device *out_dev, bool ingress)
{
	struct mlxsw_afa_mirror *mirror;
	int err;
@@ -876,13 +874,12 @@ mlxsw_afa_mirror_create(struct mlxsw_afa_block *block,
		return ERR_PTR(-ENOMEM);

	err = block->afa->ops->mirror_add(block->afa->ops_priv,
					  local_in_port, local_out_port,
					  local_in_port, out_dev,
					  ingress, &mirror->span_id);
	if (err)
		goto err_mirror_add;

	mirror->ingress = ingress;
	mirror->local_out_port = local_out_port;
	mirror->local_in_port = local_in_port;
	mirror->resource.destructor = mlxsw_afa_mirror_destructor;
	mlxsw_afa_resource_add(block, &mirror->resource);
@@ -909,13 +906,13 @@ mlxsw_afa_block_append_allocated_mirror(struct mlxsw_afa_block *block,
}

int
mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block,
			      u8 local_in_port, u8 local_out_port, bool ingress)
mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block, u8 local_in_port,
			      const struct net_device *out_dev, bool ingress)
{
	struct mlxsw_afa_mirror *mirror;
	int err;

	mirror = mlxsw_afa_mirror_create(block, local_in_port, local_out_port,
	mirror = mlxsw_afa_mirror_create(block, local_in_port, out_dev,
					 ingress);
	if (IS_ERR(mirror))
		return PTR_ERR(mirror);
+6 −3
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#define _MLXSW_CORE_ACL_FLEX_ACTIONS_H

#include <linux/types.h>
#include <linux/netdevice.h>

struct mlxsw_afa;
struct mlxsw_afa_block;
@@ -48,9 +49,10 @@ struct mlxsw_afa_ops {
	void (*kvdl_fwd_entry_del)(void *priv, u32 kvdl_index);
	int (*counter_index_get)(void *priv, unsigned int *p_counter_index);
	void (*counter_index_put)(void *priv, unsigned int counter_index);
	int (*mirror_add)(void *priv, u8 locol_in_port, u8 local_out_port,
	int (*mirror_add)(void *priv, u8 local_in_port,
			  const struct net_device *out_dev,
			  bool ingress, int *p_span_id);
	void (*mirror_del)(void *priv, u8 locol_in_port, u8 local_out_port,
	void (*mirror_del)(void *priv, u8 local_in_port, int span_id,
			   bool ingress);
};

@@ -70,7 +72,8 @@ int mlxsw_afa_block_append_trap(struct mlxsw_afa_block *block, u16 trap_id);
int mlxsw_afa_block_append_trap_and_forward(struct mlxsw_afa_block *block,
					    u16 trap_id);
int mlxsw_afa_block_append_mirror(struct mlxsw_afa_block *block,
				  u8 local_in_port, u8 local_out_port,
				  u8 local_in_port,
				  const struct net_device *out_dev,
				  bool ingress);
int mlxsw_afa_block_append_fwd(struct mlxsw_afa_block *block,
			       u8 local_port, bool in_port);
+142 −3
Original line number Diff line number Diff line
/*
 * drivers/net/ethernet/mellanox/mlxsw/reg.h
 * Copyright (c) 2015-2017 Mellanox Technologies. All rights reserved.
 * Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved.
 * Copyright (c) 2015-2016 Ido Schimmel <idosch@mellanox.com>
 * Copyright (c) 2015 Elad Raz <eladr@mellanox.com>
 * Copyright (c) 2015-2017 Jiri Pirko <jiri@mellanox.com>
 * Copyright (c) 2016 Yotam Gigi <yotamg@mellanox.com>
 * Copyright (c) 2017 Petr Machata <petrm@mellanox.com>
 * Copyright (c) 2017-2018 Petr Machata <petrm@mellanox.com>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
@@ -6772,8 +6772,104 @@ MLXSW_ITEM32(reg, mpat, qos, 0x04, 26, 1);
 */
MLXSW_ITEM32(reg, mpat, be, 0x04, 25, 1);

enum mlxsw_reg_mpat_span_type {
	/* Local SPAN Ethernet.
	 * The original packet is not encapsulated.
	 */
	MLXSW_REG_MPAT_SPAN_TYPE_LOCAL_ETH = 0x0,

	/* Encapsulated Remote SPAN Ethernet L3 GRE.
	 * The packet is encapsulated with GRE header.
	 */
	MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3 = 0x3,
};

/* reg_mpat_span_type
 * SPAN type.
 * Access: RW
 */
MLXSW_ITEM32(reg, mpat, span_type, 0x04, 0, 4);

/* Remote SPAN - Ethernet VLAN
 * - - - - - - - - - - - - - -
 */

/* reg_mpat_eth_rspan_vid
 * Encapsulation header VLAN ID.
 * Access: RW
 */
MLXSW_ITEM32(reg, mpat, eth_rspan_vid, 0x18, 0, 12);

/* Encapsulated Remote SPAN - Ethernet L2
 * - - - - - - - - - - - - - - - - - - -
 */

enum mlxsw_reg_mpat_eth_rspan_version {
	MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER = 15,
};

/* reg_mpat_eth_rspan_version
 * RSPAN mirror header version.
 * Access: RW
 */
MLXSW_ITEM32(reg, mpat, eth_rspan_version, 0x10, 18, 4);

/* reg_mpat_eth_rspan_mac
 * Destination MAC address.
 * Access: RW
 */
MLXSW_ITEM_BUF(reg, mpat, eth_rspan_mac, 0x12, 6);

/* reg_mpat_eth_rspan_tp
 * Tag Packet. Indicates whether the mirroring header should be VLAN tagged.
 * Access: RW
 */
MLXSW_ITEM32(reg, mpat, eth_rspan_tp, 0x18, 16, 1);

/* Encapsulated Remote SPAN - Ethernet L3
 * - - - - - - - - - - - - - - - - - - -
 */

enum mlxsw_reg_mpat_eth_rspan_protocol {
	MLXSW_REG_MPAT_ETH_RSPAN_PROTOCOL_IPV4,
	MLXSW_REG_MPAT_ETH_RSPAN_PROTOCOL_IPV6,
};

/* reg_mpat_eth_rspan_protocol
 * SPAN encapsulation protocol.
 * Access: RW
 */
MLXSW_ITEM32(reg, mpat, eth_rspan_protocol, 0x18, 24, 4);

/* reg_mpat_eth_rspan_ttl
 * Encapsulation header Time-to-Live/HopLimit.
 * Access: RW
 */
MLXSW_ITEM32(reg, mpat, eth_rspan_ttl, 0x1C, 4, 8);

/* reg_mpat_eth_rspan_smac
 * Source MAC address
 * Access: RW
 */
MLXSW_ITEM_BUF(reg, mpat, eth_rspan_smac, 0x22, 6);

/* reg_mpat_eth_rspan_dip*
 * Destination IP address. The IP version is configured by protocol.
 * Access: RW
 */
MLXSW_ITEM32(reg, mpat, eth_rspan_dip4, 0x4C, 0, 32);
MLXSW_ITEM_BUF(reg, mpat, eth_rspan_dip6, 0x40, 16);

/* reg_mpat_eth_rspan_sip*
 * Source IP address. The IP version is configured by protocol.
 * Access: RW
 */
MLXSW_ITEM32(reg, mpat, eth_rspan_sip4, 0x5C, 0, 32);
MLXSW_ITEM_BUF(reg, mpat, eth_rspan_sip6, 0x50, 16);

static inline void mlxsw_reg_mpat_pack(char *payload, u8 pa_id,
				       u16 system_port, bool e)
				       u16 system_port, bool e,
				       enum mlxsw_reg_mpat_span_type span_type)
{
	MLXSW_REG_ZERO(mpat, payload);
	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,
	mlxsw_reg_mpat_e_set(payload, e);
	mlxsw_reg_mpat_qos_set(payload, 1);
	mlxsw_reg_mpat_be_set(payload, 1);
	mlxsw_reg_mpat_span_type_set(payload, span_type);
}

static inline void mlxsw_reg_mpat_eth_rspan_pack(char *payload, u16 vid)
{
	mlxsw_reg_mpat_eth_rspan_vid_set(payload, vid);
}

static inline void
mlxsw_reg_mpat_eth_rspan_l2_pack(char *payload,
				 enum mlxsw_reg_mpat_eth_rspan_version version,
				 const char *mac,
				 bool tp)
{
	mlxsw_reg_mpat_eth_rspan_version_set(payload, version);
	mlxsw_reg_mpat_eth_rspan_mac_memcpy_to(payload, mac);
	mlxsw_reg_mpat_eth_rspan_tp_set(payload, tp);
}

static inline void
mlxsw_reg_mpat_eth_rspan_l3_ipv4_pack(char *payload, u8 ttl,
				      const char *smac,
				      u32 sip, u32 dip)
{
	mlxsw_reg_mpat_eth_rspan_ttl_set(payload, ttl);
	mlxsw_reg_mpat_eth_rspan_smac_memcpy_to(payload, smac);
	mlxsw_reg_mpat_eth_rspan_protocol_set(payload,
				    MLXSW_REG_MPAT_ETH_RSPAN_PROTOCOL_IPV4);
	mlxsw_reg_mpat_eth_rspan_sip4_set(payload, sip);
	mlxsw_reg_mpat_eth_rspan_dip4_set(payload, dip);
}

static inline void
mlxsw_reg_mpat_eth_rspan_l3_ipv6_pack(char *payload, u8 ttl,
				      const char *smac,
				      struct in6_addr sip, struct in6_addr dip)
{
	mlxsw_reg_mpat_eth_rspan_ttl_set(payload, ttl);
	mlxsw_reg_mpat_eth_rspan_smac_memcpy_to(payload, smac);
	mlxsw_reg_mpat_eth_rspan_protocol_set(payload,
				    MLXSW_REG_MPAT_ETH_RSPAN_PROTOCOL_IPV6);
	mlxsw_reg_mpat_eth_rspan_sip6_memcpy_to(payload, (void *)&sip);
	mlxsw_reg_mpat_eth_rspan_dip6_memcpy_to(payload, (void *)&dip);
}

/* MPAR - Monitoring Port Analyzer Register
+27 −23
Original line number Diff line number Diff line
/*
 * drivers/net/ethernet/mellanox/mlxsw/spectrum.c
 * Copyright (c) 2015-2017 Mellanox Technologies. All rights reserved.
 * Copyright (c) 2015-2018 Mellanox Technologies. All rights reserved.
 * Copyright (c) 2015-2017 Jiri Pirko <jiri@mellanox.com>
 * Copyright (c) 2015 Ido Schimmel <idosch@mellanox.com>
 * 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,
				      bool ingress)
{
	enum mlxsw_sp_span_type span_type;
	struct mlxsw_sp_port *to_port;
	struct net_device *to_dev;

	to_dev = tcf_mirred_dev(a);
@@ -1267,17 +1266,10 @@ mlxsw_sp_port_add_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,
		return -EINVAL;
	}

	if (!mlxsw_sp_port_dev_check(to_dev)) {
		netdev_err(mlxsw_sp_port->dev, "Cannot mirror to a non-spectrum port");
		return -EOPNOTSUPP;
	}
	to_port = netdev_priv(to_dev);

	mirror->to_local_port = to_port->local_port;
	mirror->ingress = ingress;
	span_type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
	return mlxsw_sp_span_mirror_add(mlxsw_sp_port, to_port, span_type,
					true);
	return mlxsw_sp_span_mirror_add(mlxsw_sp_port, to_dev, span_type,
					true, &mirror->span_id);
}

static void
@@ -1288,7 +1280,7 @@ mlxsw_sp_port_del_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,

	span_type = mirror->ingress ?
			MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
	mlxsw_sp_span_mirror_del(mlxsw_sp_port, mirror->to_local_port,
	mlxsw_sp_span_mirror_del(mlxsw_sp_port, mirror->span_id,
				 span_type, true);
}

@@ -3675,14 +3667,24 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
		goto err_afa_init;
	}

	err = mlxsw_sp_span_init(mlxsw_sp);
	if (err) {
		dev_err(mlxsw_sp->bus_info->dev, "Failed to init span system\n");
		goto err_span_init;
	}

	/* Initialize router after SPAN is initialized, so that the FIB and
	 * neighbor event handlers can issue SPAN respin.
	 */
	err = mlxsw_sp_router_init(mlxsw_sp);
	if (err) {
		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize router\n");
		goto err_router_init;
	}

	/* Initialize netdevice notifier after router is initialized, so that
	 * the event handler can use router structures.
	/* Initialize netdevice notifier after router and SPAN is initialized,
	 * so that the event handler can use router structures and call SPAN
	 * respin.
	 */
	mlxsw_sp->netdevice_nb.notifier_call = mlxsw_sp_netdevice_event;
	err = register_netdevice_notifier(&mlxsw_sp->netdevice_nb);
@@ -3691,12 +3693,6 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
		goto err_netdev_notifier;
	}

	err = mlxsw_sp_span_init(mlxsw_sp);
	if (err) {
		dev_err(mlxsw_sp->bus_info->dev, "Failed to init span system\n");
		goto err_span_init;
	}

	err = mlxsw_sp_acl_init(mlxsw_sp);
	if (err) {
		dev_err(mlxsw_sp->bus_info->dev, "Failed to initialize ACL\n");
@@ -3722,12 +3718,12 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
err_dpipe_init:
	mlxsw_sp_acl_fini(mlxsw_sp);
err_acl_init:
	mlxsw_sp_span_fini(mlxsw_sp);
err_span_init:
	unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb);
err_netdev_notifier:
	mlxsw_sp_router_fini(mlxsw_sp);
err_router_init:
	mlxsw_sp_span_fini(mlxsw_sp);
err_span_init:
	mlxsw_sp_afa_fini(mlxsw_sp);
err_afa_init:
	mlxsw_sp_counter_pool_fini(mlxsw_sp);
@@ -3753,9 +3749,9 @@ static void mlxsw_sp_fini(struct mlxsw_core *mlxsw_core)
	mlxsw_sp_ports_remove(mlxsw_sp);
	mlxsw_sp_dpipe_fini(mlxsw_sp);
	mlxsw_sp_acl_fini(mlxsw_sp);
	mlxsw_sp_span_fini(mlxsw_sp);
	unregister_netdevice_notifier(&mlxsw_sp->netdevice_nb);
	mlxsw_sp_router_fini(mlxsw_sp);
	mlxsw_sp_span_fini(mlxsw_sp);
	mlxsw_sp_afa_fini(mlxsw_sp);
	mlxsw_sp_counter_pool_fini(mlxsw_sp);
	mlxsw_sp_switchdev_fini(mlxsw_sp);
@@ -4639,10 +4635,18 @@ static int mlxsw_sp_netdevice_event(struct notifier_block *nb,
				    unsigned long event, void *ptr)
{
	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
	struct mlxsw_sp_span_entry *span_entry;
	struct mlxsw_sp *mlxsw_sp;
	int err = 0;

	mlxsw_sp = container_of(nb, struct mlxsw_sp, netdevice_nb);
	if (event == NETDEV_UNREGISTER) {
		span_entry = mlxsw_sp_span_entry_find_by_port(mlxsw_sp, dev);
		if (span_entry)
			mlxsw_sp_span_entry_invalidate(mlxsw_sp, span_entry);
	}
	mlxsw_sp_span_respin(mlxsw_sp);

	if (mlxsw_sp_netdev_is_ipip_ol(mlxsw_sp, dev))
		err = mlxsw_sp_netdevice_ipip_ol_event(mlxsw_sp, dev,
						       event, ptr);
Loading