From: Michael Tremer Date: Mon, 11 Mar 2013 13:34:49 +0000 (+0100) Subject: batman-adv: Enhance functionality. X-Git-Url: http://git.ipfire.org/?p=people%2Fstevee%2Fnetwork.git;a=commitdiff_plain;h=e6993835cf6b7b5c134853209f3ca51c42db0942 batman-adv: Enhance functionality. * Created a -port hook, which enables us to bridge several wireless adapters. * Make hotplugging work. --- diff --git a/functions.batman-adv b/functions.batman-adv index f4a19c55..77cf9bf9 100644 --- a/functions.batman-adv +++ b/functions.batman-adv @@ -19,16 +19,183 @@ # # ############################################################################### +function batman_adv_start() { + # Load the batman kernel module. + module_load "batman-adv" +} + function batman_adv_interface_add() { local device=${1} assert isset device - cmd_quiet batctl interface add ${device} + local port=${2} + assert isset port + + # Make sure, batman is running. + batman_adv_start + + assert device_is_batman_adv_port "${port}" + + fwrite "${SYS_CLASS_NET}/${port}/batman_adv/mesh_iface" "${device}" } function batman_adv_interface_del() { + local port=${1} + assert isset port + + fwrite "${SYS_CLASS_NET}/${port}/batman_adv/mesh_iface" "none" +} + +function batman_adv_get_aggregated_ogms() { + local device=${1} + assert isset device + + local value="$(fread ${SYS_CLASS_NET}/${device}/mesh/aggregated_ogms)" + case "${value}" in + enabled) + return ${EXIT_TRUE} + ;; + disabled) + return ${EXIT_FALSE} + ;; + esac + + return ${EXIT_ERROR} +} + +function batman_adv_get_ap_isolation() { + local device=${1} + assert isset device + + local value="$(fread ${SYS_CLASS_NET}/${device}/mesh/ap_isolation)" + case "${value}" in + enabled) + return ${EXIT_TRUE} + ;; + disabled) + return ${EXIT_FALSE} + ;; + esac + + return ${EXIT_ERROR} +} + +function batman_adv_get_bonding_mode() { + local device=${1} + assert isset device + + local value="$(fread ${SYS_CLASS_NET}/${device}/mesh/bonding)" + case "${value}" in + enabled) + return ${EXIT_TRUE} + ;; + disabled) + return ${EXIT_FALSE} + ;; + esac + + return ${EXIT_ERROR} +} + +function batman_adv_get_distributed_arp_table() { + local device=${1} + assert isset device + + local value="$(fread ${SYS_CLASS_NET}/${device}/mesh/distributed_arp_table)" + case "${value}" in + enabled) + return ${EXIT_TRUE} + ;; + disabled) + return ${EXIT_FALSE} + ;; + esac + + return ${EXIT_ERROR} +} + +function batman_adv_get_bridge_loop_avoidance() { + local device=${1} + assert isset device + + local value="$(fread ${SYS_CLASS_NET}/${device}/mesh/bridge_loop_avoidance)" + case "${value}" in + enabled) + return ${EXIT_TRUE} + ;; + disabled) + return ${EXIT_FALSE} + ;; + esac + + return ${EXIT_ERROR} +} + +function batman_adv_get_fragmentation() { + local device=${1} + assert isset device + + local value="$(fread ${SYS_CLASS_NET}/${device}/mesh/fragmentation)" + case "${value}" in + enabled) + return ${EXIT_TRUE} + ;; + disabled) + return ${EXIT_FALSE} + ;; + esac + + return ${EXIT_ERROR} +} + +function batman_adv_get_gateway_mode() { + local device=${1} + assert isset device + + local value="$(fread ${SYS_CLASS_NET}/${device}/mesh/gw_mode)" + case "${value}" in + on) + return ${EXIT_TRUE} + ;; + off) + return ${EXIT_FALSE} + ;; + esac + + return ${EXIT_ERROR} +} + +function batman_adv_get_gateway_bandwidth() { + local device=${1} + assert isset device + + fread "${SYS_CLASS_NET}/${device}/mesh/gw_bandwidth" +} + +function batman_adv_get_gateway_selection_class() { + local device=${1} + assert isset device + + fread "${SYS_CLASS_NET}/${device}/mesh/gw_sel_class" +} + +function batman_adv_get_hop_penalty() { + local device=${1} + assert isset device + + fread "${SYS_CLASS_NET}/${device}/mesh/hop_penalty" +} + +function batman_adv_get_originator_interval() { + local device=${1} + assert isset device + + fread "${SYS_CLASS_NET}/${device}/mesh/orig_interval" +} + +function batman_adv_get_routing_algorithm() { local device=${1} assert isset device - cmd_quiet batctl interface del ${device} + fread "${SYS_CLASS_NET}/${device}/mesh/routing_algo" } diff --git a/functions.cli b/functions.cli index c24c9e94..2d35e642 100644 --- a/functions.cli +++ b/functions.cli @@ -268,7 +268,7 @@ function cli_print_fmt1() { local level=${1} shift - local space=$(( 30 - (${level} * ${#IDENT}) )) + local space=$(( 34 - (${level} * ${#IDENT}) )) local format="%-${space}s %s" cli_print ${level} "${format}" "$@" diff --git a/functions.constants b/functions.constants index b7c4c52e..21b44fca 100644 --- a/functions.constants +++ b/functions.constants @@ -80,5 +80,6 @@ DEVICE_PRINT_LINE1=" %-24s %s\n" PORT_PATTERN="pN" PORT_PATTERN_ACCESSPOINT="apN" -PORT_PATTERN_BATMANADV="bN" +PORT_PATTERN_BATMAN_ADV="batN" +PORT_PATTERN_BATMAN_ADV_PORT="batpN" PORT_PATTERN_WIRELESS="wN" diff --git a/functions.device b/functions.device index 6de949e0..b15e15ec 100644 --- a/functions.device +++ b/functions.device @@ -146,6 +146,16 @@ function device_get_ifindex() { print "$(<${path})" } +# Check if the device is a batman-adv bridge +function device_is_batman_adv() { + [ -d "${SYS_CLASS_NET}/${1}/mesh" ] +} + +# Check if the device is a batman-adv bridge port +function device_is_batman_adv_port() { + [ -d "${SYS_CLASS_NET}/${1}/batman_adv" ] +} + # Check if the device is a bonding device function device_is_bonding() { [ -d "/sys/class/net/${1}/bonding" ] @@ -165,7 +175,6 @@ function device_is_bridge() { function device_is_bridge_attached() { local device=${1} - [ -d "${SYS_CLASS_NET}/${device}/brport" ] } @@ -297,6 +306,12 @@ function device_get_type() { elif device_is_ppp ${device}; then echo "ppp" + elif device_is_batman_adv ${device}; then + echo "batman-adv" + + elif device_is_batman_adv_port ${device}; then + echo "batman-adv-port" + elif device_is_loopback ${device}; then echo "loopback" diff --git a/hooks/ports/batman-adv b/hooks/ports/batman-adv index cdbf7335..a2cb151e 100755 --- a/hooks/ports/batman-adv +++ b/hooks/ports/batman-adv @@ -21,51 +21,26 @@ . /usr/lib/network/header-port -HOOK_SETTINGS="HOOK ADDRESS MESH_ID SSID CHANNEL COUNTRY_CODE PHY" +HOOK_SETTINGS="HOOK ADDRESS SLAVES" -ADDRESS=$(mac_generate) -CHANNEL=1 -COUNTRY_CODE="US" -MESH_ID= -SSID= +PORT_CHILDREN_VAR="SLAVES" -# batman-adv inserts an additional header of 28 bytes, so we set the MTU -# to 1528, that normal ethernet packets with 1500 bytes can pass the network. -MTU=1528 -MTU=1500 +ADDRESS=$(mac_generate) +SLAVES= function _check() { assert isset ADDRESS assert ismac ADDRESS - assert isset CHANNEL - assert isset COUNTRY_CODE - assert isset MESH_ID - assert ismac MESH_ID - assert isset PHY - assert ismac PHY - assert isset SSID } function _create() { while [ $# -gt 0 ]; do case "${1}" in --address=*) - ADDRESS=$(cli_get_val ${1}) - ;; - --channel=*) - CHANNEL=$(cli_get_val ${1}) - ;; - --country-code=*) - COUNTRY_CODE=$(cli_get_val ${1}) - ;; - --phy=*) - PHY=$(cli_get_val ${1}) + ADDRESS="$(cli_get_val ${1})" ;; - --ssid=*) - SSID=$(cli_get_val ${1}) - ;; - --mesh-id=*) - MESH_ID=$(cli_get_val ${1}) + --slaves=*) + SLAVES="$(cli_get_val ${1})" ;; *) warning "Ignoring unknown argument '${1}'" @@ -74,11 +49,7 @@ function _create() { shift done - # Save address of phy do identify it again - PHY=$(phy_get ${PHY}) - PHY=$(phy_get_address ${PHY}) - - local port=$(port_find_free ${PORT_PATTERN_BATMANADV}) + local port=$(port_find_free ${PORT_PATTERN_BATMAN_ADV}) assert isset port config_write $(port_file ${port}) ${HOOK_SETTINGS} @@ -95,17 +66,21 @@ function _edit() { while [ $# -gt 0 ]; do case "${1}" in - --channel=*) - CHANNEL=$(cli_get_val ${1}) - ;; - --country-code=*) - COUNTRY_CODE=$(cli_get_val ${1}) + --address=*) + ADDRESS="$(cli_get_val ${1})" ;; - --mesh-id=*) - MESH_ID=$(cli_get_val ${1}) + --add-slave=*) + SLAVES="${SLAVES} $(cli_get_val ${1})" ;; - --ssid=*) - SSID=$(cli_get_val ${1}) + --del-slave=*) + local slave="$(cli_get_val ${1})" + + local s slaves + for s in ${SLAVES}; do + [ "${slave}" = "${s}" ] && continue + slaves="${slaves} ${s}" + done + SLAVES="${slaves}" ;; *) warning "Unknown argument '${1}'" @@ -125,30 +100,22 @@ function _up() { config_read $(port_file ${port}) - # Check if the PHY is present. - local phy=$(phy_get ${PHY}) - if ! isset phy; then - log DEBUG "phy '${PHY}' is not present" - exit ${EXIT_ERROR} - fi - - # Create the wireless device, if it does not exist, yet. - if ! device_exists ${port}; then - wireless_create ${port} \ - --address="${ADDRESS}" \ - --phy="${phy}" \ - --type="ibss" - fi + # This cannot be started manually, but is created automatically + # when a slave device is brought up and set up by _hotplug. - # Set the MTU. - device_set_mtu "${port}" "${MTU}" + local slave + for slave in ${SLAVES}; do + port_up "${slave}" + done - # Join the ad-hoc network. - wireless_ibss_join "${port}" --channel="${CHANNEL}" \ - --bssid="${MESH_ID}" --essid="${SSID}" + # If the port has been created (does not happen, when there are + # no slaves), we bring it up. + if device_exists "${port}"; then + # Set the address. + device_set_address "${port}" "${ADDRESS}" - # Add the device as a batman-adv device. - batman_adv_interface_add "${port}" + device_set_up "${port}" + fi exit ${EXIT_OK} } @@ -157,16 +124,12 @@ function _down() { local port=${1} assert isset port - # Remove the batman-adv device. - batman_adv_interface_del "${port}" - - # Leave the ad-hoc network. - wireless_ibss_leave "${port}" + config_read $(port_file ${port}) - # Remove the device if it is still present. - if device_exists ${port}; then - wireless_remove ${port} - fi + local slave + for slave in ${SLAVES}; do + port_down "${slave}" + done exit ${EXIT_OK} } @@ -178,22 +141,77 @@ function _hotplug() { local phy=${2} assert isset phy - assert port_exists ${port} + # Bring up the device. + port_up "${port}" - # Read configuration of port. - config_read $(port_file ${port}) + exit ${EXIT_OK} +} + +function _status() { + local port=${1} + assert isset port + + cli_device_headline "${port}" --long + + cli_headline 2 "B.A.T.M.A.N." + + # Routing algorithm + cli_print_fmt1 2 "Routing Algorithm" \ + "$(batman_adv_get_routing_algorithm "${port}")" + + # Space + cli_space + + # Originator interval + cli_print_fmt1 2 "Originator Interval" \ + "$(batman_adv_get_originator_interval "${port}") ms" + + # Aggregated originator messages + batman_adv_get_aggregated_ogms "${port}" + cli_print_fmt1 2 "Aggregated Originator Messages" "$(cli_print_bool $?)" - # Get the address of the phy. - local phy_address=$(phy_get_address ${phy}) + # AP isolation + batman_adv_get_ap_isolation "${port}" + cli_print_fmt1 2 "Access Point Isolation" "$(cli_print_bool $?)" - # Check if the phy is the same we have - # read from the configuration file. - if [ "${PHY}" = "${phy_address}" ]; then - wireless_create ${port} \ - --address="${ADDRESS}" \ - --phy="${phy_address}" \ - --type="ibss" + # Bonding mode + batman_adv_get_bonding_mode "${port}" + cli_print_fmt1 2 "Bonding Mode" "$(cli_print_bool $?)" + + # Bridge loop avoidance + batman_adv_get_bridge_loop_avoidance "${port}" + cli_print_fmt1 2 "Bridge Loop Avoidance" "$(cli_print_bool $?)" + + # Distributed ARP table + batman_adv_get_distributed_arp_table "${port}" + cli_print_fmt1 2 "Distributed ARP Table" "$(cli_print_bool $?)" + + # Fragmentation + batman_adv_get_fragmentation "${port}" + cli_print_fmt1 2 "Fragmentation" "$(cli_print_bool $?)" + + # Hop penalty + cli_print_fmt1 2 "Hop Penalty" \ + "$(batman_adv_get_hop_penalty "${port}")" + cli_space + + # Gateway + cli_headline 3 "Gateway" + + # Gateway mode + batman_adv_get_gateway_mode "${port}" + local gw_enabled=$? + + cli_print_fmt1 3 "Enabled" "$(cli_print_bool ${gw_enabled})" + + if [ ${gw_enabled} -eq ${EXIT_TRUE} ]; then + cli_print_fmt1 3 "Bandwidth" \ + "$(batman_adv_get_gateway_bandwidth "${port}")" + cli_print_fmt1 3 "Selection Class" \ + "$(batman_adv_get_gateway_selection_class "${port}")" fi + cli_space + exit ${EXIT_OK} } diff --git a/hooks/ports/batman-adv-port b/hooks/ports/batman-adv-port new file mode 100755 index 00000000..0d44ba35 --- /dev/null +++ b/hooks/ports/batman-adv-port @@ -0,0 +1,221 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2013 Michael Tremer # +# # +# 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-port + +HOOK_SETTINGS="HOOK ADDRESS MESH_ID SSID CHANNEL COUNTRY_CODE PHY" + +ADDRESS=$(mac_generate) +CHANNEL=1 +COUNTRY_CODE="US" +MESH_ID= +SSID= + +# batman-adv inserts an additional header of 28 bytes, so we set the MTU +# to 1528, that normal ethernet packets with 1500 bytes can pass the network. +MTU=1528 + +function _check() { + assert isset ADDRESS + assert ismac ADDRESS + assert isset CHANNEL + assert isset COUNTRY_CODE + assert isset MESH_ID + assert ismac MESH_ID + assert isset PHY + assert ismac PHY + assert isset SSID +} + +function _create() { + while [ $# -gt 0 ]; do + case "${1}" in + --address=*) + ADDRESS=$(cli_get_val ${1}) + ;; + --channel=*) + CHANNEL=$(cli_get_val ${1}) + ;; + --country-code=*) + COUNTRY_CODE=$(cli_get_val ${1}) + ;; + --phy=*) + PHY=$(cli_get_val ${1}) + ;; + --ssid=*) + SSID=$(cli_get_val ${1}) + ;; + --mesh-id=*) + MESH_ID=$(cli_get_val ${1}) + ;; + *) + warning "Ignoring unknown argument '${1}'" + ;; + esac + shift + done + + # Save address of phy do identify it again + PHY=$(phy_get ${PHY}) + PHY=$(phy_get_address ${PHY}) + + local port=$(port_find_free ${PORT_PATTERN_BATMAN_ADV_PORT}) + assert isset port + + config_write $(port_file ${port}) ${HOOK_SETTINGS} + + exit ${EXIT_OK} +} + +function _edit() { + local port=${1} + assert isset port + shift + + config_read $(port_file ${port}) + + while [ $# -gt 0 ]; do + case "${1}" in + --channel=*) + CHANNEL=$(cli_get_val ${1}) + ;; + --country-code=*) + COUNTRY_CODE=$(cli_get_val ${1}) + ;; + --mesh-id=*) + MESH_ID=$(cli_get_val ${1}) + ;; + --ssid=*) + SSID=$(cli_get_val ${1}) + ;; + *) + warning "Unknown argument '${1}'" + ;; + esac + shift + done + + config_write $(port_file ${port}) ${HOOK_SETTINGS} + + exit ${EXIT_OK} +} + +function _up() { + local port=${1} + assert isset port + + config_read $(port_file ${port}) + + # Check if the PHY is present. + local phy=$(phy_get ${PHY}) + if ! isset phy; then + log DEBUG "phy '${PHY}' is not present" + exit ${EXIT_ERROR} + fi + + # Create the wireless device, if it does not exist, yet. + if ! device_exists ${port}; then + wireless_create ${port} \ + --address="${ADDRESS}" \ + --phy="${phy}" \ + --type="ibss" + fi + + # Set the MTU. + device_set_mtu "${port}" "${MTU}" + + # Join the ad-hoc network. + wireless_ibss_join "${port}" --channel="${CHANNEL}" \ + --bssid="${MESH_ID}" --essid="${SSID}" + + # Add the device as a batman-adv device. + local parent="$(_find_parent ${port})" + if isset parent; then + batman_adv_interface_add "${parent}" "${port}" + fi + + exit ${EXIT_OK} +} + +function _down() { + local port=${1} + assert isset port + + # Remove the batman-adv device. + batman_adv_interface_del "${port}" + + # Leave the ad-hoc network. + wireless_ibss_leave "${port}" + + # Remove the device if it is still present. + if device_exists ${port}; then + wireless_remove ${port} + fi + + exit ${EXIT_OK} +} + +function _hotplug() { + local port=${1} + assert isset port + + local phy=${2} + assert isset phy + + assert port_exists ${port} + + # Read configuration of port. + config_read $(port_file ${port}) + + # Get the address of the phy. + local phy_address=$(phy_get_address ${phy}) + + # Check if the phy is the same we have + # read from the configuration file. + if [ "${PHY}" = "${phy_address}" ]; then + # Bring up the device. + port_up "${port}" + fi + + exit ${EXIT_OK} +} + +function _find_parent() { + local port=${1} + assert isset port + + local p child hook + for p in $(ports_get); do + hook=$(port_get_hook "${p}") + + if [ "${hook}" = "batman-adv" ]; then + for child in $(port_get_children "${p}"); do + log ERROR "child=${child}" + [ "${child}" = "${port}" ] || continue + + print "${p}" + return ${EXIT_OK} + done + fi + done + + return ${EXIT_ERROR} +} diff --git a/hooks/zones/bridge.ports/batman-adv b/hooks/zones/bridge.ports/batman-adv new file mode 120000 index 00000000..3857774a --- /dev/null +++ b/hooks/zones/bridge.ports/batman-adv @@ -0,0 +1 @@ +ethernet \ No newline at end of file diff --git a/udev/network-hotplug b/udev/network-hotplug index 063d33fb..f469e6ce 100755 --- a/udev/network-hotplug +++ b/udev/network-hotplug @@ -55,8 +55,8 @@ case "${ACTION}" in port_create ethernet ${INTERFACE} ;; - # Handle wireless devices. - wireless) + # Handle batman-adv and wireless devices. + batman-adv|batman-adv-port|wireless) # Save the phy of this device for later. phy=$(phy_get ${INTERFACE}) assert isset phy