• Vladimir Oltean's avatar
    net: dsa: introduce tagger-owned storage for private and shared data · dc452a47
    Vladimir Oltean authored
    Ansuel is working on register access over Ethernet for the qca8k switch
    family. This requires the qca8k tagging protocol driver to receive
    frames which aren't intended for the network stack, but instead for the
    qca8k switch driver itself.
    
    The dp->priv is currently the prevailing method for passing data back
    and forth between the tagging protocol driver and the switch driver.
    However, this method is riddled with caveats.
    
    The DSA design allows in principle for any switch driver to return any
    protocol it desires in ->get_tag_protocol(). The dsa_loop driver can be
    modified to do just that. But in the current design, the memory behind
    dp->priv has to be allocated by the switch driver, so if the tagging
    protocol is paired to an unexpected switch driver, we may end up in NULL
    pointer dereferences inside the kernel, or worse (a switch driver may
    allocate dp->priv according to the expectations of a different tagger).
    
    The latter possibility is even more plausible considering that DSA
    switches can dynamically change tagging protocols in certain cases
    (dsa <-> edsa, ocelot <-> ocelot-8021q), and the current design lends
    itself to mistakes that are all too easy to make.
    
    This patch proposes that the tagging protocol driver should manage its
    own memory, instead of relying on the switch driver to do so.
    After analyzing the different in-tree needs, it can be observed that the
    required tagger storage is per switch, therefore a ds->tagger_data
    pointer is introduced. In principle, per-port storage could also be
    introduced, although there is no need for it at the moment. Future
    changes will replace the current usage of dp->priv with ds->tagger_data.
    
    We define a "binding" event between the DSA switch tree and the tagging
    protocol. During this binding event, the tagging protocol's ->connect()
    method is called first, and this may allocate some memory for each
    switch of the tree. Then a cross-chip notifier is emitted for the
    switches within that tree, and they are given the opportunity to fix up
    the tagger's memory (for example, they might set up some function
    pointers that represent virtual methods for consuming packets).
    Because the memory is owned by the tagger, there exists a ->disconnect()
    method for the tagger (which is the place to free the resources), but
    there doesn't exist a ->disconnect() method for the switch driver.
    This is part of the design. The switch driver should make minimal use of
    the public part of the tagger data, and only after type-checking it
    using the supplied "proto" argument.
    
    In the code there are in fact two binding events, one is the initial
    event in dsa_switch_setup_tag_protocol(). At this stage, the cross chip
    notifier chains aren't initialized, so we call each switch's connect()
    method by hand. Then there is dsa_tree_bind_tag_proto() during
    dsa_tree_change_tag_proto(), and here we have an old protocol and a new
    one. We first connect to the new one before disconnecting from the old
    one, to simplify error handling a bit and to ensure we remain in a valid
    state at all times.
    Co-developed-by: default avatarAnsuel Smith <ansuelsmth@gmail.com>
    Signed-off-by: default avatarAnsuel Smith <ansuelsmth@gmail.com>
    Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
    Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
    dc452a47
dsa.h 37.6 KB