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

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

Merge branch 'mlxsw-fw-mark-offload'



Jiri Pirko says:

====================
mlxsw: Introduce support for offload forward mark

Ido says:
This patchset enables the forwarding of certain control packets by the
device instead of relying on the CPU to do the forwarding.

The first two patches simplify the current switchdev offload forward
infrastructure and make it usable for stacked devices. This is done by
moving the packet and port marking to the bridge driver instead of the
switch driver.

Patches 3-5 add the mlxsw specific bits to support the forward mark.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2a313cdf 1c6c6d22
Loading
Loading
Loading
Loading
+4 −9
Original line number Diff line number Diff line
@@ -283,15 +283,10 @@ be sent to the port netdev for processing by the bridge driver. The
bridge should not reflood the packet to the same ports the device flooded,
otherwise there will be duplicate packets on the wire.

To avoid duplicate packets, the device/driver should mark a packet as already
forwarded using skb->offload_fwd_mark.  The same mark is set on the device
ports in the domain using dev->offload_fwd_mark.  If the skb->offload_fwd_mark
is non-zero and matches the forwarding egress port's dev->skb_mark, the kernel
will drop the skb right before transmit on the egress port, with the
understanding that the device already forwarded the packet on same egress port.
The driver can use switchdev_port_fwd_mark_set() to set a globally unique mark
for port's dev->offload_fwd_mark, based on the port's parent ID (switch ID) and
a group ifindex.
To avoid duplicate packets, the switch driver should mark a packet as already
forwarded by setting the skb->offload_fwd_mark bit. The bridge driver will mark
the skb using the ingress bridge port's mark and prevent it from being forwarded
through any bridge port with the same mark.

It is possible for the switch device to not handle flooding and push the
packets up to the bridge driver for flooding.  This is not ideal as the number
+1 −0
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ struct mlxsw_rx_listener {
	void (*func)(struct sk_buff *skb, u8 local_port, void *priv);
	u8 local_port;
	u16 trap_id;
	enum mlxsw_reg_hpkt_action action;
};

struct mlxsw_event_listener {
+40 −116
Original line number Diff line number Diff line
@@ -2570,123 +2570,47 @@ static void mlxsw_sp_rx_listener_func(struct sk_buff *skb, u8 local_port,
	netif_receive_skb(skb);
}

static const struct mlxsw_rx_listener mlxsw_sp_rx_listener[] = {
static void mlxsw_sp_rx_listener_mark_func(struct sk_buff *skb, u8 local_port,
					   void *priv)
{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_FDB_MC,
	},
	skb->offload_fwd_mark = 1;
	return mlxsw_sp_rx_listener_func(skb, local_port, priv);
}

#define MLXSW_SP_RXL(_func, _trap_id, _action)			\
	{							\
		.func = _func,					\
		.local_port = MLXSW_PORT_DONT_CARE,		\
		.trap_id = MLXSW_TRAP_ID_##_trap_id,		\
		.action = MLXSW_REG_HPKT_ACTION_##_action,	\
	}

static const struct mlxsw_rx_listener mlxsw_sp_rx_listener[] = {
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, FDB_MC, TRAP_TO_CPU),
	/* Traps for specific L2 packet types, not trapped as FDB MC */
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_STP,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_LACP,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_EAPOL,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_LLDP,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_MMRP,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_MVRP,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_RPVST,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_DHCP,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_IGMP_QUERY,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_IGMP_V1_REPORT,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_IGMP_V2_REPORT,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_IGMP_V2_LEAVE,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_IGMP_V3_REPORT,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_ARPBC,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_ARPUC,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_MTUERROR,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_TTLERROR,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_LBERROR,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_OSPF,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_IP2ME,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_RTR_INGRESS0,
	},
	{
		.func = mlxsw_sp_rx_listener_func,
		.local_port = MLXSW_PORT_DONT_CARE,
		.trap_id = MLXSW_TRAP_ID_HOST_MISS_IPV4,
	},
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, STP, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, LACP, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, EAPOL, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, LLDP, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, MMRP, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, MVRP, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, RPVST, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_mark_func, DHCP, MIRROR_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_mark_func, IGMP_QUERY, MIRROR_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, IGMP_V1_REPORT, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, IGMP_V2_REPORT, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, IGMP_V2_LEAVE, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, IGMP_V3_REPORT, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_mark_func, ARPBC, MIRROR_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_mark_func, ARPUC, MIRROR_TO_CPU),
	/* L3 traps */
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, MTUERROR, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, TTLERROR, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, LBERROR, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_mark_func, OSPF, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, IP2ME, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, RTR_INGRESS0, TRAP_TO_CPU),
	MLXSW_SP_RXL(mlxsw_sp_rx_listener_func, HOST_MISS_IPV4, TRAP_TO_CPU),
};

static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)
@@ -2713,7 +2637,7 @@ static int mlxsw_sp_traps_init(struct mlxsw_sp *mlxsw_sp)
		if (err)
			goto err_rx_listener_register;

		mlxsw_reg_hpkt_pack(hpkt_pl, MLXSW_REG_HPKT_ACTION_TRAP_TO_CPU,
		mlxsw_reg_hpkt_pack(hpkt_pl, mlxsw_sp_rx_listener[i].action,
				    mlxsw_sp_rx_listener[i].trap_id);
		err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(hpkt), hpkt_pl);
		if (err)
+1 −1
Original line number Diff line number Diff line
@@ -2412,7 +2412,7 @@ static int rocker_port_rx_proc(const struct rocker *rocker,
	skb->protocol = eth_type_trans(skb, rocker_port->dev);

	if (rx_flags & ROCKER_RX_FLAGS_FWD_OFFLOAD)
		skb->offload_fwd_mark = rocker_port->dev->offload_fwd_mark;
		skb->offload_fwd_mark = 1;

	rocker_port->dev->stats.rx_packets++;
	rocker_port->dev->stats.rx_bytes += skb->len;
+0 −4
Original line number Diff line number Diff line
@@ -2558,7 +2558,6 @@ static int ofdpa_port_init(struct rocker_port *rocker_port)
	struct ofdpa_port *ofdpa_port = rocker_port->wpriv;
	int err;

	switchdev_port_fwd_mark_set(ofdpa_port->dev, NULL, false);
	rocker_port_set_learning(rocker_port,
				 !!(ofdpa_port->brport_flags & BR_LEARNING));

@@ -2817,7 +2816,6 @@ static int ofdpa_port_bridge_join(struct ofdpa_port *ofdpa_port,
		ofdpa_port_internal_vlan_id_get(ofdpa_port, bridge->ifindex);

	ofdpa_port->bridge_dev = bridge;
	switchdev_port_fwd_mark_set(ofdpa_port->dev, bridge, true);

	return ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0);
}
@@ -2836,8 +2834,6 @@ static int ofdpa_port_bridge_leave(struct ofdpa_port *ofdpa_port)
		ofdpa_port_internal_vlan_id_get(ofdpa_port,
						ofdpa_port->dev->ifindex);

	switchdev_port_fwd_mark_set(ofdpa_port->dev, ofdpa_port->bridge_dev,
				    false);
	ofdpa_port->bridge_dev = NULL;

	err = ofdpa_port_vlan_add(ofdpa_port, NULL, OFDPA_UNTAGGED_VID, 0);
Loading