]>
Commit | Line | Data |
---|---|---|
ec8f0f0c GS |
1 | #!/bin/bash |
2 | # Copyright (C) 2014 Nicira, Inc. | |
3 | # | |
4 | # Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | # you may not use this file except in compliance with the License. | |
6 | # You may obtain a copy of the License at: | |
7 | # | |
8 | # http://www.apache.org/licenses/LICENSE-2.0 | |
9 | # | |
10 | # Unless required by applicable law or agreed to in writing, software | |
11 | # distributed under the License is distributed on an "AS IS" BASIS, | |
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | # See the License for the specific language governing permissions and | |
14 | # limitations under the License. | |
15 | ||
a8353802 GS |
16 | # Check for programs we'll need. |
17 | search_path () { | |
18 | save_IFS=$IFS | |
19 | IFS=: | |
20 | for dir in $PATH; do | |
21 | IFS=$save_IFS | |
22 | if test -x "$dir/$1"; then | |
23 | return 0 | |
ec8f0f0c | 24 | fi |
ec8f0f0c | 25 | done |
a8353802 GS |
26 | IFS=$save_IFS |
27 | echo >&2 "$0: $1 not found in \$PATH, please install and try again" | |
28 | exit 1 | |
ec8f0f0c GS |
29 | } |
30 | ||
31 | ovs_vsctl () { | |
32 | ovs-vsctl --timeout=60 "$@" | |
33 | } | |
34 | ||
35 | create_netns_link () { | |
36 | mkdir -p /var/run/netns | |
37 | if [ ! -e /var/run/netns/"$PID" ]; then | |
38 | ln -s /proc/"$PID"/ns/net /var/run/netns/"$PID" | |
39 | trap 'delete_netns_link' 0 | |
40 | for signal in 1 2 3 13 14 15; do | |
41 | trap 'delete_netns_link; trap - $signal; kill -$signal $$' $signal | |
42 | done | |
43 | fi | |
44 | } | |
45 | ||
46 | delete_netns_link () { | |
47 | rm -f /var/run/netns/"$PID" | |
48 | } | |
49 | ||
348efd04 GS |
50 | get_port_for_container_interface () { |
51 | CONTAINER="$1" | |
52 | INTERFACE="$2" | |
53 | ||
54 | PORT=`ovs_vsctl --data=bare --no-heading --columns=name find interface \ | |
55 | external_ids:container_id="$CONTAINER" \ | |
56 | external_ids:container_iface="$INTERFACE"` | |
57 | if [ -z "$PORT" ]; then | |
58 | echo >&2 "$UTIL: Failed to find any attached port" \ | |
59 | "for CONTAINER=$CONTAINER and INTERFACE=$INTERFACE" | |
60 | fi | |
61 | echo "$PORT" | |
62 | } | |
63 | ||
ec8f0f0c GS |
64 | add_port () { |
65 | BRIDGE="$1" | |
66 | INTERFACE="$2" | |
67 | CONTAINER="$3" | |
ec8f0f0c | 68 | |
05444f07 GS |
69 | if [ -z "$BRIDGE" ] || [ -z "$INTERFACE" ] || [ -z "$CONTAINER" ]; then |
70 | echo >&2 "$UTIL add-port: not enough arguments (use --help for help)" | |
ec8f0f0c GS |
71 | exit 1 |
72 | fi | |
73 | ||
05444f07 GS |
74 | shift 3 |
75 | while [ $# -ne 0 ]; do | |
76 | case $1 in | |
77 | --ipaddress=*) | |
78 | ADDRESS=`expr X"$1" : 'X[^=]*=\(.*\)'` | |
79 | shift | |
80 | ;; | |
81 | --macaddress=*) | |
82 | MACADDRESS=`expr X"$1" : 'X[^=]*=\(.*\)'` | |
83 | shift | |
84 | ;; | |
85 | --gateway=*) | |
86 | GATEWAY=`expr X"$1" : 'X[^=]*=\(.*\)'` | |
87 | shift | |
88 | ;; | |
6dd3cc39 GS |
89 | --mtu=*) |
90 | MTU=`expr X"$1" : 'X[^=]*=\(.*\)'` | |
91 | shift | |
92 | ;; | |
05444f07 GS |
93 | *) |
94 | echo >&2 "$UTIL add-port: unknown option \"$1\"" | |
95 | exit 1 | |
96 | ;; | |
97 | esac | |
98 | done | |
99 | ||
70934438 GM |
100 | # Check if a port is already attached for the given container and interface |
101 | PORT=`get_port_for_container_interface "$CONTAINER" "$INTERFACE" \ | |
102 | 2>/dev/null` | |
103 | if [ -n "$PORT" ]; then | |
104 | echo >&2 "$UTIL: Port already attached" \ | |
105 | "for CONTAINER=$CONTAINER and INTERFACE=$INTERFACE" | |
106 | exit 1 | |
107 | fi | |
108 | ||
8a856a63 PER |
109 | if ovs_vsctl br-exists "$BRIDGE" || \ |
110 | ovs_vsctl add-br "$BRIDGE"; then :; else | |
ec8f0f0c GS |
111 | echo >&2 "$UTIL: Failed to create bridge $BRIDGE" |
112 | exit 1 | |
113 | fi | |
114 | ||
115 | if PID=`docker inspect -f '{{.State.Pid}}' "$CONTAINER"`; then :; else | |
116 | echo >&2 "$UTIL: Failed to get the PID of the container" | |
117 | exit 1 | |
118 | fi | |
119 | ||
120 | create_netns_link | |
121 | ||
122 | # Create a veth pair. | |
123 | ID=`uuidgen | sed 's/-//g'` | |
124 | PORTNAME="${ID:0:13}" | |
125 | ip link add "${PORTNAME}_l" type veth peer name "${PORTNAME}_c" | |
126 | ||
127 | # Add one end of veth to OVS bridge. | |
128 | if ovs_vsctl --may-exist add-port "$BRIDGE" "${PORTNAME}_l" \ | |
129 | -- set interface "${PORTNAME}_l" \ | |
130 | external_ids:container_id="$CONTAINER" \ | |
131 | external_ids:container_iface="$INTERFACE"; then :; else | |
132 | echo >&2 "$UTIL: Failed to add "${PORTNAME}_l" port to bridge $BRIDGE" | |
133 | ip link delete "${PORTNAME}_l" | |
134 | exit 1 | |
135 | fi | |
136 | ||
137 | ip link set "${PORTNAME}_l" up | |
138 | ||
139 | # Move "${PORTNAME}_c" inside the container and changes its name. | |
140 | ip link set "${PORTNAME}_c" netns "$PID" | |
141 | ip netns exec "$PID" ip link set dev "${PORTNAME}_c" name "$INTERFACE" | |
142 | ip netns exec "$PID" ip link set "$INTERFACE" up | |
143 | ||
6dd3cc39 GS |
144 | if [ -n "$MTU" ]; then |
145 | ip netns exec "$PID" ip link set dev "$INTERFACE" mtu "$MTU" | |
146 | fi | |
147 | ||
ec8f0f0c GS |
148 | if [ -n "$ADDRESS" ]; then |
149 | ip netns exec "$PID" ip addr add "$ADDRESS" dev "$INTERFACE" | |
150 | fi | |
a14bf25a | 151 | |
05444f07 GS |
152 | if [ -n "$MACADDRESS" ]; then |
153 | ip netns exec "$PID" ip link set dev "$INTERFACE" address "$MACADDRESS" | |
154 | fi | |
155 | ||
a14bf25a GS |
156 | if [ -n "$GATEWAY" ]; then |
157 | ip netns exec "$PID" ip route add default via "$GATEWAY" | |
158 | fi | |
ec8f0f0c GS |
159 | } |
160 | ||
161 | del_port () { | |
162 | BRIDGE="$1" | |
163 | INTERFACE="$2" | |
164 | CONTAINER="$3" | |
165 | ||
166 | if [ "$#" -lt 3 ]; then | |
167 | usage | |
168 | exit 1 | |
169 | fi | |
170 | ||
348efd04 | 171 | PORT=`get_port_for_container_interface "$CONTAINER" "$INTERFACE"` |
ec8f0f0c | 172 | if [ -z "$PORT" ]; then |
ec8f0f0c GS |
173 | exit 1 |
174 | fi | |
175 | ||
176 | ovs_vsctl --if-exists del-port "$PORT" | |
177 | ||
178 | ip link delete "$PORT" | |
179 | } | |
180 | ||
181 | del_ports () { | |
182 | BRIDGE="$1" | |
183 | CONTAINER="$2" | |
184 | if [ "$#" -lt 2 ]; then | |
185 | usage | |
186 | exit 1 | |
187 | fi | |
188 | ||
189 | PORTS=`ovs_vsctl --data=bare --no-heading --columns=name find interface \ | |
190 | external_ids:container_id="$CONTAINER"` | |
191 | if [ -z "$PORTS" ]; then | |
192 | exit 0 | |
193 | fi | |
194 | ||
195 | for PORT in $PORTS; do | |
196 | ovs_vsctl --if-exists del-port "$PORT" | |
197 | ip link delete "$PORT" | |
198 | done | |
199 | } | |
200 | ||
348efd04 GS |
201 | set_vlan () { |
202 | BRIDGE="$1" | |
203 | INTERFACE="$2" | |
204 | CONTAINER_ID="$3" | |
205 | VLAN="$4" | |
206 | ||
207 | if [ "$#" -lt 4 ]; then | |
208 | usage | |
209 | exit 1 | |
210 | fi | |
211 | ||
212 | PORT=`get_port_for_container_interface "$CONTAINER_ID" "$INTERFACE"` | |
213 | if [ -z "$PORT" ]; then | |
214 | exit 1 | |
215 | fi | |
216 | ovs_vsctl set port "$PORT" tag="$VLAN" | |
217 | } | |
218 | ||
ec8f0f0c GS |
219 | usage() { |
220 | cat << EOF | |
221 | ${UTIL}: Performs integration of Open vSwitch with Docker. | |
222 | usage: ${UTIL} COMMAND | |
223 | ||
224 | Commands: | |
05444f07 GS |
225 | add-port BRIDGE INTERFACE CONTAINER [--ipaddress="ADDRESS"] |
226 | [--gateway=GATEWAY] [--macaddress="MACADDRESS"] | |
6dd3cc39 | 227 | [--mtu=MTU] |
ec8f0f0c GS |
228 | Adds INTERFACE inside CONTAINER and connects it as a port |
229 | in Open vSwitch BRIDGE. Optionally, sets ADDRESS on | |
230 | INTERFACE. ADDRESS can include a '/' to represent network | |
6dd3cc39 GS |
231 | prefix length. Optionally, sets a GATEWAY, MACADDRESS |
232 | and MTU. e.g.: | |
05444f07 GS |
233 | ${UTIL} add-port br-int eth1 c474a0e2830e |
234 | --ipaddress=192.168.1.2/24 --gateway=192.168.1.1 | |
6dd3cc39 | 235 | --macaddress="a2:c3:0d:49:7f:f8" --mtu=1450 |
ec8f0f0c GS |
236 | del-port BRIDGE INTERFACE CONTAINER |
237 | Deletes INTERFACE inside CONTAINER and removes its | |
238 | connection to Open vSwitch BRIDGE. e.g.: | |
239 | ${UTIL} del-port br-int eth1 c474a0e2830e | |
240 | del-ports BRIDGE CONTAINER | |
241 | Removes all Open vSwitch interfaces from CONTAINER. e.g.: | |
242 | ${UTIL} del-ports br-int c474a0e2830e | |
348efd04 GS |
243 | set-vlan BRIDGE INTERFACE CONTAINER VLAN |
244 | Configures the INTERFACE of CONTAINER attached to BRIDGE | |
245 | to become an access port of VLAN. e.g.: | |
246 | ${UTIL} set-vlan br-int eth1 c474a0e2830e 5 | |
ec8f0f0c GS |
247 | Options: |
248 | -h, --help display this help message. | |
249 | EOF | |
250 | } | |
251 | ||
252 | UTIL=$(basename $0) | |
a8353802 GS |
253 | search_path ovs-vsctl |
254 | search_path docker | |
255 | search_path uuidgen | |
ec8f0f0c GS |
256 | |
257 | if (ip netns) > /dev/null 2>&1; then :; else | |
258 | echo >&2 "$UTIL: ip utility not found (or it does not support netns),"\ | |
259 | "cannot proceed" | |
260 | exit 1 | |
261 | fi | |
262 | ||
263 | if [ $# -eq 0 ]; then | |
264 | usage | |
265 | exit 0 | |
266 | fi | |
267 | ||
268 | case $1 in | |
269 | "add-port") | |
270 | shift | |
271 | add_port "$@" | |
272 | exit 0 | |
273 | ;; | |
274 | "del-port") | |
275 | shift | |
276 | del_port "$@" | |
277 | exit 0 | |
278 | ;; | |
279 | "del-ports") | |
280 | shift | |
281 | del_ports "$@" | |
282 | exit 0 | |
283 | ;; | |
348efd04 GS |
284 | "set-vlan") |
285 | shift | |
286 | set_vlan "$@" | |
287 | exit 0 | |
288 | ;; | |
ec8f0f0c GS |
289 | -h | --help) |
290 | usage | |
291 | exit 0 | |
292 | ;; | |
293 | *) | |
294 | echo >&2 "$UTIL: unknown command \"$1\" (use --help for help)" | |
295 | exit 1 | |
296 | ;; | |
297 | esac |