c1f04d76903efecde1c0c10242a148a81dd1d688
[project/luci2/ui.git] / luci2 / htdocs / luci2 / view / network.switch.js
1 L.ui.view.extend({
2         title: L.tr('Switch'),
3         description: L.tr('The network ports on this device can be combined to several VLANs in which computers can communicate directly with each other. VLANs are often used to separate different network segments. Often there is by default one Uplink port for a connection to the next greater network like the internet and other ports for a local network.'),
4
5         switchPortState: L.cbi.ListValue.extend({
6                 choices: [
7                         [ 'n', L.trc('Switch port state', 'off')      ],
8                         [ 'u', L.trc('Switch port state', 'untagged') ],
9                         [ 't', L.trc('Switch port state', 'tagged')   ]
10                 ],
11
12                 init: function(name, options)
13                 {
14                         var self = this;
15
16                         options.datatype = function(val, elem)
17                         {
18                                 if (val == 'u')
19                                 {
20                                         var u = false;
21                                         var sections = self.section.sections();
22
23                                         for (var i = 0; i < sections.length; i++)
24                                         {
25                                                 var v = self.formvalue(sections[i]['.name']);
26                                                 if (v == 'u')
27                                                 {
28                                                         if (u)
29                                                                 return L.tr('Port must not be untagged in multiple VLANs');
30
31                                                         u = true;
32                                                 }
33                                         }
34                                 }
35
36                                 return true;
37                         };
38
39                         this.callSuper('init', name, options);
40                 },
41
42                 ucivalue: function(sid)
43                 {
44                         var ports = (this.map.get('network', sid, 'ports') || '').match(/[0-9]+[tu]?/g);
45
46                         if (ports)
47                                 for (var i = 0; i < ports.length; i++)
48                                         if (ports[i].match(/^([0-9]+)([tu]?)$/))
49                                                 if (RegExp.$1 == this.name)
50                                                         return RegExp.$2 || 'u';
51
52                         return 'n';
53                 },
54
55                 save: function(sid)
56                 {
57                         return;
58                 }
59         }),
60
61         execute: function() {
62                 var self = this;
63                 L.network.listSwitchNames().then(function(switches) {
64                         L.rpc.batch();
65
66                         for (var i = 0; i < switches.length; i++)
67                                 L.network.getSwitchInfo(switches[i]);
68
69                         return L.rpc.flush();
70                 }).then(function(switches) {
71                         var m = new L.cbi.Map('network', {
72                                 readonly:    !self.options.acls['switch']
73                         });
74
75                         for (var i = 0; i < switches.length; i++)
76                         {
77                                 var swname    = switches[i]['switch'];
78
79                                 var vid_opt   = 'vlan';
80                                 var v4k_opt   = undefined;
81                                 var pvid_opt  = undefined;
82                                 var max_vid   = switches[i].num_vlans - 1;
83                                 var num_vlans = switches[i].num_vlans;
84
85                                 for (var j = 0; j < switches[i].vlan_attrs.length; j++)
86                                 {
87                                         switch (switches[i].vlan_attrs[j].name)
88                                         {
89                                         case 'tag':
90                                         case 'vid':
91                                         case 'pvid':
92                                                 vid_opt = switches[i].vlan_attrs[j].name;
93                                                 max_vid = 4095;
94                                                 break;
95                                         }
96                                 }
97
98                                 for (var j = 0; j < switches[i].port_attrs.length; j++)
99                                 {
100                                         switch (switches[i].port_attrs[j].name)
101                                         {
102                                         case 'pvid':
103                                                 pvid_opt = switches[i].port_attrs[j].name;
104                                                 break;
105                                         }
106                                 }
107
108
109                                 var sw = m.section(L.cbi.TypedSection, 'switch', {
110                                         caption:  L.tr('Switch "%s"').format(switches[i].model),
111                                         swname:   swname
112                                 });
113
114                                 sw.filter = function(section) {
115                                         return (section['.name'] == this.options.swname ||
116                                                         section.name     == this.options.swname);
117                                 };
118
119                                 for (var j = 0; j < switches[i].attrs.length; j++)
120                                 {
121                                         switch (switches[i].attrs[j].name)
122                                         {
123                                         case 'enable_vlan':
124                                                 sw.option(L.cbi.CheckboxValue, 'enable_vlan', {
125                                                         caption:     L.tr('Enable VLAN functionality')
126                                                 });
127                                                 break;
128
129                                         case 'enable_learning':
130                                                 sw.option(L.cbi.CheckboxValue, 'enable_learning', {
131                                                         caption:     L.tr('Enable learning and aging'),
132                                                         initial:     true,
133                                                         optional:    true
134                                                 });
135                                                 break;
136
137                                         case 'max_length':
138                                                 sw.option(L.cbi.CheckboxValue, 'max_length', {
139                                                         caption:     L.tr('Enable Jumbo Frame passthrough'),
140                                                         enabled:     '3',
141                                                         optional:    true
142                                                 });
143                                                 break;
144
145                                         case 'enable_vlan4k':
146                                                 v4k_opt = switches[i].attrs[j].name;
147                                                 break;
148                                         }
149                                 }
150
151                                 var vlans = m.section(L.cbi.TableSection, 'switch_vlan', {
152                                         caption:     L.tr('VLANs on "%s"').format(switches[i].model),
153                                         swname:      swname,
154                                         addremove:   true,
155                                         add_caption: L.tr('Add VLAN entry …')
156                                 });
157
158                                 vlans.add = function() {
159                                         var sections = this.sections();
160                                         var used_vids = { };
161
162                                         for (var j = 0; j < sections.length; j++)
163                                         {
164                                                 var v = this.map.get('network', sections[j]['.name'], 'vlan');
165                                                 if (v)
166                                                         used_vids[v] = true;
167                                         }
168
169                                         for (var j = 1; j < num_vlans; j++)
170                                         {
171                                                 if (used_vids[j.toString()])
172                                                         continue;
173
174                                                 var sid = this.map.add('network', 'switch_vlan');
175                                                 this.map.set('network', sid, 'device', this.options.swname);
176                                                 this.map.set('network', sid, 'vlan', j);
177                                                 break;
178                                         }
179                                 };
180
181                                 vlans.filter = function(section) {
182                                         return (section.device == this.options.swname);
183                                 };
184
185                                 vlans.sections = function() {
186                                         var s = this.callSuper('sections');
187
188                                         s.sort(function(a, b) {
189                                                 var x = parseInt(a[vid_opt] || a.vlan);
190                                                 if (isNaN(x))
191                                                         x = 9999;
192
193                                                 var y = parseInt(b[vid_opt] || b.vlan);
194                                                 if (isNaN(y))
195                                                         y = 9999;
196
197                                                 return (x - y);
198                                         });
199
200                                         return s;
201                                 };
202
203                                 var port_opts = [ ];
204
205                                 var vo = vlans.option(L.cbi.InputValue, vid_opt, {
206                                         caption:     L.tr('VLAN ID'),
207                                         datatype:    function(val) {
208                                                 var sections = vlans.sections();
209                                                 var used_vids = { };
210
211                                                 for (var j = 0; j < sections.length; j++)
212                                                 {
213                                                         var v = vlans.fields[vid_opt].formvalue(sections[j]['.name']);
214                                                         if (!v)
215                                                                 continue;
216
217                                                         if (used_vids[v])
218                                                                 return L.tr('VLAN ID must be unique');
219
220                                                         used_vids[v] = true;
221                                                 }
222
223                                                 v = parseInt(v, 10);
224
225                                                 if (isNaN(v))
226                                                         return L.tr('Invalid VLAN ID');
227
228                                                 if (v < 1 || v > max_vid)
229                                                         return L.tr('VLAN ID must be value between %u and %u').format(1, max_vid);
230
231                                                 return true;
232                                         }
233                                 });
234
235                                 vo.ucivalue = function(sid) {
236                                         var id = this.map.get('network', sid, vid_opt);
237
238                                         if (isNaN(parseInt(id)))
239                                                 id = this.map.get('network', sid, 'vlan');
240
241                                         return id;
242                                 };
243
244                                 vo.save = function(sid) {
245                                         var old_ports = this.map.get('network', sid, 'ports');
246                                         var new_ports = '';
247
248                                         for (var j = 0; j < port_opts.length; j++)
249                                         {
250                                                 var v = port_opts[j].formvalue(sid);
251                                                 if (v != 'n')
252                                                         new_ports += '%s%d%s'.format(
253                                                                 new_ports ? ' ' : '', j,
254                                                                 (v == 'u') ? '' : 't');
255                                         }
256
257                                         if (new_ports != old_ports)
258                                                 this.map.set('network', sid, 'ports', new_ports);
259
260                                         if (v4k_opt)
261                                         {
262                                                 var s = sw.sections();
263                                                 for (var j = 0; j < s.length; j++)
264                                                         this.map.set('network', s[j]['.name'], v4k_opt, '1');
265                                         }
266
267                                         this.callSuper('save', sid);
268                                 };
269
270                                 for (var j = 0; j < switches[i].num_ports; j++)
271                                 {
272                                         var label = L.trc('Switch port label', 'Port %d').format(j);
273
274                                         if (j == switches[i].cpu_port)
275                                                 label = L.trc('Switch port label', 'CPU');
276
277                                         var po = vlans.option(self.switchPortState, j.toString(), {
278                                                 caption: label + '<br /><small id="portstatus-%s-%d"></small>'.format(swname, j)
279                                         });
280
281                                         port_opts.push(po);
282                                 }
283                         }
284
285                         m.insertInto('#map');
286
287                         self.repeat(function() {
288                                 return L.network.getSwitchStatus(swname).then(function(ports) {
289                                         for (var j = 0; j < ports.length; j++)
290                                         {
291                                                 var s = L.tr('No link');
292                                                 var d = '&#160;';
293
294                                                 if (ports[j].link)
295                                                 {
296                                                         s = '%dbaseT'.format(ports[j].speed);
297                                                         d = ports[j].full_duplex ? L.tr('Full-duplex') : L.tr('Half-duplex');
298                                                 }
299
300                                                 $('#portstatus-%s-%d'.format(swname, j))
301                                                         .empty().append(s + '<br />' + d);
302                                         }
303                                 });
304                         }, 5000);
305                 });
306         }
307 });