public inbox for netdev@vger.kernel.org 
 help / color / mirror / Atom feed
From: Jiri Pirko <jiri@resnulli•us>
To: netdev@vger•kernel.org
Cc: davem@davemloft•net, petrm@mellanox•com, idosch@mellanox•com,
	mlxsw@mellanox•com, xeb@mail•ru, dsa@cumulusnetworks•com
Subject: [patch net-next 14/15] mlxsw: spectrum_span: Support mirror to gretap
Date: Tue, 27 Feb 2018 14:53:48 +0100	[thread overview]
Message-ID: <20180227135349.11637-15-jiri@resnulli.us> (raw)
In-Reply-To: <20180227135349.11637-1-jiri@resnulli.us>

From: Petr Machata <petrm@mellanox•com>

When a user requests mirror from a mlxsw physical port (possibly based
on an ACL match) to a gretap netdevice, the driver needs to resolve the
request to a particular physical port that the mirrored packets will
egress through, and a suite of configuration keys (importantly, IP and
MAC addresses). That means calling into routing and neighbor kernel code
to simulate the decisions made by the system for packets passing through
a gretap netdevice.

Add a new instance of mlxsw_sp_span_entry_ops to support this.

Signed-off-by: Petr Machata <petrm@mellanox•com>
Reviewed-by: Ido Schimmel <idosch@mellanox•com>
Signed-off-by: Jiri Pirko <jiri@mellanox•com>
---
 drivers/net/ethernet/mellanox/mlxsw/Kconfig        |   2 +
 .../net/ethernet/mellanox/mlxsw/spectrum_span.c    | 167 ++++++++++++++++++++-
 .../net/ethernet/mellanox/mlxsw/spectrum_span.h    |   8 +
 3 files changed, 175 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
index d56eea310509..830c3e28505e 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
@@ -78,6 +78,8 @@ config MLXSW_SPECTRUM
 	depends on IPV6 || IPV6=n
 	select PARMAN
 	select MLXFW
+	depends on NET_IPGRE
+	depends on !(MLXSW_CORE=y && NET_IPGRE=m)
 	default m
 	---help---
 	  This driver supports Mellanox Technologies Spectrum Ethernet
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
index 57df57c7a405..d5fda4f13c31 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.c
@@ -1,6 +1,7 @@
 /*
  * drivers/net/ethernet/mellanox/mlxsw/mlxsw_span.c
  * Copyright (c) 2018 Mellanox Technologies. All rights reserved.
+ * Copyright (c) 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:
@@ -32,9 +33,12 @@
  */
 
 #include <linux/list.h>
+#include <net/arp.h>
+#include <net/gre.h>
 
 #include "spectrum.h"
 #include "spectrum_span.h"
