2b8d60cd1a70c4d5001b0b470c29845bcf68eb76
[project/luci.git] / applications / luci-app-olsr / luasrc / model / cbi / olsr / olsrd6.lua
1 --[[
2 LuCI - Lua Configuration Interface
3
4 Copyright 2008 Steven Barth <steven@midlink.org>
5 Copyright 2010 Jo-Philipp Wich <xm@subsignal.org>
6
7 Licensed under the Apache License, Version 2.0 (the "License");
8 you may not use this file except in compliance with the License.
9 You may obtain a copy of the License at
10
11         http://www.apache.org/licenses/LICENSE-2.0
12
13 $Id$
14 ]]--
15
16 require("luci.tools.webadmin")
17 local fs  = require "nixio.fs"
18 local util = require "luci.util"
19 local ip = require "luci.ip"
20
21 local has_ipip  = fs.glob("/etc/modules.d/[0-9]*-ipip")()
22
23 m = Map("olsrd6", translate("OLSR Daemon"),
24         translate("The OLSR daemon is an implementation of the Optimized Link State Routing protocol. "..
25         "As such it allows mesh routing for any network equipment. "..
26         "It runs on any wifi card that supports ad-hoc mode and of course on any ethernet device. "..
27         "Visit <a href='http://www.olsr.org'>olsrd.org</a> for help and documentation."))
28
29 function m.on_parse()
30         local has_defaults = false
31
32         m.uci:foreach("olsrd6", "InterfaceDefaults",
33                 function(s)
34                         has_defaults = true
35                         return false
36                 end)
37
38         if not has_defaults then
39                 m.uci:section("olsrd6", "InterfaceDefaults")
40         end
41 end
42
43 function write_float(self, section, value)
44     local n = tonumber(value)
45     if n ~= nil then
46         return Value.write(self, section, "%.1f" % n) 
47     end
48 end
49
50 s = m:section(TypedSection, "olsrd6", translate("General settings"))
51 s.anonymous = true
52
53 s:tab("general",  translate("General Settings"))
54 s:tab("lquality", translate("Link Quality Settings"))
55 s:tab("smartgw", translate("SmartGW"), not has_ipip and translate("Warning: kmod-ipip is not installed. Without kmod-ipip SmartGateway will not work, please install it."))
56 s:tab("advanced", translate("Advanced Settings"))
57
58 poll = s:taboption("advanced", Value, "Pollrate", translate("Pollrate"),
59         translate("Polling rate for OLSR sockets in seconds. Default is 0.05."))
60 poll.optional = true
61 poll.datatype = "ufloat"
62 poll.placeholder = "0.05"
63
64 nicc = s:taboption("advanced", Value, "NicChgsPollInt", translate("Nic changes poll interval"),
65         translate("Interval to poll network interfaces for configuration changes (in seconds). Default is \"2.5\"."))
66 nicc.optional = true
67 nicc.datatype = "ufloat"
68 nicc.placeholder = "2.5"
69
70 tos = s:taboption("advanced", Value, "TosValue", translate("TOS value"),
71         translate("Type of service value for the IP header of control traffic. Default is \"16\"."))
72 tos.optional = true
73 tos.datatype = "uinteger"
74 tos.placeholder = "16"
75
76 fib = s:taboption("general", ListValue, "FIBMetric", translate("FIB metric"),
77         translate ("FIBMetric controls the metric value of the host-routes OLSRd sets. "..
78         "\"flat\" means that the metric value is always 2. This is the preferred value "..
79         "because it helps the linux kernel routing to clean up older routes. "..
80         "\"correct\" uses the hopcount as the metric value. "..
81         "\"approx\" use the hopcount as the metric value too, but does only update the hopcount if the nexthop changes too. "..
82         "Default is \"flat\"."))
83 fib:value("flat")
84 fib:value("correct")
85 fib:value("approx")
86
87 lql = s:taboption("lquality", ListValue, "LinkQualityLevel", translate("LQ level"),
88         translate("Link quality level switch between hopcount and cost-based (mostly ETX) routing.<br />"..
89         "<b>0</b> = do not use link quality<br />"..
90         "<b>2</b> = use link quality for MPR selection and routing<br />"..
91         "Default is \"2\""))
92 lql:value("2")
93 lql:value("0")
94
95 lqage = s:taboption("lquality", Value, "LinkQualityAging", translate("LQ aging"),
96         translate("Link quality aging factor (only for lq level 2). Tuning parameter for etx_float and etx_fpm, smaller values "..
97         "mean slower changes of ETX value. (allowed values are between 0.01 and 1.0)"))
98 lqage.optional = true
99 lqage:depends("LinkQualityLevel", "2")
100
101 lqa = s:taboption("lquality", ListValue, "LinkQualityAlgorithm", translate("LQ algorithm"),
102         translate("Link quality algorithm (only for lq level 2).<br />"..
103         "<b>etx_float</b>: floating point ETX with exponential aging<br />"..
104         "<b>etx_fpm</b>  : same as etx_float, but with integer arithmetic<br />"..
105         "<b>etx_ff</b>   : ETX freifunk, an etx variant which use all OLSR traffic (instead of only hellos) for ETX calculation<br />"..
106         "<b>etx_ffeth</b>: incompatible variant of etx_ff that allows ethernet links with ETX 0.1.<br />"..
107         "Defaults to \"etx_ff\""))
108 lqa.optional = true
109 lqa:value("etx_ff")
110 lqa:value("etx_fpm")
111 lqa:value("etx_float")
112 lqa:value("etx_ffeth")
113 lqa:depends("LinkQualityLevel", "2")
114 lqa.optional = true
115
116 lqfish = s:taboption("lquality", Flag, "LinkQualityFishEye", translate("LQ fisheye"),
117         translate("Fisheye mechanism for TCs (checked means on). Default is \"on\""))
118 lqfish.default = "1"
119 lqfish.optional = true
120
121 hyst = s:taboption("lquality", Flag, "UseHysteresis", translate("Use hysteresis"),
122         translate("Hysteresis for link sensing (only for hopcount metric). Hysteresis adds more robustness to the link sensing "..
123         "but delays neighbor registration. Defaults is \"yes\""))
124 hyst.default = "yes"
125 hyst.enabled = "yes"
126 hyst.disabled = "no"
127 hyst:depends("LinkQualityLevel", "0")
128 hyst.optional = true
129 hyst.rmempty = true
130
131 port = s:taboption("general", Value, "OlsrPort", translate("Port"),
132         translate("The port OLSR uses. This should usually stay at the IANA assigned port 698. It can have a value between 1 and 65535."))
133 port.optional = true
134 port.default = "698"
135 port.rmempty = true
136
137 mainip = s:taboption("general", Value, "MainIp", translate("Main IP"),
138         translate("Sets the main IP (originator ip) of the router. This IP will NEVER change during the uptime of olsrd. "..
139         "Default is ::, which triggers usage of the IP of the first interface."))
140 mainip.optional = true
141 mainip.rmempty = true
142 mainip.datatype = "ipaddr"
143 mainip.placeholder = "::"
144
145 sgw = s:taboption("smartgw", Flag, "SmartGateway", translate("Enable"), translate("Enable SmartGateway. If it is disabled, then " ..
146         "all other SmartGateway parameters are ignored. Default is \"no\"."))
147 sgw.default="no"
148 sgw.enabled="yes"
149 sgw.disabled="no"
150 sgw.rmempty = true
151
152 sgwnat = s:taboption("smartgw", Flag, "SmartGatewayAllowNAT", translate("Allow gateways with NAT"), translate("Allow the selection of an outgoing ipv4 gateway with NAT"))
153 sgwnat:depends("SmartGateway", "yes")
154 sgwnat.default="yes"
155 sgwnat.enabled="yes"
156 sgwnat.disabled="no"
157 sgwnat.optional = true
158 sgwnat.rmempty = true
159
160 sgwuplink = s:taboption("smartgw", ListValue, "SmartGatewayUplink", translate("Announce uplink"), translate("Which kind of uplink is exported to the other mesh nodes. " ..
161         "An uplink is detected by looking for a local HNA6 ::ffff:0:0/96 or 2000::/3. Default setting is \"both\"."))
162 sgwuplink:value("none")
163 sgwuplink:value("ipv4")
164 sgwuplink:value("ipv6")
165 sgwuplink:value("both")
166 sgwuplink:depends("SmartGateway", "yes")
167 sgwuplink.default="both"
168 sgwuplink.optional = true
169 sgwuplink.rmempty = true
170
171 sgwulnat = s:taboption("smartgw", Flag, "SmartGatewayUplinkNAT", translate("Uplink uses NAT"), translate("If this Node uses NAT for connections to the internet. " ..
172         "Default is \"yes\"."))
173 sgwulnat:depends("SmartGatewayUplink", "ipv4")
174 sgwulnat:depends("SmartGatewayUplink", "both")
175 sgwulnat.default="yes"
176 sgwulnat.enabled="yes"
177 sgwulnat.disabled="no"
178 sgwnat.optional = true
179 sgwnat.rmempty = true
180
181 sgwspeed = s:taboption("smartgw", Value, "SmartGatewaySpeed", translate("Speed of the uplink"), translate("Specifies the speed of "..
182         "the uplink in kilobits/s. First parameter is upstream, second parameter is downstream. Default is \"128 1024\"."))
183 sgwspeed:depends("SmartGatewayUplink", "ipv4")
184 sgwspeed:depends("SmartGatewayUplink", "ipv6")
185 sgwspeed:depends("SmartGatewayUplink", "both")
186 sgwspeed.optional = true
187 sgwspeed.rmempty = true
188
189 sgwprefix = s:taboption("smartgw", Value, "SmartGatewayPrefix", translate("IPv6-Prefix of the uplink"), translate("This can be used " ..
190         "to signal the external IPv6 prefix of the uplink to the clients. This might allow a client to change it's local IPv6 address to " ..
191         "use the IPv6 gateway without any kind of address translation. The maximum prefix length is 64 bits. " ..
192         "Default is \"::/0\" (no prefix)."))
193 sgwprefix:depends("SmartGatewayUplink", "ipv6")
194 sgwprefix:depends("SmartGatewayUplink", "both")
195 sgwprefix.optional = true
196 sgwprefix.rmempty = true
197
198 willingness = s:taboption("advanced", ListValue, "Willingness", translate("Willingness"),
199                 translate("The fixed willingness to use. If not set willingness will be calculated dynamically based on battery/power status. Default is \"3\"."))
200 for i=0,7 do
201         willingness:value(i)
202 end
203 willingness.optional = true
204 willingness.default = "3"
205
206 natthr = s:taboption("advanced", Value, "NatThreshold", translate("NAT threshold"),
207         translate("If the route to the current gateway is to be changed, the ETX value of this gateway is "..
208         "multiplied with this value before it is compared to the new one. "..
209         "The parameter can be a value between 0.1 and 1.0, but should be close to 1.0 if changed.<br />"..
210         "<b>WARNING:</b> This parameter should not be used together with the etx_ffeth metric!<br />"..
211         "Defaults to \"1.0\"."))
212 for i=1,0.1,-0.1 do
213         natthr:value(i)
214 end
215 natthr:depends("LinkQualityAlgorithm", "etx_ff")
216 natthr:depends("LinkQualityAlgorithm", "etx_float")
217 natthr:depends("LinkQualityAlgorithm", "etx_fpm")
218 natthr.default = "1.0"
219 natthr.optional = true
220 natthr.write = write_float
221
222
223 i = m:section(TypedSection, "InterfaceDefaults", translate("Interfaces Defaults"))
224 i.anonymous = true
225 i.addremove = false
226
227 i:tab("general", translate("General Settings"))
228 i:tab("addrs",   translate("IP Addresses"))
229 i:tab("timing",  translate("Timing and Validity"))
230
231 mode = i:taboption("general", ListValue, "Mode", translate("Mode"),
232         translate("Interface Mode is used to prevent unnecessary packet forwarding on switched ethernet interfaces. "..
233         "valid Modes are \"mesh\" and \"ether\". Default is \"mesh\"."))
234 mode:value("mesh")
235 mode:value("ether")
236 mode.optional = true
237 mode.rmempty = true
238
239
240 weight = i:taboption("general", Value, "Weight", translate("Weight"),
241         translate("When multiple links exist between hosts the weight of interface is used to determine the link to use. "..
242         "Normally the weight is automatically calculated by olsrd based on the characteristics of the interface, "..
243         "but here you can specify a fixed value. Olsrd will choose links with the lowest value.<br />"..
244         "<b>Note:</b> Interface weight is used only when LinkQualityLevel is set to 0. "..
245         "For any other value of LinkQualityLevel, the interface ETX value is used instead."))
246 weight.optional = true
247 weight.datatype = "uinteger"
248 weight.placeholder = "0"
249
250 lqmult = i:taboption("general", DynamicList, "LinkQualityMult", translate("LinkQuality Multiplicator"),
251         translate("Multiply routes with the factor given here. Allowed values are between 0.01 and 1.0. "..
252         "It is only used when LQ-Level is greater than 0. Examples:<br />"..
253         "reduce LQ to fd91:662e:3c58::1 by half: fd91:662e:3c58::1 0.5<br />"..
254         "reduce LQ to all nodes on this interface by 20%: default 0.8"))
255 lqmult.optional = true
256 lqmult.rmempty = true
257 lqmult.cast = "table"
258 lqmult.placeholder = "default 1.0"
259
260 function lqmult.validate(self, value)
261         for _, v in pairs(value) do
262                 if v ~= "" then
263                         local val = util.split(v, " ")
264                         local host = val[1]
265                         local mult = val[2]
266                         if not host or not mult then
267                                 return nil, translate("LQMult requires two values (IP address or 'default' and multiplicator) seperated by space.")
268                         end
269                         if not (host == "default" or ip.IPv6(host)) then
270                                 return nil, translate("Can only be a valid IPv6 address or 'default'")
271                         end
272                         if not tonumber(mult) or tonumber(mult) > 1 or tonumber(mult) < 0.01 then
273                                 return nil, translate("Invalid Value for LQMult-Value. Must be between 0.01 and 1.0.")
274                         end
275                         if not mult:match("[0-1]%.[0-9]+") then
276                                 return nil, translate("Invalid Value for LQMult-Value. You must use a decimal number between 0.01 and 1.0 here.")
277                         end
278                 end
279         end
280         return value
281 end
282
283 ip6m = i:taboption("addrs", Value, "IPv6Multicast", translate("IPv6 multicast"),
284         translate("IPv6 multicast address. Default is \"FF02::6D\", the manet-router linklocal multicast."))
285 ip6m.optional = true
286 ip6m.datatype = "ip6addr"
287 ip6m.placeholder = "FF02::6D"
288
289 ip6s = i:taboption("addrs", Value, "IPv6Src", translate("IPv6 source"),
290         translate("IPv6 src prefix. OLSRd will choose one of the interface IPs which matches the prefix of this parameter. "..
291         "Default is \"0::/0\", which triggers the usage of a not-linklocal interface IP."))
292 ip6s.optional = true
293 ip6s.datatype = "ip6addr"
294 ip6s.placeholder = "0::/0"
295
296
297 hi = i:taboption("timing", Value, "HelloInterval", translate("Hello interval"))
298 hi.optional = true
299 hi.datatype = "ufloat"
300 hi.placeholder = "5.0"
301 hi.write = write_float
302
303 hv = i:taboption("timing", Value, "HelloValidityTime", translate("Hello validity time"))
304 hv.optional = true
305 hv.datatype = "ufloat"
306 hv.placeholder = "40.0"
307 hv.write = write_float
308
309 ti = i:taboption("timing", Value, "TcInterval", translate("TC interval"))
310 ti.optional = true
311 ti.datatype = "ufloat"
312 ti.placeholder = "2.0"
313 ti.write = write_float
314
315 tv = i:taboption("timing", Value, "TcValidityTime", translate("TC validity time"))
316 tv.optional = true
317 tv.datatype = "ufloat"
318 tv.placeholder = "256.0"
319 tv.write = write_float
320
321 mi = i:taboption("timing", Value, "MidInterval", translate("MID interval"))
322 mi.optional = true
323 mi.datatype = "ufloat"
324 mi.placeholder = "18.0"
325 mi.write = write_float
326
327 mv = i:taboption("timing", Value, "MidValidityTime", translate("MID validity time"))
328 mv.optional = true
329 mv.datatype = "ufloat"
330 mv.placeholder = "324.0"
331 mv.write = write_float
332
333 ai = i:taboption("timing", Value, "HnaInterval", translate("HNA interval"))
334 ai.optional = true
335 ai.datatype = "ufloat"
336 ai.placeholder = "18.0"
337 ai.write = write_float
338
339 av = i:taboption("timing", Value, "HnaValidityTime", translate("HNA validity time"))
340 av.optional = true
341 av.datatype = "ufloat"
342 av.placeholder = "108.0"
343 av.write = write_float
344
345
346 ifs = m:section(TypedSection, "Interface", translate("Interfaces"))
347 ifs.addremove = true
348 ifs.anonymous = true
349 ifs.extedit   = luci.dispatcher.build_url("admin/services/olsrd6/iface/%s")
350 ifs.template  = "cbi/tblsection"
351
352 function ifs.create(...)
353         local sid = TypedSection.create(...)
354         luci.http.redirect(ifs.extedit % sid)
355 end
356
357 ign = ifs:option(Flag, "ignore", translate("Enable"))
358 ign.enabled  = "0"
359 ign.disabled = "1"
360 ign.rmempty = false
361 function ign.cfgvalue(self, section)
362         return Flag.cfgvalue(self, section) or "0"
363 end
364
365 network = ifs:option(DummyValue, "interface", translate("Network"))
366 network.template = "cbi/network_netinfo"
367
368 mode = ifs:option(DummyValue, "Mode", translate("Mode"))
369 function mode.cfgvalue(...)
370         return Value.cfgvalue(...) or m.uci:get_first("olsrd6", "InterfaceDefaults", "Mode", "mesh")
371 end
372
373 hello = ifs:option(DummyValue, "_hello", translate("Hello"))
374 function hello.cfgvalue(self, section)
375         local i = tonumber(m.uci:get("olsrd6", section, "HelloInterval"))     or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "HelloInterval", 5))
376         local v = tonumber(m.uci:get("olsrd6", section, "HelloValidityTime")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "HelloValidityTime", 40))
377         return "%.01fs / %.01fs" %{ i, v }
378 end
379
380 tc = ifs:option(DummyValue, "_tc", translate("TC"))
381 function tc.cfgvalue(self, section)
382         local i = tonumber(m.uci:get("olsrd6", section, "TcInterval"))     or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "TcInterval", 2))
383         local v = tonumber(m.uci:get("olsrd6", section, "TcValidityTime")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "TcValidityTime", 256))
384         return "%.01fs / %.01fs" %{ i, v }
385 end
386
387 mid = ifs:option(DummyValue, "_mid", translate("MID"))
388 function mid.cfgvalue(self, section)
389         local i = tonumber(m.uci:get("olsrd6", section, "MidInterval"))     or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "MidInterval", 18))
390         local v = tonumber(m.uci:get("olsrd6", section, "MidValidityTime")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "MidValidityTime", 324))
391         return "%.01fs / %.01fs" %{ i, v }
392 end
393
394 hna = ifs:option(DummyValue, "_hna", translate("HNA"))
395 function hna.cfgvalue(self, section)
396         local i = tonumber(m.uci:get("olsrd6", section, "HnaInterval"))     or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "HnaInterval", 18))
397         local v = tonumber(m.uci:get("olsrd6", section, "HnaValidityTime")) or tonumber(m.uci:get_first("olsrd6", "InterfaceDefaults", "HnaValidityTime", 108))
398         return "%.01fs / %.01fs" %{ i, v }
399 end
400
401 return m