Skip to content

Commit

Permalink
Merge pull request #441 from tiiuae/upgrade-cbma-to-v0.1.3
Browse files Browse the repository at this point in the history
  • Loading branch information
TIISR authored Apr 24, 2024
2 parents 785e27a + 79eeae2 commit 082b52a
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 13 deletions.
8 changes: 4 additions & 4 deletions modules/sc-mesh-secure-deployment/src/nats/cbma/VERSION
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
GIT_VERSION=v0.1.2-old_requirements_fixes
GIT_SHA=845b15b2bdf90862d40ec851066a8319552118dc
EPOCH_TIMESTAMP=1711146541
PRECISE_DATE_TIMESTAMP="2024-03-22 - 22:29:01.515125682"
GIT_VERSION=v0.1.3-old_requirements_fixes
GIT_SHA=9092b41ff906eb78dbeacf4e43cb2dcb2e3d5ec2
EPOCH_TIMESTAMP=1713779760
PRECISE_DATE_TIMESTAMP="2024-04-22 - 09:56:00.316748021"
13 changes: 13 additions & 0 deletions modules/sc-mesh-secure-deployment/src/nats/cbma/cbma.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from utils.logging import get_logger, setup_global_file_logging
from utils.networking import get_interface_link_local_ipv6_address, get_mac_from_ipv6
from utils.multicast import bytes_2_multicast_postfix
from utils.common import run_command_retcode
from models.certificates import CBMACertificates
from models.cbma import ICBMA

Expand All @@ -18,6 +19,8 @@
from macsec.macsec import MACsec


CBMA_ROOT = os.path.normpath(os.path.dirname(__file__))

SIGNALS = [signal.SIGINT, signal.SIGTERM]


Expand Down Expand Up @@ -101,6 +104,11 @@ def multicast_secure_connection_callback(ipv6: str) -> bool:

signal.signal(signal.SIGCHLD, self.__child_handler)

l_or_u = 'u' if self.is_upper else 'l'
create_br_str = f"bash -x {CBMA_ROOT}/scripts/mess/create_bridge.sh {l_or_u} {self.interface}"
if run_command_retcode(create_br_str.split()):
raise Exception('Unable to create MACsec bridge')


def __child_handler(self, signum: int, frame) -> None:
while True:
Expand Down Expand Up @@ -190,5 +198,10 @@ def stop(self) -> bool:
self.logger.error(f"Unable to stop MACsec process {pid}")
success = False

l_or_u = 'u' if self.is_upper else 'l'
cleanup_br_str = f"bash -x {CBMA_ROOT}/scripts/mess/cleanup_bridge.sh {l_or_u} {self.interface}"
if run_command_retcode(cleanup_br_str.split()):
success = False

self.logger.info(f"CBMA cleanup was {'' if success else 'not '}successful")
return success
18 changes: 9 additions & 9 deletions modules/sc-mesh-secure-deployment/src/nats/cbma/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,34 +109,34 @@ def is_interface_running(self, interface: str) -> bool:


def start_interface(self, interface: str) -> bool:
logger.info(f"Starting CBMA in ${interface}")
logger.info(f"Starting CBMA in {interface}")
if not (process := self.processes.get(interface, None)):
logger.error(f"No existing CBMA process found for ${interface}")
logger.error(f"No existing CBMA process found for {interface}")
return False
if self.is_interface_running(interface):
logger.debug(f"CBMA is already running in ${interface}")
logger.debug(f"CBMA is already running in {interface}")
return True

process.start()
process.join(timeout=self.PROCESS_START_TIMEOUT)
if not process.is_alive():
logger.error(f"Unable to start CBMA in ${interface}")
logger.error(f"Unable to start CBMA in {interface}")
return False
logger.debug(f"Successfully started CBMA in ${interface}")
logger.debug(f"Successfully started CBMA in {interface}")
return True


