summaryrefslogtreecommitdiff
path: root/net/bridge/br_input.c
diff options
context:
space:
mode:
authorVladimir Oltean <vladimir.oltean@nxp.com>2020-05-10 19:37:40 +0300
committerJakub Kicinski <kuba@kernel.org>2020-05-11 05:52:33 +0300
commit9eb8eff0cf2f1e1afc0756bb30cb9746ba90dd07 (patch)
tree6b41633b856834a8cc2a05bdfde065475b19f702 /net/bridge/br_input.c
parent90d9834ecd6b92880765cbcafba373ce33a7cb05 (diff)
downloadlinux-9eb8eff0cf2f1e1afc0756bb30cb9746ba90dd07.tar.xz
net: bridge: allow enslaving some DSA master network devices
Commit 8db0a2ee2c63 ("net: bridge: reject DSA-enabled master netdevices as bridge members") added a special check in br_if.c in order to check for a DSA master network device with a tagging protocol configured. This was done because back then, such devices, once enslaved in a bridge would become inoperative and would not pass DSA tagged traffic anymore due to br_handle_frame returning RX_HANDLER_CONSUMED. But right now we have valid use cases which do require bridging of DSA masters. One such example is when the DSA master ports are DSA switch ports themselves (in a disjoint tree setup). This should be completely equivalent, functionally speaking, from having multiple DSA switches hanging off of the ports of a switchdev driver. So we should allow the enslaving of DSA tagged master network devices. Instead of the regular br_handle_frame(), install a new function br_handle_frame_dummy() on these DSA masters, which returns RX_HANDLER_PASS in order to call into the DSA specific tagging protocol handlers, and lift the restriction from br_add_if. Suggested-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Suggested-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Tested-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/bridge/br_input.c')
-rw-r--r--net/bridge/br_input.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c
index d5c34f36f0f4..59a318b9f646 100644
--- a/net/bridge/br_input.c
+++ b/net/bridge/br_input.c
@@ -17,6 +17,7 @@
#endif
#include <linux/neighbour.h>
#include <net/arp.h>
+#include <net/dsa.h>
#include <linux/export.h>
#include <linux/rculist.h>
#include "br_private.h"
@@ -257,7 +258,7 @@ frame_finish:
* Return NULL if skb is handled
* note: already called with rcu_read_lock
*/
-rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
+static rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
{
struct net_bridge_port *p;
struct sk_buff *skb = *pskb;
@@ -359,3 +360,23 @@ drop:
}
return RX_HANDLER_CONSUMED;
}
+
+/* This function has no purpose other than to appease the br_port_get_rcu/rtnl
+ * helpers which identify bridged ports according to the rx_handler installed
+ * on them (so there _needs_ to be a bridge rx_handler even if we don't need it
+ * to do anything useful). This bridge won't support traffic to/from the stack,
+ * but only hardware bridging. So return RX_HANDLER_PASS so we don't steal
+ * frames from the ETH_P_XDSA packet_type handler.
+ */
+static rx_handler_result_t br_handle_frame_dummy(struct sk_buff **pskb)
+{
+ return RX_HANDLER_PASS;
+}
+
+rx_handler_func_t *br_get_rx_handler(const struct net_device *dev)
+{
+ if (netdev_uses_dsa(dev))
+ return br_handle_frame_dummy;
+
+ return br_handle_frame;
+}