Skip to content

Commit e9ad4c4

Browse files
authored
Merge pull request #484 from tiiuae/bridge_control
Change br-lan control
2 parents 61d2773 + f4af286 commit e9ad4c4

File tree

2 files changed

+116
-27
lines changed

2 files changed

+116
-27
lines changed

modules/sc-mesh-secure-deployment/src/nats/conf/default_ms_config.yaml

+18-12
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,16 @@ CBMA:
2121
- sap0
2222
- sta0
2323
- wfd0
24-
white_interfaces:
24+
- end0
25+
- end1
26+
white_interfaces:
2527
red_interfaces:
2628
- wlan1
2729
- usb0
30+
- eth0
31+
- end0
32+
- end1
33+
- lan1
2834

2935
BATMAN:
3036
routing_algo: BATMAN_V
@@ -35,17 +41,17 @@ BATMAN:
3541
hardif:
3642
halow1: 20
3743

38-
VLAN:
44+
#VLAN:
3945
# Remember that IP address definitions for such interface that is added to
4046
# CBMA's red_interfaces list (i.e. br-lan bridge) are not effective.
41-
vlan_black:
42-
parent_interface: eth0
43-
vlan_id: 100
44-
ipv4_address: 192.168.1.1
45-
ipv4_subnet_mask: 255.255.255.0
46-
ipv6_local_address: fe80::192.168.1.1
47-
ipv6_prefix_length: 64
48-
vlan_red:
49-
parent_interface: eth0
50-
vlan_id: 200
47+
# vlan_black:
48+
# parent_interface: eth0
49+
# vlan_id: 100
50+
# ipv4_address: 192.168.1.1
51+
# ipv4_subnet_mask: 255.255.255.0
52+
# ipv6_local_address: fe80::192.168.1.1
53+
# ipv6_prefix_length: 64
54+
# vlan_red:
55+
# parent_interface: eth0
56+
# vlan_id: 200
5157

modules/sc-mesh-secure-deployment/src/nats/src/cbma_adaptation.py

