| | 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 | ]==] |