]> git.ipfire.org Git - network.git/blobdiff - src/hooks/zones/bridge
bridge: Reorder functions into the common order
[network.git] / src / hooks / zones / bridge
old mode 100755 (executable)
new mode 100644 (file)
index a534871..fb81673
 
 HOOK_MANPAGE="network-zone-bridge"
 
-HOOK_SETTINGS="HOOK STP STP_FORWARD_DELAY STP_HELLO STP_MAXAGE STP_MODE"
-HOOK_SETTINGS="${HOOK_SETTINGS} STP_PRIORITY MAC MTU"
+HOOK_SETTINGS="HOOK ADDRESS STP STP_FORWARD_DELAY STP_HELLO STP_MAXAGE"
+HOOK_SETTINGS="${HOOK_SETTINGS} STP_PRIORITY MTU"
+
+HOOK_PORT_SETTINGS="COST PRIORITY"
 
 # Default values
-MAC=$(mac_generate)
 MTU=1500
 STP="on"
-STP_MODE="rstp"
 STP_FORWARD_DELAY=0
 STP_HELLO=2
 STP_MAXAGE=20
 STP_PRIORITY=512
 
-function hook_check() {
-       assert ismac MAC
+hook_check_settings() {
+       assert ismac ADDRESS
+       assert isset MTU && assert mtu_is_valid "ethernet" "${MTU}"
+
+       # Spanning Tree Protocol
        assert isbool STP
-       assert isoneof STP_MODE stp rstp
        assert isinteger STP_HELLO
        assert isinteger STP_FORWARD_DELAY
        assert isinteger STP_PRIORITY
-       assert isinteger MTU
 }
 
-function hook_parse_cmdline() {
+hook_parse_cmdline() {
        while [ $# -gt 0 ]; do
                case "${1}" in
-                       --stp=*)
-                               STP=${1#--stp=}
+                       --address=*)
+                               ADDRESS="$(cli_get_val "${1}")"
+
+                               if ! mac_is_valid "${ADDRESS}"; then
+                                       error "Invalid MAC address: ${ADDRESS}"
+                                       return ${EXIT_ERROR}
+                               fi
                                ;;
-                       --stp-mode=*)
-                               STP_MODE=${1#--stp-mode=}
+
+                       --mtu=*)
+                               MTU="$(cli_get_val "${1}")"
+
+                               if ! mtu_is_valid "ethernet" "${MTU}"; then
+                                       error "Invalid MTU: ${MTU}"
+                                       return ${EXIT_ERROR}
+                               fi
                                ;;
+
+                       --stp=*)
+                               STP="$(cli_get_val "${1}")"
+
+                               if enabled STP; then
+                                       STP="on"
+                               elif disabled STP; then
+                                       STP="off"
+                               else
+                                       error "Invalid value for STP: ${STP}"
+                                       return ${EXIT_ERROR}
+                               fi
+                               ;;
+
                        --stp-hello=*)
-                               STP_HELLO=${1#--stp-hello=}
+                               STP_HELLO="$(cli_get_val "${1}")"
+
+                               if ! isinteger STP_HELLO; then
+                                       error "Invalid STP hello time: ${STP_HELLO}"
+                                       return ${EXIT_ERROR}
+                               fi
                                ;;
+
                        --stp-forward-delay=*)
-                               STP_FORWARD_DELAY=${1#--stp-forward-delay=}
+                               STP_FORWARD_DELAY="$(cli_get_val "${1}")"
+
+                               if ! isinteger STP_FORWARD_DELAY; then
+                                       error "Invalid STP forwarding delay: ${STP_FORWARD_DELAY}"
+                                       return ${EXIT_ERROR}
+                               fi
                                ;;
+
                        --stp-priority=*)
-                               STP_PRIORITY=${1#--stp-priority=}
-                               ;;
-                       --mtu=*)
-                               MTU=${1#--mtu=}
-                               ;;
-                       --mac=*)
-                               MAC=${1#--mac=}
+                               STP_PRIORITY="$(cli_get_val "${1}")"
+
+                               if ! isinteger STP_PRIORITY; then
+                                       error "Invalid STP priority: ${STP_PRIORITY}"
+                                       return ${EXIT_ERROR}
+                               fi
                                ;;
+
                        *)
-                               warning "Ignoring unknown option '${1}'"
+                               error "Unknown argument: ${1}"
+                               return ${EXIT_ERROR}
                                ;;
                esac
                shift
        done
+
+       # Generate a random MAC address if the user passed no one
+       if isset ADDRESS; then
+               ADDRESS="$(mac_generate)"
+       fi
+
+       return ${EXIT_OK}
 }
 
