rpcd: add luci2.network.ping, luci2.network.ping6, luci2.network.tracroute, luci2...
[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 vid_opt   = 'vlan';
78                                 var v4k_opt   = undefined;
79                                 var pvid_opt  = undefined;
80                                 var max_vid   = switches[i].num_vlans - 1;
81                                 var num_vlans = switches[i].num_vlans;
82
83                                 for (var j = 0; j < switches[i].vlan_attrs.length; j++)
84                                 {
85                                         switch (switches[i].vlan_attrs[j].name)
86                                         {
87                                         case 'tag':
88                                         case 'vid':
89                                         case 'pvid':
90                                                 vid_opt = switches[i].vlan_attrs[j].name;
91                                                 max_vid = 4095;
92                                                 break;
93                                         }
94                                 }
95
96                                 for (var j = 0; j < switches[i].port_attrs.length; j++)
97                                 {
98                                         switch (switches[i].port_attrs[j].name)
99                                         {
100                                         case 'pvid':
101                                                 pvid_opt = switches[i].port_attrs[j].name;
102                                                 break;
103                                         }
104                                 }
105
106
107                                 var sw = m.section(L.cbi.TypedSection, 'switch', {
108                                         caption:  L.tr('Switch "%s"').format(switches[i].model),
109                                         swname:   switches[i]['switch']
110                                 });
111
112                                 sw.filter = function(section) {
113                                         return (section['.name'] == this.options.swname ||
114                                                         section.name     == this.options.swname);
115                                 };
116
117                                 for (var j = 0; j < switches[i].attrs.length; j++)
118                                 {
119                                         switch (switches[i].attrs[j].name)
120                                         {
121                                         case 'enable_vlan':
122                                                 sw.option(L.cbi.CheckboxValue, 'enable_vlan', {
123                                                         caption:     L.tr('Enable VLAN functionality')
124                                                 });
125                                                 break;
126
127                                         case 'enable_learning':
128                                                 sw.option(L.cbi.CheckboxValue, 'enable_learning', {
129                                                         caption:     L.tr('Enable learning and aging'),
130                                                         initial:     true,
131                                                         optional:    true
132                                                 });
133                                                 break;
134
135                                         case 'max_length':
136                                                 sw.option(L.cbi.CheckboxValue, 'max_length', {
137                                                         caption:     L.tr('Enable Jumbo Frame passthrough'),
138                                                         enabled:     '3',
139                                                         optional:    true
140                                                 });
141                                                 break;
142
143                                         case 'enable_vlan4k':
144                                                 v4k_opt = switches[i].attrs[j].name;
145                                                 break;
146                                         }
147                                 }
148
149                                 var vlans = m.section(L.cbi.TableSection, 'switch_vlan', {
150                                         caption:     L.tr('VLANs on "%s"').format(switches[i].model),
151                                         swname:      switches[i]['switch'],
152                                         addremove:   true,
153                                         add_caption: L.tr('Add VLAN entry …')
154                                 });
155
156                                 vlans.add = function() {
157                                         var sections = this.sections();
158                                         var used_vids = { };
159
160                                         for (var j = 0; j < sections.length; j++)
161                                         {
162                                                 var v = this.map.get('network', sections[j]['.name'], 'vlan');
163                                                 if (v)
164                                                         used_vids[v] = true;
165                                         }
166
167                                         for (var j = 1; j < num_vlans; j++)
168                                         {
169                                                 if (used_vids[j.toString()])
170                                                         continue;
171
172                                                 var sid = this.map.add('network', 'switch_vlan');
173                                                 this.map.set('network', sid, 'device', this.options.swname);
174                                                 this.map.set('network', sid, 'vlan', j);
175                                                 break;
176                                         }
177                                 };
178
179                                 vlans.filter = function(section) {
180                                         return (section.device == this.options.swname);
181                                 };
182
183                                 vlans.sections = function() {
184                                         var s = this.callSuper('sections');
185
186                                         s.sort(function(a, b) {
187                                                 var x = parseInt(a[vid_opt] || a.vlan);
188                                                 if (isNaN(x))
189                                                         x = 9999;
190
191                                                 var y = parseInt(b[vid_opt] || b.vlan);
192                                                 if (isNaN(y))
193                                                         y = 9999;
194
195                                                 return (x - y);
196                                         });
197
198                                         return s;
199                                 };
200
201                                 var port_opts = [ ];
202
203                                 var vo = vlans.option(L.cbi.InputValue, vid_opt, {
204                                         caption:     L.tr('VLAN ID'),
205                                         datatype:    function(val) {
206                                                 var sections = vlans.sections();
207                                                 var used_vids = { };
208
209                                                 for (var j = 0; j < sections.length; j++)
210                                                 {
211                                                         var v = vlans.fields[vid_opt].formvalue(sections[j]['.name']);
212                                                         if (!v)
213                                                                 continue;
214
215                                                         if (used_vids[v])
216                                                                 return L.tr('VLAN ID must be unique');
217
218                                                         used_vids[v] = true;
219                                                 }
220
221                                                 v = parseInt(v, 10);
222
223                                                 if (isNaN(v))
224                                                         return L.tr('Invalid VLAN ID');
225
226                                                 if (v < 1 || v > max_vid)
227                                                         return L.tr('VLAN ID must be value between %u and %u').format(1, max_vid);
228
229                                                 return true;
230                                         }
231                                 });
232
233                                 vo.ucivalue = function(sid) {
234                                         var id = this.map.get('network', sid, vid_opt);
235
236                                         if (isNaN(parseInt(id)))
237                                                 id = this.map.get('network', sid, 'vlan');
238
239                                         return id;
240                                 };
241
242                                 vo.save = function(sid) {
243                                         var old_ports = this.map.get('network', sid, 'ports');
244                                         var new_ports = '';
245
246                                         for (var j = 0; j < port_opts.length; j++)
247                                         {
248                                                 var v = port_opts[j].formvalue(sid);
249                                                 if (v != 'n')
250                                                         new_ports += '%s%d%s'.format(
251                                                                 new_ports ? ' ' : '', j,
252                                                                 (v == 'u') ? '' : 't');
253                                         }
254
255                                         if (new_ports != old_ports)
256                                                 this.map.set('network', sid, 'ports', new_ports);
257
258                                         if (v4k_opt)
259                                         {
260                                                 var s = sw.sections();
261                                                 for (var j = 0; j < s.length; j++)
262                                                         this.map.set('network', s[j]['.name'], v4k_opt, '1');
263                                         }
264
265                                         this.callSuper('save', sid);
266                                 };
267
268                                 for (var j = 0; j < switches[i].num_ports; j++)
269                                 {
270                                         var label = L.trc('Switch port label', 'Port %d').format(j);
271
272                                         if (j == switches[i].cpu_port)
273                                                 label = L.trc('Switch port label', 'CPU');
274
275                                         var po = vlans.option(self.switchPortState, j.toString(), {
276                                                 caption: label
277                                         });
278
279                                         port_opts.push(po);
280                                 }
281                         }
282
283                         return m.insertInto('#map');
284                 });
285         }
286 });