Skip to content

Commit 6986b1e

Browse files
jukkarnashif
authored andcommitted
net: bridge: Overhaul the code to use virtual interfaces
The legacy bridging code prevented normal IP traffic to the bridged Ethernet interfaces. This is not intuitive and differs how bridging setup works in Linux. This commit changes that and creates a separate virtual interface that is doing the actual bridging. This enables the bridged Ethernet interfaces to work normally and provide IP connectivity. How this works in practice: * User needs to enable CONFIG_NET_ETHERNET_BRIDGE * User needs to have a device with more than one Ethernet interface * After booting, the net-shell or program API can be used to add interfaces to the bridge like this. net bridge addif 1 3 2 where the 1 is the bridge interface index and 2 and 3 are the Ethernet interface indices. * The bridging is then finally enabled / started when the bridge interface 1 is taken up net iface up 1 * If bridged interfaces are removed from the bridge (minimum of two interfaces are needed there), then the bridging is disabled automatically. The bridge interface stays up in this case and can be taken down manually. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 5fdbbf7 commit 6986b1e

File tree

9 files changed

+589
-370
lines changed

9 files changed

+589
-370
lines changed

doc/releases/migration-guide-4.0.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,18 @@ Networking
220220
all the network shell activities can be found under ``net`` shell command.
221221
After this change the bridge shell is used by ``net bridge`` command.
222222

223+
* The Ethernet bridging code is changed to allow similar configuration experience
224+
as in Linux. The bridged Ethernet interface can be used normally even if bridging
225+
is enabled. The actual bridging is done by a separate virtual network interface that
226+
directs network packets to bridged Ethernet interfaces.
227+
The :c:func:`eth_bridge_iface_allow_tx` is removed as it is not needed because the
228+
bridged Ethernet interface can send and receive data normally.
229+
The :c:func:`eth_bridge_listener_add` and :c:func:`eth_bridge_listener_remove` are
230+
removed as same functionality can be achieved using promiscuous API.
231+
Because the bridge interface is a normal network interface,
232+
the :c:func:`eth_bridge_iface_add` and :c:func:`eth_bridge_iface_remove`
233+
will take network interface pointer as a first parameter.
234+
223235
Other Subsystems
224236
****************
225237

