ovs-docker 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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. # Check for programs we'll need.
  16. search_path () {
  17. save_IFS=$IFS
  18. IFS=:
  19. for dir in $PATH; do
  20. IFS=$save_IFS
  21. if test -x "$dir/$1"; then
  22. return 0
  23. fi
  24. done
  25. IFS=$save_IFS
  26. echo >&2 "$0: $1 not found in \$PATH, please install and try again"
  27. exit 1
  28. }
  29. ovs_vsctl () {
  30. ovs-vsctl --timeout=60 "$@"
  31. }
  32. create_netns_link () {
  33. mkdir -p /var/run/netns
  34. if [ ! -e /var/run/netns/"$PID" ]; then
  35. ln -s /proc/"$PID"/ns/net /var/run/netns/"$PID"
  36. trap 'delete_netns_link' 0
  37. for signal in 1 2 3 13 14 15; do
  38. trap 'delete_netns_link; trap - $signal; kill -$signal $$' $signal
  39. done
  40. fi
  41. }
  42. delete_netns_link () {
  43. rm -f /var/run/netns/"$PID"
  44. }
  45. get_port_for_container_interface () {
  46. CONTAINER="$1"
  47. INTERFACE="$2"
  48. PORT=`ovs_vsctl --data=bare --no-heading --columns=name find interface \
  49. external_ids:container_id="$CONTAINER" \
  50. external_ids:container_iface="$INTERFACE"`
  51. if [ -z "$PORT" ]; then
  52. echo >&2 "$UTIL: Failed to find any attached port" \
  53. "for CONTAINER=$CONTAINER and INTERFACE=$INTERFACE"
  54. fi
  55. echo "$PORT"
  56. }
  57. add_port () {
  58. BRIDGE="$1"
  59. INTERFACE="$2"
  60. CONTAINER="$3"
  61. if [ -z "$BRIDGE" ] || [ -z "$INTERFACE" ] || [ -z "$CONTAINER" ]; then
  62. echo >&2 "$UTIL add-port: not enough arguments (use --help for help)"
  63. exit 1
  64. fi
  65. shift 3
  66. while [ $# -ne 0 ]; do
  67. case $1 in
  68. --ipaddress=*)
  69. ADDRESS=`expr X"$1" : 'X[^=]*=\(.*\)'`
  70. shift
  71. ;;
  72. --macaddress=*)
  73. MACADDRESS=`expr X"$1" : 'X[^=]*=\(.*\)'`
  74. shift
  75. ;;
  76. --gateway=*)
  77. GATEWAY=`expr X"$1" : 'X[^=]*=\(.*\)'`
  78. shift
  79. ;;
  80. --mtu=*)
  81. MTU=`expr X"$1" : 'X[^=]*=\(.*\)'`
  82. shift
  83. ;;
  84. *)
  85. echo >&2 "$UTIL add-port: unknown option \"$1\""
  86. exit 1
  87. ;;
  88. esac
  89. done
  90. # Check if a port is already attached for the given container and interface
  91. PORT=`get_port_for_container_interface "$CONTAINER" "$INTERFACE" \
  92. 2>/dev/null`
  93. if [ -n "$PORT" ]; then
  94. echo >&2 "$UTIL: Port already attached" \
  95. "for CONTAINER=$CONTAINER and INTERFACE=$INTERFACE"
  96. exit 1
  97. fi
  98. if ovs_vsctl br-exists "$BRIDGE" || \
  99. ovs_vsctl add-br "$BRIDGE"; then :; else
  100. echo >&2 "$UTIL: Failed to create bridge $BRIDGE"
  101. exit 1
  102. fi
  103. if PID=`docker inspect -f '{{.State.Pid}}' "$CONTAINER"`; then :; else
  104. echo >&2 "$UTIL: Failed to get the PID of the container"
  105. exit 1
  106. fi
  107. create_netns_link
  108. # Create a veth pair.
  109. ID=`uuidgen | sed 's/-//g'`
  110. PORTNAME="${ID:0:13}"
  111. ip link add "${PORTNAME}_l" type veth peer name "${PORTNAME}_c"
  112. # Add one end of veth to OVS bridge.
  113. if ovs_vsctl --may-exist add-port "$BRIDGE" "${PORTNAME}_l" \
  114. -- set interface "${PORTNAME}_l" \
  115. external_ids:container_id="$CONTAINER" \
  116. external_ids:container_iface="$INTERFACE"; then :; else
  117. echo >&2 "$UTIL: Failed to add "${PORTNAME}_l" port to bridge $BRIDGE"
  118. ip link delete "${PORTNAME}_l"
  119. exit 1
  120. fi
  121. ip link set "${PORTNAME}_l" up
  122. # Move "${PORTNAME}_c" inside the container and changes its name.
  123. ip link set "${PORTNAME}_c" netns "$PID"
  124. ip netns exec "$PID" ip link set dev "${PORTNAME}_c" name "$INTERFACE"
  125. ip netns exec "$PID" ip link set "$INTERFACE" up
  126. if [ -n "$MTU" ]; then
  127. ip netns exec "$PID" ip link set dev "$INTERFACE" mtu "$MTU"
  128. fi
  129. if [ -n "$ADDRESS" ]; then
  130. ip netns exec "$PID" ip addr add "$ADDRESS" dev "$INTERFACE"
  131. fi
  132. if [ -n "$MACADDRESS" ]; then
  133. ip netns exec "$PID" ip link set dev "$INTERFACE" address "$MACADDRESS"
  134. fi
  135. if [ -n "$GATEWAY" ]; then
  136. ip netns exec "$PID" ip route add default via "$GATEWAY"
  137. fi
  138. }
  139. del_port () {
  140. BRIDGE="$1"
  141. INTERFACE="$2"
  142. CONTAINER="$3"
  143. if [ "$#" -lt 3 ]; then
  144. usage
  145. exit 1
  146. fi
  147. PORT=`get_port_for_container_interface "$CONTAINER" "$INTERFACE"`
  148. if [ -z "$PORT" ]; then
  149. exit 1
  150. fi
  151. ovs_vsctl --if-exists del-port "$PORT"
  152. ip link delete "$PORT"
  153. }
  154. del_ports () {
  155. BRIDGE="$1"
  156. CONTAINER="$2"
  157. if [ "$#" -lt 2 ]; then
  158. usage
  159. exit 1
  160. fi
  161. PORTS=`ovs_vsctl --data=bare --no-heading --columns=name find interface \
  162. external_ids:container_id="$CONTAINER"`
  163. if [ -z "$PORTS" ]; then
  164. exit 0
  165. fi
  166. for PORT in $PORTS; do
  167. ovs_vsctl --if-exists del-port "$PORT"
  168. ip link delete "$PORT"
  169. done
  170. }
  171. set_vlan () {
  172. BRIDGE="$1"
  173. INTERFACE="$2"
  174. CONTAINER_ID="$3"
  175. VLAN="$4"
  176. if [ "$#" -lt 4 ]; then
  177. usage
  178. exit 1
  179. fi
  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. usage() {
  187. cat << EOF
  188. ${UTIL}: Performs integration of Open vSwitch with Docker.
  189. usage: ${UTIL} COMMAND
  190. Commands:
  191. add-port BRIDGE INTERFACE CONTAINER [--ipaddress="ADDRESS"]
  192. [--gateway=GATEWAY] [--macaddress="MACADDRESS"]
  193. [--mtu=MTU]
  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. Optionally, sets a GATEWAY, MACADDRESS
  198. and MTU. e.g.:
  199. ${UTIL} add-port br-int eth1 c474a0e2830e
  200. --ipaddress=192.168.1.2/24 --gateway=192.168.1.1
  201. --macaddress="a2:c3:0d:49:7f:f8" --mtu=1450
  202. del-port BRIDGE INTERFACE CONTAINER
  203. Deletes INTERFACE inside CONTAINER and removes its
  204. connection to Open vSwitch BRIDGE. e.g.:
  205. ${UTIL} del-port br-int eth1 c474a0e2830e
  206. del-ports BRIDGE CONTAINER
  207. Removes all Open vSwitch interfaces from CONTAINER. e.g.:
  208. ${UTIL} del-ports br-int c474a0e2830e
  209. set-vlan BRIDGE INTERFACE CONTAINER VLAN
  210. Configures the INTERFACE of CONTAINER attached to BRIDGE
  211. to become an access port of VLAN. e.g.:
  212. ${UTIL} set-vlan br-int eth1 c474a0e2830e 5
  213. Options:
  214. -h, --help display this help message.
  215. EOF
  216. }
  217. UTIL=$(basename $0)
  218. search_path ovs-vsctl
  219. search_path docker
  220. search_path uuidgen
  221. if (ip netns) > /dev/null 2>&1; then :; else
  222. echo >&2 "$UTIL: ip utility not found (or it does not support netns),"\
  223. "cannot proceed"
  224. exit 1
  225. fi
  226. if [ $# -eq 0 ]; then
  227. usage
  228. exit 0
  229. fi
  230. case $1 in
  231. "add-port")
  232. shift
  233. add_port "$@"
  234. exit 0
  235. ;;
  236. "del-port")
  237. shift
  238. del_port "$@"
  239. exit 0
  240. ;;
  241. "del-ports")
  242. shift
  243. del_ports "$@"
  244. exit 0
  245. ;;
  246. "set-vlan")
  247. shift
  248. set_vlan "$@"
  249. exit 0
  250. ;;
  251. -h | --help)
  252. usage
  253. exit 0
  254. ;;
  255. *)
  256. echo >&2 "$UTIL: unknown command \"$1\" (use --help for help)"
  257. exit 1
  258. ;;
  259. esac