From: Scott Feldman <redacted>
v3:
- Per Nicolas Dichtel review: remove errant empty union.
v2:
- Per davem review: in sk_buff, union fwd_mark with secmark to save space
since features appear to be mutually exclusive.
- Per Simon Horman review:
- fix grammar in switchdev.txt wrt fwd_mark
- remove some unrelated changes that snuck in
v1:
This patchset was previously submitted as RFC. No changes from the last
version (v2) sent under RFC. Including RFC version history here for reference.
RFC v2:
- s/fwd_mark/offload_fwd_mark
- use consume_skb rather than kfree_skb when dropping pkt on egress.
- Use Jiri's suggestion to use ifindex of one of the ports in a group
as the mark for all the ports in the group. This can be done with
no additional storage (no hashtable from v1). To pull it off, we
need some simple recursive routines to walk the netdev tree ensuring
all leaves in the tree (ports) in the same group (e.g. bridge)
belonging to the same switch device will have the same offload fwd mark.
Maybe someone sees a better design for the recusive routines? They're
not too bad, and should cover the stacked driver cases.
RFC v1:
With switchdev support for offloading L2/L3 forwarding data path to a
switch device, we have a general problem where both the device and the
kernel may forward the packet, resulting in duplicate packets on the wire.
Anytime a packet is forwarded by the device and a copy is sent to the CPU,
there is potential for duplicate forwarding, as the kernel may also do a
forwarding lookup and send the packet on the wire.
The specific problem this patch series is interested in solving is avoiding
duplicate packets on bridged ports. There was a previous RFC from Roopa
(http://marc.info/?l=linux-netdev&m=142687073314252&w=2) to address this
problem, but didn't solve the problem of mixed ports in the bridge from
different devices; there was no way to exclude some ports from forwarding
and include others. This RFC solves that problem by tagging the ingressing
packet with a unique mark, and then comparing the packet mark with the
egress port mark, and skip forwarding when there is a match. For the mixed
ports bridge case, only those ports with matching marks are skipped.
The switchdev port driver must do two things:
1) Generate a fwd_mark for each switch port, using some unique key of the
switch device (and optionally port). This is done when the port netdev
is registered or if the port's group membership changes (joins/leaves
a bridge, for example).
2) On packet ingress from port, mark the skb with the ingress port's
fwd_mark. If the device supports it, it's useful to only mark skbs
which were already forwarded by the device. If the device does not
support such indication, all skbs can be marked, even if they're
local dst.
Two new 32-bit fields are added to struct sk_buff and struct netdevice to
hold the fwd_mark. I've wrapped these with CONFIG_NET_SWITCHDEV for now. I
tried using skb->mark for this purpose, but ebtables can overwrite the
skb->mark before the bridge gets it, so that will not work.
In general, this fwd_mark can be used for any case where a packet is
forwarded by the device and a copy is sent to the CPU, to avoid the kernel
re-forwarding the packet. sFlow is another use-case that comes to mind,
but I haven't explored the details.
Scott Feldman (5):
net: don't reforward packets already forwarded by offload device
net: add phys ID compare helper to test if two IDs are the same
switchdev: add offload_fwd_mark generator helper
rocker: add offload_fwd_mark support
switchdev: update documentation for offload_fwd_mark
Documentation/networking/switchdev.txt | 14 +++-
drivers/net/ethernet/rocker/rocker.c | 11 ++++
drivers/net/ethernet/rocker/rocker.h | 1 +
include/linux/netdevice.h | 13 ++++
include/linux/skbuff.h | 9 ++-
include/net/switchdev.h | 9 +++
net/core/dev.c | 10 +++
net/switchdev/switchdev.c | 111 ++++++++++++++++++++++++++++++--
8 files changed, 169 insertions(+), 9 deletions(-)
--
1.7.10.4
From: Scott Feldman <redacted>
Just before queuing skb for xmit on port, check if skb has been marked by
switchdev port driver as already fordwarded by device. If so, drop skb. A
non-zero skb->offload_fwd_mark field is set by the switchdev port
driver/device on ingress to indicate the skb has already been forwarded by
the device to egress ports with matching dev->skb_mark. The switchdev port
driver would assign a non-zero dev->offload_skb_mark for each device port
netdev during registration, for example.
Signed-off-by: Scott Feldman <redacted>
Acked-by: Jiri Pirko <jiri@resnulli.us>
Acked-by: Roopa Prabhu <redacted>
---
include/linux/netdevice.h | 6 ++++++
include/linux/skbuff.h | 9 ++++++++-
net/core/dev.c | 10 ++++++++++
3 files changed, 24 insertions(+), 1 deletion(-)
@@ -1697,6 +1699,10 @@ struct net_device {structxps_dev_maps__rcu*xps_maps;#endif+#ifdef CONFIG_NET_SWITCHDEV+u32offload_fwd_mark;+#endif+/* These may be needed for future network-power-down code. *//*
From: Scott Feldman <redacted>
skb->offload_fwd_mark and dev->offload_fwd_mark are 32-bit and should be
unique for device and may even be unique for a sub-set of ports within
device, so add switchdev helper function to generate unique marks based on
port's switch ID and group_ifindex. group_ifindex would typically be the
container dev's ifindex, such as the bridge's ifindex.
The generator uses a global hash table to store offload_fwd_marks hashed by
{switch ID, group_ifindex} key.
Signed-off-by: Scott Feldman <redacted>
Acked-by: Jiri Pirko <jiri@resnulli.us>
---
include/net/switchdev.h | 9 ++++
net/switchdev/switchdev.c | 103 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 112 insertions(+)
@@ -1039,3 +1039,106 @@ void switchdev_fib_ipv4_abort(struct fib_info *fi)fi->fib_net->ipv4.fib_offload_disabled=true;}EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_abort);++staticboolswitchdev_port_same_parent_id(structnet_device*a,+structnet_device*b)+{+structswitchdev_attra_attr={+.id=SWITCHDEV_ATTR_PORT_PARENT_ID,+.flags=SWITCHDEV_F_NO_RECURSE,+};+structswitchdev_attrb_attr={+.id=SWITCHDEV_ATTR_PORT_PARENT_ID,+.flags=SWITCHDEV_F_NO_RECURSE,+};++if(switchdev_port_attr_get(a,&a_attr)||+switchdev_port_attr_get(b,&b_attr))+returnfalse;++returnnetdev_phys_item_id_same(&a_attr.u.ppid,&b_attr.u.ppid);+}++staticu32switchdev_port_fwd_mark_get(structnet_device*dev,+structnet_device*group_dev)+{+structnet_device*lower_dev;+structlist_head*iter;++netdev_for_each_lower_dev(group_dev,lower_dev,iter){+if(lower_dev==dev)+continue;+if(switchdev_port_same_parent_id(dev,lower_dev))+returnlower_dev->offload_fwd_mark;+returnswitchdev_port_fwd_mark_get(dev,lower_dev);+}++returndev->ifindex;+}++staticvoidswitchdev_port_fwd_mark_reset(structnet_device*group_dev,+u32old_mark,u32*reset_mark)+{+structnet_device*lower_dev;+structlist_head*iter;++netdev_for_each_lower_dev(group_dev,lower_dev,iter){+if(lower_dev->offload_fwd_mark==old_mark){+if(!*reset_mark)+*reset_mark=lower_dev->ifindex;+lower_dev->offload_fwd_mark=*reset_mark;+}+switchdev_port_fwd_mark_reset(lower_dev,old_mark,reset_mark);+}+}++/**+*switchdev_port_fwd_mark_set-Setportoffloadforwardingmark+*+*@dev:portdevice+*@group_dev:containingdevice+*@joining:trueifdevisjoininggroup;falseifleavinggroup+*+*Anungroupedport'soffloadmarkisjustitsifindex.Agrouped+*port's(memberofabridge,forexample)offloadmarkistheifindex+*ofoneoftheportsinthegroupwiththesameparent(switch)ID.+*Portsonthesamedeviceinthesamegroupwillhavethesamemark.+*+*Example:+*+*br0ifindex=9+*sw1p1ifindex=2mark=2+*sw1p2ifindex=3mark=2+*sw2p1ifindex=4mark=5+*sw2p2ifindex=5mark=5+*+*Ifsw2p2leavesthebridge,we'llhave:+*+*br0ifindex=9+*sw1p1ifindex=2mark=2+*sw1p2ifindex=3mark=2+*sw2p1ifindex=4mark=4+*sw2p2ifindex=5mark=5+*/+voidswitchdev_port_fwd_mark_set(structnet_device*dev,+structnet_device*group_dev,+booljoining)+{+u32mark=dev->ifindex;+u32reset_mark=0;++if(group_dev&&joining){+mark=switchdev_port_fwd_mark_get(dev,group_dev);+}elseif(group_dev&&!joining){+if(dev->offload_fwd_mark==mark)+/* Ohoh, this port was the mark reference port,+*butit'sleavingthegroup,soresetthe+*markfortheremainingportsinthegroup.+*/+switchdev_port_fwd_mark_reset(group_dev,mark,+&reset_mark);+}++dev->offload_fwd_mark=mark;+}+EXPORT_SYMBOL_GPL(switchdev_port_fwd_mark_set);
From: Scott Feldman <redacted>
If device flags ingress packet as "fwd offload", mark the
skb->offlaod_fwd_mark using the ingress port's dev->offlaod_fwd_mark. This
will be the hint to the kernel that this packet has already been forwarded
by device to egress ports matching skb->offlaod_fwd_mark.
For rocker, derive port dev->offlaod_fwd_mark based on device switch ID and
port ifindex. If port is bridged, use the bridge ifindex rather than the
port ifindex.
Signed-off-by: Scott Feldman <redacted>
Acked-by: Jiri Pirko <jiri@resnulli.us>
---
drivers/net/ethernet/rocker/rocker.c | 11 +++++++++++
drivers/net/ethernet/rocker/rocker.h | 1 +
2 files changed, 12 insertions(+)
@@ -279,8 +279,18 @@ and unknown unicast packets to all ports in domain, if allowed by port's current STP state. The switch driver, knowing which ports are within which vlan L2 domain, can program the switch device for flooding. The packet should also 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.-XXX: the mechanism to avoid duplicate flood packets is being discuseed.+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. 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
From: Nicolas Dichtel <hidden> Date: 2015-07-20 07:21:43
Le 19/07/2015 03:24, sfeldma@gmail.com a écrit :
From: Scott Feldman <redacted>
Just before queuing skb for xmit on port, check if skb has been marked by
switchdev port driver as already fordwarded by device. If so, drop skb. A
non-zero skb->offload_fwd_mark field is set by the switchdev port
driver/device on ingress to indicate the skb has already been forwarded by
the device to egress ports with matching dev->skb_mark. The switchdev port
driver would assign a non-zero dev->offload_skb_mark for each device port
netdev during registration, for example.
Signed-off-by: Scott Feldman <redacted>
Acked-by: Jiri Pirko <jiri@resnulli.us>
Acked-by: Roopa Prabhu <redacted>
Hi Scott,
On 18/07/15 18:24, sfeldma@gmail.com wrote:
From: Scott Feldman <redacted>
v3:
- Per Nicolas Dichtel review: remove errant empty union.
v2:
- Per davem review: in sk_buff, union fwd_mark with secmark to save space
since features appear to be mutually exclusive.
- Per Simon Horman review:
- fix grammar in switchdev.txt wrt fwd_mark
- remove some unrelated changes that snuck in
v1:
This patchset was previously submitted as RFC. No changes from the last
version (v2) sent under RFC. Including RFC version history here for reference.
This looks good to me, and it looks like this is also relevant for
DSA-driven switches, however I am not exactly clear on how we could
potentially use this on such switches.
For Broadcom tags, there is a reason code forwarded along with the tag
making it to the CPU, and the "mirror" bit sounds like something that
should dictate whether we should be setting the fwd_mark or not.
What does it look like on Marvell switches?
RFC v2:
- s/fwd_mark/offload_fwd_mark
- use consume_skb rather than kfree_skb when dropping pkt on egress.
- Use Jiri's suggestion to use ifindex of one of the ports in a group
as the mark for all the ports in the group. This can be done with
no additional storage (no hashtable from v1). To pull it off, we
need some simple recursive routines to walk the netdev tree ensuring
all leaves in the tree (ports) in the same group (e.g. bridge)
belonging to the same switch device will have the same offload fwd mark.
Maybe someone sees a better design for the recusive routines? They're
not too bad, and should cover the stacked driver cases.
RFC v1:
With switchdev support for offloading L2/L3 forwarding data path to a
switch device, we have a general problem where both the device and the
kernel may forward the packet, resulting in duplicate packets on the wire.
Anytime a packet is forwarded by the device and a copy is sent to the CPU,
there is potential for duplicate forwarding, as the kernel may also do a
forwarding lookup and send the packet on the wire.
The specific problem this patch series is interested in solving is avoiding
duplicate packets on bridged ports. There was a previous RFC from Roopa
(http://marc.info/?l=linux-netdev&m=142687073314252&w=2) to address this
problem, but didn't solve the problem of mixed ports in the bridge from
different devices; there was no way to exclude some ports from forwarding
and include others. This RFC solves that problem by tagging the ingressing
packet with a unique mark, and then comparing the packet mark with the
egress port mark, and skip forwarding when there is a match. For the mixed
ports bridge case, only those ports with matching marks are skipped.
The switchdev port driver must do two things:
1) Generate a fwd_mark for each switch port, using some unique key of the
switch device (and optionally port). This is done when the port netdev
is registered or if the port's group membership changes (joins/leaves
a bridge, for example).
2) On packet ingress from port, mark the skb with the ingress port's
fwd_mark. If the device supports it, it's useful to only mark skbs
which were already forwarded by the device. If the device does not
support such indication, all skbs can be marked, even if they're
local dst.
Two new 32-bit fields are added to struct sk_buff and struct netdevice to
hold the fwd_mark. I've wrapped these with CONFIG_NET_SWITCHDEV for now. I
tried using skb->mark for this purpose, but ebtables can overwrite the
skb->mark before the bridge gets it, so that will not work.
In general, this fwd_mark can be used for any case where a packet is
forwarded by the device and a copy is sent to the CPU, to avoid the kernel
re-forwarding the packet. sFlow is another use-case that comes to mind,
but I haven't explored the details.
Scott Feldman (5):
net: don't reforward packets already forwarded by offload device
net: add phys ID compare helper to test if two IDs are the same
switchdev: add offload_fwd_mark generator helper
rocker: add offload_fwd_mark support
switchdev: update documentation for offload_fwd_mark
Documentation/networking/switchdev.txt | 14 +++-
drivers/net/ethernet/rocker/rocker.c | 11 ++++
drivers/net/ethernet/rocker/rocker.h | 1 +
include/linux/netdevice.h | 13 ++++
include/linux/skbuff.h | 9 ++-
include/net/switchdev.h | 9 +++
net/core/dev.c | 10 +++
net/switchdev/switchdev.c | 111 ++++++++++++++++++++++++++++++--
8 files changed, 169 insertions(+), 9 deletions(-)
From: Andrew Lunn <andrew@lunn.ch> Date: 2015-07-20 18:15:31
This looks good to me, and it looks like this is also relevant for
DSA-driven switches, however I am not exactly clear on how we could
potentially use this on such switches.
For Broadcom tags, there is a reason code forwarded along with the tag
making it to the CPU, and the "mirror" bit sounds like something that
should dictate whether we should be setting the fwd_mark or not.
What does it look like on Marvell switches?
Hi Florian
There are some bits indicating some status information. But these are
more to do with BDPU, IGMP/MLD and ARP.
I've not yet had time to dig into the details here. I suspect the D in
DSA is going to make this very interesting.
Andrew
With switchdev support for offloading L2/L3 forwarding data path to a
switch device, we have a general problem where both the device and the
kernel may forward the packet, resulting in duplicate packets on the wire.
Anytime a packet is forwarded by the device and a copy is sent to the CPU,
there is potential for duplicate forwarding, as the kernel may also do a
forwarding lookup and send the packet on the wire.
The specific problem this patch series is interested in solving is avoiding
duplicate packets on bridged ports. There was a previous RFC from Roopa
(http://marc.info/?l=linux-netdev&m=142687073314252&w=2) to address this
problem, but didn't solve the problem of mixed ports in the bridge from
different devices; there was no way to exclude some ports from forwarding
and include others. This RFC solves that problem by tagging the ingressing
packet with a unique mark, and then comparing the packet mark with the
egress port mark, and skip forwarding when there is a match. For the mixed
ports bridge case, only those ports with matching marks are skipped.
The switchdev port driver must do two things:
1) Generate a fwd_mark for each switch port, using some unique key of the
switch device (and optionally port). This is done when the port netdev
is registered or if the port's group membership changes (joins/leaves
a bridge, for example).
2) On packet ingress from port, mark the skb with the ingress port's
fwd_mark. If the device supports it, it's useful to only mark skbs
which were already forwarded by the device. If the device does not
support such indication, all skbs can be marked, even if they're
local dst.
Two new 32-bit fields are added to struct sk_buff and struct netdevice to
hold the fwd_mark. I've wrapped these with CONFIG_NET_SWITCHDEV for now. I
tried using skb->mark for this purpose, but ebtables can overwrite the
skb->mark before the bridge gets it, so that will not work.
In general, this fwd_mark can be used for any case where a packet is
forwarded by the device and a copy is sent to the CPU, to avoid the kernel
re-forwarding the packet. sFlow is another use-case that comes to mind,
but I haven't explored the details.