def stop_interface(self, interface: str) -> bool:
logger.info(f"Stopping CBMA in ${interface}")
logger.info(f"Stopping CBMA in {interface}")
if not (process := self.processes.get(interface, None)):
logger.error(f"No existing CBMA process found for ${interface}")
logger.error(f"No existing CBMA process found for {interface}")
return False
if not self.is_interface_running(interface):
logger.debug(f"CBMA is already stopped in ${interface}")
logger.debug(f"CBMA is already stopped in {interface}")
return True
if not self.__stop_interface_process(interface, process):
return False
logger.debug(f"Successfully stopped CBMA in ${interface}")
logger.debug(f"Successfully stopped CBMA in {interface}")
return True


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/bash


export SCN='/sys/class/net'

cleanup_bridge_if_needed()
{
for I in $SCN/$MACBR_NAME/lower_*; do
if [ "$I" = "$SCN/$MACBR_NAME/lower_*" ]; then
ebtables -t nat -D OUTPUT -j "$MACBR_NAME" --logical-out "$MACBR_NAME"
ebtables -t nat -X "$MACBR_NAME"
ip link delete "$MACBR_NAME"
fi
break
done
}

if [ $# -ne 2 ]; then
>&2 echo "Usage: $0 u bat0"
>&2 echo "Usage: $0 l wlan0"
exit 1
fi
export L_OR_U="$1"
export BASE_INTERFACE_NAME="$2"

MAC_REGEX='[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}'
if ! grep -Eiqx "$MAC_REGEX" "$SCN/$BASE_INTERFACE_NAME/address"; then
>&2 echo "Error: '$BASE_INTERFACE_NAME' does not look like a usable interface"
exit 2
fi
export LOCAL_MAC=`cat "$SCN/$BASE_INTERFACE_NAME/address"`
export MACBR_NAME=`echo "${L_OR_U}mb$LOCAL_MAC" | tr -d ':'`

# Workaround to use ebtables-legacy as "--logical-out" seems to be broken in ebtables-nft
if ! ebtables -V | grep -iq legacy; then
! type ebtables-legacy >/dev/null 2>&1 || alias ebtables="ebtables-legacy"
fi

cleanup_bridge_if_needed
exit $?
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/bin/bash


# kernel bugs force MACSEC_OVERHEAD=24 in create_macscbub_interface() but should still be ok
export MACSEC_OVERHEAD=16

# needs more testing, an overhead of 32 might even occur if batman-adv uses 4 address mode
export BATMAN_OVERHEAD=24

export HOPEFULLY1500=1400
export SCN='/sys/class/net'


create_bridge_if_needed()
{
if [ ! -e "$SCN/$MACBR_NAME/bridge" ]; then
if ! ip link add name "$MACBR_NAME" address "$LOCAL_MAC" mtu "$MACBR_MTU" type bridge; then
return `false`
fi
ip link set dev "$MACBR_NAME" group "$GROUP_ID" || true
ip link set dev "$MACBR_NAME" arp off || true
ip link set dev "$MACBR_NAME" multicast off || true
ip link set dev "$MACBR_NAME" alias "$LEVEL MACVLAN/MACsec bridge above $BASE_INTERFACE_NAME" || true
ip link set dev "$MACBR_NAME" addrgenmode eui64 || true
ip link set dev "$MACBR_NAME" type bridge no_linklocal_learn 1 || true
ebtables -t nat -N "$MACBR_NAME" || true
ebtables -t nat -A OUTPUT -j "$MACBR_NAME" --logical-out "$MACBR_NAME" || true
if ! ip link set dev "$MACBR_NAME" up \
|| ! batctl meshif "$BATMAN_NAME" interface add "$MACBR_NAME"; then
ip link delete "$MACBR_NAME"
return `false`
fi
fi
}


if [ $# -ne 2 ]; then
>&2 echo "Usage: $0 u bat0"
>&2 echo "Usage: $0 l wlan0"
exit 1
fi
export L_OR_U="$1"
export BASE_INTERFACE_NAME="$2"

case "$L_OR_U" in
u)
export LEVEL='Upper'
export BATMAN_NAME='bat1'
export MACBR_MTU=$(( $HOPEFULLY1500 + $BATMAN_OVERHEAD ))
;;
l)
export LEVEL='Lower'
export BATMAN_NAME='bat0'
export MACBR_MTU=$(( $HOPEFULLY1500 + $BATMAN_OVERHEAD + $MACSEC_OVERHEAD + $BATMAN_OVERHEAD ))
;;
*)
>&2 echo "Error: unknown level '$L_OR_U'"
exit 2
esac
MAC_REGEX='[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}:[0-9a-f]{2}'
if ! grep -Eiqx "$MAC_REGEX" "$SCN/$BASE_INTERFACE_NAME/address"; then
>&2 echo "Error: '$BASE_INTERFACE_NAME' does not look like a usable interface"
exit 3
fi
export GROUP_ID=`cat "$SCN/$BASE_INTERFACE_NAME/ifindex"`
export LOCAL_MAC=`cat "$SCN/$BASE_INTERFACE_NAME/address"`
export MACBR_NAME=`echo "${L_OR_U}mb$LOCAL_MAC" | tr -d ':'`