+98-15
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def __init__(
6060
self.BR_NAME: str = Constants.BR_NAME.value
6161
self.LOWER_BATMAN: str = Constants.LOWER_BATMAN.value
6262
self.UPPER_BATMAN: str = Constants.UPPER_BATMAN.value
63-
self.ALLOWED_KIND_LIST = {"vlan", "batadv"}
63+
self.ALLOWED_KIND_LIST = {"vlan", "batadv", "dsa"}
6464

6565
# Set minimum required configuration
6666
self.__white_interfaces = [self.LOWER_BATMAN]
@@ -116,9 +116,11 @@ def __validate_cbma_config(
116116
black_interfaces: List[str] = []
117117

118118
# Validate input param types
119-
if not isinstance(white_interfaces, list) or \
120-
not isinstance(red_interfaces, list) or \
121-
not isinstance(exclude_interfaces, list):
119+
if (
120+
not isinstance(white_interfaces, list)
121+
or not isinstance(red_interfaces, list)
122+
or not isinstance(exclude_interfaces, list)
123+
):
122124
self.logger.error("Input params are not lists!")
123125
return False
124126

@@ -270,6 +272,7 @@ def __delete_vlan_interfaces(self) -> bool:
270272
interface.interface_name == vlan_name
271273
for interface in self.__interfaces
272274
):
275+
self.__shutdown_interface(vlan_name)
273276
# Delete existing VLAN interface
274277
subprocess.run(["ip", "link", "delete", vlan_name], check=True)
275278
except subprocess.CalledProcessError as e:
@@ -310,8 +313,8 @@ def __get_interfaces(self) -> None:
310313
# thus should add only physical interfaces, vlan and batadv interfaces
311314
if kind is None or kind in self.ALLOWED_KIND_LIST:
312315
interfaces.append(interface_info)
313-
# We want to monitor also br-lan status thus expcetion to basic rules
314-
elif kind == "bridge" and ifname== Constants.BR_NAME.value:
316+
# We want to monitor also br-lan status thus exception to basic rules
317+
elif kind == "bridge" and ifname == Constants.BR_NAME.value:
315318
interfaces.append(interface_info)
316319
ip.close()
317320

@@ -362,6 +365,7 @@ def __add_interface_to_bridge(
362365
ip = IPRoute()
363366

364367
try:
368+
# Get the index of the bridge
365369
bridge_indices = ip.link_lookup(ifname=bridge_name)
366370
if bridge_indices:
367371
bridge_index = bridge_indices[0]
@@ -374,7 +378,6 @@ def __add_interface_to_bridge(
374378

375379
# Get the index of the interface to add
376380
interface_indices = ip.link_lookup(ifname=interface_to_add)
377-
378381
if not interface_indices:
379382
self.logger.debug(
380383
"Cannot add interface %s to bridge %s!",
@@ -384,9 +387,27 @@ def __add_interface_to_bridge(
384387
return
385388

386389
interface_index = interface_indices[0]
387-
# Add the interface to the bridge
388-
ip.link("set", index=interface_index, master=bridge_index)
389390

391+
# Get the current interface details
392+
interface_info = ip.get_links(interface_index)[0]
393+
current_master = interface_info.get("master")
394+
395+
if current_master == bridge_index:
396+
self.logger.info(
397+
"Interface %s is already part of the bridge %s.",
398+
interface_to_add,
399+
bridge_name,
400+
)
401+
else:
402+
# Add the interface to the bridge
403+
ip.link("set", index=interface_index, master=bridge_index)
404+
self.logger.info(
405+
"Successfully added interface %s to bridge %s.",
406+
interface_to_add,
407+
bridge_name,
408+
)
409+
# Bring the interface up
410+
self.__set_interface_up(interface_to_add)
390411
except Exception as e:
391412
self.logger.error(
392413
"Error adding interface %s to bridge %s! Error: %s",
@@ -415,6 +436,7 @@ def __shutdown_interface(self, interface_name: str) -> None:
415436
try:
416437
index = ip.link_lookup(ifname=interface_name)[0]
417438
ip.link("set", index=index, state="down")
439+
ip.link("set", index=index, master=None)
418440
except IndexError:
419441
self.logger.debug(
420442
"Not able to shutdown interface %s! Interface not found!",
@@ -510,6 +532,35 @@ def __update_cbma_interface_lists(self) -> None:
510532
if interface in self.__lower_cbma_interfaces:
511533
self.__lower_cbma_interfaces.remove(interface)
512534

535+
def __update_red_interfaces_list(self):
536+
"""
537+
Updates the red_interfaces list:
538+
1. Filters red_interfaces to keep only those interfaces that exist in self.__interfaces.
539+
2. Handles mutually exclusive interfaces, removing eth/end interfaces if a lan interface is found.
540+
3. Ensures "UPPER_BATMAN" is present in the red_interfaces list.
541+
"""
542+
# Step 1: Filter red_interfaces to keep only interfaces that exist in self.__interfaces.
543+
red_interfaces = [
544+
interface
545+
for interface in self.__red_interfaces
546+
if any(iface.interface_name == interface for iface in self.__interfaces)
547+
]
548+
549+
# Step 2: Remove eth_end_interfaces if any lan interface is found in red_interfaces.
550+
lan_interfaces = {"lan1", "lan2", "lan3"}
551+
eth_end_interfaces = {"eth0", "end0", "end1"}
552+
553+
if any(lan in red_interfaces for lan in lan_interfaces):
554+
red_interfaces = [
555+
iface for iface in red_interfaces if iface not in eth_end_interfaces
556+
]
557+
558+
# Step 3: Ensure "UPPER_BATMAN" is present in the red_interfaces list.
559+
if self.UPPER_BATMAN not in red_interfaces:
560+
red_interfaces.append(self.UPPER_BATMAN)
561+
# Update the internal red interfaces list.
562+
self.__red_interfaces = red_interfaces
563+
513564
def __wait_for_ap(self, timeout: int = 4) -> bool:
514565
start_time = time.time()
515566
while True:
@@ -587,13 +638,40 @@ def __create_mac(self, randomized: bool = False, interface_mac: str = "") -> str
587638
return bytes(mac).hex(sep=":", bytes_per_sep=1)
588639
else:
589640
# Flip the locally administered bit
590-
mac_bytes = bytearray.fromhex(interface_mac.replace(':', ''))
641+
mac_bytes = bytearray.fromhex(interface_mac.replace(":", ""))
591642
mac_bytes[0] ^= 0x2
592-
return mac_bytes.hex(sep=':', bytes_per_sep=1)
643+
return mac_bytes.hex(sep=":", bytes_per_sep=1)
644+
645+
def __create_mac_for_bridge(self) -> str:
646+
"""
647+
Creates a MAC address for the bridge. MAC is created from osf, eth0,
648+
end0, end1 or wlan1 interface MAC by flipping the local admin bit.
649+
In case all those interfaces are configured as black interfaces
650+
(i.e. they are configured as red or white interfaces or excluded from CBMA)
651+
then a random MAC is generated for the bridge.
652+
653+
:return: generated MAC for the bridge usage
654+
"""
655+
interfaces: List[str] = ["osf", "eth0", "end0", "end1", "wlan1"]
656+
for interface in interfaces:
657+
if (
658+
interface in self.__white_interfaces
659+
or interface in self.__red_interfaces
660+
or interface in self.__na_cbma_interfaces
661+
):
662+
mac = self.__get_mac_addr(interface)
663+
if mac:
664+
# Flip the locally administered bit
665+
mac_bytes = bytearray.fromhex(mac.replace(":", ""))
666+
if not (mac_bytes[0] & 0x2):
667+
mac_bytes[0] |= 0x2
668+
return mac_bytes.hex(sep=":", bytes_per_sep=1)
669+
# Generate random MAC in case didn't get any earlier
670+
return self.__create_mac(True)
593671

594672
def __init_batman_and_bridge(self) -> None:
595673
if_name = self.__comms_ctrl.settings.mesh_vif[0]
596-
if if_name.startswith("halow"):
674+
if if_name.startswith("halow") or if_name.startswith("morse"):
597675
if_pattern = "wlp*s0"
598676
for interface_name in self.__comms_ctrl.settings.mesh_vif:
599677
if fnmatch.fnmatch(interface_name, if_pattern):
@@ -615,7 +693,7 @@ def __init_batman_and_bridge(self) -> None:
615693
self.__create_bridge(self.BR_NAME)
616694

617695
# Set random MAC address for the bridge
618-
self.__set_interface_mac(self.BR_NAME, self.__create_mac(True))
696+
self.__set_interface_mac(self.BR_NAME, self.__create_mac_for_bridge())
619697
self.__wait_for_interface(self.LOWER_BATMAN)
620698
self.__wait_for_interface(self.UPPER_BATMAN)
621699

@@ -661,7 +739,7 @@ def __setup_radios(self) -> bool:
661739
for interface_name in self.__comms_ctrl.settings.mesh_vif:
662740
self.logger.debug("mesh_vif: %s", interface_name)
663741
timeout = 5
664-
if interface_name.startswith("halow"):
742+
if interface_name.startswith("halow") or interface_name.startswith("morse"):
665743
timeout = 20
666744
self.__wait_for_interface(interface_name, timeout)
667745

@@ -734,6 +812,7 @@ def setup_cbma(self) -> bool:
734812
self.__init_batman_and_bridge()
735813

736814
self.__update_cbma_interface_lists()
815+
self.__update_red_interfaces_list()
737816

738817
# Set radios on
739818
self.__setup_radios()
@@ -962,6 +1041,11 @@ def __setup_upper_cbma(self) -> bool:
9621041
return intf_added
9631042

9641043
def __cleanup_cbma(self) -> None:
1044+
"""
1045+
Shuts down /which removes them from bridge also) Batman interfaces
1046+
and then deletes them. Also deletes any created VLAN interfaces but
1047+
lets bridge remain for eample for ethernet usage.
1048+
"""
9651049
self.__get_interfaces()
9661050
self.__shutdown_interface(self.LOWER_BATMAN)
9671051
self.__shutdown_interface(self.UPPER_BATMAN)
@@ -970,7 +1054,6 @@ def __cleanup_cbma(self) -> None:
9701054
self.__batman.destroy_batman_interface(self.UPPER_BATMAN)
9711055

9721056
self.__delete_vlan_interfaces()
973-
self.__shutdown_and_delete_bridge(self.BR_NAME)
9741057

9751058
def __stop_controller(self, controller, name: str) -> bool:
9761059
"""

0 commit comments

Comments
 (0)