+#include "spectrum_ipip.h"
 
 int mlxsw_sp_span_init(struct mlxsw_sp *mlxsw_sp)
 {
@@ -127,17 +131,176 @@ struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_phys = {
 	.deconfigure = mlxsw_sp_span_entry_phys_deconfigure,
 };
 
+static struct net_device *
+mlxsw_sp_span_gretap4_route(const struct net_device *to_dev,
+			    __be32 *saddrp, __be32 *daddrp)
+{
+	struct ip_tunnel *tun = netdev_priv(to_dev);
+	struct net_device *dev = NULL;
+	struct ip_tunnel_parm parms;
+	struct rtable *rt = NULL;
+	struct flowi4 fl4;
+
+	/* We assume "dev" stays valid after rt is put. */
+	ASSERT_RTNL();
+
+	parms = mlxsw_sp_ipip_netdev_parms4(to_dev);
+	ip_tunnel_init_flow(&fl4, parms.iph.protocol, *daddrp, *saddrp,
+			    0, 0, parms.link, tun->fwmark);
+
+	rt = ip_route_output_key(tun->net, &fl4);
+	if (IS_ERR(rt))
+		return NULL;
+
+	if (rt->rt_type != RTN_UNICAST)
+		goto out;
+
+	dev = rt->dst.dev;
+	*saddrp = fl4.saddr;
+	*daddrp = rt->rt_gateway;
+
+out:
+	ip_rt_put(rt);
+	return dev;
+}
+
+static int mlxsw_sp_span_dmac(struct neigh_table *tbl,
+			      const void *pkey,
+			      struct net_device *l3edev,
+			      unsigned char dmac[ETH_ALEN])
+{
+	struct neighbour *neigh = neigh_lookup(tbl, pkey, l3edev);
+	int err = 0;
+
+	if (!neigh) {
+		neigh = neigh_create(tbl, pkey, l3edev);
+		if (IS_ERR(neigh))
+			return PTR_ERR(neigh);
+	}
+
+	neigh_event_send(neigh, NULL);
+
+	read_lock_bh(&neigh->lock);
+	if ((neigh->nud_state & NUD_VALID) && !neigh->dead)
+		memcpy(dmac, neigh->ha, ETH_ALEN);
+	else
+		err = -ENOENT;
+	read_unlock_bh(&neigh->lock);
+
+	neigh_release(neigh);
+	return err;
+}
+
+static int
+mlxsw_sp_span_entry_unoffloadable(struct mlxsw_sp_span_parms *sparmsp)
+{
+	sparmsp->dest_port = NULL;
+	return 0;
+}
+
+static int
+mlxsw_sp_span_entry_tunnel_parms_common(struct net_device *l3edev,
+					union mlxsw_sp_l3addr saddr,
+					union mlxsw_sp_l3addr daddr,
+					union mlxsw_sp_l3addr gw,
+					__u8 ttl,
+					struct neigh_table *tbl,
+					struct mlxsw_sp_span_parms *sparmsp)
+{
+	unsigned char dmac[ETH_ALEN];
+
+	if (mlxsw_sp_l3addr_is_zero(gw))
+		gw = daddr;
+
+	if (!l3edev || !mlxsw_sp_port_dev_check(l3edev) ||
+	    mlxsw_sp_span_dmac(tbl, &gw, l3edev, dmac))
+		return mlxsw_sp_span_entry_unoffloadable(sparmsp);
+
+	sparmsp->dest_port = netdev_priv(l3edev);
+	sparmsp->ttl = ttl;
+	memcpy(sparmsp->dmac, dmac, ETH_ALEN);
+	memcpy(sparmsp->smac, l3edev->dev_addr, ETH_ALEN);
+	sparmsp->saddr = saddr;
+	sparmsp->daddr = daddr;
+	return 0;
+}
+
+static int
+mlxsw_sp_span_entry_gretap4_parms(const struct net_device *to_dev,
+				  struct mlxsw_sp_span_parms *sparmsp)
+{
+	struct ip_tunnel_parm tparm = mlxsw_sp_ipip_netdev_parms4(to_dev);
+	union mlxsw_sp_l3addr saddr = { .addr4 = tparm.iph.saddr };
+	union mlxsw_sp_l3addr daddr = { .addr4 = tparm.iph.daddr };
+	bool inherit_tos = tparm.iph.tos & 0x1;
+	bool inherit_ttl = !tparm.iph.ttl;
+	union mlxsw_sp_l3addr gw = daddr;
+	struct net_device *l3edev;
+
+	if (!(to_dev->flags & IFF_UP) ||
+	    /* Reject tunnels with GRE keys, checksums, etc. */
+	    tparm.i_flags || tparm.o_flags ||
+	    /* Require a fixed TTL and a TOS copied from the mirrored packet. */
+	    inherit_ttl || !inherit_tos ||
+	    /* A destination address may not be "any". */
+	    mlxsw_sp_l3addr_is_zero(daddr))
+		return mlxsw_sp_span_entry_unoffloadable(sparmsp);
+
+	l3edev = mlxsw_sp_span_gretap4_route(to_dev, &saddr.addr4, &gw.addr4);
+	return mlxsw_sp_span_entry_tunnel_parms_common(l3edev, saddr, daddr, gw,
+						       tparm.iph.ttl,
+						       &arp_tbl, sparmsp);
+}
+
+static int
+mlxsw_sp_span_entry_gretap4_configure(struct mlxsw_sp_span_entry *span_entry,
+				      struct mlxsw_sp_span_parms sparms)
+{
+	struct mlxsw_sp_port *dest_port = sparms.dest_port;
+	struct mlxsw_sp *mlxsw_sp = dest_port->mlxsw_sp;
+	u8 local_port = dest_port->local_port;
+	char mpat_pl[MLXSW_REG_MPAT_LEN];
+	int pa_id = span_entry->id;
+
+	/* Create a new port analayzer entry for local_port. */
+	mlxsw_reg_mpat_pack(mpat_pl, pa_id, local_port, true,
+			    MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3);
+	mlxsw_reg_mpat_eth_rspan_l2_pack(mpat_pl,
+				    MLXSW_REG_MPAT_ETH_RSPAN_VERSION_NO_HEADER,
+				    sparms.dmac, false);
+	mlxsw_reg_mpat_eth_rspan_l3_ipv4_pack(mpat_pl,
+					      sparms.ttl, sparms.smac,
+					      be32_to_cpu(sparms.saddr.addr4),
+					      be32_to_cpu(sparms.daddr.addr4));
+
+	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(mpat), mpat_pl);
+}
+
+static void
+mlxsw_sp_span_entry_gretap4_deconfigure(struct mlxsw_sp_span_entry *span_entry)
+{
+	mlxsw_sp_span_entry_deconfigure_common(span_entry,
+					MLXSW_REG_MPAT_SPAN_TYPE_REMOTE_ETH_L3);
+}
+
+static const struct mlxsw_sp_span_entry_ops mlxsw_sp_span_entry_ops_gretap4 = {
+	.can_handle = is_gretap_dev,
+	.parms = mlxsw_sp_span_entry_gretap4_parms,
+	.configure = mlxsw_sp_span_entry_gretap4_configure,
+	.deconfigure = mlxsw_sp_span_entry_gretap4_deconfigure,
+};
+
 static const
 struct mlxsw_sp_span_entry_ops *const mlxsw_sp_span_entry_types[] = {
 	&mlxsw_sp_span_entry_ops_phys,
+	&mlxsw_sp_span_entry_ops_gretap4,
 };
 
 static int
 mlxsw_sp_span_entry_nop_parms(const struct net_device *to_dev,
 			      struct mlxsw_sp_span_parms *sparmsp)
 {
-	sparmsp->dest_port = NULL;
-	return 0;
+	return mlxsw_sp_span_entry_unoffloadable(sparmsp);
 }
 
 static int
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h
index b6dcd7d7277c..948aceb512c5 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_span.h
@@ -35,6 +35,9 @@
 #define _MLXSW_SPECTRUM_SPAN_H
 
 #include <linux/types.h>