# Workaround to use ebtables-legacy as "--logical-out" seems to be broken in ebtables-nft
if ! ebtables -V | grep -iq legacy; then
! type ebtables-legacy >/dev/null 2>&1 || alias ebtables="ebtables-legacy"
fi

create_bridge_if_needed
exit $?
34 changes: 34 additions & 0 deletions modules/sc-mesh-secure-deployment/src/nats/cbma/standalone.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,37 @@

from models.certificates import CBMACertificates
from controller import CBMAController
from utils.common import run_command_retcode
from utils.networking import get_interface_mac_address
from utils.logging import get_logger


logger = get_logger(log_dir='.')


BATMAN_ROUTING_ALG = 'BATMAN_V'

def get_interface_locally_administed_mac(interface: str) -> str:
mac = get_interface_mac_address(interface)
mac_bytes = bytearray.fromhex(mac.replace(':', ''))
mac_bytes[0] ^= 0x2 # Locally administered bit
return mac_bytes.hex(sep=':', bytes_per_sep=1)

def create_batman(batman: str, mac: str) -> None:
create_batman_str = f"batctl meshif {batman} interface create routing_algo {BATMAN_ROUTING_ALG}"
set_batman_mac_str = f"ip link set {batman} address {mac}"
set_batman_up_str = f"ip link set {batman} up"
for cmd_str in [create_batman_str, set_batman_mac_str, set_batman_up_str]:
if run_command_retcode(cmd_str.split()):
sys.exit(255)

def destroy_batman(batman: str) -> None:
if glob(f"/sys/class/net/{batman}/lower_*"):
return
destroy_batman_str = f"ip link del {batman}"
run_command_retcode(destroy_batman_str.split())


if __name__ == '__main__':
parser = argparse.ArgumentParser(description='CBMA standalone parameters')
parser.add_argument(
Expand Down Expand Up @@ -59,6 +84,10 @@
else:
interfaces = args.interfaces if isinstance(args.interfaces, list) else [args.interfaces]

if not interfaces:
logger.error("No interfaces found")
sys.exit(255)

if args.batman in interfaces:
logger.error(f"{args.batman} found in both -i {' '.join(interfaces)} and -b {args.batman} flags")
sys.exit(255)
Expand All @@ -83,6 +112,9 @@
logger.error(f"Exception when creating the CBMAController: {e}")
sys.exit(255)

if not (existing_batman := f"/sys/class/net/{args.batman}" in glob("/sys/class/net/*")):
mac = get_interface_locally_administed_mac(interfaces[0])
create_batman(args.batman, mac)
try:
logger.info(f"Adding {interfaces} to the CBMAController")
for iface in interfaces:
Expand All @@ -94,5 +126,7 @@
logger.info('Interrupting...')
finally:
controller.stop()
if not existing_batman:
destroy_batman(args.batman)

logger.info('Exiting')

0 comments on commit 082b52a

Please sign in to comment.