| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233 |
- #!/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 separate 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
|