netmode: add support for global bridge backend

This commit is contained in:
Mohd Husaam Mehdi 2026-03-05 13:09:23 +05:30
parent f7dbd51605
commit 8937a319f1
2 changed files with 205 additions and 4 deletions

View file

@ -40,6 +40,7 @@ configure_interfaces() {
_log "Interface configs: $interface_configs"
_log "MAC addresses: $mac_addrs"
_log "Bridge backend: $BRIDGE_BACKEND"
# Parse the combined configuration into parallel arrays
local OLD_IFS="$IFS"
@ -280,11 +281,17 @@ configure_interfaces() {
MACVLAN_PRESENT=1
fi
_log "Parsed: mode=$mode, vlan_type=$vlan_type, cvid=$cvid, svid=$svid, mac=$mac_addr, proto=$proto, purpose=$purpose"
_log "Parsed: mode=$mode, vlan_type=$vlan_type, cvid=$cvid, svid=$svid, mac=$mac_addr, proto=$proto, purpose=$purpose, legacy=$PARSE_LEGACY"
case "$mode" in
bridge)
# Create bridge using helper function
# If legacy=false (default), bridge-vlan will be created and we need shared bridge
if [ "$PARSE_LEGACY" = "0" ] && { [ "$vlan_type" = "tagged" ] || [ "$vlan_type" = "wan-tagged" ] || [ "$vlan_type" = "transparent-qinq" ] || [ "$vlan_type" = "tagged-qinq" ] || [ "$vlan_type" = "qinq" ]; }; then
BRIDGE_VLAN_PRESENT=1
bridge_vlan_mtu="$if_mtu"
_log "Bridge type with legacy=false detected, will create shared bridge for bridge-vlan configurations"
fi
create_bridge "$if_name" "$if_type" "$port_list" "$if_mac" "$if_mtu"
;;

View file

@ -11,6 +11,7 @@
BRIDGE_ALL_PORTS=""
BRIDGE_CREATED="0"
SHARED_BRIDGE_NAME="br-vlan"
BRIDGE_BACKEND="$(uci -q get netmode.global.bridge_backend || echo "bridge-vlan")"
#
# Validation Functions
@ -633,7 +634,6 @@ parse_interface_type() {
local _disabled="0"
local _purpose="" # mgmt, inet (internet) or iptv
# Check for modifiers (must be at the end of the string)
# Process -disabled and -d (both set disabled flag)
if echo "$type_spec" | grep -qE -- '-(disabled|d)$'; then
_disabled="1"
@ -1204,7 +1204,7 @@ create_routed_interface() {
logger -s -p user.info -t "$_log_prefix" "Routed interface $if_name created: device=$device_name"
}
# Create bridge device and interface
# Create bridge device and interface (with optional bridge-vlan support)
create_bridge() {
local bridge_name="$1"
local bridge_type="$2"
@ -1229,8 +1229,16 @@ create_bridge() {
local actual_ports=$(parse_port_list "$port_list")
logger -s -p user.info -t "$_log_prefix" "Parsed ports: $actual_ports"
logger -s -p user.info -t "$_log_prefix" "VLAN type: $vlan_type, cvid: $cvid, svid: $svid"
logger -s -p user.info -t "$_log_prefix" "VLAN type: $vlan_type, cvid: $cvid, svid: $svid, legacy: $legacy"
# Check if we should use bridge-vlan mode (new default)
# Use bridge-vlan for tagged, wan-tagged, and qinq types when BRIDGE_BACKEND != legacy
if [ "$BRIDGE_BACKEND" != "legacy" ]; then
create_bridge_vlan_from_bridge_type "$bridge_name" "$bridge_type" "$port_list" "$mac_addr" "$mtu"
return 0
fi
# Legacy mode: Create traditional bridge device
# Create interface
local if_name="${bridge_name}"
local br_dev_name="br-${bridge_name}"
@ -1349,6 +1357,192 @@ create_bridge() {
logger -s -p user.info -t "$_log_prefix" "Bridge $bridge_name created successfully"
}
# Create bridge-vlan configuration from bridge:tagged, bridge:wan-tagged, etc. types (legacy=false)
# This creates bridge-vlan stanzas using a shared br-wan bridge
# For QinQ scenarios, uses 8021ad device for svid
create_bridge_vlan_from_bridge_type() {
local bridge_name="$1"
local bridge_type="$2"
local port_list="$3"
local mac_addr="$4"
local mtu="$5"
local _log_prefix="netmode-advanced"
logger -s -p user.info -t "$_log_prefix" "Creating bridge-vlan from bridge type: $bridge_name, type: $bridge_type, ports: $port_list"
# Parse bridge type
parse_interface_type "$bridge_type"
local proto="$PARSE_PROTO"
local vlan_type="$PARSE_VLAN_TYPE"
local cvid="$PARSE_CVID"
local svid="$PARSE_SVID"
local disabled="$PARSE_DISABLED"
# Parse ports
local actual_ports=$(parse_port_list "$port_list")
logger -s -p user.info -t "$_log_prefix" "Parsed ports: $actual_ports"
logger -s -p user.info -t "$_log_prefix" "Bridge-VLAN type: $vlan_type, cvid: $cvid, svid: $svid"
# Determine VLAN ID for bridge-vlan
# For transparent-qinq with only svid, use svid as the VLAN ID
# For other types, use cvid as the VLAN ID
local vlan_id=""
if [ "$vlan_type" = "transparent-qinq" ] && [ -z "$cvid" ] && [ -n "$svid" ]; then
vlan_id="$svid"
elif [ -n "$cvid" ]; then
vlan_id="$cvid"
elif [ -n "$svid" ]; then
vlan_id="$svid"
fi
if [ -z "$vlan_id" ]; then
logger -s -p user.err -t "$_log_prefix" "ERROR: No VLAN ID specified for bridge-vlan mode"
return 1
fi
# Create interface section
local if_name="${bridge_name}"
local br_vlan_dev="${SHARED_BRIDGE_NAME}.${vlan_id}"
uci -q delete "network.${if_name}"
uci -q set "network.${if_name}=interface"
uci -q set "network.${if_name}.proto=${proto}"
uci -q set "network.${if_name}.device=${br_vlan_dev}"
# Set MAC address if provided
if [ -n "$mac_addr" ]; then
local resolved_mac=$(resolve_mac_address "$mac_addr")
uci -q set "network.${if_name}.macaddr=${resolved_mac}"
logger -s -p user.info -t "$_log_prefix" "Setting MAC address: $mac_addr -> $resolved_mac"
fi
[ "$disabled" = "1" ] && uci -q set "network.${if_name}.disabled=1"
# Create bridge-vlan section
local brvlan_sec_name="brv_${vlan_id}_${bridge_name}"
uci -q delete "network.${brvlan_sec_name}"
uci -q set "network.${brvlan_sec_name}=bridge-vlan"
uci -q set "network.${brvlan_sec_name}.device=${SHARED_BRIDGE_NAME}"
uci -q set "network.${brvlan_sec_name}.vlan=${vlan_id}"
uci -q delete "network.${brvlan_sec_name}.ports"
# Get WAN port for tagging decisions
local wan_port=$WAN_PORT
# Handle QinQ for transparent-qinq, tagged-qinq, qinq modes
# Create 8021ad device for svid if needed
if { [ "$vlan_type" = "transparent-qinq" ] || [ "$vlan_type" = "tagged-qinq" ] || [ "$vlan_type" = "qinq" ]; } && [ -n "$svid" ]; then
logger -s -p user.info -t "$_log_prefix" "Creating 8021ad device for QinQ svid: $svid"
# First, collect ports for the 8021ad device
for port in $actual_ports; do
local port_tpid=$(_extract_tpid "$port")
local port_clean=$(_strip_tpid "$port")
# Add this port to the base bridge
add_to_bridge_ports "$port_clean"
done
# Create 8021ad device for svid with first port (convention: use eth/ae interface)
# The 8021ad device will be created separately per port combination if needed
# For simplicity, we'll use one 8021ad device per svid
local first_port=$(echo "$actual_ports" | awk '{print $1}')
first_port=$(_strip_tpid "$first_port")
# Create the 8021ad device for svid
logger -s -p user.info -t "$_log_prefix" "Creating 8021ad device: ${first_port}.${svid} for svid=$svid"
local ad_device=$(create_vlan_device "$first_port" "$svid" "8021ad")
# Add the 8021ad device to bridge ports
add_to_bridge_ports "$ad_device"
fi
# Add ports with appropriate tagging
for port in $actual_ports; do
local port_to_add="$port"
local is_wan="0"
# Extract and strip tpid suffix before processing
local port_tpid=$(_extract_tpid "$port")
local port=$(_strip_tpid "$port")
# Check if explicit untagged is set
if echo "$port_to_add" | grep -qE '(:u\*?|:u)'; then
# Port has explicit untagged marker
if echo "$port_to_add" | grep -q ':u\*'; then
# Untagged egress-only
port_to_add="${port}:u*"
logger -s -p user.info -t "$_log_prefix" "Port $port set as untagged egress-only"
else
# Untagged
port_to_add="${port}:u"
logger -s -p user.info -t "$_log_prefix" "Port $port set as untagged"
fi
else
# Determine tagging based on VLAN type
[ "$port" = "$wan_port" ] && is_wan="1"
case "$vlan_type" in
none)
# Transparent - untagged
port_to_add="${port}:u"
;;
tagged)
# All ports tagged
port_to_add="${port}:t"
;;
wan-tagged)
# Only WAN tagged
if [ "$is_wan" = "1" ]; then
port_to_add="${port}:t"
else
port_to_add="${port}:u"
fi
;;
transparent-qinq)
# For transparent-qinq:
# If svid only: ports are untagged for cvid, or untagged egress-only for bare egress
# LAN ports: untagged egress-only (:u*)
# WAN port: add to s-vlan as untagged
if [ "$is_wan" = "1" ]; then
port_to_add="${port}:u"
else
port_to_add="${port}:u*"
fi
;;
tagged-qinq)
# All ports single-tagged (for c-vlan bridging)
port_to_add="${port}:t"
;;
qinq)
# All ports double-tagged
port_to_add="${port}:t"
;;
esac
fi
logger -s -p user.info -t "$_log_prefix" "Adding port to bridge-vlan: $port -> $port_to_add"
# Add base port to shared bridge
add_to_bridge_ports "${port}"
# Add port to bridge-vlan with tagging
uci -q add_list "network.${brvlan_sec_name}.ports=${port_to_add}"
set_mtu_for_port "${port}" "${mtu}"
done
logger -s -p user.info -t "$_log_prefix" "Bridge-VLAN $bridge_name (VLAN ${vlan_id}) created successfully"
}
# Clean up all existing bridges, VLANs, and routed interfaces
cleanup_interfaces() {
logger -s -p user.info -t "netmode-advanced" "Cleaning up existing interfaces"