include/zephyr/net/ethernet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ struct ethernet_context {
653653
atomic_t flags;
654654

655655
#if defined(CONFIG_NET_ETHERNET_BRIDGE)
656-
struct eth_bridge_iface_context bridge;
656+
struct net_if *bridge;
657657
#endif
658658

659659
/** Carrier ON/OFF handler worker. This is used to create

include/zephyr/net/ethernet_bridge.h

Lines changed: 44 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
/*
1010
* Copyright (c) 2021 BayLibre SAS
11+
* Copyright (c) 2024 Nordic Semiconductor
1112
*
1213
* SPDX-License-Identifier: Apache-2.0
1314
*/
@@ -33,42 +34,36 @@ extern "C" {
3334

3435
/** @cond INTERNAL_HIDDEN */
3536

36-
struct eth_bridge {
37+
#if defined(CONFIG_NET_ETHERNET_BRIDGE)
38+
#define NET_ETHERNET_BRIDGE_ETH_INTERFACE_COUNT CONFIG_NET_ETHERNET_BRIDGE_ETH_INTERFACE_COUNT
39+
#else
40+
#define NET_ETHERNET_BRIDGE_ETH_INTERFACE_COUNT 1
41+
#endif
42+
43+
struct eth_bridge_iface_context {
44+
/* Lock to protect access to interface array below */
3745
struct k_mutex lock;
38-
sys_slist_t interfaces;
39-
sys_slist_t listeners;
40-
bool initialized;
41-
};
4246

43-
#define ETH_BRIDGE_INITIALIZER(obj) \
44-
{ \
45-
.lock = { }, \
46-
.interfaces = SYS_SLIST_STATIC_INIT(&obj.interfaces), \
47-
.listeners = SYS_SLIST_STATIC_INIT(&obj.listeners), \
48-
}
47+
/* The actual bridge virtual interface */
48+
struct net_if *iface;
4949

50-
/** @endcond */
50+
/* What Ethernet interfaces are bridged together */
51+
struct net_if *eth_iface[NET_ETHERNET_BRIDGE_ETH_INTERFACE_COUNT];
5152

52-
/**
53-
* @brief Statically define and initialize a bridge instance.
54-
*
55-
* @param name Name of the bridge object
56-
*/
57-
#define ETH_BRIDGE_INIT(name) \
58-
STRUCT_SECTION_ITERABLE(eth_bridge, name) = \
59-
ETH_BRIDGE_INITIALIZER(name)
53+
/* How many interfaces are bridged atm */
54+
size_t count;
6055

61-
/** @cond INTERNAL_HIDDEN */
56+
/* Bridge instance id */
57+
int id;
6258

63-
struct eth_bridge_iface_context {
64-
sys_snode_t node;
65-
struct eth_bridge *instance;
66-
bool allow_tx;
67-
};
59+
/* Is the bridge interface initialized */
60+
bool is_init : 1;
61+
62+
/* Has user configured the bridge */
63+
bool is_setup : 1;
6864

69-
struct eth_bridge_listener {
70-
sys_snode_t node;
71-
struct k_fifo pkt_queue;
65+
/* Is the interface enabled or not */
66+
bool status : 1;
7267
};
7368

7469
/** @endcond */
@@ -77,77 +72,32 @@ struct eth_bridge_listener {
7772
* @brief Add an Ethernet network interface to a bridge
7873
*
7974
* This adds a network interface to a bridge. The interface is then put
80-
* into promiscuous mode, all packets received by this interface are sent
81-
* to the bridge, and any other packets sent to the bridge (with some
82-
* exceptions) are transmitted via this interface.
83-
*
84-
* For transmission from the bridge to occur via this interface, it is
85-
* necessary to enable TX mode with eth_bridge_iface_tx(). TX mode is
86-
* initially disabled.
75+
* into promiscuous mode. After more than one Ethernet interfaces are
76+
* added to the bridge interface, the bridge interface is setup.
77+
* After the setup is done, the bridge interface can be brought up so
78+
* that it can start bridging L2 traffic.
8779
*
88-
* Once an interface is added to a bridge, all its incoming traffic is
89-
* diverted to the bridge. However, packets sent out with net_if_queue_tx()
90-
* via this interface are not subjected to the bridge.
91-
*
92-
* @param br A pointer to an initialized bridge object
80+
* @param br A pointer to a bridge interface
9381
* @param iface Interface to add
9482
*
9583
* @return 0 if OK, negative error code otherwise.
9684
*/
97-
int eth_bridge_iface_add(struct eth_bridge *br, struct net_if *iface);
85+
int eth_bridge_iface_add(struct net_if *br, struct net_if *iface);
9886

9987
/**
100-
* @brief Remove an Ethernet network interface from a bridge
88+
* @brief Remove an Ethernet network interface from a bridge.
10189
*
102-
* @param br A pointer to an initialized bridge object
103-
* @param iface Interface to remove
90+
* If the bridge interface setup has only one Ethernet interface left
91+
* after this function call, the bridge is disabled as it cannot bridge
92+
* the L2 traffic any more. The bridge interface is left in UP state
93+
* if this case.
10494
*
105-
* @return 0 if OK, negative error code otherwise.
106-
*/
107-
int eth_bridge_iface_remove(struct eth_bridge *br, struct net_if *iface);
108-
109-
/**
110-
* @brief Enable/disable transmission mode for a bridged interface
111-
*
112-
* When TX mode is off, the interface may receive packets and send them to
113-
* the bridge but no packets coming from the bridge will be sent through this
114-
* interface. When TX mode is on, both incoming and outgoing packets are
115-
* allowed.
116-
*
117-
* @param iface Interface to configure
118-
* @param allow true to activate TX mode, false otherwise
119-
*
120-
* @return 0 if OK, negative error code otherwise.
121-
*/
122-
int eth_bridge_iface_allow_tx(struct net_if *iface, bool allow);
123-
124-
/**
125-
* @brief Add (register) a listener to the bridge
126-
*
127-
* This lets a software listener register a pointer to a provided FIFO for
128-
* receiving packets sent to the bridge. The listener is responsible for
129-
* emptying the FIFO with k_fifo_get() which will return a struct net_pkt
130-
* pointer, and releasing the packet with net_pkt_unref() when done with it.
131-
*
132-
* The listener wishing not to receive any more packets should simply
133-
* unregister itself with eth_bridge_listener_remove().
134-
*
135-
* @param br A pointer to an initialized bridge object
136-
* @param l A pointer to an initialized listener instance.
137-
*
138-
* @return 0 if OK, negative error code otherwise.
139-
*/
140-
int eth_bridge_listener_add(struct eth_bridge *br, struct eth_bridge_listener *l);
141-
142-
/**
143-
* @brief Remove (unregister) a listener from the bridge
144-
*
145-
* @param br A pointer to an initialized bridge object
146-
* @param l A pointer to the listener instance to be removed.
95+
* @param br A pointer to a bridge interface
96+
* @param iface Interface to remove
14797
*
14898
* @return 0 if OK, negative error code otherwise.
14999
*/
150-
int eth_bridge_listener_remove(struct eth_bridge *br, struct eth_bridge_listener *l);
100+
int eth_bridge_iface_remove(struct net_if *br, struct net_if *iface);
151101

152102
/**
153103
* @brief Get bridge index according to pointer
@@ -156,28 +106,28 @@ int eth_bridge_listener_remove(struct eth_bridge *br, struct eth_bridge_listener
156106
*
157107
* @return Bridge index
158108
*/
159-
int eth_bridge_get_index(struct eth_bridge *br);
109+
int eth_bridge_get_index(struct net_if *br);
160110

161111
/**
162112
* @brief Get bridge instance according to index
163113
*
164114
* @param index Bridge instance index
165115
*
166-
* @return Pointer to bridge instance or NULL if not found.
116+
* @return Pointer to bridge interface or NULL if not found.
167117
*/
168-
struct eth_bridge *eth_bridge_get_by_index(int index);
118+
struct net_if *eth_bridge_get_by_index(int index);
169119

170120
/**
171121
* @typedef eth_bridge_cb_t
172122
* @brief Callback used while iterating over bridge instances
173123
*
174-
* @param br Pointer to bridge instance
124+
* @param br Pointer to bridge context instance
175125
* @param user_data User supplied data
176126
*/
177-
typedef void (*eth_bridge_cb_t)(struct eth_bridge *br, void *user_data);
127+
typedef void (*eth_bridge_cb_t)(struct eth_bridge_iface_context *br, void *user_data);
178128

179129
/**
180-
* @brief Go through all the bridge instances in order to get
130+
* @brief Go through all the bridge context instances in order to get
181131
* information about them. This is mainly useful in
182132
* net-shell to print data about currently active bridges.
183133
*

include/zephyr/net/virtual.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ enum virtual_interface_caps {
4343
/** Virtual LAN interface (VLAN) */
4444
VIRTUAL_INTERFACE_VLAN = BIT(2),
4545

46+
/** Virtual Ethernet bridge interface. */
47+
VIRTUAL_INTERFACE_BRIDGE = BIT(3),
48+
4649
/** @cond INTERNAL_HIDDEN */
4750
/* Marker for capabilities - must be at the end of the enum.
4851
* It is here because the capability list cannot be empty.

subsys/net/l2/ethernet/Kconfig

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,29 @@ source "subsys/net/l2/ethernet/lldp/Kconfig"
100100
config NET_ETHERNET_BRIDGE
101101
bool "Ethernet Bridging support"
102102
select NET_PROMISCUOUS_MODE
103+
select NET_L2_VIRTUAL
103104
help
104105
Enables Ethernet bridging where packets can be transparently
105106
forwarded across interfaces registered to a bridge.
106107

108+
config NET_ETHERNET_BRIDGE_COUNT
109+
int "Max number of bridge interfaces"
110+
default 1
111+
range 1 16
112+
depends on NET_ETHERNET_BRIDGE
113+
help
114+
How many bridge interfaces are created. Each interface can bridge
115+
two or more Ethernet interfaces.
116+
117+
config NET_ETHERNET_BRIDGE_ETH_INTERFACE_COUNT
118+
int "Max number of Ethernet interfaces bridged together"
119+
default 2
120+
range 2 32
121+
depends on NET_ETHERNET_BRIDGE
122+
help
123+
How many Ethernet interfaces can be bridged together per each
124+
bridge interface.
125+
107126
if NET_ETHERNET_BRIDGE
108127
module = NET_ETHERNET_BRIDGE
109128
module-dep = NET_LOG
@@ -112,23 +131,20 @@ module-help = Enables Ethernet Bridge code to output debug messages.
112131
source "subsys/net/Kconfig.template.log_config.net"
113132
endif # NET_ETHERNET_BRIDGE
114133

134+
config NET_ETHERNET_BRIDGE_TXRX_DEBUG
135+
bool "Debug received and sent packets in bridge"
136+
depends on NET_L2_ETHERNET_LOG_LEVEL_DBG && NET_ETHERNET_BRIDGE
137+
help
138+
Enables printing of received and sent network packets.
139+
This can produce lot of output so it is disabled by default.
140+
115141
config NET_ETHERNET_BRIDGE_SHELL
116142
bool "Ethernet Bridging management shell"
117143
depends on NET_ETHERNET_BRIDGE
118144
select NET_SHELL
119145
help
120146
Enables shell utility to manage bridge configuration interactively.
121147

122-
config NET_ETHERNET_BRIDGE_DEFAULT
123-
bool "Declare one bridge instance for shell usage"
124-
depends on NET_ETHERNET_BRIDGE_SHELL
125-
default y
126-
help
127-
If the bridge shell is the sole user of the bridge code then
128-
it needs at least one bridge instance to be useful.
129-
Say y if this is the case. If you only want to inspect
130-
existing bridge instances then say n.
131-
132148
config NET_ETHERNET_FORWARD_UNRECOGNISED_ETHERTYPE
133149
bool "Forward unrecognized EtherType frames further into net stack"
134150
default y if NET_SOCKETS_PACKET

0 commit comments

Comments
 (0)