]> git.ipfire.org Git - people/stevee/network.git/commitdiff
Add hotplugging for zones (and ports of those)
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 21 Dec 2014 22:36:07 +0000 (22:36 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 21 Dec 2014 22:36:07 +0000 (22:36 +0000)
src/functions/functions.hook
src/functions/functions.hotplug
src/functions/functions.zone
src/header-zone
src/hooks/ports/batman-adv
src/hooks/zones/bridge
src/udev/network-hotplug

index 5b8283561fde9361297efc24d6c552da36332b7e..4c21f1ace6134539819c105b900c2dfebda23a54 100644 (file)
@@ -26,7 +26,7 @@ HOOK_COMMANDS_PORT="hook_create hook_down hook_edit hook_hotplug \
        hook_hotplug_rename hook_info hook_status hook_up"
 
 HOOK_COMMANDS_ZONE="hook_add hook_create hook_discover hook_down hook_edit hook_help \
-       hook_info hook_remove hook_status hook_up \
+       hook_info hook_remove hook_status hook_up hook_hotplug \
        \
        hook_config_create hook_config_edit hook_config_remove hook_config_show \
        \
index 6e71e0c4814cfb4c9f5f41df6ea70f9639583363..80089ac3821ef668e5b236dbf2a54c67b2acf66f 100644 (file)
@@ -50,6 +50,26 @@ function hotplug_propagate_all_ports() {
        done
 }
 
+function hotplug_propagate_all_zones() {
+       hotplug_assert_in_hotplug_event
+
+       local zone
+       for zone in $(zones_get_all); do
+               zone_hotplug_event "${zone}"
+               local ret="${?}"
+
+               # Log warning for crashed hooks
+               case "${ret}" in
+                       ${EXIT_OK}|${EXIT_NOT_HANDLED})
+                               : # do nothing
+                               ;;
+                       *)
+                               log WARNING "Unknown exit code for zone '${zone}': ${ret}"
+                               ;;
+               esac
+       done
+}
+
 function hotplug_event_port_is_interface() {
        hotplug_assert_in_hotplug_event
 
@@ -59,7 +79,7 @@ function hotplug_event_port_is_interface() {
        [ "${port}" = "${INTERFACE}" ]
 }
 
-function hotplug_event_port_is_slave() {
+function hotplug_event_interface_is_slave_of_port() {
        hotplug_assert_in_hotplug_event
 
        local port="${1}"
@@ -69,7 +89,20 @@ function hotplug_event_port_is_slave() {
        isset INTERFACE || return ${EXIT_FALSE}
 
        local slaves="$(port_get_slaves "${port}")"
-       list_match "${INTERFACE}" ${SLAVES}
+       list_match "${INTERFACE}" ${slaves}
+}
+
+function hotplug_event_interface_is_port_of_zone() {
+       hotplug_assert_in_hotplug_event
+
+       local zone="${1}"
+       assert isset zone
+
+       # Return false if INTERFACE is not set
+       isset INTERFACE || return ${EXIT_FALSE}
+
+       local ports="$(zone_get_ports "${zone}")"
+       list_match "${INTERFACE}" ${ports}
 }
 
 function hotplug_event_port_uses_phy() {
index 2a04ccf13f796192068c1799a630c14dbd796fa1..cad0b790e50f795b82ec6db44299b0db4186cee2 100644 (file)
@@ -81,6 +81,28 @@ function zone_start() {
        service_start "network@${zone}.service"
 }
 
+function zone_start_auto() {
+       local zone="${1}"
+       assert zone_exists "${zone}"
+
+       # If the zone has already been started, we
+       # will reload it so the current configuration
+       # is re-applied.
+       if zone_is_active "${zone}"; then
+               zone_reload "${zone}"
+               return ${?}
+
+       # If the zone is still down, but in auto-start mode,
+       # we will start it.
+       elif zone_is_enabled "${zone}"; then
+               zone_start "${zone}"
+               return ${?}
+       fi
+
+       # Otherwise, nothing will be done.
+       return ${EXIT_OK}
+}
+
 function zone_stop() {
        # This function will bring down the zone
        # 'asynchronously' with help of systemd.
@@ -100,24 +122,11 @@ function zone_reload() {
 
 function zone_hotplug_event() {
        local zone="${1}"
-       assert zone_exists "${zone}"
-
-       # If the zone has already been started, we
-       # will reload it so the current configuration
-       # is re-applied.
-       if zone_is_active "${zone}"; then
-               zone_reload "${zone}"
-               return ${?}
+       assert isset zone
 
-       # If the zone is still down, but in auto-start mode,
-       # we will start it.
-       elif zone_is_enabled "${zone}"; then
-               zone_start "${zone}"
-               return ${?}
-       fi
+       hotplug_assert_in_hotplug_event
 
-       # Otherwise, nothing will be done.
-       return ${EXIT_OK}
+       zone_cmd "hotplug" "${zone}"
 }
 
 function zone_enable() {
@@ -183,6 +192,27 @@ function zone_is_active() {
        return ${EXIT_FALSE}
 }
 
+function zone_is_enabled_or_active() {
+       local zone="${1}"
+       assert isset zone
+
+       zone_is_enabled "${zone}" || zone_is_active "${zone}"
+}
+
+function zone_cmd() {
+       local cmd="${1}"
+       local port="${2}"
+       shift 2
+
+       assert isset cmd
+       assert isset zone
+
+       local hook="$(zone_get_hook ${zone})"
+       assert isset hook
+
+       hook_exec zone "${hook}" "${cmd}" "${zone}" $@
+}
+
 function zone_create() {
        local zone=${1}
        local hook=${2}
index 808a54a79e492153835d630027ed5b74370b9905..3241eb5a4f99110a81f9190d5d0c58dd254b2c0a 100644 (file)
@@ -23,6 +23,12 @@ function hook_info() {
        echo "HOOK=\"${HOOK}\""
 }
 
+function hook_hotplug() {
+       # If the hook does not handle the hotplug event, it
+       # must return EXIT_NOT_HANDLED.
+       exit ${EXIT_NOT_HANDLED}
+}
+
 function hook_create() {
        local zone="${1}"
        assert isset zone
index 15e8a96f120a673727dd0059adebbe8d4ea30848..4dd1e9e89a65da732b5d856c11645bc721245860 100644 (file)
@@ -161,7 +161,7 @@ function hook_hotplug() {
 
                        # Handle slave devices that have just been created and
                        # attach them.
-                       elif hotplug_event_port_is_slave "${port}"; then
+                       elif hotplug_event_interface_is_slave_of_port "${port}"; then
                                device_exists "${port}" || port_up "${port}"
 
                                batman_adv_attach "${port}" "${INTERFACE}"
index 595d0d4e6d21847011adac26e9aac4609783744f..d72564a7c0fd86c72998c27a3241db88cea5e8ec 100644 (file)
@@ -87,88 +87,117 @@ function hook_up() {
        zone_settings_read "${zone}" ${HOOK_SETTINGS}
 
        # 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="${MAC}" \
+                       --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 up all ports
+       zone_ports_up "${zone}"
+
+       # Bring up all configurations
+       zone_configs_up "${zone}"
+
+       exit ${EXIT_OK}
+}
+
+function hook_hotplug() {
+       local zone="${1}"
+       assert isset zone
 
-       # Bring all ports up
-       zone_ports_up ${zone}
-       zone_configs_up ${zone}
+       case "$(hotplug_action)" in
+               add)
+                       # Handle ports of this zone that have just been added
+                       if hotplug_event_interface_is_port_of_zone "${zone}"; then
+                               # Bring up the zone if it is enabled but not active, yet.
+                               if zone_is_enabled "${zone}" && ! zone_is_active "${zone}"; then
+                                       zone_start "${zone}"
+                               fi
+
+                               hook_port_up "${zone}" "${INTERFACE}"
+                       fi
+                       ;;
+               remove)
+                       # Handle ports of this zone that have just been removed
+                       if hotplug_event_interface_is_port_of_zone "${zone}"; then
+                               hook_port_down "${zone}" "${INTERFACE}"
+                       fi
+                       ;;
+               *)
+                       exit ${EXIT_NOT_HANDLED}
+                       ;;
+       esac
 
        exit ${EXIT_OK}
 }
 
 function hook_down() {
-       local zone=${1}
+       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}"
 
-       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}
+       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
+       if stp_is_enabled "${zone}"; then
                local proto=$(stp_bridge_get_protocol ${zone})
 
                cli_print_fmt1 2 "Version"      "$(stp_get_name ${proto})"
@@ -199,11 +228,11 @@ 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}
@@ -283,13 +312,13 @@ function hook_port_up() {
        local zone="${1}"
        local port="${2}"
 
-       # Try bringing up the port
-       port_up "${port}"
-
-       # If the port could not be brought up, we will
-       # log an error message and exit.
+       # 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
-               log WARNING "Port '${port}' cannot be attached to zone '${zone}' as it does not exist"
+               port_up "${port}"
+
                exit ${EXIT_OK}
        fi
 
@@ -306,6 +335,9 @@ function hook_port_up() {
 
        # TODO Apply priority (#10609)
 
+       # Make sure that the port is up
+       device_set_up "${port}"
+
        exit ${EXIT_OK}
 }
 
@@ -315,9 +347,11 @@ function hook_port_down() {
        local zone="${1}"
        local port="${2}"
 
-       bridge_detach_device "${zone}" "${port}"
+       if device_exists "${port}"; then
+               bridge_detach_device "${zone}" "${port}"
 
-       port_down "${port}"
+               port_down "${port}"
+       fi
 
        exit ${EXIT_OK}
 }
index 416a9ff1e3675c87f75c9a784590c74b2434a268..21dc4dd7137a84c8181eb50bc5df4d0414b1fc2f 100644 (file)
@@ -115,16 +115,8 @@ case "${SUBSYSTEM}" in
                # Propagate the hotplug event to all configured port hooks
                hotplug_propagate_all_ports || exit ${EXIT_ERROR}
 
-               # Check, if the device is configured in a zone.
-               # If so, propagate the event to the zone, too.
-               case "${ACTION}" in
-                       add)
-                               zone="$(port_zone "${INTERFACE}")"
-                               if isset zone; then
-                                       zone_hotplug_event "${zone}" || exit ${EXIT_ERROR}
-                               fi
-                               ;;
-               esac
+               # Propagate the hotplug event to all configured zones
+               hotplug_propagate_all_zones || exit ${EXIT_ERROR}
 
                exit ${EXIT_OK}
                ;;