1. 16 2月, 2022 4 次提交
    • V
      net: bridge: vlan: notify switchdev only when something changed · 27c5f74c
      Vladimir Oltean 提交于
      Currently, when a VLAN entry is added multiple times in a row to a
      bridge port, nbp_vlan_add() calls br_switchdev_port_vlan_add() each
      time, even if the VLAN already exists and nothing about it has changed:
      
      bridge vlan add dev lan12 vid 100 master static
      
      Similarly, when a VLAN is added multiple times in a row to a bridge,
      br_vlan_add_existing() doesn't filter at all the calls to
      br_switchdev_port_vlan_add():
      
      bridge vlan add dev br0 vid 100 self
      
      This behavior makes driver-level accounting of VLANs impossible, since
      it is enough for a single deletion event to remove a VLAN, but the
      addition event can be emitted an unlimited number of times.
      
      The cause for this can be identified as follows: we rely on
      __vlan_add_flags() to retroactively tell us whether it has changed
      anything about the VLAN flags or VLAN group pvid. So we'd first have to
      call __vlan_add_flags() before calling br_switchdev_port_vlan_add(), in
      order to have access to the "bool *changed" information. But we don't
      want to change the event ordering, because we'd have to revert the
      struct net_bridge_vlan changes we've made if switchdev returns an error.
      
      So to solve this, we need another function that tells us whether any
      change is going to occur in the VLAN or VLAN group, _prior_ to calling
      __vlan_add_flags().
      
      Split __vlan_add_flags() into a precommit and a commit stage, and rename
      it to __vlan_flags_update(). The precommit stage,
      __vlan_flags_would_change(), will determine whether there is any reason
      to notify switchdev due to a change of flags (note: the BRENTRY flag
      transition from false to true is treated separately: as a new switchdev
      entry, because we skipped notifying the master VLAN when it wasn't a
      brentry yet, and therefore not as a change of flags).
      
      With this lookahead/precommit function in place, we can avoid notifying
      switchdev if nothing changed for the VLAN and VLAN group.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      27c5f74c
    • V
      net: bridge: vlan: make __vlan_add_flags react only to PVID and UNTAGGED · cab2cd77
      Vladimir Oltean 提交于
      Currently there is a very subtle aspect to the behavior of
      __vlan_add_flags(): it changes the struct net_bridge_vlan flags and
      pvid, yet it returns true ("changed") even if none of those changed,
      just a transition of br_vlan_is_brentry(v) took place from false to
      true.
      
      This can be seen in br_vlan_add_existing(), however we do not actually
      rely on this subtle behavior, since the "if" condition that checks that
      the vlan wasn't a brentry before had a useless (until now) assignment:
      
      	*changed = true;
      
      Make things more obvious by actually making __vlan_add_flags() do what's
      written on the box, and be more specific about what is actually written
      on the box. This is needed because further transformations will be done
      to __vlan_add_flags().
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Acked-by: NNikolay Aleksandrov <nikolay@nvidia.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      cab2cd77
    • V
      net: bridge: vlan: don't notify to switchdev master VLANs without BRENTRY flag · 3116ad06
      Vladimir Oltean 提交于
      When a VLAN is added to a bridge port and it doesn't exist on the bridge
      device yet, it gets created for the multicast context, but it is
      'hidden', since it doesn't have the BRENTRY flag yet:
      
      ip link add br0 type bridge && ip link set swp0 master br0
      bridge vlan add dev swp0 vid 100 # the master VLAN 100 gets created
      bridge vlan add dev br0 vid 100 self # that VLAN becomes brentry just now
      
      All switchdev drivers ignore switchdev notifiers for VLAN entries which
      have the BRENTRY unset, and for good reason: these are merely private
      data structures used by the bridge driver. So we might just as well not
      notify those at all.
      
      Cleanup in the switchdev drivers that check for the BRENTRY flag is now
      possible, and will be handled separately, since those checks just became
      dead code.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Acked-by: NNikolay Aleksandrov <nikolay@nvidia.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      3116ad06
    • V
      net: bridge: vlan: check early for lack of BRENTRY flag in br_vlan_add_existing · b2bc58d4
      Vladimir Oltean 提交于
      When a VLAN is added to a bridge port, a master VLAN gets created on the
      bridge for context, but it doesn't have the BRENTRY flag.
      
      Then, when the same VLAN is added to the bridge itself, that enters
      through the br_vlan_add_existing() code path and gains the BRENTRY flag,
      thus it becomes "existing".
      
      It seems natural to check for this condition early, because the current
      code flow is to notify switchdev of the addition of a VLAN that isn't a
      brentry, just to delete it immediately afterwards.
      Signed-off-by: NVladimir Oltean <vladimir.oltean@nxp.com>
      Acked-by: NNikolay Aleksandrov <nikolay@nvidia.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      b2bc58d4
  2. 15 2月, 2022 1 次提交
  3. 14 2月, 2022 8 次提交
  4. 11 2月, 2022 13 次提交
  5. 10 2月, 2022 13 次提交
  6. 09 2月, 2022 1 次提交
    • X
      vlan: move dev_put into vlan_dev_uninit · d6ff94af
      Xin Long 提交于
      Shuang Li reported an QinQ issue by simply doing:
      
        # ip link add dummy0 type dummy
        # ip link add link dummy0 name dummy0.1 type vlan id 1
        # ip link add link dummy0.1 name dummy0.1.2 type vlan id 2
        # rmmod 8021q
      
       unregister_netdevice: waiting for dummy0.1 to become free. Usage count = 1
      
      When rmmods 8021q, all vlan devs are deleted from their real_dev's vlan grp
      and added into list_kill by unregister_vlan_dev(). dummy0.1 is unregistered
      before dummy0.1.2, as it's using for_each_netdev() in __rtnl_kill_links().
      
      When unregisters dummy0.1, dummy0.1.2 is not unregistered in the event of
      NETDEV_UNREGISTER, as it's been deleted from dummy0.1's vlan grp. However,
      due to dummy0.1.2 still holding dummy0.1, dummy0.1 will keep waiting in
      netdev_wait_allrefs(), while dummy0.1.2 will never get unregistered and
      release dummy0.1, as it delays dev_put until calling dev->priv_destructor,
      vlan_dev_free().
      
      This issue was introduced by Commit 563bcbae ("net: vlan: fix a UAF in
      vlan_dev_real_dev()"), and this patch is to fix it by moving dev_put() into
      vlan_dev_uninit(), which is called after NETDEV_UNREGISTER event but before
      netdev_wait_allrefs().
      
      Fixes: 563bcbae ("net: vlan: fix a UAF in vlan_dev_real_dev()")
      Reported-by: NShuang Li <shuali@redhat.com>
      Signed-off-by: NXin Long <lucien.xin@gmail.com>
      Signed-off-by: NDavid S. Miller <davem@davemloft.net>
      d6ff94af