applications/luci-olsr: Save RAM while getting the default route, very good hint...
[project/luci.git] / applications / luci-olsr / luasrc / controller / olsr.lua
1 module("luci.controller.olsr", package.seeall)
2
3 function index()
4         if not nixio.fs.access("/etc/config/olsrd") then
5                 return
6         end
7
8         require("luci.i18n").loadc("olsr")
9         local i18n = luci.i18n.translate
10
11         local page  = node("admin", "status", "olsr")
12         page.target = template("status-olsr/overview")
13         page.title  = "OLSR"
14         page.i18n   = "olsr"
15         page.subindex = true
16
17         local page  = node("admin", "status", "olsr", "neighbors")
18         page.target = call("action_neigh")
19         page.title  = i18n("Neighbors")
20         page.subindex = true
21         page.order  = 5
22
23         local page  = node("admin", "status", "olsr", "routes")
24         page.target = call("action_routes")
25         page.title  = i18n("Routen")
26         page.order  = 10
27
28         local page  = node("admin", "status", "olsr", "topology")
29         page.target = call("action_topology")
30         page.title  = i18n("Topologie")
31         page.order  = 20
32
33         local page  = node("admin", "status", "olsr", "hna")
34         page.target = call("action_hna")
35         page.title  = "HNA"
36         page.order  = 30
37
38         local page  = node("admin", "status", "olsr", "mid")
39         page.target = call("action_mid")
40         page.title  = "MID"
41         page.order  = 50
42
43         local page  = node("admin", "status", "olsr", "smartgw")
44         page.target = call("action_smartgw")
45         page.title  = "SmartGW"
46         page.order  = 60
47
48         local page  = node("admin", "status", "olsr", "interfaces")
49         page.target = call("action_interfaces")
50         page.title  = i18n("Interfaces")
51         page.order  = 70
52
53         local ol = entry(
54                 {"admin", "services", "olsrd"},
55                 cbi("olsr/olsrd"), "OLSR"
56         )
57         ol.i18n = "olsr"
58         ol.subindex = true
59
60         entry(
61                 {"admin", "services", "olsrd", "iface"},
62                 cbi("olsr/olsrdiface")
63         ).leaf = true
64
65         entry(
66                 {"admin", "services", "olsrd", "hna"},
67                 cbi("olsr/olsrdhna"), "HNA Announcements"
68         )
69
70         oplg = entry(
71                 {"admin", "services", "olsrd", "plugins"},
72                 cbi("olsr/olsrdplugins"), "Plugins"
73         )
74         oplg.i18n = "olsr"
75         oplg.leaf = true
76         oplg.subindex = true
77
78         local uci = require("luci.model.uci").cursor()
79         uci:foreach("olsrd", "LoadPlugin",
80                 function (section)
81                         local lib = section.library
82                         entry(
83                                 {"admin", "services", "olsrd", "plugins", lib },
84                                 cbi("olsr/olsrdplugins"),
85                                 nil --'Plugin "%s"' % lib:gsub("^olsrd_",""):gsub("%.so.+$","")
86                         )
87                 end
88         )
89 end
90
91 function action_neigh()
92         local data = fetch_txtinfo("links")
93
94         if not data or not data.Links then
95                 luci.template.render("status-olsr/error_olsr")
96                 return nil
97         end
98
99         local function compare(a, b)
100                 local c = tonumber(a.Cost)
101                 local d = tonumber(b.Cost)
102
103                 if not c or c == 0 then
104                         return false
105                 end
106
107                 if not d or d == 0 then
108                         return true
109                 end
110
111                 return c < d
112         end
113
114         table.sort(data.Links, compare)
115
116         luci.template.render("status-olsr/neighbors", {links=data.Links})
117 end
118
119 function action_routes()
120         local data = fetch_txtinfo("routes")
121
122         if not data or not data.Routes then
123                 luci.template.render("status-olsr/error_olsr")
124                 return nil
125         end
126
127         local function compare(a, b)
128                 local c = tonumber(a.ETX)
129                 local d = tonumber(b.ETX)
130
131                 if not c or c == 0 then
132                         return false
133                 end
134
135                 if not d or d == 0 then
136                         return true
137                 end
138
139                 return c < d
140         end
141
142         table.sort(data.Routes, compare)
143
144         luci.template.render("status-olsr/routes", {routes=data.Routes})
145 end
146
147 function action_topology()
148         local data = fetch_txtinfo("topology")
149
150         if not data or not data.Topology then
151                 luci.template.render("status-olsr/error_olsr")
152                 return nil
153         end
154
155         local function compare(a, b)
156                 return a["Dest. IP"] < b["Dest. IP"]
157         end
158
159         table.sort(data.Topology, compare)
160
161         luci.template.render("status-olsr/topology", {routes=data.Topology})
162 end
163
164 function action_hna()
165         local data = fetch_txtinfo("hna")
166
167         if not data or not data.HNA then
168                 luci.template.render("status-olsr/error_olsr")
169                 return nil
170         end
171
172         local function compare(a, b)
173                 return a.Destination < b.Destination
174         end
175
176         table.sort(data.HNA, compare)
177
178         luci.template.render("status-olsr/hna", {routes=data.HNA})
179 end
180
181 function action_mid()
182         local data = fetch_txtinfo("mid")
183
184         if not data or not data.MID then
185                 luci.template.render("status-olsr/error_olsr")
186                 return nil
187         end
188
189         local function compare(a, b)
190                 return a["IP address"] < b["IP address"]
191         end
192
193         table.sort(data.MID, compare)
194
195         luci.template.render("status-olsr/mid", {mids=data.MID})
196 end
197
198 function action_smartgw()
199         local data = fetch_txtinfo("gateways")
200
201         if not data or not data.Gateways then
202                 luci.template.render("status-olsr/error_olsr")
203                 return nil
204         end
205
206         local function compare(a, b)
207                 return a["ETX"] < b["ETX"]
208         end
209
210         table.sort(data.Gateways, compare)
211
212         luci.template.render("status-olsr/smartgw", {gws=data.Gateways})
213 end
214
215 function action_interfaces()
216         local data = fetch_txtinfo("interfaces")
217
218         if not data or not data.Interfaces then
219                 luci.template.render("status-olsr/error_olsr")
220                 return nil
221         end
222
223         luci.template.render("status-olsr/interfaces", {iface=data.Interfaces})
224 end
225
226 -- Internal
227 function fetch_txtinfo(otable)
228         require("luci.sys")
229         local uci = require "luci.model.uci".cursor_state()
230         otable = otable or ""
231         local rawdata = luci.sys.httpget("http://127.0.0.1:2006/"..otable)
232         local rawdatav6 = luci.sys.httpget("http://[::1]:2006/"..otable)
233         local data = {}
234         local dataindex = 0
235         local name = ""
236         local defaultgw
237
238         if #rawdata ~= 0 then
239                 local tables = luci.util.split(luci.util.trim(rawdata), "\r?\n\r?\n", nil, true)
240
241                 if otable == "links" then
242                         local route = {}
243                         luci.sys.net.routes(function(r) if r.dest:prefix() == 0 then defaultgw = r.gateway:string() end end)
244                 end
245
246                 for i, tbl in ipairs(tables) do
247                         local lines = luci.util.split(tbl, "\r?\n", nil, true)
248                         name  = table.remove(lines, 1):sub(8)
249                         local keys  = luci.util.split(table.remove(lines, 1), "\t")
250                         local split = #keys - 1
251                         if not data[name] then
252                                 data[name] = {}
253                         end
254
255                         for j, line in ipairs(lines) do
256                                 dataindex = ( dataindex + 1 )
257                                 di = dataindex
258                                 local fields = luci.util.split(line, "\t", split)
259                                 data[name][di] = {}
260                                 for k, key in pairs(keys) do
261                                         if key == "Remote IP" or key == "Dest. IP" or key == "Gateway IP" or key == "Gateway" then
262                                                 data[name][di][key] = fields[k]
263                                                 hostname = nixio.getnameinfo(fields[k], "inet")
264                                                 if hostname then
265                                                         data[name][di]["Hostname"] = hostname
266                                                 end
267                                                 if key == "Remote IP" and defaultgw then
268                                                         if defaultgw == fields[k] then
269                                                                 data[name][di]["defaultgw"] = 1
270                                                         end
271                                                 end
272                                         elseif key == "Local IP" then
273                                                 data[name][di][key] = fields[k]
274                                                 data[name][di]['Local Device'] = fields[k]
275                                                 uci:foreach("network", "interface",
276                                                         function(s)
277                                                                 localip = string.gsub(fields[k], '      ', '')
278                                                                 if s.ipaddr == localip then
279                                                                         data[name][di]['Local Device'] = s['.name'] or interface
280                                                                 end
281                                                         end)
282                                         elseif key == "Interface" then
283                                                 data[name][di][key] = fields[k]
284                                                 uci:foreach("network", "interface",
285                                                 function(s)
286                                                         interface = string.gsub(fields[k], '    ', '')
287                                                         if s.ifname == interface then
288                                                                 data[name][di][key] = s['.name'] or interface
289                                                         end
290                                                 end)
291                                         else
292                                             data[name][di][key] = fields[k]
293                                 end
294                                 end
295                                 if data[name][di].Linkcost then
296                                         data[name][di].LinkQuality,
297                                         data[name][di].NLQ,
298                                         data[name][di].ETX =
299                                         data[name][di].Linkcost:match("([%w.]+)/([%w.]+)[%s]+([%w.]+)")
300                                 end
301                         end
302                 end
303         end
304
305         if #rawdatav6 ~= 0 then
306                 local tables = luci.util.split(luci.util.trim(rawdatav6), "\r?\n\r?\n", nil, true)
307                 for i, tbl in ipairs(tables) do
308                         local lines = luci.util.split(tbl, "\r?\n", nil, true)
309                         name  = table.remove(lines, 1):sub(8)
310                         local keys  = luci.util.split(table.remove(lines, 1), "\t")
311                         local split = #keys - 1
312                         if not data[name] then
313                                 data[name] = {}
314                         end
315                         for j, line in ipairs(lines) do
316                                 dataindex = ( dataindex + 1 )
317                                 di = dataindex
318                                 local fields = luci.util.split(line, "\t", split)
319                                 data[name][di] = {}
320                                 for k, key in pairs(keys) do
321                                         if key == "Remote IP" then
322                                                 data[name][di][key] = "[" .. fields[k] .. "]"
323                                                 hostname = nixio.getnameinfo(fields[k], "inet6")
324                                                 if hostname then
325                                                         data[name][di]["Hostname"] = hostname
326                                                 end
327                                         elseif key == "Local IP" then
328                                                 data[name][di][key] = fields[k]
329                                                 data[name][di]['Local Device'] = fields[k]
330                                                 uci:foreach("network", "interface",
331                                                 function(s)
332                                                         local localip = string.gsub(fields[k], '        ', '')
333                                                         if s.ip6addr then
334                                                                 local ip6addr = string.gsub(s.ip6addr, '\/.*', '')
335                                                                 if ip6addr == localip then
336                                                                         data[name][di]['Local Device'] = s['.name'] or s.interface
337                                                                 end
338                                                         end
339                                                 end)
340                                         elseif key == "Dest. IP" then
341                                                 data[name][di][key] = "[" .. fields[k] .. "]"
342                                         elseif key == "Last hop IP" then
343                                                 data[name][di][key] = "[" .. fields[k] .. "]"
344                                         elseif key == "IP address" then
345                                                 data[name][di][key] = "[" .. fields[k] .. "]"
346                                         elseif key == "Gateway" then
347                                                 data[name][di][key] = "[" .. fields[k] .. "]"
348                                         else
349                                                 data[name][di][key] = fields[k]
350                                         end
351                                 end
352
353                                 if data[name][di].Linkcost then
354                                         data[name][di].LinkQuality,
355                                         data[name][di].NLQ,
356                                         data[name][di].ETX =
357                                         data[name][di].Linkcost:match("([%w.]+)/([%w.]+)[%s]+([%w.]+)")
358                                 end
359                         end
360                 end
361         end
362
363
364         if data then
365             return data
366         end
367 end