53649dde5579f1ec053dab993d32c25a8be72d0e
[project/luci.git] / libs / core / luasrc / model / network.lua
1 --[[
2 LuCI - Network model
3
4 Copyright 2009 Jo-Philipp Wich <xm@subsignal.org>
5
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17
18 ]]--
19
20 local type, pairs, ipairs, loadfile, table, i18n
21 = type, pairs, ipairs, loadfile, table, luci.i18n
22
23 local lmo = require "lmo"
24 local nxo = require "nixio"
25 local nfs = require "nixio.fs"
26 local iwi = require "iwinfo"
27 local ipc = require "luci.ip"
28 local utl = require "luci.util"
29 local uct = require "luci.model.uci.bind"
30
31 module "luci.model.network"
32
33 -- load extensions
34 local ext
35 local handler = { }
36
37 for ext in nfs.glob(utl.libpath() .. "/model/network/*.lua") do
38 if nfs.access(ext) then
39 local m = loadfile(ext)
40 if m then
41 handler[#handler+1] = m()
42 end
43 end
44 end
45
46 function foreach_handler(code, ...)
47 local h
48 for _, h in ipairs(handler) do
49 if code(h, ...) then
50 return true
51 end
52 end
53 return false
54 end
55
56 local ub = uct.bind("network")
57 local ifs, brs, sws
58
59 function init(cursor)
60 if cursor then
61 cursor:unload("network")
62 cursor:load("network")
63 ub:init(cursor)
64
65 ifs = { }
66 brs = { }
67 sws = { }
68
69 -- init handler
70 foreach_handler(function(h)
71 h:init(cursor)
72 h:find_interfaces(ifs, brs)
73 end)
74
75 -- read interface information
76 local n, i
77 for n, i in ipairs(nxo.getifaddrs()) do
78 local name = i.name:match("[^:]+")
79 local prnt = name:match("^([^%.]+)%.")
80
81 if not _M:ignore_interface(name) then
82 ifs[name] = ifs[name] or {
83 idx = i.ifindex or n,
84 name = name,
85 rawname = i.name,
86 flags = { },
87 ipaddrs = { },
88 ip6addrs = { }
89 }
90
91 if prnt then
92 sws[name] = true
93 sws[prnt] = true
94 end
95
96 if i.family == "packet" then
97 ifs[name].flags = i.flags
98 ifs[name].stats = i.data
99 ifs[name].macaddr = i.addr
100 elseif i.family == "inet" then
101 ifs[name].ipaddrs[#ifs[name].ipaddrs+1] = ipc.IPv4(i.addr, i.netmask)
102 elseif i.family == "inet6" then
103 ifs[name].ip6addrs[#ifs[name].ip6addrs+1] = ipc.IPv6(i.addr, i.netmask)
104 end
105 end
106 end
107
108 -- read bridge informaton
109 local b, l
110 for l in utl.execi("brctl show") do
111 if not l:match("STP") then
112 local r = utl.split(l, "%s+", nil, true)
113 if #r == 4 then
114 b = {
115 name = r[1],
116 id = r[2],
117 stp = r[3] == "yes",
118 ifnames = { ifs[r[4]] }
119 }
120 if b.ifnames[1] then
121 b.ifnames[1].bridge = b
122 end
123 brs[r[1]] = b
124 elseif b then
125 b.ifnames[#b.ifnames+1] = ifs[r[2]]
126 b.ifnames[#b.ifnames].bridge = b
127 end
128 end
129 end
130 end
131 end
132
133 function has_ipv6(self)
134 return nfs.access("/proc/net/ipv6_route")
135 end
136
137 function add_network(self, n, options)
138 if n and #n > 0 and n:match("^[a-zA-Z0-9_]+$") and not self:get_network(n) then
139 if ub.uci:section("network", "interface", n, options) then
140 return network(n)
141 end
142 end
143 end
144
145 function get_network(self, n)
146 if n and ub.uci:get("network", n) == "interface" then
147 return network(n)
148 end
149 end
150
151 function get_networks(self)
152 local nets = { }
153 ub.uci:foreach("network", "interface",
154 function(s)
155 nets[#nets+1] = network(s['.name'])
156 end)
157 return nets
158 end
159
160 function del_network(self, n)
161 local r = ub.uci:delete("network", n)
162 if r then
163 ub.uci:foreach("network", "alias",
164 function(s)
165 if s.interface == n then
166 ub.uci:delete("network", s['.name'])
167 end
168 end)
169 ub.uci:foreach("network", "route",
170 function(s)
171 if s.interface == n then
172 ub.uci:delete("network", s['.name'])
173 end
174 end)
175 ub.uci:foreach("network", "route6",
176 function(s)
177 if s.interface == n then
178 ub.uci:delete("network", s['.name'])
179 end
180 end)
181
182 foreach_handler(function(h) h:del_network(n) end)
183 end
184 return r
185 end
186
187 function rename_network(self, old, new)
188 local r
189 if new and #new > 0 and new:match("^[a-zA-Z0-9_]+$") and not self:get_network(new) then
190 r = ub.uci:section("network", "interface", new,
191 ub.uci:get_all("network", old))
192
193 if r then
194 ub.uci:foreach("network", "alias",
195 function(s)
196 if s.interface == old then
197 ub.uci:set("network", s['.name'], "interface", new)
198 end
199 end)
200 ub.uci:foreach("network", "route",
201 function(s)
202 if s.interface == old then
203 ub.uci:set("network", s['.name'], "interface", new)
204 end
205 end)
206 ub.uci:foreach("network", "route6",
207 function(s)
208 if s.interface == old then
209 ub.uci:set("network", s['.name'], "interface", new)
210 end
211 end)
212
213 foreach_handler(function(h) h:rename_network(old, new) end)
214 end
215 end
216 return r or false
217 end
218
219 function get_interface(self, i)
220 if ifs[i] then
221 return interface(i)
222 else
223 local j
224 for j, _ in pairs(ifs) do
225 if ifs[j].sid == i then
226 return interface(j)
227 end
228 end
229 end
230 end
231
232 function get_interfaces(self)
233 local ifaces = { }
234 local iface
235 for iface, _ in pairs(ifs) do
236 ifaces[#ifaces+1] = interface(iface)
237 end
238 return ifaces
239 end
240
241 function ignore_interface(self, x)
242 if foreach_handler(function(h) return h:ignore_interface(x) end) then
243 return true
244 else
245 return (x:match("^wmaster%d") or x:match("^wifi%d")
246 or x:match("^hwsim%d") or x:match("^imq%d") or x == "lo")
247 end
248 end
249
250
251 network = ub:section("interface")
252 network:property("device")
253 network:property("ifname")
254 network:property("proto")
255 network:property("type")
256
257 function network.name(self)
258 return self.sid
259 end
260
261 function network.is_bridge(self)
262 return (self:type() == "bridge")
263 end
264
265 function network.add_interface(self, ifname)
266 local ifaces, iface
267
268 if type(ifname) ~= "string" then
269 ifaces = { ifname:name() }
270 else
271 ifaces = ub:list(ifname)
272 end
273
274 for _, iface in ipairs(ifaces) do
275 if ifs[iface] then
276 -- make sure the interface is removed from all networks
277 local i = interface(iface)
278 local n = i:get_network()
279 if n then n:del_interface(iface) end
280
281 if ifs[iface].handler then
282 ifs[iface].handler:add_interface(self, iface, ifs[iface])
283 else
284 self:ifname(ub:list((self:ifname() or ''), iface))
285 end
286 end
287 end
288 end
289
290 function network.del_interface(self, ifname)
291 if type(ifname) ~= "string" then
292 ifname = ifname:name()
293 end
294
295 if ifs[ifname] and ifs[ifname].handler then
296 ifs[ifname].handler:del_interface(self, ifname, ifs[ifname])
297 else
298 self:ifname(ub:list((self:ifname() or ''), nil, ifname))
299 end
300 end
301
302 function network.get_interfaces(self)
303 local ifaces = { }
304 local iface
305 for _, iface in ipairs(ub:list(self:ifname())) do
306 iface = iface:match("[^:]+")
307 if ifs[iface] then
308 ifaces[#ifaces+1] = interface(iface)
309 end
310 end
311 for iface, _ in pairs(ifs) do
312 if ifs[iface].network == self:name() then
313 ifaces[#ifaces+1] = interface(iface)
314 end
315 end
316 return ifaces
317 end
318
319 function network.contains_interface(self, iface)
320 local i
321 local ifaces = ub:list(self:ifname())
322
323 if type(iface) ~= "string" then
324 iface = iface:name()
325 end
326
327 for _, i in ipairs(ifaces) do
328 if i == iface then
329 return true
330 end
331 end
332
333 for i, _ in pairs(ifs) do
334 if ifs[i].dev and ifs[i].dev.network == self:name() then
335 return true
336 end
337 end
338
339 return false
340 end
341
342
343 interface = utl.class()
344 function interface.__init__(self, ifname)
345 if ifs[ifname] then
346 self.ifname = ifname
347 self.dev = ifs[ifname]
348 self.br = brs[ifname]
349 end
350 end
351
352 function interface.name(self)
353 return self.ifname
354 end
355
356 function interface.mac(self)
357 return self.dev.macaddr or "00:00:00:00:00:00"
358 end
359
360 function interface.ipaddrs(self)
361 return self.dev.ipaddrs or { }
362 end
363
364 function interface.ip6addrs(self)
365 return self.dev.ip6addrs or { }
366 end
367
368 function interface.type(self)
369 if self.dev and self.dev.type then
370 return self.dev.type
371 elseif brs[self.ifname] then
372 return "bridge"
373 elseif sws[self.ifname] or self.ifname:match("%.") then
374 return "switch"
375 else
376 return "ethernet"
377 end
378 end
379
380 function interface.shortname(self)
381 if self.dev and self.dev.handler then
382 return self.dev.handler:shortname(self)
383 else
384 return self.ifname
385 end
386 end
387
388 function interface.get_i18n(self)
389 if self.dev and self.dev.handler then
390 return self.dev.handler:get_i18n(self)
391 else
392 return "%s: %q" %{ self:get_type_i18n(), self:name() }
393 end
394 end
395
396 function interface.get_type_i18n(self)
397 local x = self:type()
398 if x == "wifi" then
399 return i18n.translate("Wireless Adapter")
400 elseif x == "bridge" then
401 return i18n.translate("Bridge")
402 elseif x == "switch" then
403 return i18n.translate("Ethernet Switch")
404 else
405 return i18n.translate("Ethernet Adapter")
406 end
407 end
408
409 function interface.ports(self)
410 if self.br then
411 local iface
412 local ifaces = { }
413 for _, iface in ipairs(self.br.ifnames) do
414 ifaces[#ifaces+1] = interface(iface.name)
415 end
416 return ifaces
417 end
418 end
419
420 function interface.bridge_id(self)
421 if self.br then
422 return self.br.id
423 else
424 return nil
425 end
426 end
427
428 function interface.bridge_stp(self)
429 if self.br then
430 return self.br.stp
431 else
432 return false
433 end
434 end
435
436 function interface.is_up(self)
437 return self.dev.flags and self.dev.flags.up
438 end
439
440 function interface.is_bridge(self)
441 return (self:type() == "bridge")
442 end
443
444 function interface.is_bridgeport(self)
445 return self.dev and self.dev.bridge and true or false
446 end
447
448 function interface.tx_bytes(self)
449 return self.dev and self.dev.stats
450 and self.dev.stats.tx_bytes or 0
451 end
452
453 function interface.rx_bytes(self)
454 return self.dev and self.dev.stats
455 and self.dev.stats.rx_bytes or 0
456 end
457
458 function interface.tx_packets(self)
459 return self.dev and self.dev.stats
460 and self.dev.stats.tx_packets or 0
461 end
462
463 function interface.rx_packets(self)
464 return self.dev and self.dev.stats
465 and self.dev.stats.rx_packets or 0
466 end
467
468 function interface.get_network(self)
469 if self.dev and self.dev.network then
470 self.network = _M:get_network(self.dev.network)
471 end
472
473 if not self.network then
474 local net
475 for _, net in ipairs(_M:get_networks()) do
476 if net:contains_interface(self.ifname) then
477 self.network = net
478 return net
479 end
480 end
481 else
482 return self.network
483 end
484 end
485
486 --[==[
487 #!/usr/bin/lua
488
489 local uci = require "luci.model.uci".cursor_state()
490 local utl = require "luci.util"
491 local sys = require "luci.sys"
492 local lip = require "luci.ip"
493 local nxo = require "nixio"
494 local nfs = require "nixio.fs"
495
496 -- patch uci
497 local x = getmetatable(uci)
498
499 function x:list(...)
500 local val = self:get(...)
501 local lst = { }
502
503 if type(val) == "list" then
504 local _, v
505 for _, v in ipairs(val) do
506 local i
507 for i in v:gmatch("%S+") do
508 lst[#lst+1] = i
509 end
510 end
511 elseif type(val) == "string" then
512 local i
513 for i in val:gmatch("%S+") do
514 lst[#lst+1] = i
515 end
516 end
517
518 return lst
519 end
520
521
522 system = utl.class()
523
524 system._switches = { }
525 system._vlans = { }
526
527 function system:__init__()
528 self._networks = { }
529
530 uci:foreach("network2", "interface",
531 function(s)
532 self._networks[#self._networks+1] = system.network(s, self)
533 end)
534 end
535
536 function system:networks()
537 local index = 0
538 return function()
539 if index <= #self._networks then
540 index = index + 1
541 return self._networks[index]
542 else
543 return nil
544 end
545 end
546 end
547
548 function system:find_network(name)
549 local v
550 for _, v in ipairs(self._networks) do
551 if v:name() == name then
552 return v
553 end
554 end
555 end
556
557 function system:find_interface(name)
558 local v
559 for _, v in ipairs(self._networks) do
560 local i
561 for i in v:interfaces() do
562 if i:is_bridge() then
563 local p
564 for p in i:interfaces() do
565 if p:name() == name then
566 return p
567 end
568 end
569 end
570
571 if i:name() == name then
572 return i
573 end
574 end
575 end
576 end
577
578 function system:delete_network(name)
579 local i
580 for i = 1, #self._networks do
581 if self._networks[i]:name() == name then
582 local x
583
584 for x in self._networks[i]:aliases() do
585 uci:delete("network2", x:name())
586 end
587
588 for x in self._networks[i]:routes() do
589 uci:delete("network2", x:name())
590 end
591
592 uci:delete("network2", self._networks[i])
593 table.remove(self._networks, i)
594
595 return true
596 end
597 end
598 return false
599 end
600
601 function system:print()
602 local v
603 for v in self:networks() do
604 print(v:name())
605 v:print()
606 print("--")
607 end
608 end
609
610 function system.ignore_iface(ifn)
611 return (nil ~= (
612 ifn:match("^wlan%d") or
613 ifn:match("^ath%d") or
614 ifn:match("^wl%d") or
615 ifn:match("^imq%d") or
616 ifn:match("^br%-") or
617 ifn:match("^/dev/")
618 ))
619 end
620
621 function system.find_wifi_networks(net)
622 local lst = { }
623 local cnt = 0
624
625 uci:foreach("wireless", "wifi-iface",
626 function(s)
627 if s.device and s.network == net then
628 lst[#lst+1] = { s.device, s['.name'], cnt }
629 end
630 cnt = cnt + 1
631 end)
632
633 return lst
634 end
635
636 function system.find_iface_names(net)
637 local lst = { }
638
639 local val = uci:list("network2", net, "device")
640 if #val == 0 or val[1]:match("^/dev/") then
641 val = uci:list("network2", net, "ifname")
642 end
643
644 local ifn
645 for _, ifn in ipairs(val) do
646 if not system.ignore_iface(ifn) then
647 lst[#lst+1] = ifn
648 end
649 end
650
651 return lst
652 end
653
654 function system.find_switch(name)
655 local swname, swdev, swvlan
656
657 -- find switch
658 uci:foreach("network2", "switch",
659 function(s)
660 swname = s.name or s['.name']
661
662 -- special: rtl8366s is eth0 (wan is eth1)
663 if swname == "rtl8366s" then
664 swdev = "eth0"
665
666 -- special: rtl8366rb is eth0 (wan + lan)
667 elseif swname == "rtl8366rb" then
668 swdev = "eth0"
669
670 -- treat swname as swdev
671 else
672 swdev = swname
673 end
674
675 return false
676 end)
677
678 -- find first vlan
679 if swdev then
680 uci:foreach("network2", "switch_vlan",
681 function(s)
682 if s.device == swname then
683 local vlan = tonumber(s.vlan)
684 if vlan and (not swvlan or vlan < swvlan) then
685 swvlan = vlan
686 end
687 end
688 end)
689 end
690
691
692 local veth, vlan = name:match("^(%S+)%.(%d+)$")
693
694 -- have vlan id and matching switch
695 if vlan and veth == swdev then
696 return swname, swdev, vlan
697
698 -- have no vlan id but matching switch, assume first switch vlan
699 elseif not vlan and name == swdev then
700 return swname, swdev, swvlan
701
702 -- have vlan and no matching switch, assume software vlan
703 elseif vlan then
704 return nil, veth, vlan
705 end
706 end
707
708
709 system.network = utl.class()
710
711 function system.network:__init__(s, sys)
712 self._name = s['.name']
713 self._sys = sys
714 self._routes = { }
715 self._aliases = { }
716
717 if s.type == "bridge" then
718 self._interfaces = { system.network.bridge(s['.name'], self) }
719 else
720 self._interfaces = { }
721
722 local ifn
723
724 -- find wired ifaces
725 for _, ifn in ipairs(system.find_iface_names(self._name)) do
726 self._interfaces[#self._interfaces+1] = system.network.iface(ifn, self)
727 end
728
729 -- find wifi networks
730 for _, ifn in ipairs(system.find_wifi_networks(self._name)) do
731 self._interfaces[#self._interfaces+1] = system.network.iface(ifn, self)
732 end
733 end
734
735 -- find ipv4 routes
736 uci:foreach("network2", "route",
737 function(s)
738 if s.interface == self._name and s.target then
739 self._routes[#self._routes+1] = system.network.route(s, self)
740 end
741 end)
742
743 -- find ipv6 routes
744 uci:foreach("network2", "route6",
745 function(s)
746 if s.interface == self._name and s.target then
747 self._routes[#self._routes+1] = system.network.route(s, self)
748 end
749 end)
750
751 -- find aliases
752 uci:foreach("network2", "alias",
753 function(s)
754 if s.interface == self._name and s.proto then
755 self._aliases[#self._aliases+1] = system.network.alias(s, self)
756 end
757 end)
758 end
759
760 function system.network:name()
761 return self._name
762 end
763
764 function system.network:system()
765 return self._sys
766 end
767
768 function system.network:interfaces()
769 local index = 0
770 return function()
771 if index <= #self._interfaces then
772 index = index + 1
773 return self._interfaces[index]
774 else
775 return nil
776 end
777 end
778 end
779
780 function system.network:interface()
781 return self._interfaces[1]
782 end
783
784 function system.network:num_routes()
785 return #self._routes
786 end
787
788 function system.network:routes()
789 local index = 0
790 return function()
791 if index <= #self._routes then
792 index = index + 1
793 return self._routes[index]
794 else
795 return nil
796 end
797 end
798 end
799
800 function system.network:num_aliases()
801 return #self._aliases
802 end
803
804 function system.network:aliases()
805 local index = 0
806 return function()
807 if index <= #self._aliases then
808 index = index + 1
809 return self._aliases[index]
810 else
811 return nil
812 end
813 end
814 end
815
816 function system.network:delete_route(rt)
817 local i
818 for i = 1, #self._routes do
819 if self._routes[i]:name() == rt:name() then
820 uci:delete("network2", rt:name())
821 table.remove(self._routes, i)
822 return true
823 end
824 end
825 return false
826 end
827
828 function system.network:delete_alias(al)
829 local i
830 for i = 1, #self._aliases do
831 if self._aliases[i]:name() == al:name() then
832 uci:delete("network2", al:name())
833 table.remove(self._aliases, i)
834 return true
835 end
836 end
837 return false
838 end
839
840 function system.network:print()
841 self:interface():print()
842 end
843
844
845 system.network.iface = utl.class()
846
847 function system.network.iface:__init__(ifn, net, parent)
848 self._net = net
849 self._parent = parent
850
851 -- is a wifi iface
852 if type(ifn) == "table" then
853 local wifidev, network, index = unpack(ifn)
854
855 self._name = "%s.%d" %{ wifidev, index }
856 self._wifidev = wifidev
857 self._wifinet = index
858 self._ifname = uci:get("wireless", network, "ifname") or self._name
859
860 -- is a wired iface
861 else
862 self._name = ifn
863 self._ifname = ifn
864
865 local switch, swdev, vlan = system.find_switch(self._ifname)
866
867 if switch then
868 self._switch = system.switch(switch, swdev, self)
869 end
870
871 if vlan then
872 self._vlan = system.vlan(vlan, self._switch, self)
873 end
874 end
875 end
876
877 function system.network.iface:name()
878 return self._name
879 end
880
881 function system.network.iface:parent()
882 return self._parent
883 end
884
885 function system.network.iface:network()
886 return self._net
887 end
888
889 function system.network.iface:is_managed()
890 return (self._net ~= nil)
891 end
892
893 function system.network.iface:is_vlan()
894 return (self._vlan ~= nil)
895 end
896
897 function system.network.iface:is_software_vlan()
898 return (not self._switch and self._vlan ~= nil)
899 end
900
901 function system.network.iface:is_hardware_vlan()
902 return (self._switch ~= nil and self._vlan ~= nil)
903 end
904
905 function system.network.iface:_sysfs(path, default)
906 path = "/sys/class/net/%s/%s" %{ self._ifname, path }
907
908 local data = nfs.readfile(path)
909
910 if type(default) == "number" then
911 return tonumber(data) or default
912 elseif data and #data > 0 then
913 return data and data:gsub("%s+$", "") or default
914 end
915
916 return default
917 end
918
919 function system.network.iface:rx_bytes()
920 return self:_sysfs("statistics/rx_bytes", 0)
921 end
922
923 function system.network.iface:tx_bytes()
924 return self:_sysfs("statistics/tx_bytes", 0)
925 end
926
927 function system.network.iface:rx_packets()
928 return self:_sysfs("statistics/rx_packets", 0)
929 end
930
931 function system.network.iface:tx_packets()
932 return self:_sysfs("statistics/tx_packets", 0)
933 end
934
935 function system.network.iface:macaddr()
936 return self:_sysfs("address")
937 end
938
939 function system.network.iface:mtu()
940 return self:_sysfs("mtu", 1500)
941 end
942
943 function system.network.iface:is_bridge()
944 return (self:_sysfs("bridge/max_age", 0) > 0)
945 end
946
947 function system.network.iface:is_bridge_port()
948 return (self:_sysfs("brport/port_no", 0) > 0)
949 end
950
951 function system.network.iface:delete()
952 if self._wifidev then
953 local cnt = 0
954 uci:foreach("wireless", "wifi-iface",
955 function(s)
956 cnt = cnt + 1
957 if s.device == self._wifidev and cnt == self._wifinet then
958 uci:delete("wireless", s['.name'])
959 return false
960 end
961 end)
962 end
963 end
964
965 function system.network.iface:print()
966 if self._wifidev then
967 print(" wifi: ", self._wifidev, "net: ", self._wifinet)
968 else
969 print(" iface: ", self._name)
970 end
971
972 print(" rx: ", self:rx_bytes(), self:rx_packets())
973 print(" tx: ", self:tx_bytes(), self:tx_packets())
974 print(" mtu: ", self:mtu())
975 print(" mac: ", self:macaddr())
976 print(" bridge? ", self:is_bridge())
977 print(" port? ", self:is_bridge_port())
978 print(" swvlan? ", self:is_software_vlan())
979 print(" hwvlan? ", self:is_hardware_vlan())
980
981 if self._switch then
982 self._switch:print()
983 end
984
985 if self._vlan then
986 self._vlan:print()
987 end
988 end
989
990
991 system.network.bridge = utl.class(system.network.iface)
992
993 function system.network.bridge:__init__(brn, net)
994 self._net = net
995 self._name = "br-" .. brn
996 self._ifname = self._name
997 self._interfaces = { }
998
999 local ifn
1000
1001 -- find wired ifaces
1002 for _, ifn in ipairs(system.find_iface_names(brn)) do
1003 self._interfaces[#self._interfaces+1] = system.network.iface(ifn, net, self)
1004 end
1005
1006 -- find wifi networks
1007 for _, ifn in ipairs(system.find_wifi_networks(brn)) do
1008 self._interfaces[#self._interfaces+1] = system.network.iface(ifn, net, self)
1009 end
1010 end
1011
1012 function system.network.bridge:interfaces()
1013 local index = 0
1014 return function()
1015 if index <= #self._interfaces then
1016 index = index + 1
1017 return self._interfaces[index]
1018 else
1019 return nil
1020 end
1021 end
1022 end
1023
1024 function system.network.bridge:print()
1025 local v
1026 for v in self:interfaces() do
1027 io.write(" port: ")
1028 v:print()
1029 end
1030 print(" rx: ", self:rx_bytes(), self:rx_packets())
1031 print(" tx: ", self:tx_bytes(), self:tx_packets())
1032 print(" mtu: ", self:mtu())
1033 print(" mac: ", self:macaddr())
1034 print(" bridge? ", self:is_bridge())
1035 print(" port? ", self:is_bridge_port())
1036 end
1037
1038
1039 system.network.route = utl.class()
1040
1041 function system.network.route:__init__(rt, net)
1042 self._net = net
1043 self._name = rt['.name']
1044 self._ipv6 = (rt['.type'] == "route6")
1045 self._mtu = tonumber(rt.mtu) or (net and net:interface():mtu() or 1500)
1046 self._metric = tonumber(rt.metric) or 0
1047
1048 if self._ipv6 then
1049 self._gateway = lip.IPv6(rt.gateway or "::")
1050 self._target = lip.IPv6(rt.target or "::")
1051 else
1052 self._gateway = lip.IPv4(rt.gateway or "0.0.0.0")
1053 self._target = lip.IPv4(rt.target or "0.0.0.0", rt.netmask or "0.0.0.0")
1054 end
1055 end
1056
1057 function system.network.route:name()
1058 return self._name
1059 end
1060
1061 function system.network.route:network()
1062 return self._net
1063 end
1064
1065 function system.network.route:mtu()
1066 return self._mtu
1067 end
1068
1069 function system.network.route:metric()
1070 return self._metric
1071 end
1072
1073 function system.network.route:is_ipv4()
1074 return not self._ipv6
1075 end
1076
1077 function system.network.route:is_ipv6()
1078 return self._ipv6
1079 end
1080
1081 function system.network.route:target()
1082 return self._target
1083 end
1084
1085 function system.network.route:gateway()
1086 return self._gateway
1087 end
1088
1089
1090 system.network.alias = utl.class()
1091
1092 function system.network.alias:__init__(a, net)
1093 self._net = net
1094 self._name = a['.name']
1095 end
1096
1097
1098 system.switch = utl.class()
1099
1100 function system.switch:__init__(switch, swdev, net)
1101 self._name = switch
1102 self._ifname = swdev
1103 self._net = net
1104
1105 if not system._switches[switch] then
1106 local x = io.popen("swconfig dev %q help 2>/dev/null" % switch)
1107 if x then
1108 local desc = x:read("*l")
1109
1110 if desc then
1111 local name, num_ports, num_cpu, num_vlans =
1112 desc:match("Switch %d: %S+%((.-)%), ports: (%d+) %(cpu @ (%d+)%), vlans: (%d+)")
1113
1114 self._model = name
1115 self._ports = tonumber(num_ports)
1116 self._cpuport = tonumber(num_cpu)
1117 self._vlans = tonumber(num_vlans)
1118 end
1119
1120 x:close()
1121
1122 elseif nfs.access("/proc/switch/%s" % switch) then
1123 self._model = self:_proc("driver", switch)
1124 self._ports = self:_proc_count("port", 6)
1125 self._vlans = self:_proc_count("vlan", 16)
1126 end
1127
1128 -- defaults
1129 self._model = self._model or switch
1130 self._ports = self._ports or 6
1131 self._vlans = self._vlans or 16
1132 self._cpuport = self._cpuport or 5
1133
1134 system._switches[switch] = self
1135 else
1136 self._model = system._switches[switch]._model
1137 self._ports = system._switches[switch]._ports
1138 self._vlans = system._switches[switch]._vlans
1139 self._cpuport = system._switches[switch]._cpuport
1140 end
1141 end
1142
1143 function system.switch:_proc(path, default)
1144 local data = nfs.readfile("/proc/switch/%s/%s" %{ self._name, path })
1145 if data then
1146 return data:gsub("%s+$", "")
1147 end
1148 return default
1149 end
1150
1151 function system.switch:_proc_count(path, default)
1152 local cnt = 0
1153 for _ in nfs.dir("/proc/switch/%s/%s" %{ self._name, path }) do
1154 cnt = cnt + 1
1155 end
1156 return cnt > 0 and cnt or default
1157 end
1158
1159 function system.switch:name()
1160 return self._name
1161 end
1162
1163 function system.switch:model()
1164 return self._model
1165 end
1166
1167 function system.switch:num_possible_vlans()
1168 return self._vlans
1169 end
1170
1171 function system.switch:num_active_vlans()
1172 local cnt = 0
1173 uci:foreach("network2", "switch_vlan",
1174 function(s)
1175 if s.device == self._name then cnt = cnt + 1 end
1176 end)
1177 return cnt
1178 end
1179
1180 function system.switch:vlans()
1181 local index = 0
1182 local vlans = { }
1183
1184 uci:foreach("network2", "switch_vlan",
1185 function(s)
1186 if s.device == self._name and tonumber(s.vlan) then
1187 vlans[#vlans+1] = tonumber(s.vlan)
1188 end
1189 end)
1190
1191 return function()
1192 if index <= #vlans then
1193 index = index + 1
1194 return system.vlan(vlans[index], self)
1195 else
1196 return nil
1197 end
1198 end
1199 end
1200
1201 function system.switch:num_ports()
1202 return self._ports
1203 end
1204
1205 function system.switch:delete_vlan(vlan)
1206 local rv = false
1207
1208 uci:foreach("network2", "switch_vlan",
1209 function(s)
1210 if s.device == self._name and tonumber(s.vlan) == vlan then
1211 rv = true
1212 uci:delete("network2", s['.name'])
1213
1214 if system._vlans[s.device] and system._vlans[s.device][vlan] then
1215 table.remove(system._vlans[s.device], vlan)
1216 end
1217
1218 return false
1219 end
1220 end)
1221
1222 return rv
1223 end
1224
1225 function system.switch:print()
1226 print("Switch:", self._model)
1227 print(" Ports:", self._ports, "Cpu:", self._cpuport)
1228 print(" Vlans:", self._vlans)
1229 end
1230
1231
1232 system.vlan = utl.class()
1233
1234 function system.vlan:__init__(vlan, switch, iface)
1235 self._vlan = vlan
1236 self._switch = switch
1237 self._iface = iface
1238
1239 local swid = (switch and switch:name()) or (iface and iface:name()) or ""
1240
1241 if not system._vlans[swid] or not system._vlans[swid][vlan] then
1242 self._ports = { }
1243
1244 if switch then
1245 uci:foreach("network2", "switch_vlan",
1246 function(s)
1247 if s.device == switch:name() and tonumber(s.vlan) == vlan then
1248 local p
1249 for _, p in ipairs(uci:list("network2", s['.name'], "ports")) do
1250 self._ports[#self._ports+1] = system.vlan.port(p, self)
1251 end
1252 self._name = s['.name']
1253 end
1254 end)
1255 else
1256 self._ports[#self._ports+1] = system.vlan.port("0t", self)
1257 end
1258
1259 system._vlans[swid] = system._vlans[swid] or { }
1260 system._vlans[swid][vlan] = self
1261 else
1262 self._ports = system._vlans[swid][vlan]._ports
1263 end
1264 end
1265
1266 function system.vlan:name()
1267 return self._name
1268 end
1269
1270 function system.vlan:number()
1271 return self._vlan
1272 end
1273
1274 function system.vlan:switch()
1275 return self._switch
1276 end
1277
1278 function system.vlan:interface()
1279 return self._iface
1280 end
1281
1282 function system.vlan:is_software()
1283 return (self._switch == nil)
1284 end
1285
1286 function system.vlan:is_hardware()
1287 return not self:is_software()
1288 end
1289
1290 function system.vlan:num_ports()
1291 return #self._ports
1292 end
1293
1294 function system.vlan:ports()
1295 local index = 0
1296 return function()
1297 if index <= #self._ports then
1298 index = index + 1
1299 return self._ports[index]
1300 else
1301 return nil
1302 end
1303 end
1304 end
1305
1306 function system.vlan:_update()
1307 local i
1308 local ports = { }
1309
1310 for i = 1, #self._ports do
1311 ports[#ports+1] = self._ports[i]:string()
1312 end
1313
1314 uci:set("network2", self._name, "ports", table.concat(ports, " "))
1315 end
1316
1317 function system.vlan:delete_port(port)
1318 if self._switch then
1319 local i
1320 for i = 1, #self._ports do
1321 if self._ports[i]:number() == port then
1322 table.remove(self._ports, i)
1323 self:_update()
1324 return true
1325 end
1326 end
1327 end
1328 return false
1329 end
1330
1331 function system.vlan:print()
1332 print(" Vlan:", self._vlan, "Software?", self:is_software())
1333 local p
1334 for p in self:ports() do
1335 p:print()
1336 end
1337 end
1338
1339
1340 system.vlan.port = utl.class()
1341
1342 function system.vlan.port:__init__(port, vlan)
1343 local num, tag = port:match("^(%d+)([tu]?)")
1344
1345 self._vlan = vlan
1346 self._port = tonumber(num)
1347 self._tagged = (tag == "t")
1348 end
1349
1350 function system.vlan.port:number()
1351 return self._port
1352 end
1353
1354 function system.vlan.port:vlan()
1355 return self._vlan
1356 end
1357
1358 function system.vlan.port:string()
1359 return "%i%s" %{ self._port, self._tagged ? "t" : "" }
1360 end
1361
1362 function system.vlan.port:is_tagged()
1363 return self._tagged
1364 end
1365
1366 function system.vlan.port:print()
1367 print(" Port:", self._port, "Tagged:", self._tagged)
1368 end
1369
1370
1371 -- ------------------------------
1372
1373 local s = system()
1374
1375 s:print()
1376
1377 s:find_network("wan"):print()
1378 s:find_interface("eth0"):parent():print()
1379
1380 ]==]