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