diff options
Diffstat (limited to '')
-rwxr-xr-x | heartbeat/iface-bridge | 843 |
1 files changed, 843 insertions, 0 deletions
diff --git a/heartbeat/iface-bridge b/heartbeat/iface-bridge new file mode 100755 index 0000000..a4e50ad --- /dev/null +++ b/heartbeat/iface-bridge @@ -0,0 +1,843 @@ +#!/bin/sh +# +# OCF Resource Agent compliant iface-bridge script. +# +# Implements network Bridge interface management +# +# Copyright (C) 2013 Red Hat, Inc. All rights reserved. +# Author: Fabio M. Di Nitto <fdinitto@redhat.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# +# + +# TODO: +# * Eventually improve bridge_check to verify all runtime +# parameters. Is it really necessary? +# * consider add support for advanced multicast timers tuning +# sethashel <bridge> <int> set hash elasticity default 4 +# sethashmax <bridge> <int> set hash max default 512 +# setmclmc <bridge> <int> set multicast last member count default 2, ? +# setmcsqc <bridge> <int> set multicast startup query count default 2, ? +# setmclmi <bridge> <time> set multicast last member interval default HZ +# setmcmi <bridge> <time> set multicast membership interval default 260 * HZ +# setmcqpi <bridge> <time> set multicast querier interval default 255 * HZ +# setmcqi <bridge> <time> set multicast query interval detault 125 * HZ +# setmcqri <bridge> <time> set multicast query response interval default 10 * HZ +# setmcqri <bridge> <time> set multicast startup query interval default 125 * hZ / 4 +# +# +# OCF parameters are as below +# OCF_RESKEY_bridge_name +# OCF_RESKEY_bridge_slaves +# OCF_RESKEY_bridge_ageing +# OCF_RESKEY_port_hairpin +# OCF_RESKEY_stp +# OCF_RESKEY_stp_bridgeprio +# OCF_RESKEY_stp_fd +# OCF_RESKEY_stp_maxage +# OCF_RESKEY_stp_hello +# OCF_RESKEY_stp_pathcost +# OCF_RESKEY_stp_portprio +# OCF_RESKEY_multicast_router +# OCF_RESKEY_multicast_snooping +# OCF_RESKEY_multicast_querier +# OCF_RESKEY_multicast_port_router +# + +####################################################################### +# Initialization: + +: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} +. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + +# Defaults +OCF_RESKEY_stp_default=false +OCF_RESKEY_stp_fd_default=0 +OCF_RESKEY_multicast_router_default=1 +OCF_RESKEY_multicast_snooping_default=1 +OCF_RESKEY_multicast_querier_default=0 + +: ${OCF_RESKEY_stp=${OCF_RESKEY_stp_default}} +: ${OCF_RESKEY_stp_fd=${OCF_RESKEY_stp_fd_default}} +: ${OCF_RESKEY_multicast_router=${OCF_RESKEY_multicast_router_default}} +: ${OCF_RESKEY_multicast_snooping=${OCF_RESKEY_multicast_snooping_default}} +: ${OCF_RESKEY_multicast_querier=${OCF_RESKEY_multicast_querier_default}} + +# binaries +: ${BRCTL:=brctl} + +####################################################################### + +bridge_usage() { + cat <<END +usage: $0 {start|stop|status|monitor|validate-all|meta-data} + +Expects to have a fully populated OCF RA-compliant environment set. +END +} + +bridge_meta_data() { + cat <<END +<?xml version="1.0"?> +<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> +<resource-agent name="iface-bridge" version="1.0"> + <version>1.0</version> + + <longdesc lang="en"> + This resource manages Bridge network interfaces. + It can add, remove, configure bridges and spanning-tree. + </longdesc> + + <shortdesc lang="en"> + Manages Bridge network interfaces. + </shortdesc> + + <parameters> + <parameter name="bridge_name" unique="1" required="1"> + <longdesc lang="en"> + Define the name of the bridge (max 15 charaters). + </longdesc> + <shortdesc lang="en"> + Name of the bridge + </shortdesc> + <content type="string"/> + </parameter> + + <parameter name="bridge_slaves" unique="1"> + <longdesc lang="en"> + Define the list of interfaces, space separated, to add to the bridge. + The list can be empty. + </longdesc> + <shortdesc lang="en"> + Network interface + </shortdesc> + <content type="string"/> + </parameter> + + <parameter name="bridge_ageing" unique="0"> + <longdesc lang="en"> + Set the ethernet (MAC) address ageing time in seconds. + </longdesc> + <shortdesc lang="en"> + MAC ageing in seconds. + </shortdesc> + <content type="integer"/> + </parameter> + + <parameter name="port_hairpin" unique="0"> + <longdesc lang="en"> + Set hairpin forwarding mode. + A list of ports that should have hairpin enabled + can be specified using the following + Example: eth0 eth1 + </longdesc> + <shortdesc lang="en"> + Set hairpin forwarding mode. + </shortdesc> + <content type="string"/> + </parameter> + + <parameter name="stp" unique="0"> + <longdesc lang="en"> + Enable or disable Spanning Tree Protocol on the bridge. + </longdesc> + <shortdesc lang="en"> + Spanning Tree Protocol + </shortdesc> + <content type="boolean" default="${OCF_RESKEY_stp_default}"/> + </parameter> + + <parameter name="stp_bridgeprio" unique="0"> + <longdesc lang="en"> + Set the bridge's priority to defined value. The priority value is a + number between 0 and 65535), and has no dimension. Lower priority values are + preferred. The bridge with the lowest priority will be elected as root bridge. + </longdesc> + <shortdesc lang="en"> + Set the bridge's priority. + </shortdesc> + <content type="integer"/> + </parameter> + + <parameter name="stp_fd" unique="0"> + <longdesc lang="en"> + Set the bridge forward delay (in seconds). + </longdesc> + <shortdesc lang="en"> + Set the bridge forward delay. + </shortdesc> + <content type="integer" default="${OCF_RESKEY_stp_fd_default}"/> + </parameter> + + <parameter name="stp_maxage" unique="0"> + <longdesc lang="en"> + Set the bridge maximum message age (in seconds). + </longdesc> + <shortdesc lang="en"> + Set the bridge maximum message age. + </shortdesc> + <content type="integer"/> + </parameter> + + <parameter name="stp_hello" unique="0"> + <longdesc lang="en"> + Set the bridge hello time (in seconds). + </longdesc> + <shortdesc lang="en"> + Set the bridge hello time. + </shortdesc> + <content type="integer"/> + </parameter> + + <parameter name="stp_pathcost" unique="0"> + <longdesc lang="en"> + Set the port cost. This is a dimensionless metric. + A list of port/cost can be specified using the following + format: unpromoted cost unpromoted cost. + Example: eth0 100 eth1 1000 + </longdesc> + <shortdesc lang="en"> + Set the port cost. + </shortdesc> + <content type="string"/> + </parameter> + + <parameter name="stp_portprio" unique="0"> + <longdesc lang="en"> + Set the port priority. This is a number between 0 and 63. + $BRCTL man page reports a value between 0 and 255, but + tests show a limit of 63 on a live system. + This metric is used in the designated port and root port + selection algorithms. + A list of port/priority can be specified using the following + format: unpromoted cost unpromoted cost. + Example: eth0 10 eth1 60 + </longdesc> + <shortdesc lang="en"> + Set the port priority. + </shortdesc> + <content type="string"/> + </parameter> + + <parameter name="multicast_router" unique="0"> + <longdesc lang="en"> + Enable or disable multicast routing on the bridge. + </longdesc> + <shortdesc lang="en"> + Enable or disable multicast routing. + </shortdesc> + <content type="boolean" default="${OCF_RESKEY_multicast_router_default}"/> + </parameter> + + <parameter name="multicast_snooping" unique="0"> + <longdesc lang="en"> + Enable or disable multicast snooping on the bridge. + </longdesc> + <shortdesc lang="en"> + Enable or disable multicast snooping. + </shortdesc> + <content type="boolean" default="${OCF_RESKEY_multicast_snooping_default}"/> + </parameter> + + <parameter name="multicast_port_router" unique="0"> + <longdesc lang="en"> + Enable or disable a port from the multicast router. + Kernel enables all port by default. + A list of port can be specified using the following + format: unpromoted 0|1 unpromoted 0|1. + Example: eth0 1 eth1 0 + </longdesc> + <shortdesc lang="en"> + Enable or disable a port from the multicast router. + </shortdesc> + <content type="string"/> + </parameter> + </parameters> + + <actions> + <action name="start" timeout="30s" /> + <action name="stop" timeout="20s" /> + <action name="status" timeout="20s" depth="0" interval="10s" /> + <action name="monitor" timeout="20s" depth="0" interval="10s" /> + <action name="meta-data" timeout="5s" /> + <action name="validate-all" timeout="20s" /> + </actions> +</resource-agent> +END +} + +# commodity function +# split_string eth0 100 eth1 1000 eth2 100 +# eth0 100 +# eth1 1000 +# eth2 100 + +split_string() { + while [ -n "$1" ]; do + echo $1 $2 + shift && shift + done +} + +# check if the interface is admin up/down + +iface_is_up() { + if ! $IP2UTIL -o link show $1 | \ + sed -e 's#.*<##g' -e 's#>.*##' -e 's#LOWER_UP##g' | \ + grep -q UP; then + return 1 + fi + return 0 +} + +# check if the slaves have link layer up/down +# see kernel network documentation on meaning of LOWER_UP flag +# for more in depth explanation on how it works +# NOTE: this check is not reliable in virt environment +# since interfaces are always LOWER_UP. There is no way +# from the guest to know if the host has disconnected somehow + +iface_lower_is_up() { + if ! $IP2UTIL -o link show $1 | \ + grep -q LOWER_UP; then + return 1 + fi + return 0 +} + +# wrapup function to check if any interface defined in +# option lists is a slave + +iface_is_slave() { + for slave in $OCF_RESKEY_bridge_slaves; do + if [ "$1" = "$slave" ]; then + return 0 + fi + done + return 1 +} + +bridge_validate() { + check_binary $BRCTL + check_binary $IP2UTIL + + if [ -z "$OCF_RESKEY_bridge_name" ]; then + ocf_log err "Invalid OCF_RESKEY_bridge_name: value cannot be empty" + return 1 + fi + + # the echo .. is the equivalent of strlen in bash + # + # /usr/include/linux/if.h:#define IFNAMSIZ 16 + # needs to include 0 byte end string + + if [ "${#OCF_RESKEY_bridge_name}" -gt 15 ]; then + ocf_log err "Invalid OCF_RESKEY_bridge_name: name is too long" + return 1 + fi + + if [ ! -d "/sys/class/net" ]; then + ocf_log err "Unable to find sysfs network class in /sys" + return 1 + fi + + for slave in $OCF_RESKEY_bridge_slaves; do + if [ ! -e "/sys/class/net/$slave" ]; then + ocf_log err "Invalid OCF_RESKEY_bridge_slaves: $slave does not exists" + return 1 + fi + done + + # check if declared harpin ports are slaves + for hairpin in $OCF_RESKEY_port_hairpin; do + if ! iface_is_slave $hairpin; then + ocf_log err "Invalid OCF_RESKEY_port_hairpin: $hairpin is not listed in OCF_RESKEY_bridge_slaves" + return 1 + fi + done + + if [ -n "$OCF_RESKEY_bridge_ageing" ]; then + if ! ocf_is_decimal "$OCF_RESKEY_bridge_ageing"; then + ocf_log err "Invalid OCF_RESKEY_bridge_ageing: must be a decimal value (0 or greater)" + return 1 + fi + fi + + # OCF_RESKEY_stp_fd needs special handling as it can be 0 or greater + # but only when configured before OCF_RESKEY_stp. + # if enabled after OCF_RESKEY_stp with stp=true the value range is + # different. It is not clear from the man page or brctl documentation + # what the range is ahead of time. + if [ -n "$OCF_RESKEY_stp_fd" ]; then + if ! ocf_is_decimal "$OCF_RESKEY_stp_fd" || \ + [ "$OCF_RESKEY_stp_fd" -lt 0 ]; then + ocf_log err "Invalid OCF_RESKEY_stp_fd: must be a decimal value (0 or greater)" + return 1 + fi + fi + + if ocf_is_true "$OCF_RESKEY_stp"; then + + if [ -n "$OCF_RESKEY_stp_bridgeprio" ]; then + if ! ocf_is_decimal "$OCF_RESKEY_stp_bridgeprio" || \ + [ "$OCF_RESKEY_stp_bridgeprio" -gt 65535 ]; then + ocf_log err "Invalid OCF_RESKEY_stp_bridgeprio: must be a decimal value between 0 and 65535 included" + return 1 + fi + fi + + if [ -n "$OCF_RESKEY_stp_hello" ]; then + if ! ocf_is_decimal "$OCF_RESKEY_stp_hello"; then + ocf_log err "Invalid OCF_RESKEY_stp_hello: must be a decimal value (0 or greater)" + return 1 + fi + fi + + if [ -n "$OCF_RESKEY_stp_maxage" ]; then + if ! ocf_is_decimal "$OCF_RESKEY_stp_maxage"; then + ocf_log err "Invalid OCF_RESKEY_stp_maxage: must be a decimal value (0 or greater)" + return 1 + fi + fi + + if [ -n "$OCF_RESKEY_stp_pathcost" ]; then + split_string $OCF_RESKEY_stp_pathcost | { while read iface cost; do + if ! iface_is_slave $iface; then + ocf_log err "Invalid OCF_RESKEY_stp_pathcost: $iface is not listed in OCF_RESKEY_bridge_slaves" + return 1 + fi + + if ! ocf_is_decimal $cost; then + ocf_log err "Invalid OCF_RESKEY_stp_pathcost: cost must be a decimal value (0 or great)" + return 1 + fi + done + } + fi + + if [ -n "$OCF_RESKEY_stp_portprio" ]; then + split_string $OCF_RESKEY_stp_portprio | { while read iface prio; do + if ! iface_is_slave $iface; then + ocf_log err "Invalid OCF_RESKEY_stp_portprio: $iface is not listed in OCF_RESKEY_bridge_slaves" + return 1 + fi + + if ! ocf_is_decimal $prio || \ + [ "$prio" -gt "63" ]; then + ocf_log err "Invalid OCF_RESKEY_stp_portprio: priority must be a decimal value between 0 and 63 included" + return 1 + fi + done + } + fi + + fi + + if [ -n "$OCF_RESKEY_multicast_port_router" ]; then + split_string $OCF_RESKEY_multicast_port_router | { while read iface mcport; do + if ! iface_is_slave $iface; then + ocf_log err "Invalid OCF_RESKEY_multicast_port_router: $iface is not listed in OCF_RESKEY_bridge_slaves" + return 1 + fi + + if ! ocf_is_decimal $mcport || \ + [ "$mcport" -gt "1" ]; then + ocf_log err "Invalid OCF_RESKEY_multicast_port_router: valuer must be 0 (disabled) or 1 (enabled)" + return 1 + fi + done + } + fi + + return 0 +} + +bridge_check() { + if [ -e "/sys/class/net/$OCF_RESKEY_bridge_name" ]; then + if [ ! -e "$HA_RSCTMP/iface-bridge.$OCF_RESKEY_bridge_name" ]; then + return $OCF_ERR_GENERIC + fi + else + if [ -e "$HA_RSCTMP/iface-bridge.$OCF_RESKEY_bridge_name" ]; then + error="$(rm -f "$HA_RSCTMP/iface-bridge.$OCF_RESKEY_bridge_name" 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to remove stale lock file for bridge $OCF_RESKEY_bridge_name: $error" + return $OCF_ERR_GENERIC + fi + fi + return $OCF_NOT_RUNNING + fi + + # we check if all slaves are still part of the bridge + for slave in $OCF_RESKEY_bridge_slaves; do + if [ ! -e "/sys/class/net/$OCF_RESKEY_bridge_name/brif/$slave" ]; then + ocf_log err "Interface $slave is not part of the bridge $OCF_RESKEY_bridge_name" + return $OCF_ERR_GENERIC + fi + if ! iface_is_up $slave; then + ocf_log err "Interface $slave of the bridge $OCF_RESKEY_bridge_name is administratively down" + return $OCF_ERR_GENERIC + fi + done + + # check if bridge is still "UP" + # is there a cleaner way? + + if ! iface_is_up $OCF_RESKEY_bridge_name; then + ocf_log err "Bridge $OCF_RESKEY_bridge_name is administratively down" + return $OCF_ERR_GENERIC + fi + + if ! iface_lower_is_up $OCF_RESKEY_bridge_name; then + ocf_log err "Bridge $OCF_RESKEY_bridge_name has no active link-layer slaves" + return $OCF_ERR_GENERIC + fi + + return $OCF_SUCCESS +} + +# we need a simpler stop version to clean after us if start fails +# without involving any error checking +# rolling back in case of failure is otherwise complex + +bridge_force_stop() { + $IP2UTIL link set dev "$OCF_RESKEY_bridge_name" down 2>&1 + for slave in $OCF_RESKEY_bridge_slaves; do + $IP2UTIL link set dev "$slave" down 2>&1 + done + $BRCTL delbr "$OCF_RESKEY_bridge_name" 2>&1 + rm -f "$HA_RSCTMP/iface-bridge.$OCF_RESKEY_bridge_name" 2>&1 +} + +bridge_start() { + # check if the bridge already exists + bridge_check + ret=$? + if [ "$ret" != "$OCF_NOT_RUNNING" ]; then + return $ret + fi + + # create the bridge + error="$($BRCTL addbr "$OCF_RESKEY_bridge_name" 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to create bridge $OCF_RESKEY_bridge_name: $error" + return $OCF_ERR_GENERIC + fi + + # add slaves if configured + for slave in $OCF_RESKEY_bridge_slaves; do + error="$($BRCTL addif "$OCF_RESKEY_bridge_name" "$slave" 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to add interface $slave to bridge $OCF_RESKEY_bridge_name: $error" + return $OCF_ERR_GENERIC + fi + done + + # set haripin forward mode + for hairpin in $OCF_RESKEY_port_hairpin; do + error="$($BRCTL hairpin "$OCF_RESKEY_bridge_name" "$hairpin" on 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set hairpin on for interface $hairpin to bridge $OCF_RESKEY_bridge_name: $error" + return $OCF_ERR_GENERIC + fi + done + + # set bridge ageing + if [ -n "$OCF_RESKEY_bridge_ageing" ]; then + error="$($BRCTL setageing "$OCF_RESKEY_bridge_name" "$OCF_RESKEY_bridge_ageing" 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set bridge $OCF_RESKEY_bridge_name ageing to $OCF_RESKEY_bridge_ageing: $error" + return $OCF_ERR_GENERIC + fi + fi + + # OCF_RESKEY_stp_fd needs special handling as it can be 0 or greater + # but only when configured before OCF_RESKEY_stp. + # if enabled after OCF_RESKEY_stp with stp=true the value range is + # different. It is not clear from the man page or brctl documentation + # what the range is ahead of time. + if [ -n "$OCF_RESKEY_stp_fd" ]; then + error="$($BRCTL setfd "$OCF_RESKEY_bridge_name" "$OCF_RESKEY_stp_fd" 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set bridge forward delay $OCF_RESKEY_stp_fd on bridge $OCF_RESKEY_bridge_name : $error" + return $OCF_ERR_GENERIC + fi + fi + + # enable/disable spanning tree protocol + if ocf_is_true "$OCF_RESKEY_stp"; then + error="$($BRCTL stp "$OCF_RESKEY_bridge_name" on 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to enable STP on bridge $OCF_RESKEY_bridge_name : $error" + return $OCF_ERR_GENERIC + fi + + # set bridge priority + if [ -n "$OCF_RESKEY_stp_bridgeprio" ]; then + error="$($BRCTL setbridgeprio "$OCF_RESKEY_bridge_name" "$OCF_RESKEY_stp_bridgeprio" 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set bridge priority $OCF_RESKEY_stp_bridgeprio on bridge $OCF_RESKEY_bridge_name : $error" + return $OCF_ERR_GENERIC + fi + fi + + # set hello timer + if [ -n "$OCF_RESKEY_stp_hello" ]; then + error="$($BRCTL sethello "$OCF_RESKEY_bridge_name" "$OCF_RESKEY_stp_hello" 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set bridge hello timer $OCF_RESKEY_stp_hello on bridge $OCF_RESKEY_bridge_name : $error" + return $OCF_ERR_GENERIC + fi + fi + + + # set max age + if [ -n "$OCF_RESKEY_stp_maxage" ]; then + error="$($BRCTL setmaxage "$OCF_RESKEY_bridge_name" "$OCF_RESKEY_stp_maxage" 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set bridge max age $OCF_RESKEY_stp_maxage on bridge $OCF_RESKEY_bridge_name : $error" + return $OCF_ERR_GENERIC + fi + fi + + # set path cost per port + if [ -n "$OCF_RESKEY_stp_pathcost" ]; then + split_string $OCF_RESKEY_stp_pathcost | { while read iface cost; do + error="$($BRCTL setpathcost "$OCF_RESKEY_bridge_name" "$iface" "$cost" 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set pathcost $cost for interface $iface on bridge $OCF_RESKEY_bridge_name : $error" + return $OCF_ERR_GENERIC + fi + done + } + fi + + # set port priority per port + if [ -n "$OCF_RESKEY_stp_portprio" ]; then + split_string $OCF_RESKEY_stp_portprio | { while read iface prio; do + error="$($BRCTL setportprio "$OCF_RESKEY_bridge_name" "$iface" "$prio" 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set portprio $prio for interface $iface on bridge $OCF_RESKEY_bridge_name : $error" + return $OCF_ERR_GENERIC + fi + done + } + fi + else + # stp off is default via brctl/kernel interface but it + # is best to force it since we don't know if default + # has changed across kernel releases + error="$($BRCTL stp "$OCF_RESKEY_bridge_name" off 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to disable STP on bridge $OCF_RESKEY_bridge_name : $error" + return $OCF_ERR_GENERIC + fi + fi + + # set slaves up + for slave in $OCF_RESKEY_bridge_slaves; do + error="$($IP2UTIL link set dev "$slave" up 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set slave $slave for bridge $OCF_RESKEY_bridge_name up: $error" + return $OCF_ERR_GENERIC + fi + done + + # set the bridge up + error="$($IP2UTIL link set dev "$OCF_RESKEY_bridge_name" up 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set bridge $OCF_RESKEY_bridge_name up: $error" + return $OCF_ERR_GENERIC + fi + + # multicast operations can only be executed after the bridge is up + # and configured. + + # enable/disable multicast router + if ocf_is_true "$OCF_RESKEY_multicast_router"; then + mcrouter=1 + else + mcrouter=0 + fi + if [ -e "/sys/class/net/$OCF_RESKEY_bridge_name/bridge/multicast_router" ]; then + error="$(echo $mcrouter > /sys/class/net/$OCF_RESKEY_bridge_name/bridge/multicast_router 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set OCF_RESKEY_multicast_router for bridge $OCF_RESKEY_bridge_name: $error" + return $OCF_ERR_GENERIC + fi + else + ocf_log warn "Unable to set multicast router on bridge $OCF_RESKEY_bridge_name because kernel does not support it" + fi + + # enable/disable multicast snoopint + if ocf_is_true "$OCF_RESKEY_multicast_snooping"; then + mcsnooping=1 + else + mcsnooping=0 + fi + if [ -e "/sys/class/net/$OCF_RESKEY_bridge_name/bridge/multicast_snooping" ]; then + error="$(echo $mcsnooping > /sys/class/net/$OCF_RESKEY_bridge_name/bridge/multicast_snooping 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set OCF_RESKEY_multicast_snooping for bridge $OCF_RESKEY_bridge_name: $error" + return $OCF_ERR_GENERIC + fi + else + ocf_log warn "Unable to set multicast snooping on bridge $OCF_RESKEY_bridge_name because kernel does not support it" + fi + + # enable/disable multicast querier + if ocf_is_true "$OCF_RESKEY_multicast_querier"; then + mcquerier=1 + else + mcquerier=0 + fi + if [ -e "/sys/class/net/$OCF_RESKEY_bridge_name/bridge/multicast_querier" ]; then + error="$(echo $mcquerier > /sys/class/net/$OCF_RESKEY_bridge_name/bridge/multicast_querier 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set OCF_RESKEY_multicast_querier for bridge $OCF_RESKEY_bridge_name: $error" + return $OCF_ERR_GENERIC + fi + else + ocf_log warn "Unable to set multicast querier on bridge $OCF_RESKEY_bridge_name because kernel does not support it" + fi + + # set multicast router per port + if [ -n "$OCF_RESKEY_multicast_port_router" ]; then + split_string $OCF_RESKEY_multicast_port_router | { while read iface mcport; do + if [ -e "/sys/class/net/$iface/brport/multicast_router" ]; then + error="$(echo $mcport > /sys/class/net/$iface/brport/multicast_router 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set OCF_RESKEY_multicast_port_router $mcport for interface $iface on bridge $OCF_RESKEY_bridge_name : $error" + return $OCF_ERR_GENERIC + fi + else + ocf_log warn "Unable to set multicast port router on bridge $OCF_RESKEY_bridge_name because kernel does not support it" + fi + done + } + fi + + error="$(touch "$HA_RSCTMP/iface-bridge.$OCF_RESKEY_bridge_name")" + if [ "$?" != "0" ]; then + ocf_log err "Unable to write lock file for bridge $OCF_RESKEY_bridge_name: $error" + return $OCF_ERR_GENERIC + fi + + return $OCF_SUCCESS +} + +bridge_stop() { + bridge_check + ret=$? + if [ "$ret" = "$OCF_NOT_RUNNING" ]; then + return $OCF_SUCCESS + fi + if [ "$ret" != "$OCF_SUCCESS" ]; then + return $ret + fi + + # set bridge down + error="$($IP2UTIL link set dev "$OCF_RESKEY_bridge_name" down 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set bridge $OCF_RESKEY_bridge_name down: $error" + return $OCF_ERR_GENERIC + fi + + # set slaves down + for slave in $OCF_RESKEY_bridge_slaves; do + error="$($IP2UTIL link set dev "$slave" down 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to set slave $slave for bridge $OCF_RESKEY_bridge_name down: $error" + return $OCF_ERR_GENERIC + fi + done + + # delete bridge + error="$($BRCTL delbr "$OCF_RESKEY_bridge_name" 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to delete bridge $OCF_RESKEY_bridge_name: $error" + return $OCF_ERR_GENERIC + fi + + error="$(rm -f "$HA_RSCTMP/iface-bridge.$OCF_RESKEY_bridge_name" 2>&1)" + if [ "$?" != "0" ]; then + ocf_log err "Unable to remove lock file for bridge $OCF_RESKEY_bridge_name: $error" + return $OCF_ERR_GENERIC + fi + + return $OCF_SUCCESS +} + +case $__OCF_ACTION in + meta-data) + bridge_meta_data + exit $OCF_SUCCESS + ;; + usage|help) + bridge_usage + exit $OCF_SUCCESS + ;; +esac + +if [ ! -d "$HA_RSCTMP" ]; then + ocf_log debug "$HA_RSCTMP not found, we are probably being executed manually" + mkdir -p "$HA_RSCTMP" +fi + +if [ -n "$__OCF_ACTION" ] && ! bridge_validate; then + exit $OCF_ERR_CONFIGURED +fi + +case $__OCF_ACTION in + start|stop) + if ! ocf_is_root; then + ocf_log err "You must be root for $__OCF_ACTION operation." + exit $OCF_ERR_PERM + fi + ;; +esac + +case $__OCF_ACTION in + start) + bridge_start + ret=$? + if [ "$ret" != "$OCF_SUCCESS" ]; then + bridge_force_stop + fi + exit $ret + ;; + stop) + bridge_stop + exit $? + ;; + status|monitor) + bridge_check + exit $? + ;; + validate-all) + # bridge_validate above does the trick + ;; + *) + bridge_usage + exit $OCF_ERR_UNIMPLEMENTED + ;; +esac +# vi:sw=4:ts=8: |