]> git.proxmox.com Git - mirror_ovs.git/blob - utilities/ovs-docker
ovs-docker: check if port is already attached for container/interface
[mirror_ovs.git] / utilities / ovs-docker
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
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
24 fi
25 done
26 IFS=$save_IFS
27 echo >&2 "$0: $1 not found in \$PATH, please install and try again"
28 exit 1
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
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
64 add_port () {
65 BRIDGE="$1"
66 INTERFACE="$2"
67 CONTAINER="$3"
68 ADDRESS="$4"
69 GATEWAY="$5"
70
71 if [ "$#" -lt 3 ]; then
72 usage
73 exit 1
74 fi
75
76 # Check if a port is already attached for the given container and interface
77 PORT=`get_port_for_container_interface "$CONTAINER" "$INTERFACE" \
78 2>/dev/null`
79 if [ -n "$PORT" ]; then
80 echo >&2 "$UTIL: Port already attached" \
81 "for CONTAINER=$CONTAINER and INTERFACE=$INTERFACE"
82 exit 1
83 fi
84
85 if ovs_vsctl br-exists "$BRIDGE" || \
86 ovs_vsctl add-br "$BRIDGE"; then :; else
87 echo >&2 "$UTIL: Failed to create bridge $BRIDGE"
88 exit 1
89 fi
90
91 if PID=`docker inspect -f '{{.State.Pid}}' "$CONTAINER"`; then :; else
92 echo >&2 "$UTIL: Failed to get the PID of the container"
93 exit 1
94 fi
95
96 create_netns_link
97
98 # Create a veth pair.
99 ID=`uuidgen | sed 's/-//g'`
100 PORTNAME="${ID:0:13}"
101 ip link add "${PORTNAME}_l" type veth peer name "${PORTNAME}_c"
102
103 # Add one end of veth to OVS bridge.
104 if ovs_vsctl --may-exist add-port "$BRIDGE" "${PORTNAME}_l" \
105 -- set interface "${PORTNAME}_l" \
106 external_ids:container_id="$CONTAINER" \
107 external_ids:container_iface="$INTERFACE"; then :; else
108 echo >&2 "$UTIL: Failed to add "${PORTNAME}_l" port to bridge $BRIDGE"
109 ip link delete "${PORTNAME}_l"
110 exit 1
111 fi
112
113 ip link set "${PORTNAME}_l" up
114
115 # Move "${PORTNAME}_c" inside the container and changes its name.
116 ip link set "${PORTNAME}_c" netns "$PID"
117 ip netns exec "$PID" ip link set dev "${PORTNAME}_c" name "$INTERFACE"
118 ip netns exec "$PID" ip link set "$INTERFACE" up
119
120 if [ -n "$ADDRESS" ]; then
121 ip netns exec "$PID" ip addr add "$ADDRESS" dev "$INTERFACE"
122 fi
123
124 if [ -n "$GATEWAY" ]; then
125 ip netns exec "$PID" ip route add default via "$GATEWAY"
126 fi
127 }
128
129 del_port () {
130 BRIDGE="$1"
131 INTERFACE="$2"
132 CONTAINER="$3"
133
134 if [ "$#" -lt 3 ]; then
135 usage
136 exit 1
137 fi
138
139 PORT=`get_port_for_container_interface "$CONTAINER" "$INTERFACE"`
140 if [ -z "$PORT" ]; then
141 exit 1
142 fi
143
144 ovs_vsctl --if-exists del-port "$PORT"
145
146 ip link delete "$PORT"
147 }
148
149 del_ports () {
150 BRIDGE="$1"
151 CONTAINER="$2"
152 if [ "$#" -lt 2 ]; then
153 usage
154 exit 1
155 fi
156
157 PORTS=`ovs_vsctl --data=bare --no-heading --columns=name find interface \
158 external_ids:container_id="$CONTAINER"`
159 if [ -z "$PORTS" ]; then
160 exit 0
161 fi
162
163 for PORT in $PORTS; do
164 ovs_vsctl --if-exists del-port "$PORT"
165 ip link delete "$PORT"
166 done
167 }
168
169 set_vlan () {
170 BRIDGE="$1"
171 INTERFACE="$2"
172 CONTAINER_ID="$3"
173 VLAN="$4"
174
175 if [ "$#" -lt 4 ]; then
176 usage
177 exit 1
178 fi
179
180 PORT=`get_port_for_container_interface "$CONTAINER_ID" "$INTERFACE"`
181 if [ -z "$PORT" ]; then
182 exit 1
183 fi
184 ovs_vsctl set port "$PORT" tag="$VLAN"
185 }
186
187 usage() {
188 cat << EOF
189 ${UTIL}: Performs integration of Open vSwitch with Docker.
190 usage: ${UTIL} COMMAND
191
192 Commands:
193 add-port BRIDGE INTERFACE CONTAINER [ADDRESS [GATEWAY]]
194 Adds INTERFACE inside CONTAINER and connects it as a port
195 in Open vSwitch BRIDGE. Optionally, sets ADDRESS on
196 INTERFACE. ADDRESS can include a '/' to represent network
197 prefix length. Along with ADDRESS, optionally set the
198 default gateway for the container. e.g.:
199 ${UTIL} add-port br-int eth1 c474a0e2830e 192.168.1.2/24 \
200 192.168.1.1
201 del-port BRIDGE INTERFACE CONTAINER
202 Deletes INTERFACE inside CONTAINER and removes its
203 connection to Open vSwitch BRIDGE. e.g.:
204 ${UTIL} del-port br-int eth1 c474a0e2830e
205 del-ports BRIDGE CONTAINER
206 Removes all Open vSwitch interfaces from CONTAINER. e.g.:
207 ${UTIL} del-ports br-int c474a0e2830e
208 set-vlan BRIDGE INTERFACE CONTAINER VLAN
209 Configures the INTERFACE of CONTAINER attached to BRIDGE
210 to become an access port of VLAN. e.g.:
211 ${UTIL} set-vlan br-int eth1 c474a0e2830e 5
212 Options:
213 -h, --help display this help message.
214 EOF
215 }
216
217 UTIL=$(basename $0)
218 search_path ovs-vsctl
219 search_path docker
220 search_path uuidgen
221
222 if (ip netns) > /dev/null 2>&1; then :; else
223 echo >&2 "$UTIL: ip utility not found (or it does not support netns),"\
224 "cannot proceed"
225 exit 1
226 fi
227
228 if [ $# -eq 0 ]; then
229 usage
230 exit 0
231 fi
232
233 case $1 in
234 "add-port")
235 shift
236 add_port "$@"
237 exit 0
238 ;;
239 "del-port")
240 shift
241 del_port "$@"
242 exit 0
243 ;;
244 "del-ports")
245 shift
246 del_ports "$@"
247 exit 0
248 ;;
249 "set-vlan")
250 shift
251 set_vlan "$@"
252 exit 0
253 ;;
254 -h | --help)
255 usage
256 exit 0
257 ;;
258 *)
259 echo >&2 "$UTIL: unknown command \"$1\" (use --help for help)"
260 exit 1
261 ;;
262 esac