* luci/app-olsr: first round of olsr improvements:
authorJo-Philipp Wich <jow@openwrt.org>
Sat, 13 Sep 2008 01:00:11 +0000 (01:00 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Sat, 13 Sep 2008 01:00:11 +0000 (01:00 +0000)
- implement new uci config format
- moved hna announcements and plugins to separate pages
- made all sections dynamic
- added all known plugin options as additional fields

applications/luci-olsr/luasrc/controller/olsr.lua
applications/luci-olsr/luasrc/model/cbi/olsr/olsrd.lua
applications/luci-olsr/luasrc/model/cbi/olsr/olsrdhna.lua [new file with mode: 0644]
applications/luci-olsr/luasrc/model/cbi/olsr/olsrdplugins.lua [new file with mode: 0644]

index 96226d8..f7a8ec1 100644 (file)
 module("luci.controller.olsr", package.seeall)
 
 function index()
-       if not luci.fs.isfile("/etc/config/olsr") then
+       if not luci.fs.isfile("/etc/config/olsrd") then
                return
        end
-       
+
        require("luci.i18n").loadc("olsr")
        local i18n = luci.i18n.translate
-       
+
        local page  = node("admin", "status", "olsr")
        page.target = call("action_index")
        page.title  = "OLSR"
        page.i18n   = "olsr"
-       
+
        local page  = node("admin", "status", "olsr", "routes")
        page.target = call("action_routes")
        page.title  = i18n("olsr_routes", "Routen")
        page.order  = 10
-       
+
        local page  = node("admin", "status", "olsr", "topology")
        page.target = call("action_topology")
        page.title  = i18n("olsr_topology", "Topologie")
        page.order  = 20
-       
+
        local page  = node("admin", "status", "olsr", "hna")
        page.target = call("action_hna")
        page.title  = "HNA"
        page.order  = 30
-       
+
        local page  = node("admin", "status", "olsr", "mid")
        page.target = call("action_mid")
        page.title  = "MID"
        page.order  = 50
 
-       entry({"admin", "services", "olsrd"}, cbi("olsr/olsrd"), "OLSR").i18n = "olsr"
+       entry(
+               {"admin", "services", "olsrd"},
+               cbi("olsr/olsrd"), "OLSR"
+       ).i18n = "olsr"
+
+       entry(
+               {"admin", "services", "olsrd", "hna"},
+               cbi("olsr/olsrdhna"), "HNA Announcements"
+       ).i18n = "olsr"
+
+       entry(
+               {"admin", "services", "olsrd", "plugins"},
+               cbi("olsr/olsrdplugins"), "Plugins"
+       ).i18n = "olsr"
 end
 
 function action_index()
        local data = fetch_txtinfo("links")
-       
+
        if not data or not data.Links then
                luci.template.render("status-olsr/error_olsr")
                return nil
        end
-       
+
        local function compare(a, b)
                local c = tonumber(a.ETX)
                local d = tonumber(b.ETX)
-               
+
                if not c or c == 0 then
                        return false
                end
-               
+
                if not d or d == 0 then
                        return true
                end
-               
+
                return c < d
        end
-       
+
        table.sort(data.Links, compare)
-       
+
        luci.template.render("status-olsr/index", {links=data.Links})
 end
 
 function action_routes()
        local data = fetch_txtinfo("routes")
-       
+
        if not data or not data.Routes then
                luci.template.render("status-olsr/error_olsr")
                return nil
        end
-       
+
        local function compare(a, b)
                local c = tonumber(a.ETX)
                local d = tonumber(b.ETX)
-               
+
                if not c or c == 0 then
                        return false
                end
-               
+
                if not d or d == 0 then
                        return true
                end
-               
+
                return c < d
        end
-       
+
        table.sort(data.Routes, compare)
-       
+
        luci.template.render("status-olsr/routes", {routes=data.Routes})
 end
 
 function action_topology()
        local data = fetch_txtinfo("topology")
-       
+
        if not data or not data.Topology then
                luci.template.render("status-olsr/error_olsr")
                return nil
        end
-       
+
        local function compare(a, b)
                return a["Destination IP"] < b["Destination IP"]
        end
-       
+
        table.sort(data.Topology, compare)
-       
+
        luci.template.render("status-olsr/topology", {routes=data.Topology})
 end
 
 function action_hna()
        local data = fetch_txtinfo("hna")
-       
+
        if not data or not data.HNA then
                luci.template.render("status-olsr/error_olsr")
                return nil
        end
-       
+
        local function compare(a, b)
                return a.Network < b.Network
        end
-       
+
        table.sort(data.HNA, compare)
-       
+
        luci.template.render("status-olsr/hna", {routes=data.HNA})
 end
 
 function action_mid()
        local data = fetch_txtinfo("mid")
-       
+
        if not data or not data.MID then
                luci.template.render("status-olsr/error_olsr")
                return nil
        end
-       
+
        local function compare(a, b)
                return a.IP < b.IP
        end
-       
+
        table.sort(data.MID, compare)
-       
+
        luci.template.render("status-olsr/mid", {mids=data.MID})
 end
 
@@ -149,39 +162,39 @@ function fetch_txtinfo(otable)
        require("luci.sys")
        otable = otable or ""
        local rawdata = luci.sys.httpget("http://127.0.0.1:2006/"..otable)
-       
+
        if #rawdata == 0 then
                return nil
        end
-       
+
        local data = {}
-       
+
        local tables = luci.util.split(luci.util.trim(rawdata), "\r?\n\r?\n", nil, true)
-       
+
 
        for i, tbl in ipairs(tables) do
                local lines = luci.util.split(tbl, "\r?\n", nil, true)
                local name  = table.remove(lines, 1):sub(8)
                local keys  = luci.util.split(table.remove(lines, 1), "\t")
                local split = #keys - 1
-               
+
                data[name] = {}
-               
+
                for j, line in ipairs(lines) do
                        local fields = luci.util.split(line, "\t", split)
                        data[name][j] = {}
                        for k, key in pairs(keys) do
-                               data[name][j][key] = fields[k] 
+                               data[name][j][key] = fields[k]
                        end
-                       
+
                        if data[name][j].Linkcost then
                                data[name][j].LinkQuality,
                                data[name][j].NLQ,
                                data[name][j].ETX =
-                                data[name][j].Linkcost:match("([%w.]+)/([%w.]+)[%s]+([%w.]+)")
+                               data[name][j].Linkcost:match("([%w.]+)/([%w.]+)[%s]+([%w.]+)")
                        end
                end
        end
-       
+
        return data
 end
index 80fe53c..7e134cc 100644 (file)
@@ -14,14 +14,17 @@ $Id$
 require("luci.tools.webadmin")
 require("luci.fs")
 
-m = Map("olsr", "OLSR")
+m = Map("olsrd", "OLSR")
 
-s = m:section(NamedSection, "general", "olsr")
+s = m:section(TypedSection, "olsrd", translate("olsr_general"))
+s.dynamic = true
+s.anonymous = true
 
 debug = s:option(ListValue, "DebugLevel")
 for i=0, 9 do
        debug:value(i)
 end
+debug.optional = true
 
 ipv = s:option(ListValue, "IpVersion")
 ipv:value("4", "IPv4")
@@ -30,20 +33,23 @@ ipv:value("6", "IPv6")
 noint = s:option(Flag, "AllowNoInt")
 noint.enabled = "yes"
 noint.disabled = "no"
+noint.optional = true
 
-s:option(Value, "Pollrate")
+s:option(Value, "Pollrate").optional = true
 
 tcr = s:option(ListValue, "TcRedundancy")
 tcr:value("0", translate("olsr_general_tcredundancy_0"))
 tcr:value("1", translate("olsr_general_tcredundancy_1"))
 tcr:value("2", translate("olsr_general_tcredundancy_2"))
+tcr.optional = true
 
-s:option(Value, "MprCoverage")
+s:option(Value, "MprCoverage").optional = true
 
 lql = s:option(ListValue, "LinkQualityLevel")
 lql:value("0", translate("disable"))
 lql:value("1", translate("olsr_general_linkqualitylevel_1"))
 lql:value("2", translate("olsr_general_linkqualitylevel_2"))
+lql.optional = true
 
 s:option(Value, "LinkQualityAging").optional = true
 
@@ -52,31 +58,37 @@ lqa.optional = true
 lqa:value("etx_fpm", translate("olsr_etx_fpm"))
 lqa:value("etx_float", translate("olsr_etx_float"))
 lqa:value("etx_ff", translate("olsr_etx_ff"))
+lqa.optional = true
 
 lqfish = s:option(Flag, "LinkQualityFishEye")
+lqfish.optional = true
 
-s:option(Value, "LinkQualityWinSize")
+s:option(Value, "LinkQualityWinSize").optional = true
 
-s:option(Value, "LinkQualityDijkstraLimit")
+s:option(Value, "LinkQualityDijkstraLimit").optional = true
 
 hyst = s:option(Flag, "UseHysteresis")
 hyst.enabled = "yes"
 hyst.disabled = "no"
+hyst.optional = true
 
 fib = s:option(ListValue, "FIBMetric")
 fib.optional = true
 fib:value("flat")
 fib:value("correct")
 fib:value("approx")
+fib.optional = true
 
 clrscr = s:option(Flag, "ClearScreen")
 clrscr.enabled = "yes"
 clrscr.disabled = "no"
+clrscr.optional = true
 
 willingness = s:option(ListValue, "Willingness")
 for i=0,7 do
        willingness:value(i)
 end
+willingness.optional = true
 
 
 
@@ -85,42 +97,27 @@ i.anonymous = true
 i.addremove = true
 i.dynamic = true
 
-network = i:option(ListValue, "Interface", translate("network"))
-luci.tools.webadmin.cbi_add_networks(network)
-
-i:option(Value, "Ip4Broadcast")
-i:option(Value, "HelloInterval")
-i:option(Value, "HelloValidityTime")
-i:option(Value, "TcInterval")
-i:option(Value, "TcValidityTime")
-i:option(Value, "MidInterval")
-i:option(Value, "MidValidityTime")
-i:option(Value, "HnaInterval")
-i:option(Value, "HnaValidityTime")
-
-
-p = m:section(TypedSection, "LoadPlugin")
-p.addremove = true
-p.dynamic = true
-
-lib = p:option(ListValue, "Library", translate("library"))
-lib:value("")
-for k, v in pairs(luci.fs.dir("/usr/lib")) do
-       if v:sub(1, 6) == "olsrd_" then
-               lib:value(v)
-       end
-end
-
+ign = i:option(Flag, "ignore")
+ign.enabled  = "1"
+ign.disabled = "0"
 
-for i, sect in ipairs({ "Hna4", "Hna6" }) do
-       hna = m:section(TypedSection, sect)
-       hna.addremove = true
-       hna.anonymous = true
-       hna.template  = "cbi/tblsection"
+network = i:option(ListValue, "interface", translate("network"))
+luci.tools.webadmin.cbi_add_networks(network)
 
-       net = hna:option(Value, "NetAddr")
-       msk = hna:option(Value, "Prefix")
-end
+i:option(Value, "Ip4Broadcast").optional = true
+i:option(Value, "HelloInterval").optional = true
+i:option(Value, "HelloValidityTime").optional = true
+i:option(Value, "TcInterval").optional = true
+i:option(Value, "TcValidityTime").optional = true
+i:option(Value, "MidInterval").optional = true
+i:option(Value, "MidValidityTime").optional = true
+i:option(Value, "HnaInterval").optional = true
+i:option(Value, "HnaValidityTime").optional = true
+
+adc = i:option(Flag, "AutoDetectChanges")
+adc.enabled  = "yes"
+adc.disabled = "no"
+adc.optional = true
 
 
 ipc = m:section(NamedSection, "IpcConnect")
diff --git a/applications/luci-olsr/luasrc/model/cbi/olsr/olsrdhna.lua b/applications/luci-olsr/luasrc/model/cbi/olsr/olsrdhna.lua
new file mode 100644 (file)
index 0000000..b784ea1
--- /dev/null
@@ -0,0 +1,27 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2008 Steven Barth <steven@midlink.org>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+mh = Map("olsrd", "OLSR - HNA Announcements")
+
+for i, sect in ipairs({ "Hna4", "Hna6" }) do
+       hna = mh:section(TypedSection, sect)
+       hna.addremove = true
+       hna.anonymous = true
+       hna.template  = "cbi/tblsection"
+
+       net = hna:option(Value, "NetAddr")
+       msk = hna:option(Value, "Prefix")
+end
+
+return mh
diff --git a/applications/luci-olsr/luasrc/model/cbi/olsr/olsrdplugins.lua b/applications/luci-olsr/luasrc/model/cbi/olsr/olsrdplugins.lua
new file mode 100644 (file)
index 0000000..83ed74a
--- /dev/null
@@ -0,0 +1,174 @@
+--[[
+LuCI - Lua Configuration Interface
+
+Copyright 2008 Steven Barth <steven@midlink.org>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+$Id$
+]]--
+
+require("luci.fs")
+require("luci.ip")
+
+mp = Map("olsrd", "OLSR - Plugins")
+
+p = mp:section(TypedSection, "LoadPlugin")
+p.addremove = true
+p.dynamic = true
+p.anonymous = true
+
+ign = p:option(Flag, "ignore")
+ign.enabled  = "1"
+ign.disabled = "0"
+
+lib = p:option(ListValue, "library", translate("library"))
+lib:value("")
+for k, v in pairs(luci.fs.dir("/usr/lib")) do
+       if v:sub(1, 6) == "olsrd_" then
+               lib:value(v)
+       end
+end
+
+local function Range(x,y)
+       local t = {}
+       for i = x, y do t[#t+1] = i end
+       return t
+end
+
+local function Cidr2IpMask(val)
+       local cidr = luci.ip.IPv4(val) or luci.ip.IPv6(val)
+       if not cidr then return val else return cidr end
+end
+
+local function IpMask2Cidr(val)
+       local ip, mask = val:gmatch("([^%s+])%s+([^%s+])")
+       local cidr
+       if ip and mask and ip:match(":") then
+               cidr = luci.ip.IPv6(ip, mask)
+       elseif ip and mask then
+               cidr = luci.ip.IPv4(ip, mask)
+       end
+       if not cidr then return val else return cidr end
+end
+
+
+local knownPlParams = {
+       ["olsrd_bmf.so.1.5.3"] = {
+               { Value,                "BmfInterface",                 "bmf0" },
+               { Value,                "BmfInterfaceIp",               "10.10.10.234/24" },
+               { Flag,                 "DoLocalBroadcast",             "no" },
+               { Flag,                 "CapturePacketsOnOlsrInterfaces", "yes" },
+               { ListValue,    "BmfMechanism",                 { "UnicastPromiscuous", "Broadcast" } },
+               { Value,                "BroadcastRetransmitCount",     "2" },
+               { Value,                "FanOutLimit",                  "4" },
+               { DynamicList,  "NonOlsrIf",                    "eth1" },
+       },
+
+       ["olsrd_dyn_gw.so.0.4"] = {
+               { Value,                "Interval",                             "40" },
+               { DynamicList,  "Ping",                                 "141.1.1.1" },
+               { DynamicList,  "HNA",                                  "192.168.80.0/24", Cidr2IpMask, IpMask2Cidr }
+       },
+
+       ["olsrd_httpinfo.so.0.1"] = {
+               { Value,                "port",                                 "80" },
+               { DynamicList,  "Host",                                 "163.24.87.3" },
+               { DynamicList,  "Net",                                  "0.0.0.0/0", Cidr2IpMask, IpMask2Cidr },
+       },
+
+       ["olsrd_nameservice.so.0.2"] = {
+               { DynamicList,  "name",                                 "my-name.mesh" },
+               { DynamicList,  "hosts",                                "1.2.3.4 name-for-other-interface.mesh" },
+               { Value,                "suffix",                               ".olsr" },
+               { Value,                "hosts_file",                   "/path/to/hosts_file" },
+               { Value,                "add_hosts",                    "/path/to/file" },
+               { Value,                "dns_server",                   "141.1.1.1" },
+               { Value,                "resolv_file",                  "/path/to/resolv.conf" },
+               { Value,                "interval",                             "120" },
+               { Value,                "timeout",                              "240" },
+               { Value,                "lat",                                  "12.123" },
+               { Value,                "lon",                                  "12.123" },
+               { Value,                "latlon_file",                  "/var/run/latlon.js" },
+               { Value,                "latlon_infile",                "/var/run/gps.txt" },
+               { Value,                "sighup_pid_file",              "/var/run/dnsmasq.pid" },
+               { Value,                "name_change_script",   "/usr/local/bin/announce_new_hosts.sh" },
+               { Value,                "services_change_script",       "/usr/local/bin/announce_new_services.sh" }
+       },
+
+       ["olsrd_quagga.so.0.2.2"] = {
+               { StaticList,   "redistribute",                 {
+                       "system", "kernel", "connect", "static", "rip", "ripng", "ospf",
+                       "ospf6", "isis", "bgp", "hsls"
+               } },
+               { ListValue,    "ExportRoutes",                 { "only", "both" } },
+               { Flag,                 "LocalPref",                    "true" },
+               { Value,                "Distance",                             Range(0,255) }
+       },
+
+       ["olsrd_secure.so.0.5"] = {
+               { Value,                "Keyfile",                              "/etc/private-olsr.key" }
+       },
+
+       ["olsrd_txtinfo.so.0.1"] = {
+               { Value,                "accept",                               "10.247.200.4" }
+       }
+}
+
+
+-- build plugin options with dependencies
+for plugin, options in pairs(knownPlParams) do
+       for _, option in ipairs(options) do
+               local otype, name, default, uci2cbi, cbi2uci = unpack(option)
+               local values
+
+               if type(default) == "table" then
+                       values  = default
+                       default = default[1]
+               end
+
+               if otype == Flag then
+                       local bool = p:option( Flag, name )
+                       if default == "yes" or default == "no" then
+                               bool.enabled  = "yes"
+                               bool.disabled = "no"
+                       elseif default == "on" or default == "off" then
+                               bool.enabled  = "on"
+                               bool.disabled = "off"
+                       elseif default == "1" or default == "0" then
+                               bool.enabled  = "1"
+                               bool.disabled = "0"
+                       else
+                               bool.enabled  = "true"
+                               bool.disabled = "false"
+                       end
+                       bool.default = default
+                       bool:depends({ library = plugin })
+               else
+                       local field = p:option( otype, name )
+                       if values then
+                               for _, value in ipairs(values) do
+                                       field:value( value )
+                               end
+                       end
+                       if type(uci2cbi) == "function" then
+                               function field.cfgvalue(self, section)
+                                       return uci2cbi(otype.cfgvalue(self, section))
+                               end
+                       end
+                       if type(cbi2uci) == "function" then
+                               function field.formvalue(self, section)
+                                       return cbi2uci(otype.formvalue(self, section))
+                               end
+                       end
+                       field.default = default
+                       field:depends({ library = plugin })
+               end
+       end
+end
+
+return mp