aredn: add auto distance setting option

contributing author lua code: dman776 <dman776@gmail.com>
This commit is contained in:
Joe Ayers 2019-04-01 20:48:41 -07:00 committed by Joe AE6XE
parent 71325a91d2
commit f134465edb
10 changed files with 261 additions and 23 deletions

View File

@ -105,3 +105,5 @@ CONFIG_PACKAGE_kmod-ipip=y
CONFIG_IMAGEOPT=y CONFIG_IMAGEOPT=y
CONFIG_VERSIONOPT=y CONFIG_VERSIONOPT=y
CONFIG_VERSION_DIST="AREDN" CONFIG_VERSION_DIST="AREDN"
CONFIG_PACKAGE_ATH_DYNACK=y
CONFIG_PACKAGE_ATH_DEBUG=y

View File

@ -2,7 +2,7 @@
--[[ --[[
Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks
Copyright (C) 2016 Darryl Quinn Copyright (C) 2019 Darryl Quinn
See Contributors file for additional contributors See Contributors file for additional contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@ -41,7 +41,7 @@ local api = {}
function api.getUciConfType(conf,type) function api.getUciConfType(conf,type)
local curs=uci.cursor() local curs=uci.cursor()
local ifce={} local ifce={}
curs:foreach(conf,type,function(s) ifce[s[".index"]]=s end) curs:foreach(conf,type,function(s) table.insert(ifce,s) end)
return ifce return ifce
end end

View File

@ -2,7 +2,7 @@
--[[ --[[
Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks
Copyright (C) 2016 Darryl Quinn Copyright (C) 2019 Darryl Quinn
See Contributors file for additional contributors See Contributors file for additional contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@ -38,6 +38,7 @@
local nxo = require("nixio") local nxo = require("nixio")
local ipc = require("luci.ip") local ipc = require("luci.ip")
local posix = require("posix.unistd") local posix = require("posix.unistd")
local auci = require("aredn.uci")
require("uci") require("uci")
function round2(num, idp) function round2(num, idp)
@ -108,6 +109,47 @@ function get_ip_type(ip)
return R.STRING return R.STRING
end end
-------------------------------------
-- Returns name of the radio (radio0 or radio1) for the selected wifi interface (wifi or lan)
-------------------------------------
function get_radio(ifn)
local interfaces=auci.getUciConfType("wireless", "wifi-iface")
for n, i in ipairs(interfaces) do
if i.network==ifn then
return i.device
end
end
end
-------------------------------------
-- Returns PHY name of the radio (phy0 or phy1) for the selected wifi interface (wifi or lan)
-------------------------------------
function get_radiophy(ifn)
local rname=get_radio(ifn)
return string.format("phy%d",string.sub(rname,-1))
end
-------------------------------------
-- Reset the auto-distance calculation for the radio
-------------------------------------
function reset_auto_distance()
local rc=0
local radio = get_radio("wifi") -- get radio number from /etc/config/wireless and convert to -> phy0 or phy1
local u=uci.cursor()
local distance=u:get("wireless",radio,"distance")
print("DISTANCE=" .. distance)
if distance=="0" then
local phyname = get_radiophy("wifi") -- get radio number from /etc/config/wireless and convert to -> phy0 or phy1
print("iw phy " .. phyname .. " set distance 60000")
print("iw phy " .. phyname .. " set distance auto")
os.execute("iw phy " .. phyname .. " set distance 60000")
rc=os.execute("iw phy " .. phyname .. " set distance auto")
else
rc=-1
end
return rc
end
function get_ifname(ifn) function get_ifname(ifn)
local u=uci.cursor() local u=uci.cursor()
iface=u:get("network",ifn,"ifname") iface=u:get("network",ifn,"ifname")

View File

@ -36,11 +36,6 @@ foreach $line (`cat /etc/config.mesh/_setup`)
$cfg{$1} = $2; $cfg{$1} = $2;
} }
# if distance is 0, set to 60km to ensure a tower node can be communicated with
# The 3.19.3.0 release does not have auto distance, but previous nightly builds did
# remove this statement when auto distance is put back in
$cfg{wifi_distance} = 60000 if $cfg{wifi_distance} eq '0';
foreach $line (`cat /etc/config.mesh/_setup.default`) foreach $line (`cat /etc/config.mesh/_setup.default`)
{ {
next if $line =~ /^\s*#/; next if $line =~ /^\s*#/;

View File

@ -2,7 +2,7 @@
--[[ --[[
Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks
Copyright (C) 2016 Darryl Quinn Copyright (C) 2019 Darryl Quinn
See Contributors file for additional contributors See Contributors file for additional contributors
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
@ -54,6 +54,7 @@ local AGETIME=43200
local INACTIVETIMEOUT=10000 local INACTIVETIMEOUT=10000
local tmpdir="/tmp/snrlog" local tmpdir="/tmp/snrlog"
local lastdat="/tmp/snr.dat" local lastdat="/tmp/snr.dat"
local autolog="/tmp/AutoDistReset.log"
local lasttime={} local lasttime={}
local lines={} local lines={}
local arpcache={} local arpcache={}
@ -91,6 +92,18 @@ function Neighbor.create(macaddress)
n.rx_mcs=n:findRxMcs() n.rx_mcs=n:findRxMcs()
n.rx_rate=n:findRxRate() n.rx_rate=n:findRxRate()
n.lastseen=n:findLastTime() n.lastseen=n:findLastTime()
-- check if auto-distance reset is required (new node)
local efn=n:getExistingDataFileName()
if efn==nil or ((now-n.lastseen) > 100) then -- NEW or not recently seen node
reset_auto_distance()
f, err=assert(io.open(autolog, "a"),"Cannot open file (autolog) to write!")
if (f) then
f:write(now .. "\n")
f:close()
end
file_trim(autolog,MAXLINES)
end
n.datafile=n:generateDataFileName() n.datafile=n:generateDataFileName()
return n return n
end end

View File

@ -189,12 +189,19 @@ $parms{wifi_txpower} = $wifi_txpower;
if(($parms{button_apply} or $parms{button_save}) and $wifi_enable ) if(($parms{button_apply} or $parms{button_save}) and $wifi_enable )
{ {
if($wifi_distance < 1 or $wifi_distance =~ /\D/) if($wifi_distance < 0 or $wifi_distance =~ /\D/)
{ {
push (@errors, "invalid distance value"); push (@errors, "invalid distance value");
} else { } else {
$cmd = ""; $cmd = "";
$cmd .= "iw phy ${phy} set distance $wifi_distance >/dev/null 2>&1;"; if ( $wifi_distance eq "0" )
{
$cmd .= "iw phy ${phy} set distance auto >/dev/null 2>&1;";
}
else
{
$cmd .= "iw phy ${phy} set distance $wifi_distance >/dev/null 2>&1;";
}
$cmd .= "iw dev $wifiintf set txpower fixed ${wifi_txpower}00 >/dev/null 2>&1;"; $cmd .= "iw dev $wifiintf set txpower fixed ${wifi_txpower}00 >/dev/null 2>&1;";
system $cmd; system $cmd;
} }
@ -555,12 +562,8 @@ function updDist(x) {
document.getElementsByName('wifi_distance_disp_meters')[0].value = xc; document.getElementsByName('wifi_distance_disp_meters')[0].value = xc;
dist_meters.value = xc; dist_meters.value = xc;
// if default, then ALERT! // default of 0 means 'auto', so full range is always dist-norm
if(dist_meters.value==0) { distBox.className = 'dist-norm';
distBox.className = 'dist-alert';
} else {
distBox.className = 'dist-norm';
}
} }
@ -757,15 +760,15 @@ if ( ${wifi_enable} )
for($i = wifi_maxpower($wifi_channel); $i >= 1; --$i) { selopt($i+$txpoweroffset ." dBm", $i, $wifi_txpower) } for($i = wifi_maxpower($wifi_channel); $i >= 1; --$i) { selopt($i+$txpoweroffset ." dBm", $i, $wifi_txpower) }
print "</select>&nbsp;&nbsp;<a href=\"/help.html\#power\" target=\"_blank\"><img src=\"/qmark.png\"></a></td></tr>\n"; print "</select>&nbsp;&nbsp;<a href=\"/help.html\#power\" target=\"_blank\"><img src=\"/qmark.png\"></a></td></tr>\n";
print "<tr id='dist' class='dist-norm'><td>Distance to<br />FARTHEST Neighbor</td>\n"; print "<tr id='dist' class='dist-norm'><td>Distance to<br/>FARTHEST Neighbor<br/><h3>'0' is auto</h3></td>\n";
$wifi_distance=int($wifi_distance); # in meters $wifi_distance=int($wifi_distance); # in meters
$wifi_distance_disp_km=int($wifi_distance/1000); $wifi_distance_disp_km=int($wifi_distance/1000);
$wifi_distance_disp_miles=sprintf("%.2f",$wifi_distance_disp_km*.621371192); $wifi_distance_disp_miles=sprintf("%.2f",$wifi_distance_disp_km*.621371192);
print "<td><input disabled size=6 type=text name='wifi_distance_disp_miles' value='$wifi_distance_disp_miles' title='Distance to the farthest neighbor'>&nbsp;miles<br />"; print "<td><input disabled size=6 type=text name='wifi_distance_disp_miles' value='$wifi_distance_disp_miles' title='Distance to the farthest neighbor'>&nbsp;mi<br />";
print "<input disabled size=6 type=text size=4 name='wifi_distance_disp_km' value='$wifi_distance_disp_km' title='Distance to the farthest neighbor'>&nbsp;kilometers<br />"; print "<input disabled size=6 type=text size=4 name='wifi_distance_disp_km' value='$wifi_distance_disp_km' title='Distance to the farthest neighbor'>&nbsp;km<br />";
print "<input disabled size=6 type=text size=4 name='wifi_distance_disp_meters' value='$wifi_distance' title='Distance to the farthest neighbor'>&nbsp;meters<br />"; print "<input disabled size=6 type=text size=4 name='wifi_distance_disp_meters' value='$wifi_distance' title='Distance to the farthest neighbor'>&nbsp;m<br />";
print "<input id='distance_slider' type='range' min='0' max='150' step='1' value='$wifi_distance_disp_km' oninput='updDist(this.value)' onchange='updDist(this.value)' /><br />"; print "<input id='distance_slider' type='range' min='0' max='150' step='1' value='$wifi_distance_disp_km' oninput='updDist(this.value)' onchange='updDist(this.value)' /><br />";
print "<input type='hidden' size='6' name='wifi_distance' value='$wifi_distance' />"; print "<input type='hidden' size='6' name='wifi_distance' value='$wifi_distance' />";

View File

@ -54,6 +54,9 @@ $phy=get_wlan2phy("${wifiif}");
"/tmp/rssi.log", "/tmp/rssi.log",
"/tmp/zombie.log", "/tmp/zombie.log",
"/tmp/olsrd.log", "/tmp/olsrd.log",
"/tmp/AutoDistReset.log",
"/sys/kernel/debug/ieee80211/phy0/ath9k/ack_to",
"/sys/kernel/debug/ieee80211/phy1/ath9k/ack_to"
); );
@sensitive = ( "/etc/config/vtun", @sensitive = ( "/etc/config/vtun",

View File

@ -371,17 +371,40 @@ The <strong>Distance</strong> setting adjusts the RF retry timer
to define how long the transmitter will wait for an acknowledgement to define how long the transmitter will wait for an acknowledgement
from a Neighbor station. If the distance parameter is too short, then from a Neighbor station. If the distance parameter is too short, then
the transmitter will send duplicate data packets before the acknowledgement the transmitter will send duplicate data packets before the acknowledgement
has had time to return. This value is only applicable to nodes that can has had time to return. If the distance parameter is too long, then the
transmitter will wait extra time before considering the data lost to re-transmit.
This value is only applicable to nodes that can
be communicated with directly over RF and not multiple hop nodes on the be communicated with directly over RF and not multiple hop nodes on the
greater mesh network. The value should be set to the distance in meters greater mesh network. The value should be set to the distance in meters
to the farthest direct RF node you expect to communicate with. Change to the farthest direct RF node you expect to communicate with. Change
the distance value by moving the slider. Distance values will be in multiples the distance value by moving the slider. Distance values will be in multiples
of 1000 meters (approximately 0.62 miles). A value of zero is not allowed. of 1000 meters (approximately 0.62 miles). A value of '0' will cause
the radio to auto determine the RF retry timer based on measuring the
actual time it takes acknowledgement packets to be received back. The
automatic timer is tracked using a Exponential Weighted Moving Average (EWMA) method.
'auto' is the default setting and in most all situations the optimal setting.
The best way to test an optimal distance settings is to do an 'iperf' The best way to test an optimal distance settings is to do an 'iperf'
test directly between 2 nodes to measure the performance of this RF test directly between 2 nodes to measure the performance of this RF
channel. Try different distance settings to peak out the iperf throughput. channel. Try different distance settings to peak out the iperf throughput.
</p> </p>
<p> <p>
The maximum distance settings the ath9k wireless driver allows is dependent on
the Channel Width:
<br>
<li>20MHz: 46666 meters<br></li>
<li>10MHz: 103030 meters<br></li>
<li>5MHz: 215757 meters<br></li>
</p>
<p>
The auto distance setting is best used on quality point to point links.
50% performance increases have been observed over static. Auto distance
settings does not work well with many nodes and marginal links. In this
senario, the round trip packet timing has a very wide range of time values.
Consequently the timeout value becomes inflated and inconsistent. Static settings
should be used in this situation. It is best to measure the link with iperf to
compare thoughput and determine the best distance setting.
</p>
<p>
The <strong>LAN</strong> box allows you to set the LAN IP Address The <strong>LAN</strong> box allows you to set the LAN IP Address
of the node and the address range of the DHCP server, and these should be of the node and the address range of the DHCP server, and these should be
self explanatory. The <b>LAN Mode</b> is described in the next section. self explanatory. The <b>LAN Mode</b> is described in the next section.

View File

@ -0,0 +1,156 @@
Index: openwrt/package/kernel/mac80211/patches/569-ath9k-dynack-set-max-timeout.patch
===================================================================
--- /dev/null
+++ openwrt/package/kernel/mac80211/patches/569-ath9k-dynack-set-max-timeout.patch
@@ -0,0 +1,36 @@
+--- a/drivers/net/wireless/ath/ath9k/dynack.c
++++ b/drivers/net/wireless/ath/ath9k/dynack.c
+@@ -103,9 +103,10 @@
+ struct ath_dynack *da = &ah->dynack;
+ struct ath_node *an;
+ int to = 0;
++ u32 max_to = ath_dynack_get_max_to(ah);
+
+ list_for_each_entry(an, &da->nodes, list)
+- if (an->ackto > to)
++ if (an->ackto > to && an->ackto < max_to)
+ to = an->ackto;
+
+ if (to && da->ackto != to) {
+@@ -308,8 +309,8 @@
+ */
+ void ath_dynack_node_init(struct ath_hw *ah, struct ath_node *an)
+ {
+- /* ackto = slottime + sifs + air delay */
+- u32 ackto = 9 + 16 + 64;
++ /* AREDN set ackto to max_to initialize */
++ u32 ackto = ath_dynack_get_max_to(ah);
+ struct ath_dynack *da = &ah->dynack;
+
+ an->ackto = ackto;
+@@ -343,8 +344,8 @@
+ */
+ void ath_dynack_reset(struct ath_hw *ah)
+ {
+- /* ackto = slottime + sifs + air delay */
+- u32 ackto = 9 + 16 + 64;
++ /* AREDN set ackto to max_to initialize */
++ u32 ackto = ath_dynack_get_max_to(ah);
+ struct ath_dynack *da = &ah->dynack;
+
+ da->lto = jiffies;
Index: openwrt/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
===================================================================
--- openwrt.orig/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
+++ openwrt/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
@@ -788,7 +788,11 @@ drv_mac80211_setup() {
iw phy "$phy" set antenna $txantenna $rxantenna >/dev/null 2>&1
iw phy "$phy" set antenna_gain $antenna_gain
- iw phy "$phy" set distance "$distance"
+ if [ $distance -eq 0 -a -d /sys/kernel/debug/ieee80211/$phy/ath9k ]; then
+ iw phy "$phy" set distance auto
+ else
+ iw phy "$phy" set distance "$distance"
+ fi
[ -n "$frag" ] && iw phy "$phy" set frag "${frag%%.*}"
[ -n "$rts" ] && iw phy "$phy" set rts "${rts%%.*}"
Index: openwrt/package/kernel/mac80211/patches/568-ath-dynack-set-max-timeout-according-to-clockrate.patch
===================================================================
--- /dev/null
+++ openwrt/package/kernel/mac80211/patches/568-ath-dynack-set-max-timeout-according-to-clockrate.patch
@@ -0,0 +1,93 @@
+From 72f4ba6f6b6021fcc48d07d03407c2fdb16a46c5 Mon Sep 17 00:00:00 2001
+Message-Id: <72f4ba6f6b6021fcc48d07d03407c2fdb16a46c5.1554035972.git.lorenzo@kernel.org>
+In-Reply-To: <cover.1554035972.git.lorenzo@kernel.org>
+References: <cover.1554035972.git.lorenzo@kernel.org>
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Sun, 31 Mar 2019 14:38:49 +0200
+Subject: [PATCH] ath: dynack: set max timeout according to clockrate
+
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+---
+ drivers/net/wireless/ath/ath9k/dynack.c | 36 ++++++++++++++++++-------
+ 1 file changed, 26 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath9k/dynack.c b/drivers/net/wireless/ath/ath9k/dynack.c
+index f112fa5b2eac..0627111249dd 100644
+--- a/drivers/net/wireless/ath/ath9k/dynack.c
++++ b/drivers/net/wireless/ath/ath9k/dynack.c
+@@ -20,11 +20,24 @@
+
+ #define COMPUTE_TO (5 * HZ)
+ #define LATEACK_DELAY (10 * HZ)
+-#define LATEACK_TO 256
+-#define MAX_DELAY 300
+ #define EWMA_LEVEL 96
+ #define EWMA_DIV 128
+
++/**
++ * ath_dynack_get_max_to - set max timeout according to clockrate
++ * @ah: ath hw
++ *
++ */
++static u32 ath_dynack_get_max_to(struct ath_hw *ah)
++{
++ struct ath_common *common = ath9k_hw_common(ah);
++
++ if (common->clockrate)
++ return AR_TIME_OUT_ACK / common->clockrate;
++
++ return 300;
++}
++
+ /**
+ * ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation
+ *
+@@ -116,15 +129,16 @@ static void ath_dynack_compute_ackto(struct ath_hw *ah)
+ */
+ static void ath_dynack_compute_to(struct ath_hw *ah)
+ {
+- u32 ackto, ack_ts;
+- u8 *dst, *src;
++ struct ath_dynack *da = &ah->dynack;
++ u32 ackto, ack_ts, max_to;
+ struct ieee80211_sta *sta;
+- struct ath_node *an;
+ struct ts_info *st_ts;
+- struct ath_dynack *da = &ah->dynack;
++ struct ath_node *an;
++ u8 *dst, *src;
+
+ rcu_read_lock();
+
++ max_to = ath_dynack_get_max_to(ah);
+ while (da->st_rbf.h_rb != da->st_rbf.t_rb &&
+ da->ack_rbf.h_rb != da->ack_rbf.t_rb) {
+ ack_ts = da->ack_rbf.tstamp[da->ack_rbf.h_rb];
+@@ -140,7 +154,7 @@ static void ath_dynack_compute_to(struct ath_hw *ah)
+ if (ack_ts > st_ts->tstamp + st_ts->dur) {
+ ackto = ack_ts - st_ts->tstamp - st_ts->dur;
+
+- if (ackto < MAX_DELAY) {
++ if (ackto < max_to) {
+ sta = ieee80211_find_sta_by_ifaddr(ah->hw, dst,
+ src);
+ if (sta) {
+@@ -197,11 +211,13 @@ void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb,
+ if (ieee80211_is_assoc_req(hdr->frame_control) ||
+ ieee80211_is_assoc_resp(hdr->frame_control) ||
+ ieee80211_is_auth(hdr->frame_control)) {
++ u32 max_to = ath_dynack_get_max_to(ah);
++
+ ath_dbg(common, DYNACK, "late ack\n");
+
+- ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2);
+- ath9k_hw_set_ack_timeout(ah, LATEACK_TO);
+- ath9k_hw_set_cts_timeout(ah, LATEACK_TO);
++ ath9k_hw_setslottime(ah, (max_to - 3) / 2);
++ ath9k_hw_set_ack_timeout(ah, max_to);
++ ath9k_hw_set_cts_timeout(ah, max_to);
+ if (sta) {
+ struct ath_node *an;
+
+--
+2.20.1

View File

@ -23,4 +23,5 @@
709-iperf-fw-restart.patch 709-iperf-fw-restart.patch
710-no-ping6-traceroute6.patch 710-no-ping6-traceroute6.patch
711-nano-xw-switch-config.patch 711-nano-xw-switch-config.patch
712-auto-distance-settings.patch
713-delay-snmpd-startup.patch 713-delay-snmpd-startup.patch