applications/olsr: Make sure ipv6 addresses from are in the same format when we compa...
[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         local page  = node("admin", "status", "olsr")
9         page.target = template("status-olsr/overview")
10         page.title  = _("OLSR")
11         page.subindex = true
12
13         local page  = node("admin", "status", "olsr", "neighbors")
14         page.target = call("action_neigh")
15         page.title  = _("Neighbours")
16         page.subindex = true
17         page.order  = 5
18
19         local page  = node("admin", "status", "olsr", "routes")
20         page.target = call("action_routes")
21         page.title  = _("Routes")
22         page.order  = 10
23
24         local page  = node("admin", "status", "olsr", "topology")
25         page.target = call("action_topology")
26         page.title  = _("Topology")
27         page.order  = 20
28
29         local page  = node("admin", "status", "olsr", "hna")
30         page.target = call("action_hna")
31         page.title  = _("HNA")
32         page.order  = 30
33
34         local page  = node("admin", "status", "olsr", "mid")
35         page.target = call("action_mid")
36         page.title  = _("MID")
37         page.order  = 50
38
39         local page  = node("admin", "status", "olsr", "smartgw")
40         page.target = call("action_smartgw")
41         page.title  = _("SmartGW")
42         page.order  = 60
43
44         local page  = node("admin", "status", "olsr", "interfaces")
45         page.target = call("action_interfaces")
46         page.title  = _("Interfaces")
47         page.order  = 70
48
49         local ol = entry(
50                 {"admin", "services", "olsrd"},
51                 cbi("olsr/olsrd"), "OLSR"
52         )
53         ol.subindex = true
54
55         entry(
56                 {"admin", "services", "olsrd", "iface"},
57                 cbi("olsr/olsrdiface")
58         ).leaf = true
59
60         entry(
61                 {"admin", "services", "olsrd", "hna"},
62                 cbi("olsr/olsrdhna"), _("HNA Announcements")
63         )
64
65         oplg = entry(
66                 {"admin", "services", "olsrd", "plugins"},
67                 cbi("olsr/olsrdplugins"), _("Plugins")
68         )
69
70         odsp = entry(
71                 {"admin", "services", "olsrd", "display"},
72                 cbi("olsr/olsrddisplay"), _("Display")
73                 )
74
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 local function compare_links(a, b)
92         local c = tonumber(a.Cost)
93         local d = tonumber(b.Cost)
94
95         if not c or c == 0 then
96                 return false
97         end
98
99         if not d or d == 0 then
100                 return true
101         end
102         return c < d
103 end
104
105 function action_neigh(json)
106         local data = fetch_txtinfo("links")
107
108         if not data or not data.Links then
109                 luci.template.render("status-olsr/error_olsr")
110                 return nil
111         end
112
113         table.sort(data.Links, compare_links)
114
115         luci.template.render("status-olsr/neighbors", {links=data.Links})
116 end
117
118 function action_routes()
119         local data = fetch_txtinfo("routes")
120
121         if not data or not data.Routes then
122                 luci.template.render("status-olsr/error_olsr")
123                 return nil
124         end
125
126         local function compare(a, b)
127                 local c = tonumber(a.ETX)
128                 local d = tonumber(b.ETX)
129
130                 if not c or c == 0 then
131                         return false
132                 end
133
134                 if not d or d == 0 then
135                         return true
136                 end
137
138                 return c < d
139         end
140
141         table.sort(data.Routes, compare)
142
143         luci.template.render("status-olsr/routes", {routes=data.Routes})
144 end
145
146 function action_topology()
147         local data = fetch_txtinfo("topology")
148
149         if not data or not data.Topology then
150                 luci.template.render("status-olsr/error_olsr")
151                 return nil
152         end
153
154         local function compare(a, b)
155                 return a["Dest. IP"] < b["Dest. IP"]
156         end
157
158         table.sort(data.Topology, compare)
159
160         luci.template.render("status-olsr/topology", {routes=data.Topology})
161 end
162
163 function action_hna()
164         local data = fetch_txtinfo("hna")
165
166         if not data or not data.HNA then
167                 luci.template.render("status-olsr/error_olsr")
168                 return nil
169         end
170
171         local function compare(a, b)
172                 return a.Destination < b.Destination
173         end
174
175         table.sort(data.HNA, compare)
176
177         luci.template.render("status-olsr/hna", {routes=data.HNA})
178 end
179
180 function action_mid()
181         local data = fetch_txtinfo("mid")
182
183         if not data or not data.MID then
184                 luci.template.render("status-olsr/error_olsr")
185                 return nil
186         end
187
188         local function compare(a, b)
189                 return a["IP address"] < b["IP address"]
190         end
191
192         table.sort(data.MID, compare)
193
194         luci.template.render("status-olsr/mid", {mids=data.MID})
195 end
196
197 function action_smartgw()
198         local data = fetch_txtinfo("gateways")
199
200         if not data or not data.Gateways then
201                 luci.template.render("status-olsr/error_olsr")
202                 return nil
203         end
204
205         local function compare(a, b)
206                 return a["ETX"] < b["ETX"]
207         end
208
209         table.sort(data.Gateways, compare)
210
211         luci.template.render("status-olsr/smartgw", {gws=data.Gateways})
212 end
213
214 function action_interfaces()
215         local data = fetch_txtinfo("interfaces")
216
217         if not data or not data.Interfaces then
218                 luci.template.render("status-olsr/error_olsr")
219                 return nil
220         end
221
222         luci.template.render("status-olsr/interfaces", {iface=data.Interfaces})
223 end
224
225 -- Internal
226 function fetch_txtinfo(otable)
227         require("luci.sys")
228         local uci = require "luci.model.uci".cursor_state()
229         local resolve = uci:get("luci_olsr", "general", "resolve")
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                                                 if resolve == "1" then
264                                                         hostname = nixio.getnameinfo(fields[k], "inet")
265                                                         if hostname then
266                                                                 data[name][di]["Hostname"] = hostname
267                                                         end
268                                                 end
269                                                 if key == "Remote IP" and defaultgw then
270                                                         if defaultgw == fields[k] then
271                                                                 data[name][di]["defaultgw"] = 1
272                                                         end
273                                                 end
274                                         elseif key == "Local IP" then
275                                                 data[name][di][key] = fields[k]
276                                                 data[name][di]['Local Device'] = fields[k]
277                                                 uci:foreach("network", "interface",
278                                                         function(s)
279                                                                 localip = string.gsub(fields[k], '      ', '')
280                                                                 if s.ipaddr == localip then
281                                                                         data[name][di]['Local Device'] = s['.name'] or interface
282                                                                 end
283                                                         end)
284                                         elseif key == "Interface" then
285                                                 data[name][di][key] = fields[k]
286                                                 uci:foreach("network", "interface",
287                                                 function(s)
288                                                         interface = string.gsub(fields[k], '    ', '')
289                                                         if s.ifname == interface then
290                                                                 data[name][di][key] = s['.name'] or interface
291                                                         end
292                                                 end)
293                                         else
294                                             data[name][di][key] = fields[k]
295                                 end
296                                 end
297                                 if data[name][di].Linkcost then
298                                         data[name][di].LinkQuality,
299                                         data[name][di].NLQ,
300                                         data[name][di].ETX =
301                                         data[name][di].Linkcost:match("([%w.]+)/([%w.]+)[%s]+([%w.]+)")
302                                 end
303                         end
304                 end
305         end
306
307         if #rawdatav6 ~= 0 then
308                 local tables = luci.util.split(luci.util.trim(rawdatav6), "\r?\n\r?\n", nil, true)
309                 for i, tbl in ipairs(tables) do
310                         local lines = luci.util.split(tbl, "\r?\n", nil, true)
311                         name  = table.remove(lines, 1):sub(8)
312                         local keys  = luci.util.split(table.remove(lines, 1), "\t")
313                         local split = #keys - 1
314                         if not data[name] then
315                                 data[name] = {}
316                         end
317                         for j, line in ipairs(lines) do
318                                 dataindex = ( dataindex + 1 )
319                                 di = dataindex
320                                 local fields = luci.util.split(line, "\t", split)
321                                 data[name][di] = {}
322                                 for k, key in pairs(keys) do
323                                         if key == "Remote IP" then
324                                                 data[name][di][key] = "[" .. fields[k] .. "]"
325                                                 if resolve == "1" then
326                                                         hostname = nixio.getnameinfo(fields[k], "inet6")
327                                                         if hostname then
328                                                                 data[name][di]["Hostname"] = hostname
329                                                         end
330                                                 end
331                                         elseif key == "Local IP" then
332                                                 data[name][di][key] = fields[k]
333                                                 data[name][di]['Local Device'] = fields[k]
334                                                 uci:foreach("network", "interface",
335                                                 function(s)
336                                                         local localip = string.gsub(fields[k], '        ', ''):upper()
337                                                         localip = luci.ip.IPv6(localip):string()
338                                                         if s.ip6addr then
339                                                                 s.ip6addr = luci.ip.IPv6(s.ip6addr):string()
340                                                                 local ip6addr = string.gsub(s.ip6addr, '\/.*', ''):upper()
341                                                                 if ip6addr == localip then
342                                                                         data[name][di]['Local Device'] = s['.name'] or s.interface
343                                                                 end
344                                                         end
345                                                 end)
346                                         elseif key == "Dest. IP" then
347                                                 data[name][di][key] = "[" .. fields[k] .. "]"
348                                         elseif key == "Last hop IP" then
349                                                 data[name][di][key] = "[" .. fields[k] .. "]"
350                                         elseif key == "IP address" then
351                                                 data[name][di][key] = "[" .. fields[k] .. "]"
352                                         elseif key == "Gateway" then
353                                                 data[name][di][key] = "[" .. fields[k] .. "]"
354                                         else
355                                                 data[name][di][key] = fields[k]
356                                         end
357                                 end
358
359                                 if data[name][di].Linkcost then
360                                         data[name][di].LinkQuality,
361                                         data[name][di].NLQ,
362                                         data[name][di].ETX =
363                                         data[name][di].Linkcost:match("([%w.]+)/([%w.]+)[%s]+([%w.]+)")
364                                 end
365                         end
366                 end
367         end
368
369
370         if data then
371             return data
372         end
373 end