linux_ip_namespace_setup.sh 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. #!/usr/bin/env bash
  2. #
  3. #
  4. # Copyright (c) 2021 Project CHIP Authors
  5. #
  6. # Licensed under the Apache License, Version 2.0 (the "License");
  7. # you may not use this file except in compliance with the License.
  8. # You may obtain a copy of the License at
  9. #
  10. # http://www.apache.org/licenses/LICENSE-2.0
  11. #
  12. # Unless required by applicable law or agreed to in writing, software
  13. # distributed under the License is distributed on an "AS IS" BASIS,
  14. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. # See the License for the specific language governing permissions and
  16. # limitations under the License.
  17. #
  18. #
  19. # Description:
  20. # This is a utility script that can be used by developers to do
  21. # simulate a device and controller on the same linux machine. This
  22. # script is not intended to be used in a testing framework as-is
  23. # because it requires root access to set up network namespaces.
  24. #
  25. # To use this script, compile the required device example, and
  26. # run inside the namespace using
  27. # sudo <path>/linux_ip_namespace_setup.sh -r <path_to_app>
  28. #
  29. # The controller can then be started in a new terminal and will
  30. # be able to communicate with the application as if it were on
  31. # a separate network.
  32. #
  33. NAMESPACE="MatterTester"
  34. HOST_SIDE_IF_NAME="heth0"
  35. NAMESPACE_SIDE_IF_NAME="neth0"
  36. BRIDGE_NAME="nbridge"
  37. BRIDGE_ADDR="192.168.4.50"
  38. NAMESPACE_ADDR="192.168.4.45"
  39. HOST_IPV6_ADDR=fc00::1
  40. BRIDGE_IPV6_ADDR=fc00::b
  41. NAMESPACE_IPV6_ADDR=fc00::a
  42. function run_setup() {
  43. # Create namespace.
  44. ip netns add "$NAMESPACE"
  45. # Create two virtual interfaces and link them - one on host side, one on namespace side.
  46. ip link add "$HOST_SIDE_IF_NAME" type veth peer name "$NAMESPACE_SIDE_IF_NAME"
  47. # Give the host a known IPv6 addr and set the host side up
  48. ip -6 addr add "$HOST_IPV6_ADDR"/64 dev "$HOST_SIDE_IF_NAME"
  49. ip link set "$HOST_SIDE_IF_NAME" up
  50. # Associate namespace IF with the namespace
  51. ip link set "$NAMESPACE_SIDE_IF_NAME" netns "$NAMESPACE"
  52. # Give the namespace IF an address (something nothing else is using) and set it up
  53. echo "Adding address for namespace IF"
  54. ip netns exec "$NAMESPACE" ip -6 addr add "$NAMESPACE_IPV6_ADDR"/64 dev "$NAMESPACE_SIDE_IF_NAME"
  55. ip netns exec "$NAMESPACE" ip link set dev "$NAMESPACE_SIDE_IF_NAME" up
  56. # Add a route to the namespace to go through the bridge
  57. echo "Setting routes for namespace"
  58. ip netns exec "$NAMESPACE" ip -6 route add default dev "$NAMESPACE_SIDE_IF_NAME"
  59. echo "Setup complete."
  60. }
  61. function run_add_ipv4() {
  62. # Give the namespace an IPv4 address
  63. ip netns exec "$NAMESPACE" ip addr add "$NAMESPACE_ADDR"/24 dev "$NAMESPACE_SIDE_IF_NAME"
  64. # Add a bridge, give it an address (something nothing else is using)
  65. echo "Setting up bridge"
  66. ip link add name "$BRIDGE_NAME" type bridge
  67. ip -6 addr add "$BRIDGE_IPV6_ADDR"/64 dev "$BRIDGE_NAME"
  68. ip addr add "$BRIDGE_ADDR"/24 brd + dev "$BRIDGE_NAME"
  69. # For ipv6 and ipv4 to work together, need the bridge to ignore the ipv6 packets (DROP here means don't bridge)
  70. ebtables-legacy -t broute -A BROUTING -p ipv6 -j DROP -i "$HOST_SIDE_IF_NAME"
  71. ip link set "$BRIDGE_NAME" up
  72. # Connect the host side to the bridge, so now we have bridge <-> host_side_if <-> namespace_if
  73. echo "Connecting host virtual IF to bridge"
  74. ip link set "$HOST_SIDE_IF_NAME" master "$BRIDGE_NAME"
  75. #ip netns exec ${NAMESPACE} ip route add default via ${BRIDGE_ADDR} dev ${NAMESPACE_SIDE_IF_NAME}
  76. }
  77. function run_cmd() {
  78. # Start the app in the namespace
  79. echo "Running $1 in namespace."
  80. ip netns exec "$NAMESPACE" "$1"
  81. }
  82. function run_cleanup() {
  83. # Deleting the namespace will remove the namespace and peer'd interfaces to
  84. have_ebtables_legacy=$1
  85. ip netns delete "$NAMESPACE"
  86. if ifconfig | grep "$BRIDGE_NAME"; then
  87. if [ "$have_ebtables_legacy" = true ]; then
  88. # Just try to drop the additional rule - it references our interface
  89. # so if it's there, we added it.
  90. ebtables-legacy -t broute -D BROUTING -p ipv6 -j DROP -i "$HOST_SIDE_IF_NAME" >/dev/null
  91. fi
  92. ip link delete dev "$BRIDGE_NAME" type bridge
  93. fi
  94. }
  95. function help() {
  96. echo "Usage: $file_name [ options ... ]"
  97. echo ""
  98. echo "This script is used to set up linux namespaces for Matter device testing"
  99. echo "between a controller and device on the same linux machine."
  100. echo ""
  101. echo "To use this script, run the device code in a namespace using the -r command"
  102. echo "and a controller in a separate terminal to simulate two devices communicating"
  103. echo "across a network."
  104. echo "Example:"
  105. echo "--------"
  106. echo "Terminal 1:"
  107. echo "sudo <path>/$file_name -r <path>/<application_name>"
  108. echo ""
  109. echo "Terminal 2:"
  110. echo "<path>/chip-device-ctrl"
  111. echo ""
  112. echo "This script requires sudo for setup and requires access to ebtables-legacy"
  113. echo "to set up dual ipv4/ipv6 namespaces. Defaults to ipv6 only."
  114. echo ""
  115. echo "Options:
  116. -h, --help Display this information.
  117. -s, --setup Setup an IP namespace. Will run cleanup if namespace exists.
  118. -4, --ipv4 Add ipv4 support.
  119. -r, --run filename Run file in the namespace. Will setup namespace if required.
  120. -c, --cleanup Delete namespace and routes
  121. "
  122. }
  123. declare setup=false
  124. declare filename=""
  125. declare run=false
  126. declare cleanup=false
  127. declare ipv4=false
  128. file_name=${0##*/}
  129. while (($#)); do
  130. case $1 in
  131. --help | -h)
  132. help
  133. exit 1
  134. ;;
  135. --setup | -s)
  136. setup=true
  137. ;;
  138. --run | -r)
  139. run=true
  140. filename=$2
  141. shift
  142. ;;
  143. --cleanup | -c)
  144. cleanup=true
  145. ;;
  146. --ipv4 | -4)
  147. ipv4=true
  148. ;;
  149. -*)
  150. help
  151. echo "Unknown Option \"$1\""
  152. exit 1
  153. ;;
  154. esac
  155. shift
  156. done
  157. if [[ $EUID -ne 0 ]]; then
  158. echo "You must run this script with superuser privileges."
  159. exit 1
  160. fi
  161. if ifconfig | grep "$HOST_SIDE_IF_NAME"; then
  162. issetup=true
  163. else
  164. issetup=false
  165. fi
  166. if [ "$setup" = false ] && [ "$run" = false ] && [ "$cleanup" = false ]; then
  167. echo "Must specify one or more of -s, -r, -c."
  168. exit 1
  169. fi
  170. if command -v ebtables-legacy >/dev/null; then
  171. have_ebtables_legacy=true
  172. else
  173. have_ebtables_legacy=false
  174. fi
  175. if [ "$ipv4" = true ] && [ "$have_ebtables_legacy" = false ]; then
  176. echo "To set up namespaces with ipv4/ipv6 connectivity, ebtables-legacy"
  177. echo "is required. For example, to install on machines using APT:"
  178. echo "sudo apt-get install ebtables"
  179. exit 1
  180. fi
  181. if [ "$run" = true ]; then
  182. if [ "$issetup" = false ]; then
  183. setup=true
  184. fi
  185. fi
  186. if [ "$setup" = true ]; then
  187. if [ "$issetup" = true ]; then
  188. cleanup=true
  189. fi
  190. fi
  191. if [ "$cleanup" = true ]; then
  192. run_cleanup "$have_ebtables_legacy"
  193. fi
  194. if [ "$setup" = true ]; then
  195. run_setup
  196. if [ "$ipv4" = true ]; then
  197. run_add_ipv4
  198. fi
  199. fi
  200. if [ "$run" = true ]; then
  201. run_cmd "$filename"
  202. fi