@@ -60,7 +60,7 @@ def __init__(
60
60
self .BR_NAME : str = Constants .BR_NAME .value
61
61
self .LOWER_BATMAN : str = Constants .LOWER_BATMAN .value
62
62
self .UPPER_BATMAN : str = Constants .UPPER_BATMAN .value
63
- self .ALLOWED_KIND_LIST = {"vlan" , "batadv" }
63
+ self .ALLOWED_KIND_LIST = {"vlan" , "batadv" , "dsa" }
64
64
65
65
# Set minimum required configuration
66
66
self .__white_interfaces = [self .LOWER_BATMAN ]
@@ -116,9 +116,11 @@ def __validate_cbma_config(
116
116
black_interfaces : List [str ] = []
117
117
118
118
# 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
+ ):
122
124
self .logger .error ("Input params are not lists!" )
123
125
return False
124
126
@@ -270,6 +272,7 @@ def __delete_vlan_interfaces(self) -> bool:
270
272
interface .interface_name == vlan_name
271
273
for interface in self .__interfaces
272
274
):
275
+ self .__shutdown_interface (vlan_name )
273
276
# Delete existing VLAN interface
274
277
subprocess .run (["ip" , "link" , "delete" , vlan_name ], check = True )
275
278
except subprocess .CalledProcessError as e :
@@ -310,8 +313,8 @@ def __get_interfaces(self) -> None:
310
313
# thus should add only physical interfaces, vlan and batadv interfaces
311
314
if kind is None or kind in self .ALLOWED_KIND_LIST :
312
315
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 :
315
318
interfaces .append (interface_info )
316
319
ip .close ()
317
320
@@ -362,6 +365,7 @@ def __add_interface_to_bridge(
362
365
ip = IPRoute ()
363
366
364
367
try :
368
+ # Get the index of the bridge
365
369
bridge_indices = ip .link_lookup (ifname = bridge_name )
366
370
if bridge_indices :
367
371
bridge_index = bridge_indices [0 ]
@@ -374,7 +378,6 @@ def __add_interface_to_bridge(
374
378
375
379
# Get the index of the interface to add
376
380
interface_indices = ip .link_lookup (ifname = interface_to_add )
377
-
378
381
if not interface_indices :
379
382
self .logger .debug (
380
383
"Cannot add interface %s to bridge %s!" ,
@@ -384,9 +387,27 @@ def __add_interface_to_bridge(
384
387
return
385
388
386
389
interface_index = interface_indices [0 ]
387
- # Add the interface to the bridge
388
- ip .link ("set" , index = interface_index , master = bridge_index )
389
390
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 )
390
411
except Exception as e :
391
412
self .logger .error (
392
413
"Error adding interface %s to bridge %s! Error: %s" ,
@@ -415,6 +436,7 @@ def __shutdown_interface(self, interface_name: str) -> None:
415
436
try :
416
437
index = ip .link_lookup (ifname = interface_name )[0 ]
417
438
ip .link ("set" , index = index , state = "down" )
439
+ ip .link ("set" , index = index , master = None )
418
440
except IndexError :
419
441
self .logger .debug (
420
442
"Not able to shutdown interface %s! Interface not found!" ,
@@ -510,6 +532,35 @@ def __update_cbma_interface_lists(self) -> None:
510
532
if interface in self .__lower_cbma_interfaces :
511
533
self .__lower_cbma_interfaces .remove (interface )
512
534
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
+
513
564
def __wait_for_ap (self , timeout : int = 4 ) -> bool :
514
565
start_time = time .time ()
515
566
while True :
@@ -587,13 +638,40 @@ def __create_mac(self, randomized: bool = False, interface_mac: str = "") -> str
587
638
return bytes (mac ).hex (sep = ":" , bytes_per_sep = 1 )
588
639
else :
589
640
# Flip the locally administered bit
590
- mac_bytes = bytearray .fromhex (interface_mac .replace (':' , '' ))
641
+ mac_bytes = bytearray .fromhex (interface_mac .replace (":" , "" ))
591
642
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 )
593
671
594
672
def __init_batman_and_bridge (self ) -> None :
595
673
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" ) :
597
675
if_pattern = "wlp*s0"
598
676
for interface_name in self .__comms_ctrl .settings .mesh_vif :
599
677
if fnmatch .fnmatch (interface_name , if_pattern ):
@@ -615,7 +693,7 @@ def __init_batman_and_bridge(self) -> None:
615
693
self .__create_bridge (self .BR_NAME )
616
694
617
695
# 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 ( ))
619
697
self .__wait_for_interface (self .LOWER_BATMAN )
620
698
self .__wait_for_interface (self .UPPER_BATMAN )
621
699
@@ -661,7 +739,7 @@ def __setup_radios(self) -> bool:
661
739
for interface_name in self .__comms_ctrl .settings .mesh_vif :
662
740
self .logger .debug ("mesh_vif: %s" , interface_name )
663
741
timeout = 5
664
- if interface_name .startswith ("halow" ):
742
+ if interface_name .startswith ("halow" ) or interface_name . startswith ( "morse" ) :
665
743
timeout = 20
666
744
self .__wait_for_interface (interface_name , timeout )
667
745
@@ -734,6 +812,7 @@ def setup_cbma(self) -> bool:
734
812
self .__init_batman_and_bridge ()
735
813
736
814
self .__update_cbma_interface_lists ()
815
+ self .__update_red_interfaces_list ()
737
816
738
817
# Set radios on
739
818
self .__setup_radios ()
@@ -962,6 +1041,11 @@ def __setup_upper_cbma(self) -> bool:
962
1041
return intf_added
963
1042
964
1043
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
+ """
965
1049
self .__get_interfaces ()
966
1050
self .__shutdown_interface (self .LOWER_BATMAN )
967
1051
self .__shutdown_interface (self .UPPER_BATMAN )
@@ -970,7 +1054,6 @@ def __cleanup_cbma(self) -> None:
970
1054
self .__batman .destroy_batman_interface (self .UPPER_BATMAN )
971
1055
972
1056
self .__delete_vlan_interfaces ()
973
- self .__shutdown_and_delete_bridge (self .BR_NAME )
974
1057
975
1058
def __stop_controller (self , controller , name : str ) -> bool :
976
1059
"""
0 commit comments