Loading go-apps/meep-simu5g-bridge/bridge.go +38 −2 Changes for go-apps/meep-simu5g-bridge/bridge.go: 38 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ func NewBridgeInstance(cfg *bridge.IntegrationConfig) (*BridgeInstance, error) { } /** * @brief Dials simulator host S and sends a HELLO control frame. * @brief Dials simulator host S and sends HELLO with live NAT tables. * @return Error from net.DialTimeout or TCP write. */ func (b *BridgeInstance) connectAndHello() error { Loading @@ -89,7 +89,13 @@ func (b *BridgeInstance) connectAndHello() error { b.conn = conn b.mutex.Unlock() hello := bridge.EncodeControlHello("bridge") hello := bridge.EncodeControlHelloFromConfig("bridge", b.cfg) nUe, nMec := 0, 0 if b.cfg != nil { nUe = len(b.cfg.UEMappings) nMec = len(b.cfg.MECEndpoints) } log.Info(b.cfg.SandboxLogPrefix(), " HELLO NAT tables ue=", nUe, " mec=", nMec, " dest=", addr) b.mutex.Lock() _, err = b.conn.Write(hello) b.mutex.Unlock() Loading Loading @@ -272,3 +278,33 @@ func ipv4Source(pkt []byte) net.IP { } return net.IP(pkt[12:16]).To4() } /** * @brief Extracts IPv4 destination address from a raw IPv4 packet buffer. * @param pkt Raw L3 packet bytes (minimum 20-byte IPv4 header). * @return Destination IPv4 or nil if not IPv4 or buffer too short. */ func ipv4Dest(pkt []byte) net.IP { if len(pkt) < 20 { return nil } if pkt[0]>>4 != 4 { return nil } return net.IP(pkt[16:20]).To4() } /** * @brief Returns the IPv4 protocol field (1=ICMP, 6=TCP, 17=UDP). * @param pkt Raw L3 packet bytes. * @return Protocol number, or 0 if not IPv4. */ func ipv4Proto(pkt []byte) int { if len(pkt) < 10 { return 0 } if pkt[0]>>4 != 4 { return 0 } return int(pkt[9]) } go-packages/meep-simu5g-bridge/protocol.go +42 −2 Changes for go-packages/meep-simu5g-bridge/protocol.go: 42 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ package bridge import ( "encoding/binary" "encoding/json" "time" ) Loading Loading @@ -102,6 +103,7 @@ type UEMapping struct { UeID string `json:"ueId"` SandboxIPCidr string `json:"sandboxIpCidr"` Simu5gModulePath string `json:"simu5gModulePath"` SimIP string `json:"simIp,omitempty"` // Optional; S defaults from ue_car/ue_ped path } /** Loading @@ -111,6 +113,7 @@ type MECEndpoint struct { EndpointID string `json:"endpointId"` SandboxIPCidr string `json:"sandboxIpCidr"` Simu5gModulePath string `json:"simu5gModulePath"` SimIP string `json:"simIp,omitempty"` // Optional; S defaults to 192.168.20.2 } /** Loading Loading @@ -177,12 +180,49 @@ func PacketFromDataDLFrame(payload []byte) ([]byte, bool) { } /** * @brief Builds a minimal HELLO control frame from sandbox host B. * @brief HELLO JSON body. S loadIntegrationJson reads ueMappings / mecEndpoints. */ type HelloBody struct { Role string `json:"role"` Version string `json:"version"` UEMappings []UEMapping `json:"ueMappings,omitempty"` MECEndpoints []MECEndpoint `json:"mecEndpoints,omitempty"` } /** * @brief Builds a HELLO control frame (role/version only; no NAT tables). * @param role Client role string (e.g. "bridge"). * @return Serialized CONTROL frame with JSON capability body. */ func EncodeControlHello(role string) []byte { body := []byte(`{"role":"` + role + `","version":"0.1"}`) return EncodeControlHelloFromConfig(role, nil) } /** * @brief Builds a HELLO with live Calico↔sim NAT tables for host S. * * @details Body is the same schema S already merges in handleControlPayload: * ueMappings[].sandboxIpCidr / simu5gModulePath / optional simIp, and * mecEndpoints[].sandboxIpCidr / optional simIp. Sent on connect and reconnect * so a sandbox redeploy updates S without editing omnetpp.ini. * * @param role Client role string (e.g. "bridge"). * @param cfg Integration config; nil or empty slices omit the arrays. * @return Serialized CONTROL HELLO frame. */ func EncodeControlHelloFromConfig(role string, cfg *IntegrationConfig) []byte { hello := HelloBody{Role: role, Version: "0.1"} if cfg != nil { hello.UEMappings = cfg.UEMappings hello.MECEndpoints = cfg.MECEndpoints } body, err := json.Marshal(hello) if err != nil { body, err = json.Marshal(HelloBody{Role: role, Version: "0.1"}) if err != nil { body = []byte(`{"role":"bridge","version":"0.1"}`) } } payloadLen := 4 + len(body) frame := make([]byte, FrameHeaderSize+payloadLen) binary.BigEndian.PutUint16(frame[0:2], FrameMagic) Loading tools/simu5g/monaco-harbor-integration-config.json +9 −9 Changes for tools/simu5g/monaco-harbor-integration-config.json: 9 added lines, 9 removed lines. Original line number Diff line number Diff line Loading @@ -31,49 +31,49 @@ "ueMappings": [ { "ueId": "ue-car-0", "sandboxIpCidr": "192.168.108.161/32", "sandboxIpCidr": "192.168.108.171/32", "simu5gModulePath": "MonacoHarbor.ue_car[0]" }, { "ueId": "ue-car-1", "sandboxIpCidr": "192.168.108.135/32", "sandboxIpCidr": "192.168.108.169/32", "simu5gModulePath": "MonacoHarbor.ue_car[1]" }, { "ueId": "ue-car-2", "sandboxIpCidr": "192.168.108.187/32", "sandboxIpCidr": "192.168.108.180/32", "simu5gModulePath": "MonacoHarbor.ue_car[2]" }, { "ueId": "ue-car-3", "sandboxIpCidr": "192.168.108.145/32", "sandboxIpCidr": "192.168.108.190/32", "simu5gModulePath": "MonacoHarbor.ue_car[3]" }, { "ueId": "ue-ped-0", "sandboxIpCidr": "192.168.108.164/32", "sandboxIpCidr": "192.168.108.154/32", "simu5gModulePath": "MonacoHarbor.ue_ped[0]" }, { "ueId": "ue-ped-1", "sandboxIpCidr": "192.168.108.176/32", "sandboxIpCidr": "192.168.108.188/32", "simu5gModulePath": "MonacoHarbor.ue_ped[1]" }, { "ueId": "ue-ped-2", "sandboxIpCidr": "192.168.108.156/32", "sandboxIpCidr": "192.168.108.176/32", "simu5gModulePath": "MonacoHarbor.ue_ped[2]" }, { "ueId": "ue-ped-3", "sandboxIpCidr": "192.168.108.130/32", "sandboxIpCidr": "192.168.108.134/32", "simu5gModulePath": "MonacoHarbor.ue_ped[3]" } ], "mecEndpoints": [ { "endpointId": "mep1", "sandboxIpCidr": "192.168.108.181/32", "sandboxIpCidr": "192.168.108.130/32", "simu5gModulePath": "router" } ], Loading tools/simu5g/wireshark/apparmor-local-tshark 0 → 100644 +10 −0 Changes for tools/simu5g/wireshark/apparmor-local-tshark: 10 added lines, 0 removed lines. Original line number Diff line number Diff line # Optional: allow tshark to read this repo in-place (no /tmp staging). # sudo cp tools/simu5g/wireshark/apparmor-local-tshark /etc/apparmor.d/local/tshark # sudo apparmor_parser -r /etc/apparmor.d/tshark # # The packaged /etc/apparmor.d/tshark only allows /tmp and /usr/share/wireshark. owner @{HOME}/etsi-mec-sandbox/** r, owner @{HOME}/**.lua r, owner @{HOME}/**.pcap r, owner @{HOME}/**.pcapng r, tools/simu5g/wireshark/run_tshark_s5.sh 0 → 100755 +51 −0 Changes for tools/simu5g/wireshark/run_tshark_s5.sh: 51 added lines, 0 removed lines. Original line number Diff line number Diff line #!/usr/bin/env bash # Stage the S5 dissector (and -r capture files) under /tmp so Ubuntu's tshark # AppArmor profile can read them. /usr/bin/tshark may not read $HOME. # # Usage: # ./tools/simu5g/wireshark/run_tshark_s5.sh -r B_to_S.pcap -Y s5uldl # ./tools/simu5g/wireshark/run_tshark_s5.sh B_to_S.pcap set -euo pipefail readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly LUA_SRC="${SCRIPT_DIR}/s5_uldl.lua" readonly STAGE="${TMPDIR:-/tmp}/s5uldl-$(id -u)" [[ -f "$LUA_SRC" ]] || { echo "missing $LUA_SRC" >&2; exit 1; } mkdir -p "$STAGE" cp -f "$LUA_SRC" "$STAGE/s5_uldl.lua" chmod 644 "$STAGE/s5_uldl.lua" stage_path() { local src=$1 local dest if [[ "$src" != /* ]]; then src="$(pwd)/$src" fi dest="${STAGE}/$(basename "$src")" cp -f "$src" "$dest" chmod 644 "$dest" 2>/dev/null || true printf '%s\n' "$dest" } args=(-X "lua_script:${STAGE}/s5_uldl.lua") if [[ $# -eq 1 && -f "$1" && "$1" != -* ]]; then args+=(-r "$(stage_path "$1")" -Y s5uldl) shift else while [[ $# -gt 0 ]]; do case "$1" in -r|--read-file) [[ $# -ge 2 ]] || { echo "missing file after $1" >&2; exit 2; } args+=(-r "$(stage_path "$2")") shift 2 ;; *) args+=("$1") shift ;; esac done fi exec tshark "${args[@]}" Loading
go-apps/meep-simu5g-bridge/bridge.go +38 −2 Changes for go-apps/meep-simu5g-bridge/bridge.go: 38 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ func NewBridgeInstance(cfg *bridge.IntegrationConfig) (*BridgeInstance, error) { } /** * @brief Dials simulator host S and sends a HELLO control frame. * @brief Dials simulator host S and sends HELLO with live NAT tables. * @return Error from net.DialTimeout or TCP write. */ func (b *BridgeInstance) connectAndHello() error { Loading @@ -89,7 +89,13 @@ func (b *BridgeInstance) connectAndHello() error { b.conn = conn b.mutex.Unlock() hello := bridge.EncodeControlHello("bridge") hello := bridge.EncodeControlHelloFromConfig("bridge", b.cfg) nUe, nMec := 0, 0 if b.cfg != nil { nUe = len(b.cfg.UEMappings) nMec = len(b.cfg.MECEndpoints) } log.Info(b.cfg.SandboxLogPrefix(), " HELLO NAT tables ue=", nUe, " mec=", nMec, " dest=", addr) b.mutex.Lock() _, err = b.conn.Write(hello) b.mutex.Unlock() Loading Loading @@ -272,3 +278,33 @@ func ipv4Source(pkt []byte) net.IP { } return net.IP(pkt[12:16]).To4() } /** * @brief Extracts IPv4 destination address from a raw IPv4 packet buffer. * @param pkt Raw L3 packet bytes (minimum 20-byte IPv4 header). * @return Destination IPv4 or nil if not IPv4 or buffer too short. */ func ipv4Dest(pkt []byte) net.IP { if len(pkt) < 20 { return nil } if pkt[0]>>4 != 4 { return nil } return net.IP(pkt[16:20]).To4() } /** * @brief Returns the IPv4 protocol field (1=ICMP, 6=TCP, 17=UDP). * @param pkt Raw L3 packet bytes. * @return Protocol number, or 0 if not IPv4. */ func ipv4Proto(pkt []byte) int { if len(pkt) < 10 { return 0 } if pkt[0]>>4 != 4 { return 0 } return int(pkt[9]) }
go-packages/meep-simu5g-bridge/protocol.go +42 −2 Changes for go-packages/meep-simu5g-bridge/protocol.go: 42 added lines, 2 removed lines. Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ package bridge import ( "encoding/binary" "encoding/json" "time" ) Loading Loading @@ -102,6 +103,7 @@ type UEMapping struct { UeID string `json:"ueId"` SandboxIPCidr string `json:"sandboxIpCidr"` Simu5gModulePath string `json:"simu5gModulePath"` SimIP string `json:"simIp,omitempty"` // Optional; S defaults from ue_car/ue_ped path } /** Loading @@ -111,6 +113,7 @@ type MECEndpoint struct { EndpointID string `json:"endpointId"` SandboxIPCidr string `json:"sandboxIpCidr"` Simu5gModulePath string `json:"simu5gModulePath"` SimIP string `json:"simIp,omitempty"` // Optional; S defaults to 192.168.20.2 } /** Loading Loading @@ -177,12 +180,49 @@ func PacketFromDataDLFrame(payload []byte) ([]byte, bool) { } /** * @brief Builds a minimal HELLO control frame from sandbox host B. * @brief HELLO JSON body. S loadIntegrationJson reads ueMappings / mecEndpoints. */ type HelloBody struct { Role string `json:"role"` Version string `json:"version"` UEMappings []UEMapping `json:"ueMappings,omitempty"` MECEndpoints []MECEndpoint `json:"mecEndpoints,omitempty"` } /** * @brief Builds a HELLO control frame (role/version only; no NAT tables). * @param role Client role string (e.g. "bridge"). * @return Serialized CONTROL frame with JSON capability body. */ func EncodeControlHello(role string) []byte { body := []byte(`{"role":"` + role + `","version":"0.1"}`) return EncodeControlHelloFromConfig(role, nil) } /** * @brief Builds a HELLO with live Calico↔sim NAT tables for host S. * * @details Body is the same schema S already merges in handleControlPayload: * ueMappings[].sandboxIpCidr / simu5gModulePath / optional simIp, and * mecEndpoints[].sandboxIpCidr / optional simIp. Sent on connect and reconnect * so a sandbox redeploy updates S without editing omnetpp.ini. * * @param role Client role string (e.g. "bridge"). * @param cfg Integration config; nil or empty slices omit the arrays. * @return Serialized CONTROL HELLO frame. */ func EncodeControlHelloFromConfig(role string, cfg *IntegrationConfig) []byte { hello := HelloBody{Role: role, Version: "0.1"} if cfg != nil { hello.UEMappings = cfg.UEMappings hello.MECEndpoints = cfg.MECEndpoints } body, err := json.Marshal(hello) if err != nil { body, err = json.Marshal(HelloBody{Role: role, Version: "0.1"}) if err != nil { body = []byte(`{"role":"bridge","version":"0.1"}`) } } payloadLen := 4 + len(body) frame := make([]byte, FrameHeaderSize+payloadLen) binary.BigEndian.PutUint16(frame[0:2], FrameMagic) Loading
tools/simu5g/monaco-harbor-integration-config.json +9 −9 Changes for tools/simu5g/monaco-harbor-integration-config.json: 9 added lines, 9 removed lines. Original line number Diff line number Diff line Loading @@ -31,49 +31,49 @@ "ueMappings": [ { "ueId": "ue-car-0", "sandboxIpCidr": "192.168.108.161/32", "sandboxIpCidr": "192.168.108.171/32", "simu5gModulePath": "MonacoHarbor.ue_car[0]" }, { "ueId": "ue-car-1", "sandboxIpCidr": "192.168.108.135/32", "sandboxIpCidr": "192.168.108.169/32", "simu5gModulePath": "MonacoHarbor.ue_car[1]" }, { "ueId": "ue-car-2", "sandboxIpCidr": "192.168.108.187/32", "sandboxIpCidr": "192.168.108.180/32", "simu5gModulePath": "MonacoHarbor.ue_car[2]" }, { "ueId": "ue-car-3", "sandboxIpCidr": "192.168.108.145/32", "sandboxIpCidr": "192.168.108.190/32", "simu5gModulePath": "MonacoHarbor.ue_car[3]" }, { "ueId": "ue-ped-0", "sandboxIpCidr": "192.168.108.164/32", "sandboxIpCidr": "192.168.108.154/32", "simu5gModulePath": "MonacoHarbor.ue_ped[0]" }, { "ueId": "ue-ped-1", "sandboxIpCidr": "192.168.108.176/32", "sandboxIpCidr": "192.168.108.188/32", "simu5gModulePath": "MonacoHarbor.ue_ped[1]" }, { "ueId": "ue-ped-2", "sandboxIpCidr": "192.168.108.156/32", "sandboxIpCidr": "192.168.108.176/32", "simu5gModulePath": "MonacoHarbor.ue_ped[2]" }, { "ueId": "ue-ped-3", "sandboxIpCidr": "192.168.108.130/32", "sandboxIpCidr": "192.168.108.134/32", "simu5gModulePath": "MonacoHarbor.ue_ped[3]" } ], "mecEndpoints": [ { "endpointId": "mep1", "sandboxIpCidr": "192.168.108.181/32", "sandboxIpCidr": "192.168.108.130/32", "simu5gModulePath": "router" } ], Loading
tools/simu5g/wireshark/apparmor-local-tshark 0 → 100644 +10 −0 Changes for tools/simu5g/wireshark/apparmor-local-tshark: 10 added lines, 0 removed lines. Original line number Diff line number Diff line # Optional: allow tshark to read this repo in-place (no /tmp staging). # sudo cp tools/simu5g/wireshark/apparmor-local-tshark /etc/apparmor.d/local/tshark # sudo apparmor_parser -r /etc/apparmor.d/tshark # # The packaged /etc/apparmor.d/tshark only allows /tmp and /usr/share/wireshark. owner @{HOME}/etsi-mec-sandbox/** r, owner @{HOME}/**.lua r, owner @{HOME}/**.pcap r, owner @{HOME}/**.pcapng r,
tools/simu5g/wireshark/run_tshark_s5.sh 0 → 100755 +51 −0 Changes for tools/simu5g/wireshark/run_tshark_s5.sh: 51 added lines, 0 removed lines. Original line number Diff line number Diff line #!/usr/bin/env bash # Stage the S5 dissector (and -r capture files) under /tmp so Ubuntu's tshark # AppArmor profile can read them. /usr/bin/tshark may not read $HOME. # # Usage: # ./tools/simu5g/wireshark/run_tshark_s5.sh -r B_to_S.pcap -Y s5uldl # ./tools/simu5g/wireshark/run_tshark_s5.sh B_to_S.pcap set -euo pipefail readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly LUA_SRC="${SCRIPT_DIR}/s5_uldl.lua" readonly STAGE="${TMPDIR:-/tmp}/s5uldl-$(id -u)" [[ -f "$LUA_SRC" ]] || { echo "missing $LUA_SRC" >&2; exit 1; } mkdir -p "$STAGE" cp -f "$LUA_SRC" "$STAGE/s5_uldl.lua" chmod 644 "$STAGE/s5_uldl.lua" stage_path() { local src=$1 local dest if [[ "$src" != /* ]]; then src="$(pwd)/$src" fi dest="${STAGE}/$(basename "$src")" cp -f "$src" "$dest" chmod 644 "$dest" 2>/dev/null || true printf '%s\n' "$dest" } args=(-X "lua_script:${STAGE}/s5_uldl.lua") if [[ $# -eq 1 && -f "$1" && "$1" != -* ]]; then args+=(-r "$(stage_path "$1")" -Y s5uldl) shift else while [[ $# -gt 0 ]]; do case "$1" in -r|--read-file) [[ $# -ge 2 ]] || { echo "missing file after $1" >&2; exit 2; } args+=(-r "$(stage_path "$2")") shift 2 ;; *) args+=("$1") shift ;; esac done fi exec tshark "${args[@]}"