#!/bin/bash ############################################################################### # # # IPFire.org - A linux based firewall # # Copyright (C) 2010 Michael Tremer & Christian Schmidt # # # # This program is free software: you can redistribute it and/or modify # # it under the terms of the GNU General Public License as published by # # the Free Software Foundation, either version 3 of the License, or # # (at your option) any later version. # # # # This program is distributed in the hope that it will be useful, # # but WITHOUT ANY WARRANTY; without even the implied warranty of # # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # # GNU General Public License for more details. # # # # You should have received a copy of the GNU General Public License # # along with this program. If not, see . # # # ############################################################################### . /usr/lib/network/header-zone HOOK_MANPAGE="network-zone-bridge" HOOK_SETTINGS="HOOK STP STP_FORWARD_DELAY STP_HELLO STP_MAXAGE" HOOK_SETTINGS="${HOOK_SETTINGS} STP_PRIORITY MAC MTU" HOOK_PORT_SETTINGS="COST PRIORITY" # Default values MAC="" MTU=1500 STP="on" STP_FORWARD_DELAY=0 STP_HELLO=2 STP_MAXAGE=20 STP_PRIORITY=512 hook_check_settings() { assert ismac MAC assert isbool STP assert isinteger STP_HELLO assert isinteger STP_FORWARD_DELAY assert isinteger STP_PRIORITY assert isinteger MTU } hook_parse_cmdline() { while [ $# -gt 0 ]; do case "${1}" in --stp=*) STP=${1#--stp=} ;; --stp-hello=*) STP_HELLO=${1#--stp-hello=} ;; --stp-forward-delay=*) STP_FORWARD_DELAY=${1#--stp-forward-delay=} ;; --stp-priority=*) STP_PRIORITY=${1#--stp-priority=} ;; --mtu=*) MTU=${1#--mtu=} ;; --mac=*) MAC=${1#--mac=} ;; *) warning "Ignoring unknown option '${1}'" ;; esac shift done # Generate a random MAC address if the user passed no one isset MAC || MAC="$(mac_generate)" } hook_up() { local zone=${1} assert isset 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}" fi # Enable STP if enabled STP; then stp_enable "${zone}" if isset STP_FORWARD_DELAY; then stp_bridge_set_forward_delay "${zone}" "${STP_FORWARD_DELAY}" fi if isset STP_HELLO; then stp_bridge_set_hello_time "${zone}" "${STP_HELLO}" fi if isset STP_MAXAGE; then stp_bridge_set_max_age "${zone}" "${STP_MAXAGE}" fi if isset STP_PRIORITY; then stp_bridge_set_priority "${zone}" "${STP_PRIORITY}" fi else stp_disable "${zone}" fi 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 # Bring up all configurations zone_configs_up "${zone}" 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_down() { local zone="${1}" assert isset zone if ! device_is_up "${zone}"; then warning "Zone '${zone}' is not up" exit ${EXIT_OK} fi # Stop all the configs. zone_configs_down "${zone}" # Bring down all the ports. zone_ports_down "${zone}" zone_ports_remove "${zone}" # Remove the bridge. device_set_down "${zone}" bridge_delete "${zone}" exit ${EXIT_OK} } hook_status() { local zone="${1}" assert isset zone # Print the default header. cli_device_headline "${zone}" # Exit if zone is down 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 cli_print_fmt1 2 "ID" "$(stp_bridge_get_id ${zone})" cli_print_fmt1 2 "Priority" "$(stp_bridge_get_priority ${zone})" if stp_bridge_is_root ${zone}; then cli_print 2 "This bridge is root." else cli_print_fmt1 2 "Designated root" \ "$(stp_bridge_get_designated_root ${zone})" cli_print_fmt1 2 "Root path cost" \ "$(stp_bridge_get_root_path_cost ${zone})" fi cli_space # Topology information cli_print_fmt1 2 "Topology changing" \ "$(stp_bridge_get_topology_change_detected ${zone})" cli_print_fmt1 2 "Topology change time" \ "$(beautify_time $(stp_bridge_get_topology_change_timer ${zone}))" cli_print_fmt1 2 "Topology change count" \ "$(stp_bridge_get_topology_change_count ${zone})" cli_space else cli_print 2 "Disabled" cli_space fi cli_headline 2 "Ports" zone_ports_status "${zone}" cli_space cli_headline 2 "Configurations" zone_configs_cmd status "${zone}" cli_space 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} }