-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Script for setting up linux namespaces (#7256)
* Script for setting up linux namespaces This will let developers run a controller and device on the same machines. * Apply suggestions from code review Co-authored-by: Tennessee Carmel-Veilleux <[email protected]> * reformatting. * Add example and header. * Restyled by shellharden * Restyled by shfmt Co-authored-by: Tennessee Carmel-Veilleux <[email protected]> Co-authored-by: Restyled.io <[email protected]>
- Loading branch information
Showing
1 changed file
with
233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
#!/usr/bin/env bash | ||
# | ||
# | ||
# Copyright (c) 2021 Project CHIP Authors | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
# | ||
# Description: | ||
# This is a utility script that can be used by developers to do | ||
# simulate a device and controller on the same linux machine. This | ||
# script is not intended to be used in a testing framework as-is | ||
# because it requires root access to set up network namespaces. | ||
# | ||
# To use this script, compile the required device example, and | ||
# run inside the namespace using | ||
# sudo <path>/linux_ip_namespace_setup.sh -r <path_to_app> | ||
# | ||
# The controller can then be started in a new terminal and will | ||
# be able to communicate with the application as if it were on | ||
# a separate network. | ||
# | ||
|
||
NAMESPACE="MatterTester" | ||
HOST_SIDE_IF_NAME="heth0" | ||
NAMESPACE_SIDE_IF_NAME="neth0" | ||
BRIDGE_NAME="nbridge" | ||
BRIDGE_ADDR="192.168.4.50" | ||
NAMESPACE_ADDR="192.168.4.45" | ||
HOST_IPV6_ADDR=fc00::1 | ||
BRIDGE_IPV6_ADDR=fc00::b | ||
NAMESPACE_IPV6_ADDR=fc00::a | ||
|
||
function run_setup() { | ||
# Create namespace. | ||
ip netns add "$NAMESPACE" | ||
|
||
# Create two virtual interfaces and link them - one on host side, one on namespace side. | ||
ip link add "$HOST_SIDE_IF_NAME" type veth peer name "$NAMESPACE_SIDE_IF_NAME" | ||
|
||
# Give the host a known IPv6 addr and set the host side up | ||
ip -6 addr add "$HOST_IPV6_ADDR"/64 dev "$HOST_SIDE_IF_NAME" | ||
ip link set "$HOST_SIDE_IF_NAME" up | ||
|
||
# Associate namespace IF with the namespace | ||
ip link set "$NAMESPACE_SIDE_IF_NAME" netns "$NAMESPACE" | ||
|
||
# Give the namespace IF an address (something nothing else is using) and set it up | ||
echo "Adding address for namespace IF" | ||
ip netns exec "$NAMESPACE" ip -6 addr add "$NAMESPACE_IPV6_ADDR"/64 dev "$NAMESPACE_SIDE_IF_NAME" | ||
ip netns exec "$NAMESPACE" ip link set dev "$NAMESPACE_SIDE_IF_NAME" up | ||
|
||
# Add a route to the namespace to go through the bridge | ||
echo "Setting routes for namespace" | ||
ip netns exec "$NAMESPACE" ip -6 route add default dev "$NAMESPACE_SIDE_IF_NAME" | ||
|
||
echo "Setup complete." | ||
} | ||
|
||
function run_add_ipv4() { | ||
# Give the namespace an IPv4 address | ||
ip netns exec "$NAMESPACE" ip addr add "$NAMESPACE_ADDR"/24 dev "$NAMESPACE_SIDE_IF_NAME" | ||
|
||
# Add a bridge, give it an address (something nothing else is using) | ||
echo "Setting up bridge" | ||
ip link add name "$BRIDGE_NAME" type bridge | ||
ip -6 addr add "$BRIDGE_IPV6_ADDR"/64 dev "$BRIDGE_NAME" | ||
ip addr add "$BRIDGE_ADDR"/24 brd + dev "$BRIDGE_NAME" | ||
|
||
# For ipv6 and ipv4 to work together, need the bridge to ignore the ipv6 packets (DROP here means don't bridge) | ||
ebtables-legacy -t broute -A BROUTING -p ipv6 -j DROP -i "$HOST_SIDE_IF_NAME" | ||
ip link set "$BRIDGE_NAME" up | ||
|
||
# Connect the host side to the bridge, so now we have bridge <-> host_side_if <-> namespace_if | ||
echo "Connecting host virtual IF to bridge" | ||
ip link set "$HOST_SIDE_IF_NAME" master "$BRIDGE_NAME" | ||
|
||
#ip netns exec ${NAMESPACE} ip route add default via ${BRIDGE_ADDR} dev ${NAMESPACE_SIDE_IF_NAME} | ||
} | ||
|
||
function run_cmd() { | ||
# Start the app in the namespace | ||
echo "Running $1 in namespace." | ||
ip netns exec "$NAMESPACE" "$1" | ||
} | ||
|
||
function run_cleanup() { | ||
# Deleting the namespace will remove the namespace and peer'd interfaces to | ||
have_ebtables_legacy=$1 | ||
ip netns delete "$NAMESPACE" | ||
if ifconfig | grep "$BRIDGE_NAME"; then | ||
if [ "$have_ebtables_legacy" = true ]; then | ||
# Just try to drop the additional rule - it references our interface | ||
# so if it's there, we added it. | ||
ebtables-legacy -t broute -D BROUTING -p ipv6 -j DROP -i "$HOST_SIDE_IF_NAME" >/dev/null | ||
fi | ||
ip link delete dev "$BRIDGE_NAME" type bridge | ||
fi | ||
} | ||
|
||
function help() { | ||
echo "Usage: $file_name [ options ... ]" | ||
echo "" | ||
|
||
echo "This script is used to set up linux namespaces for Matter device testing" | ||
echo "between a controller and device on the same linux machine." | ||
echo "" | ||
echo "To use this script, run the device code in a namespace using the -r command" | ||
echo "and a controller in a seperate terminal to simulate two devices communicating" | ||
echo "across a network." | ||
echo "Example:" | ||
echo "--------" | ||
echo "Terminal 1:" | ||
echo "sudo <path>/$file_name -r <path>/<application_name>" | ||
echo "" | ||
echo "Terminal 2:" | ||
echo "<path>/chip-device-ctrl" | ||
echo "" | ||
echo "This script requires sudo for setup and requires access to ebtables-legacy" | ||
echo "to set up dual ipv4/ipv6 namespaces. Defaults to ipv6 only." | ||
echo "" | ||
|
||
echo "Options: | ||
-h, --help Display this information. | ||
-s, --setup Setup an IP namespace. Will run cleanup if namespace exists. | ||
-4, --ipv4 Add ipv4 support. | ||
-r, --run filename Run file in the namespace. Will setup namespace if required. | ||
-c, --cleanup Delete namespace and routes | ||
" | ||
} | ||
|
||
declare setup=false | ||
declare filename="" | ||
declare run=false | ||
declare cleanup=false | ||
declare ipv4=false | ||
|
||
file_name=${0##*/} | ||
|
||
while (($#)); do | ||
case $1 in | ||
--help | -h) | ||
help | ||
exit 1 | ||
;; | ||
--setup | -s) | ||
setup=true | ||
;; | ||
--run | -r) | ||
run=true | ||
filename=$2 | ||
shift | ||
;; | ||
--cleanup | -c) | ||
cleanup=true | ||
;; | ||
--ipv4 | -4) | ||
ipv4=true | ||
;; | ||
-*) | ||
help | ||
echo "Unknown Option \"$1\"" | ||
exit 1 | ||
;; | ||
esac | ||
shift | ||
done | ||
|
||
if [[ $EUID -ne 0 ]]; then | ||
echo "You must run this script with superuser privileges." | ||
exit 1 | ||
fi | ||
|
||
if ifconfig | grep "$HOST_SIDE_IF_NAME"; then | ||
issetup=true | ||
else | ||
issetup=false | ||
fi | ||
|
||
if [ "$setup" = false ] && [ "$run" = false ] && [ "$cleanup" = false ]; then | ||
echo "Must specify one or more of -s, -r, -c." | ||
exit 1 | ||
fi | ||
|
||
if command -v ebtables-legacy >/dev/null; then | ||
have_ebtables_legacy=true | ||
else | ||
have_ebtables_legacy=false | ||
fi | ||
|
||
if [ "$ipv4" = true ] && [ "$have_ebtables_legacy" = false ]; then | ||
echo "To set up namespaces with ipv4/ipv6 connectivity, ebtables-legacy" | ||
echo "is required. For example, to install on machines using APT:" | ||
echo "sudo apt-get install ebtables" | ||
exit 1 | ||
fi | ||
|
||
if [ "$run" = true ]; then | ||
if [ "$issetup" = false ]; then | ||
setup=true | ||
fi | ||
fi | ||
|
||
if [ "$setup" = true ]; then | ||
if [ "$issetup" = true ]; then | ||
cleanup=true | ||
fi | ||
fi | ||
|
||
if [ "$cleanup" = true ]; then | ||
run_cleanup "$have_ebtables_legacy" | ||
fi | ||
|
||
if [ "$setup" = true ]; then | ||
run_setup | ||
if [ "$ipv4" = true ]; then | ||
run_add_ipv4 | ||
fi | ||
fi | ||
|
||
if [ "$run" = true ]; then | ||
run_cmd "$filename" | ||
fi |