+#include <linux/if_ether.h>
+
+#include "spectrum_router.h"
 
 struct mlxsw_sp;
 struct mlxsw_sp_port;
@@ -52,6 +55,11 @@ struct mlxsw_sp_span_inspected_port {
 
 struct mlxsw_sp_span_parms {
 	struct mlxsw_sp_port *dest_port; /* NULL for unoffloaded SPAN. */
+	unsigned int ttl;
+	unsigned char dmac[ETH_ALEN];
+	unsigned char smac[ETH_ALEN];
+	union mlxsw_sp_l3addr daddr;
+	union mlxsw_sp_l3addr saddr;
 };
 
 struct mlxsw_sp_span_entry_ops;
-- 
2.14.3

  parent reply	other threads:[~2018-02-27 13:54 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-27 13:53 [patch net-next 00/15] mlxsw: Offloading encapsulated SPAN Jiri Pirko
2018-02-27 13:53 ` [patch net-next 01/15] mlxsw: spectrum_ipip: Extract mlxsw_sp_l3addr_is_zero Jiri Pirko
2018-02-27 13:53 ` [patch net-next 02/15] mlxsw: spectrum_ipip: Support decoding IPv6 tunnel addresses Jiri Pirko
2018-02-27 13:53 ` [patch net-next 03/15] net: GRE: Add is_gretap_dev, is_ip6gretap_dev Jiri Pirko
2018-02-27 13:53 ` [patch net-next 04/15] ip_tunnel: Rename & publish init_tunnel_flow Jiri Pirko
2018-02-27 13:53 ` [patch net-next 05/15] mlxsw: reg: Add SPAN encapsulation to MPAT register Jiri Pirko
2018-02-27 13:53 ` [patch net-next 06/15] mlxsw: reg: Extend mlxsw_reg_mpat_pack() Jiri Pirko
2018-02-27 13:53 ` [patch net-next 07/15] mlxsw: span: Remove span_entry by span_id Jiri Pirko
2018-02-27 13:53 ` [patch net-next 08/15] mlxsw: spectrum_span: Initialize span_entry.id eagerly Jiri Pirko
2018-02-27 13:53 ` [patch net-next 09/15] mlxsw: spectrum_span: Extract mlxsw_sp_span_entry_{de,}configure() Jiri Pirko
2018-02-27 13:53 ` [patch net-next 10/15] mlxsw: spectrum: Keep mirror netdev in mlxsw_sp_span_entry Jiri Pirko
2018-02-27 13:53 ` [patch net-next 11/15] mlxsw: spectrum_span: Generalize SPAN support Jiri Pirko
2018-02-27 13:53 ` [patch net-next 12/15] mlxsw: Handle config changes pertinent to SPAN Jiri Pirko
2018-02-27 13:53 ` [patch net-next 13/15] mlxsw: Move a mirroring check to mlxsw_sp_span_entry_create Jiri Pirko
2018-02-27 13:53 ` Jiri Pirko [this message]
2018-02-27 13:53 ` [patch net-next 15/15] mlxsw: spectrum_span: Support mirror to ip6gretap Jiri Pirko
2018-02-27 20:17   ` David Ahern
2018-02-27 21:08     ` Petr Machata
2018-02-28 14:35     ` Petr Machata
2018-02-27 19:52 ` [patch net-next 00/15] mlxsw: Offloading encapsulated SPAN David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180227135349.11637-15-jiri@resnulli.us \
    --to=jiri@resnulli$(echo .)us \
    --cc=davem@davemloft$(echo .)net \
    --cc=dsa@cumulusnetworks$(echo .)com \
    --cc=idosch@mellanox$(echo .)com \
    --cc=mlxsw@mellanox$(echo .)com \
    --cc=netdev@vger$(echo .)kernel.org \
    --cc=petrm@mellanox$(echo .)com \
    --cc=xeb@mail$(echo .)ru \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox