• Vladimir Oltean's avatar
    net: mscc: ocelot: set up traps for PTP packets · 96ca08c0
    Vladimir Oltean authored
    IEEE 1588 support was declared too soon for the Ocelot switch. Out of
    reset, this switch does not apply any special treatment for PTP packets,
    i.e. when an event message is received, the natural tendency is to
    forward it by MAC DA/VLAN ID. This poses a problem when the ingress port
    is under a bridge, since user space application stacks (written
    primarily for endpoint ports, not switches) like ptp4l expect that PTP
    messages are always received on AF_PACKET / AF_INET sockets (depending
    on the PTP transport being used), and never being autonomously
    forwarded. Any forwarding, if necessary (for example in Transparent
    Clock mode) is handled in software by ptp4l. Having the hardware forward
    these packets too will cause duplicates which will confuse endpoints
    connected to these switches.
    
    So PTP over L2 barely works, in the sense that PTP packets reach the CPU
    port, but they reach it via flooding, and therefore reach lots of other
    unwanted destinations too. But PTP over IPv4/IPv6 does not work at all.
    This is because the Ocelot switch have a separate destination port mask
    for unknown IP multicast (which PTP over IP is) flooding compared to
    unknown non-IP multicast (which PTP over L2 is) flooding. Specifically,
    the driver allows the CPU port to be in the PGID_MC port group, but not
    in PGID_MCIPV4 and PGID_MCIPV6. There are several presentations from
    Allan Nielsen which explain that the embedded MIPS CPU on Ocelot
    switches is not very powerful at all, so every penny they could save by
    not allowing flooding to the CPU port module matters. Unknown IP
    multicast did not make it.
    
    The de facto consensus is that when a switch is PTP-aware and an
    application stack for PTP is running, switches should have some sort of
    trapping mechanism for PTP packets, to extract them from the hardware
    data path. This avoids both problems:
    (a) PTP packets are no longer flooded to unwanted destinations
    (b) PTP over IP packets are no longer denied from reaching the CPU since
        they arrive there via a trap and not via flooding
    
    It is not the first time when this change is attempted. Last time, the
    feedback from Allan Nielsen and Andrew Lunn was that the traps should
    not be installed by default, and that PTP-unaware switching may be
    desired for some use cases:
    https://patchwork.ozlabs.org/project/netdev/patch/20190813025214.18601-5-yangbo.lu@nxp.com/
    
    To address that feedback, the present patch adds the necessary packet
    traps according to the RX filter configuration transmitted by user space
    through the SIOCSHWTSTAMP ioctl. Trapping is done via VCAP IS2, where we
    keep 5 filters, which are amended each time RX timestamping is enabled
    or disabled on a port:
    - 1 for PTP over L2
    - 2 for PTP over IPv4 (UDP ports 319 and 320)
    - 2 for PTP over IPv6 (UDP ports 319 and 320)
    
    The cookie by which these filters (invisible to tc) are identified is
    strategically chosen such that it does not collide with the filters used
    for the ocelot-8021q tagging protocol by the Felix driver, or with the
    MRP traps set up by the Ocelot library.
    
    Other alternatives were considered, like patching user space to do
    something, but there are so many ways in which PTP packets could be made
    to reach the CPU, generically speaking, that "do what?" is a very valid
    question. The ptp4l program from the linuxptp stack already attempts to
    do something: it calls setsockopt(IP_ADD_MEMBERSHIP) (and
    PACKET_ADD_MEMBERSHIP, respectively) which translates in both cases into
    a dev_mc_add() on the interface, in the kernel:
    https://github.com/richardcochran/linuxptp/blob/v3.1.1/udp.c#L73
    https://github.com/richardcochran/linuxptp/blob/v3.1.1/raw.c
    
    Reality shows that this is not sufficient in case the interface belongs
    to a switchdev driver, as dev_mc_add() does not show the intention to
    trap a packet to the CPU, but rather the intention to not drop it (it is
    strictly for RX filtering, same as promiscuous does not mean to send all
    traffic to the CPU, but to not drop traffic with unknown MAC DA). This
    topic is a can of worms in itself, and it would be great if user space
    could just stay out of it.
    
    On the other hand, setting up PTP traps privately within the driver is
    not new by any stretch of the imagination:
    https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/net/ethernet/mellanox/mlxsw/spectrum_ptp.c#L833
    https://elixir.bootlin.com/linux/v5.16-rc2/source/drivers/net/dsa/hirschmann/hellcreek.c#L1050
    https://elixir.bootlin.com/linux/v5.16-rc2/source/include/linux/dsa/sja1105.h#L21
    
    So this is the approach taken here as well. The difference here being
    that we prepare and destroy the traps per port, dynamically at runtime,
    as opposed to driver init time, because apparently, PTP-unaware
    forwarding is a use case.
    
    Fixes: 4e3b0468 ("net: mscc: PTP Hardware Clock (PHC) support")
    Reported-by: default avatarPo Liu <po.liu@nxp.com>
    Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
    Acked-by: default avatarRichard Cochran <richardcochran@gmail.com>
    Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
    96ca08c0
ocelot.c 69.2 KB