From: Michael Tremer Date: Sun, 21 Dec 2014 22:36:07 +0000 (+0000) Subject: Add hotplugging for zones (and ports of those) X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2a969c27350669274b6cab9eb79fbb630ff811d9;p=people%2Fstevee%2Fnetwork.git Add hotplugging for zones (and ports of those) --- diff --git a/src/functions/functions.hook b/src/functions/functions.hook index 5b828356..4c21f1ac 100644 --- a/src/functions/functions.hook +++ b/src/functions/functions.hook @@ -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 \ \ diff --git a/src/functions/functions.hotplug b/src/functions/functions.hotplug index 6e71e0c4..80089ac3 100644 --- a/src/functions/functions.hotplug +++ b/src/functions/functions.hotplug @@ -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() { diff --git a/src/functions/functions.zone b/src/functions/functions.zone index 2a04ccf1..cad0b790 100644 --- a/src/functions/functions.zone +++ b/src/functions/functions.zone @@ -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} diff --git a/src/header-zone b/src/header-zone index 808a54a7..3241eb5a 100644 --- a/src/header-zone +++ b/src/header-zone @@ -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 diff --git a/src/hooks/ports/batman-adv b/src/hooks/ports/batman-adv index 15e8a96f..4dd1e9e8 100644 --- a/src/hooks/ports/batman-adv +++ b/src/hooks/ports/batman-adv @@ -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}" diff --git a/src/hooks/zones/bridge b/src/hooks/zones/bridge index 595d0d4e..d72564a7 100644 --- a/src/hooks/zones/bridge +++ b/src/hooks/zones/bridge @@ -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} } diff --git a/src/udev/network-hotplug b/src/udev/network-hotplug index 416a9ff1..21dc4dd7 100644 --- a/src/udev/network-hotplug +++ b/src/udev/network-hotplug @@ -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} ;;