-function hook_up() {
+hook_up() {
        local zone=${1}
        assert isset zone
 
-       zone_config_read ${zone}
+       zone_settings_read "${zone}"
 
        # Create the bridge if it does not already exist.
-       if ! device_exists ${zone}; then
-               bridge_create ${zone} \
-                       --address=${MAC} --mtu=${MTU}
-
-       # Adjust MAC address and MTU if needed.
-       else
-               device_set_address ${zone} ${MAC}
-               device_set_mtu ${zone} ${MTU}
+       if ! device_exists "${zone}"; then
+               bridge_create "${zone}" \
+                       --address="${ADDRESS}" \
+                       --mtu="${MTU}"
        fi
 
        # Enable STP
        if enabled STP; then
-               stp_enable ${zone}
+               stp_enable "${zone}"
 
-               if [ -n "${STP_FORWARD_DELAY}" ]; then
-                       stp_bridge_set_forward_delay ${zone} ${STP_FORWARD_DELAY}
+               if isset STP_FORWARD_DELAY; then
+                       stp_bridge_set_forward_delay "${zone}" "${STP_FORWARD_DELAY}"
                fi
 
-               if [ -n "${STP_HELLO}" ]; then
-                       stp_bridge_set_hello_time ${zone} ${STP_HELLO}
+               if isset STP_HELLO; then
+                       stp_bridge_set_hello_time "${zone}" "${STP_HELLO}"
                fi
 
-               if [ -n "${STP_MAXAGE}" ]; then
-                       stp_bridge_set_max_age ${zone} ${STP_MAXAGE}
+               if isset STP_MAXAGE; then
+                       stp_bridge_set_max_age "${zone}" "${STP_MAXAGE}"
                fi
 
-               if [ -n "${STP_PRIORITY}" ]; then
-                       stp_bridge_set_priority ${zone} ${STP_PRIORITY}
+               if isset STP_PRIORITY; then
+                       stp_bridge_set_priority "${zone}" "${STP_PRIORITY}"
                fi
        else
-               stp_disable ${zone}
+               stp_disable "${zone}"
        fi
 
-       device_set_up ${zone}
+       device_set_up "${zone}"
 
        # XXX Currently, there is a bug (in the linux kernel?) that we need to
        # set our bridges to promisc mode.
-       device_set_promisc ${zone} on
+       device_set_promisc "${zone}" on
 
-       # Bring all ports up
-       zone_ports_up ${zone}
-       zone_configs_up ${zone}
+       # Bring up all configurations
+       zone_configs_up "${zone}"
 
        exit ${EXIT_OK}
 }
 
-function hook_down() {
-       local zone=${1}
+hook_down() {
+       local zone="${1}"
        assert isset zone
 
-       if ! device_is_up ${zone}; then
+       if ! device_is_up "${zone}"; then
                warning "Zone '${zone}' is not up"
                exit ${EXIT_OK}
        fi
 
-       zone_configs_down ${zone}
-       zone_ports_down ${zone}
+       # Stop all the configs.
+       zone_configs_down "${zone}"
 
-       # XXX See remark in _up().
-       device_set_promisc ${zone} off
+       # Bring down all the ports.
+       zone_ports_down "${zone}"
+       zone_ports_remove "${zone}"
 
-       device_set_down ${zone}
-       bridge_delete ${zone}
+       # Remove the bridge.
+       device_set_down "${zone}"
+       bridge_delete "${zone}"
 
        exit ${EXIT_OK}
 }
 
-function hook_status() {
-       local zone=${1}
+hook_status() {
+       local zone="${1}"
        assert isset zone
 
        # Print the default header.
-       cli_device_headline ${zone}
+       cli_device_headline "${zone}"
 
        # Exit if zone is down
-       if ! zone_is_up ${zone}; then
+       if ! zone_is_up "${zone}"; then
                echo # Empty line
                exit ${EXIT_ERROR}
        fi
 
        cli_headline 2 "Spanning Tree Protocol information"
-       if stp_is_enabled ${zone}; then
-               local proto=$(stp_bridge_get_protocol ${zone})
-
-               cli_print_fmt1 2 "Version"      "$(stp_get_name ${proto})"
+       if stp_is_enabled "${zone}"; then
                cli_print_fmt1 2 "ID"           "$(stp_bridge_get_id ${zone})"
                cli_print_fmt1 2 "Priority"     "$(stp_bridge_get_priority ${zone})"
 
@@ -197,12 +237,210 @@ function hook_status() {
        fi
 
        cli_headline 2 "Ports"
-       zone_ports_status ${zone}
+       zone_ports_status "${zone}"
        cli_space
 
        cli_headline 2 "Configurations"
-       zone_configs_cmd status ${zone}
+       zone_configs_cmd status "${zone}"
        cli_space
 
        exit ${EXIT_OK}
 }
+
+hook_hotplug() {
+       local zone="${1}"
+       assert isset zone
+
+       case "$(hotplug_action)" in
+               add)
+                       # Attach all ports when zone is coming up
+                       if hotplug_event_interface_is_zone "${zone}"; then
+                               # Bring up all ports
+                               local port
+                               for port in $(zone_get_ports "${zone}"); do
+                                       log DEBUG "Trying to attach port ${port} to ${zone}"
+
+                                       hook_port_up "${zone}" "${port}"
+                               done
+
+                       # Handle ports of this zone that have just been added
+                       elif hotplug_event_interface_is_port_of_zone "${zone}"; then
+                               # Attach the device if the parent bridge is up
+                               if zone_is_active "${zone}"; then
+                                       hook_port_up "${zone}" "${INTERFACE}"
+                               fi
+                       fi
+                       ;;
+
+               remove)
+                       if hotplug_event_interface_is_zone "${zone}"; then
+                               # Bring down/destroy all ports
+                               local port
+                               for port in $(zone_get_ports "${zone}"); do
+                                       log DEBUG "Trying to detach port ${port} from ${zone}"
+
+                                       hook_port_down "${zone}" "${port}"
+                               done
+
+                       # Handle ports of this zone that have just been removed
+                       elif hotplug_event_interface_is_port_of_zone "${zone}"; then
+                               hook_port_down "${zone}" "${INTERFACE}"
+                       fi
+                       ;;
+
+               *)
+                       exit ${EXIT_NOT_HANDLED}
+                       ;;
+       esac
+
+       exit ${EXIT_OK}
+}
+
+hook_check_port_settings() {
+       if isset COST; then
+               assert isinteger COST
+       fi
+
+       if isset PRIORITY; then
+               assert isinteger PRIORITY
+       fi
+}
+
+hook_port_attach() {
+       # Excepting at least two arguments here
+       assert [ $# -ge 2 ]
+
+       local zone="${1}"
+       local port="${2}"
+       shift 2
+
+       if zone_has_port "${zone}" "${port}"; then
+               zone_port_settings_read "${zone}" "${port}"
+       fi
+
+       local arg
+       local val
+       while read arg; do
+               case "${arg}" in
+                       --cost=*)
+                               COST="$(cli_get_val "${arg}")"
+                               ;;
+                       --priority=*)
+                               PRIORITY="$(cli_get_val "${arg}")"
+                               ;;
+               esac
+       done <<< "$(args "$@")"
+
+       if ! zone_port_settings_write "${zone}" "${port}"; then
+               exit ${EXIT_ERROR}
+       fi
+
+       exit ${EXIT_OK}
+}
+
+hook_port_detach() {
+       assert [ $# -eq 2 ]
+
+       local zone="${1}"
+       local port="${2}"
+
+       # Shut down the port (if possible)
+       port_down "${port}"
+
+       if ! zone_port_settings_remove "${zone}" "${port}"; then
+               exit ${EXIT_ERROR}
+       fi
+
+       exit ${EXIT_OK}
+}
+
+hook_port_edit() {
+       hook_port_attach "$@"
+}
+
+hook_port_up() {
+       assert [ $# -eq 2 ]
+
+       local zone="${1}"
+       local port="${2}"
+
+       # Try bringing up the port if it has not been
+       # brought up before.
+       # We will get here as soon as the port device has
+       # been created and will then connect it with the bridge.
+       if ! device_exists "${port}"; then
+               port_create "${port}"
+
+               return ${EXIT_OK}
+       fi
+
+       # Read configuration values
+       zone_port_settings_read "${zone}" "${port}" ${HOOK_PORT_SETTINGS}
+
+       # Make sure that the port is up
+       port_up "${port}"
+
+       # Attach the port to the bridge
+       bridge_attach_device "${zone}" "${port}"
+
+       # Set STP configuration
+       if isset COST; then
+               stp_port_set_cost "${zone}" "${port}" "${COST}"
+       fi
+
+       if isset PRIORITY; then
+               stp_port_set_priority "${zone}" "${port}" "${PRIORITY}"
+       fi
+
+       return ${EXIT_OK}
+}
+
+hook_port_down() {
+       assert [ $# -eq 2 ]
+
+       local zone="${1}"
+       local port="${2}"
+
+       if device_exists "${port}"; then
+               bridge_detach_device "${zone}" "${port}"
+
+               port_down "${port}"
+       fi
+
+       return ${EXIT_OK}
+}
+
+hook_port_status() {
+       assert [ $# -eq 2 ]
+
+       local zone="${1}"
+       local port="${2}"
+
+       # Do nothing for devices which are not up and running.
+       device_exists "${port}" || exit ${EXIT_OK}
+
+       local status
+
+       # Check if the device is down.
+       if ! device_is_up "${port}"; then
+               status="${MSG_DEVICE_STATUS_DOWN}"
+
+       # Check if the device has no carrier.
+       elif ! device_has_carrier "${port}"; then
+               status="${MSG_DEVICE_STATUS_NOCARRIER}"
+
+       # Check for STP information.
+       elif stp_is_enabled "${zone}"; then
+               local state="$(stp_port_get_state "${zone}" "${port}")"
+               state="MSG_STP_${state}"
+               status="${!state}"
+
+               status="${status} - DSR: $(stp_port_get_designated_root "${zone}" "${port}")"
+               status="${status} - Cost: $(stp_port_get_cost "${zone}" "${port}")"
+       else
+               status="${MSG_DEVICE_STATUS_UP}"
+       fi
+       cli_statusline 3 "${port}" "${status}"
+
+       exit ${EXIT_OK}
+}