Add a new command - "restart" to ovs-ctl. Calling this command will save and restore the Openflow flows on each bridge while stopping and starting the userspace daemons respectively.
Also, during a force-reload-kmod, save the flows and kernel datapath configuration. Use the saved datapath configuration while readding the kernel module and the flows while starting the userspace daemons. Feature #13555. Signed-off-by: Gurucharan Shetty <gshe...@nicira.com> --- utilities/ovs-ctl.8 | 29 +++-- utilities/ovs-ctl.in | 98 +++++++++++++-- utilities/ovs-save | 331 +++++++++++++++++++++++++++++++++----------------- 3 files changed, 323 insertions(+), 135 deletions(-) diff --git a/utilities/ovs-ctl.8 b/utilities/ovs-ctl.8 index 8cbd3cf..3092d46 100644 --- a/utilities/ovs-ctl.8 +++ b/utilities/ovs-ctl.8 @@ -250,6 +250,14 @@ modules. This command does nothing and finishes successfully if the OVS daemons aren't running. . +.SH "The ``restart'' command" +. +.PP +The \fBrestart\fR command performs a \fBstop\fR followed by a \fBstart\fR +command. The command can take the same options as that of the \fBstart\fR +command. In addition, it saves and restores Openflow flows for each +individual bridge. +. .SH "The ``status'' command" . .PP @@ -279,27 +287,32 @@ implemented by Open vSwitch. The most common examples of these are bridge ``local ports''. . .IP 2. +Saves the Openflow flows of each bridge and the kernel datapath +configuration for each of the kernel datapaths. +. +.IP 3. Stops the Open vSwitch daemons, as if by a call to \fBovs\-ctl stop\fR. . -.IP 3. +.IP 4. Saves the kernel configuration state of the OVS internal interfaces listed in step 1, including IP and IPv6 addresses and routing table entries. . -.IP 4. +.IP 5. Unloads the Open vSwitch kernel module (including the bridge compatibility module if it is loaded). . -.IP 5. -Starts OVS back up, as if by a call to \fBovs\-ctl start\fR. This -reloads the kernel module and restarts the OVS daemons (including -\fBovs\-brcompatd\fR, if \fB\-\-brcompat\fR is specified). -. .IP 6. -Restores the kernel configuration state that was saved in step 3. +Starts OVS back up, as if by a call to \fBovs\-ctl start\fR. This +reloads the kernel module, restores the saved kernel datapath configuration, +restarts the OVS daemons (including \fBovs\-brcompatd\fR, if \fB\-\-brcompat\fR +is specified) and finally restores the saved Openflow flows. . .IP 7. +Restores the kernel configuration state that was saved in step 4. +. +.IP 8. Checks for daemons that may need to be restarted because they have packet sockets that are listening on old instances of Open vSwitch kernel interfaces and, if it finds any, prints a warning on stdout. diff --git a/utilities/ovs-ctl.in b/utilities/ovs-ctl.in index 2ead004..93d55dc 100755 --- a/utilities/ovs-ctl.in +++ b/utilities/ovs-ctl.in @@ -36,7 +36,11 @@ insert_openvswitch_mod_if_required () { return 0 # Load openvswitch. If that's successful then we're done. - action "Inserting openvswitch module" modprobe openvswitch && return 0 + if action "Inserting openvswitch module" modprobe openvswitch; then + [ -n "${script_datapaths}" ] && \ + action "Restoring datapath configuration" "${script_datapaths}" + return 0 + fi # If the bridge module is loaded, then that might be blocking # openvswitch. Try to unload it, if there are no bridges. @@ -50,6 +54,8 @@ insert_openvswitch_mod_if_required () { # Try loading openvswitch again. action "Inserting openvswitch module" modprobe openvswitch + [ -n "${script_datapaths}" ] && \ + action "Restoring datapath configuration" "${script_datapaths}" } insert_brcompat_mod_if_required () { @@ -293,14 +299,40 @@ internal_interfaces () { done } +save_flows () { + bridges=`ovs_vsctl list-br` + + "$datadir/scripts/ovs-save" save-flows ${bridges} > "${script_flows}" + bridges="" +} + save_interfaces () { - "$datadir/scripts/ovs-save" $ifaces > "$script" + "$datadir/scripts/ovs-save" save-interfaces ${ifaces} \ + > "${script_interfaces}" +} + +save_datapaths() { + "$datadir/scripts/ovs-save" save-datapaths ${datapaths} \ + > "${script_datapaths}" } force_reload_kmod () { ifaces=`internal_interfaces` action "Detected internal interfaces: $ifaces" true + script_interfaces=`mktemp` + script_datapaths=`mktemp` + script_flows=`mktemp` + trap 'rm -f "${script_interfaces}" "${script_flows}" \ + "${script_datapaths}"' 0 1 2 13 15 + + if action "Saving flows" save_flows; then + chmod +x "${script_flows}" + else + script_flows= + log_warning_msg "Failed to save flows." + fi + # Restart the database first, since a large database may take a # while to load, and we want to minimize forwarding disruption. stop_ovsdb @@ -308,8 +340,6 @@ force_reload_kmod () { stop_forwarding - script=`mktemp` - trap 'rm -f "$script"' 0 1 2 13 15 if action "Saving interface configuration" save_interfaces; then : else @@ -317,9 +347,18 @@ force_reload_kmod () { start_forwarding exit 1 fi - chmod +x "$script" + chmod +x "$script_interfaces" + + datapaths=`ovs-dpctl dump-dps` + if action "Saving datapath configuration" save_datapaths; then + chmod +x "${script_datapaths}" + else + log_warning_msg "Failed to save datapath configuration. The port\ + numbers may change after the restart" + script_datapaths="" + fi - for dp in `ovs-dpctl dump-dps`; do + for dp in ${datapaths}; do action "Removing datapath: $dp" ovs-dpctl del-dp "$dp" done @@ -337,7 +376,10 @@ force_reload_kmod () { start_forwarding - action "Restoring interface configuration" "$script" + [ -n "${script_flows}" ] && \ + action "Restoring saved flows" "${script_flows}" + + action "Restoring interface configuration" "$script_interfaces" rc=$? if test $rc = 0; then level=debug @@ -351,6 +393,33 @@ force_reload_kmod () { "$datadir/scripts/ovs-check-dead-ifs" } +# --------------- ## +## restart ## +## --------------- ## + + +restart () { + script_flows=`mktemp` + trap 'rm -f "${script_flows}"' 0 1 2 13 15 + + if action "Saving flows" save_flows; then + chmod +x "${script_flows}" + else + script_flows= + log_warning_msg "Failed to save flows." + fi + + # Restart the database first, since a large database may take a + # while to load, and we want to minimize forwarding disruption. + stop_ovsdb + start_ovsdb + + stop_forwarding + start_forwarding + [ -n "${script_flows}" ] && \ + action "Restoring saved flows" "${script_flows}" +} + ## --------------- ## ## enable-protocol ## ## --------------- ## @@ -455,6 +524,7 @@ scripts. System administrators should not normally invoke it directly. Commands: start start Open vSwitch daemons stop stop Open vSwitch daemons + restart stop and start Open vSwitch daemons status check whether Open vSwitch daemons are running version print versions of Open vSwitch daemons load-kmod insert modules if not already present @@ -463,18 +533,18 @@ Commands: enable-protocol enable protocol specified in options with iptables help display this help message -One of the following options is required for "start" and "force-reload-kmod": +One of the following options is required for "start", "restart" and "force-reload-kmod": --system-id=UUID set specific ID to uniquely identify this system --system-id=random use a random but persistent UUID to identify this system -Other important options for "start" and "force-reload-kmod": +Other important options for "start", "restart" and "force-reload-kmod": --system-type=TYPE set system type (e.g. "XenServer") --system-version=VERSION set system version (e.g. "5.6.100-39265p") --external-id="key=value" add given key-value pair to Open_vSwitch external-ids --delete-bridges delete all bridges just before starting ovs-vswitchd -Less important options for "start" and "force-reload-kmod": +Less important options for "start", "restart" and "force-reload-kmod": --daemon-cwd=DIR set working dir for OVS daemons (default: $DAEMON_CWD) --no-force-corefiles do not force on core dumps for OVS daemons --no-mlockall do not lock all of ovs-vswitchd into memory @@ -482,13 +552,13 @@ Less important options for "start" and "force-reload-kmod": --ovs-vswitchd-priority=NICE set ovs-vswitchd's niceness (default: $OVS_VSWITCHD_PRIORITY) --ovs-brcompatd-priority=NICE set ovs-brcompatd's niceness (default: $OVS_BRCOMPATD_PRIORITY) -Debugging options for "start" and "force-reload-kmod": +Debugging options for "start", "restart" and "force-reload-kmod": --ovsdb-server-wrapper=WRAPPER --ovs-vswitchd-wrapper=WRAPPER --ovs-vswitchd-wrapper=WRAPPER run specified daemon under WRAPPER (either 'valgrind' or 'strace') -Options for "start", "force-reload-kmod", "load-kmod", "status", and "version": +Options for "start", "restart", "force-reload-kmod", "load-kmod", "status", and "version": --brcompat enable Linux bridge compatibility module and daemon File location options: @@ -606,6 +676,9 @@ case $command in stop_forwarding stop_ovsdb ;; + restart) + restart + ;; status) rc=0 for daemon in `daemons`; do @@ -639,4 +712,3 @@ case $command in exit 1 ;; esac - diff --git a/utilities/ovs-save b/utilities/ovs-save index 297c2fa..1d951a6 100755 --- a/utilities/ovs-save +++ b/utilities/ovs-save @@ -14,20 +14,25 @@ # See the License for the specific language governing permissions and # limitations under the License. -if test "X$1" = X--help; then +usage() { + UTIL=$(basename $0) cat <<EOF -$0: saves the kernel configuration of network interfaces -usage: $0 NETDEV... +${UTIL}: Provides helper functions to save Open vSwitch's configuration. +usage: $0 COMMAND -Outputs a shell script on stdout that will restore the current -kernel configuration of the specified network interfaces, as -well as the system iptables configuration. +Commands: + save-interfaces Outputs a shell script on stdout that will restore + the current kernel configuration of the specified + network interfaces, as well as the system iptables + configuration. + save-flows Outputs a shell script on stdout that will restore + Openflow flows of each Open vSwitch bridge. + save-datapaths Outputs a shell script on stdout that will restore + the datapaths with the same port numbers as before. -This script is meant as a helper for the Open vSwitch init -script "force-reload-kmod" command. +This script is meant as a helper for the Open vSwitch init script commands. EOF - exit 0 -fi +} PATH=/sbin:/bin:/usr/sbin:/usr/bin @@ -43,116 +48,214 @@ missing_program () { IFS=$save_IFS return 0 } -if missing_program ip; then - echo "$0: ip not found in $PATH" >&2 - exit 1 -fi - -if test "$#" = 0; then - echo "# $0: no parameters given (use \"$0 --help\" for help)" -fi - -devs=$* -for dev in $devs; do - state=`ip link show dev $dev` || continue - - echo "# $dev" - # Link state (Ethernet addresses, up/down, ...) - linkcmd= - case $state in - *"state UP"* | *[,\<]"UP"[,\>]* ) - linkcmd="$linkcmd up" - ;; - *"state DOWN"*) - linkcmd="$linkcmd down" - ;; - esac - if expr "$state" : '.*\bdynamic\b' > /dev/null; then - linkcmd="$linkcmd dynamic" - fi - if qlen=`expr "$state" : '.*qlen \([0-9]+\)'`; then - linkcmd="$linkcmd txqueuelen $qlen" - fi - if hwaddr=`expr "$state" : '.*link/ether \([^ ]*\)'`; then - linkcmd="$linkcmd address $hwaddr" - fi - if brd=`expr "$state" : '.*brd \([^ ]*\)'`; then - linkcmd="$linkcmd broadcast $brd" - fi - if mtu=`expr "$state" : '.*mtu \([0-9]+\)'`; then - linkcmd="$linkcmd mtu $mtu" - fi - if test -n "$linkcmd"; then - echo ip link set dev $dev down # Required to change hwaddr. - echo ip link set dev $dev $linkcmd - fi - - # IP addresses (including IPv6). - echo "ip addr flush dev $dev 2>/dev/null" # Suppresses "Nothing to flush". - ip addr show dev $dev | while read addr; do - set -- $addr - - # Check and trim family. - family=$1 - shift - case $family in - inet | inet6) ;; - *) continue ;; - esac - - # Trim device off the end--"ip" insists on having "dev" precede it. - addrcmd= - while test $# != 0; do - case $1 in - dynamic) - # Omit kernel-maintained route. - continue 2 - ;; - scope) - if test "$2" = link; then - # Omit route derived from IP address, e.g. - # 172.16.0.0/16 derived from 172.16.12.34. - continue 2 - fi - ;; - "$dev"|"$dev:"*) - # Address label string - addrcmd="$addrcmd label $1" - shift - continue - ;; - esac - addrcmd="$addrcmd $1" - shift - done - if test "$1" != "$dev"; then - addrcmd="$addrcmd $1" - fi - echo ip -f $family addr add $addrcmd dev $dev +save_interfaces () { + if missing_program ip; then + echo "$0: ip not found in $PATH" >&2 + exit 1 + fi + + if test "$#" = 0; then + exit 0 + fi + + devs="$@" + for dev in $devs; do + state=`ip link show dev $dev` || continue + + echo "# $dev" + # Link state (Ethernet addresses, up/down, ...) + linkcmd= + case $state in + *"state UP"* | *[,\<]"UP"[,\>]* ) + linkcmd="$linkcmd up" + ;; + *"state DOWN"*) + linkcmd="$linkcmd down" + ;; + esac + if expr "$state" : '.*\bdynamic\b' > /dev/null; then + linkcmd="$linkcmd dynamic" + fi + if qlen=`expr "$state" : '.*qlen \([0-9]+\)'`; then + linkcmd="$linkcmd txqueuelen $qlen" + fi + if hwaddr=`expr "$state" : '.*link/ether \([^ ]*\)'`; then + linkcmd="$linkcmd address $hwaddr" + fi + if brd=`expr "$state" : '.*brd \([^ ]*\)'`; then + linkcmd="$linkcmd broadcast $brd" + fi + if mtu=`expr "$state" : '.*mtu \([0-9]+\)'`; then + linkcmd="$linkcmd mtu $mtu" + fi + if test -n "$linkcmd"; then + echo ip link set dev $dev down # Required to change hwaddr. + echo ip link set dev $dev $linkcmd + fi + + # IP addresses (including IPv6). + echo "ip addr flush dev $dev 2>/dev/null" # Suppresses "Nothing to flush". + ip addr show dev $dev | while read addr; do + set -- $addr + + # Check and trim family. + family=$1 + shift + case $family in + inet | inet6) ;; + *) continue ;; + esac + + # Trim device off the end--"ip" insists on having "dev" precede it. + addrcmd= + while test $# != 0; do + case $1 in + dynamic) + # Omit kernel-maintained route. + continue 2 + ;; + scope) + if test "$2" = link; then + # Omit route derived from IP address, e.g. + # 172.16.0.0/16 derived from 172.16.12.34. + continue 2 + fi + ;; + "$dev"|"$dev:"*) + # Address label string + addrcmd="$addrcmd label $1" + shift + continue + ;; + esac + addrcmd="$addrcmd $1" + shift + done + if test "$1" != "$dev"; then + addrcmd="$addrcmd $1" + fi + + echo ip -f $family addr add $addrcmd dev $dev + done + + # Routes. + echo "ip route flush dev $dev proto boot 2>/dev/null" # Suppresses "Nothing to flush". + ip route show dev $dev | while read route; do + # "proto kernel" routes are installed by the kernel automatically. + case $route in + *" proto kernel "*) continue ;; + esac + + echo "ip route add $route dev $dev" + done + + echo + done + + if missing_program iptables-save; then + echo "# iptables-save not found in $PATH, not saving iptables state" + else + echo "# global" + echo "iptables-restore <<'EOF'" + iptables-save + echo "EOF" + fi +} + +save_flows () { + if missing_program ovs-ofctl; then + echo "$0: ovs-ofctl not found in $PATH" >&2 + exit 1 + fi + + for bridge in "$@"; do + flows="`ovs-ofctl dump-flows "${bridge}" | sed -e '/NXST_FLOW/d' \ + -e 's/idle_age=[^,]*,//'`" + echo "ovs-ofctl add-flows ${bridge} - << EOF +${flows} +EOF" done +} + +save_datapaths () { + if missing_program ovs-dpctl; then + echo "$0: ovs-dpctl not found in $PATH" >&2 + exit 1 + fi + if missing_program ovs-vsctl; then + echo "$0: ovs-vsctl not found in $PATH" >&2 + exit 1 + fi + + for dp in "$@"; do + echo "ovs-dpctl add-dp ${dp}" + ovs-dpctl show $dp | while read line; do + if ! port_no=`expr "${line}" : '.*port \([0-9]\+\):'`; then + continue + fi + + netdev=`echo ${line} | awk '{print $3}'` + [ "${dp#system@}" = "${netdev}" ] && continue - # Routes. - echo "ip route flush dev $dev proto boot 2>/dev/null" # Suppresses "Nothing to flush". - ip route show dev $dev | while read route; do - # "proto kernel" routes are installed by the kernel automatically. - case $route in - *" proto kernel "*) continue ;; - esac + type=`echo ${line} | awk '{print $4}' | sed 's/[:)(]//g'` + [ ! -n "${type}" ] && type="system" - echo "ip route add $route dev $dev" + command="ovs-dpctl add-if ${dp}\ + ${netdev},type=${type},port_no=${port_no}" + + options=`echo ${line} | awk -F: '{print $3}' | sed 's/[) ]//g'` + [ -n "${options}" ] && command="${command},${options}" + + if [ "${type}" = "ipsec_gre" ] || [ "${type}" = "ipsec_stt" ]; then + if peer_cert=`ovs-vsctl get interface \ + "${netdev}" options:peer_cert 2>/dev/null`; then + if (ovs-vsctl get interface "${netdev}" \ + options:certificate >/dev/null 2>&1) ; then + command="${command},peer_cert=${peer_cert},certificate=${certificate}" + else + use_ssl_cert=`ovs-vsctl get interface "${netdev}" \ + options:use_ssl_cert 2>/dev/null` + command="${command},peer_cert=${peer_cert},use_ssl_cert=${use_ssl_cert}" + fi + else + psk=`ovs-vsctl get interface "${netdev}" \ + options:psk 2>/dev/null` + command="${command},psk=${psk}" + fi + fi + echo ${command} + done done +} - echo +while [ $# -ne 0 ] +do + case $1 in + "save-datapaths") + shift + save_datapaths "$@" + exit 0 + ;; + "save-flows") + shift + save_flows "$@" + exit 0 + ;; + "save-interfaces") + shift + save_interfaces "$@" + exit 0 + ;; + -h | --help) + usage + exit 0 + ;; + *) + echo >&2 "$0: unknown command \"$1\" (use --help for help)" + exit 1 + ;; + esac done -if missing_program iptables-save; then - echo "# iptables-save not found in $PATH, not saving iptables state" -else - echo "# global" - echo "iptables-restore <<'EOF'" - iptables-save - echo "EOF" -fi - exit 0 -- 1.7.2.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev