forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlinux_ip_namespace_setup.sh
executable file
·233 lines (202 loc) · 7.03 KB
/
linux_ip_namespace_setup.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
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 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-repl"
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