7 'require tools.widgets as widgets';
10 function getSelectableSlaves(section_id
) {
12 var NonUsableMac
= /^(00:00:00:00:00:00|null)/;
13 var interfaces
= uci
.sections('network', 'interface');
15 return network
.getDevices().then(function(devices
) {
16 for (var i
= 0; i
< devices
.length
; i
++) {
18 var NotUsable
= NonUsableMac
.test(devices
[i
].getMAC());
20 // Only "real" interfaces for slaves needed
21 if (NotUsable
== false) {
22 for (var j
= 0; j
< interfaces
.length
; j
++) {
23 if (uci
.get('network', interfaces
[j
]['.name'], 'proto') == 'bonding') {
24 var slaves
= L
.toArray(uci
.get('network', interfaces
[j
]['.name'], 'slaves'));
26 for (var k
= 0; k
< slaves
.length
; k
++) {
27 if (devices
[i
].ifname
== slaves
[k
] || devices
[i
].device
== slaves
[k
]) {
28 if (interfaces
[j
]['.name'] != section_id
) {
35 if (in_use
== false) {
36 devices
[i
].device
== null ? rv
.push(devices
[i
].ifname
) : rv
.push(devices
[i
].device
)
45 function validate_netmask_empty(section
, value
) {
46 var opt
= this.map
.lookupOption('ipaddr', section
);
47 var ipaddr
= opt
[0].formvalue(section
);
49 if (!ipaddr
|| value
) {
53 return _('Expecting: non-empty value');
57 function updatePrimaries(section
, value
) {
59 var opt
= this.map
.lookupOption('slaves', section
);
60 var selected_slaves
= opt
[0].formvalue(section
);
62 var uielem
= this.map
.lookupOption('primary', section
)[0].getUIElement(section
);
63 uielem
.clearChoices();
65 for (var i
= 0; i
< selected_slaves
.length
; i
++) {
66 uielem
.addChoices(selected_slaves
[i
], selected_slaves
[i
]);
72 function validate_arp_policy(section
, value
) {
74 var opt
= this.map
.lookupOption('link_monitoring', section
);
75 var selected_link_monitoring
= opt
[0].formvalue(section
);
77 var opt
= this.map
.lookupOption('bonding_policy', section
);
78 var selected_policy
= opt
[0].formvalue(section
);
80 if (selected_link_monitoring
== 'arp') {
81 if (selected_policy
== '802.3ad' || selected_policy
== 'balance-tlb' || selected_policy
== 'balance-alb') {
82 return _('ARP monitoring is not supported for the selected policy!');
89 function validate_arp_ip_targets(section
, value
) {
91 var opt
= this.map
.lookupOption('link_monitoring', section
);
92 var selected_link_monitoring
= opt
[0].formvalue(section
);
94 var opt
= this.map
.lookupOption('arp_ip_target', section
);
95 var selected_arp_ip_targets
= opt
[0].formvalue(section
);
97 var opt
= this.map
.lookupOption('bonding_policy', section
);
98 var selected_policy
= opt
[0].formvalue(section
);
100 if (selected_link_monitoring
== 'arp' && selected_arp_ip_targets
.length
== 0) {
101 return _('You must select at least one ARP IP target if ARP monitoring is selected!');
107 function validate_primary_interface(section
, value
) {
109 var opt
= this.map
.lookupOption('bonding_policy', section
);
110 var selected_policy
= opt
[0].formvalue(section
);
112 var opt
= this.map
.lookupOption('slaves', section
);
113 var selected_slaves
= opt
[0].formvalue(section
);
115 var opt
= this.map
.lookupOption('primary', section
);
116 var selected_primary
= opt
[0].formvalue(section
);
118 if (selected_policy
== 'active-backup' || selected_policy
== 'balance-tlb' || selected_policy
== 'balance-alb') {
119 if (selected_slaves
.filter(function(slave
) { return slave
== selected_primary
}).length
== 0)
120 return _('You must select a primary interface which is included in selected slave interfaces!');
126 return network
.registerProtocol('bonding', {
127 getI18n: function() {
128 return _('Link Aggregation (Channel Bonding)');
131 getIfname: function() {
135 getOpkgPackage: function() {
139 isFloating: function() {
143 isCreateable: function(ifname
) {
144 return getSelectableSlaves(ifname
).then(L
.bind(function(devices
) {
145 return devices
.length
== 0 ? _('No more slaves available') : null;
148 return _('No more slaves available');
151 isVirtual: function() {
155 getDevices: function() {
159 containsDevice: function(ifname
) {
160 return (network
.getIfnameOf(ifname
) == this.getIfname());
163 renderFormOptions: function(s
) {
166 o
= s
.taboption('general', form
.Value
, 'ipaddr',
168 _('The local IPv4 address'));
169 o
.datatype
= 'ip4addr';
173 o
= s
.taboption('general', form
.Value
, 'netmask',
175 _('The local IPv4 netmask'));
176 o
.datatype
= 'ip4addr';
178 o
.validate
= validate_netmask_empty
;
180 o
.value("255.255.255.0");
181 o
.value("255.255.0.0");
182 o
.value("255.0.0.0");
184 o
= s
.taboption('advanced', form
.MultiValue
, 'slaves',
185 _('Slave Interfaces'),
186 _('Specifies which slave interfaces should be attached to this bonding interface'));
187 o
.load = function(section_id
) {
188 return getSelectableSlaves(section_id
).then(L
.bind(function(devices
) {
189 for (var i
= 0; i
< devices
.length
; i
++) {
190 this.value(devices
[i
], devices
[i
]);
193 if (devices
.length
== 0) {
194 this.placeholder
= _('No more slaves available, can not save interface');
199 return uci
.get('network', section_id
, 'slaves');
202 o
.validate
= updatePrimaries
;
205 o
= s
.taboption('advanced', form
.ListValue
, 'bonding_policy',
207 _('Specifies the mode to be used for this bonding interface'));
208 o
.default = 'balance-rr';
209 o
.value('balance-rr', _('Round-Robin policy (balance-rr, 0)'));
210 o
.value('active-backup', _('Active-Backup policy (active-backup, 1)'));
211 o
.value('balance-xor', _('XOR policy (balance-xor, 2)'));
212 o
.value('broadcast', _('Broadcast policy (broadcast, 3)'));
213 o
.value('802.3ad', _('IEEE 802.3ad Dynamic link aggregation (802.3ad, 4)'));
214 o
.value('balance-tlb', _('Adaptive transmit load balancing (balance-tlb, 5)'));
215 o
.value('balance-alb', _('Adaptive load balancing (balance-alb, 6)'));
217 o
= s
.taboption('advanced', widgets
.DeviceSelect
, 'primary',
219 _('Specifies which slave is the primary device. It will always be the active slave while it is available'));
220 o
.depends('bonding_policy', 'active-backup');
221 o
.depends('bonding_policy', 'balance-tlb');
222 o
.depends('bonding_policy', 'balance-alb');
223 o
.filter = function(section_id
, value
) {
224 // Never return anything as valid, as the valid possibilities
225 // will be set in the slaves validate function
228 o
.validate
= validate_primary_interface
;
230 o
= s
.taboption('advanced', form
.ListValue
, 'primary_reselect',
231 _('Reselection policy for primary slave'),
232 _('Specifies the reselection policy for the primary slave when failure of the active slave or recovery of the primary slave occurs'));
233 o
.default = 'always';
234 o
.value('always', _('Primary becomes active slave whenever it comes back up (always, 0)'));
235 o
.value('better', _('Primary becomes active slave when it comes back up if speed and duplex better than current slave (better, 1)'));
236 o
.value('failure', _('Only if current active slave fails and the primary slave is up (failure, 2)'));
237 o
.depends('bonding_policy', 'active-backup');
238 o
.depends('bonding_policy', 'balance-tlb');
239 o
.depends('bonding_policy', 'balance-alb');
241 o
= s
.taboption('advanced', form
.Value
, 'min_links',
242 _('Minimum Number of Links'),
243 _('Specifies the minimum number of links that must be active before asserting carrier'));
244 o
.datatype
= 'uinteger';
247 o
.depends('bonding_policy', '802.3ad');
249 o
= s
.taboption('advanced', form
.Value
, 'ad_actor_sys_prio',
250 _('System Priority'),
251 _('Specifies the system priority'));
252 o
.datatype
= 'range(1,65535)';
255 o
.depends('bonding_policy', '802.3ad');
257 o
= s
.taboption('advanced', form
.Value
, 'ad_actor_system',
258 _('MAC Address For The Actor'),
259 _("Specifies the mac-address for the actor in protocol packet exchanges (LACPDUs). If empty, masters' mac address defaults to system default"));
260 o
.datatype
= 'macaddr';
262 o
.depends('bonding_policy', '802.3ad');
264 o
= s
.taboption('advanced', form
.ListValue
, 'ad_select',
265 _('Aggregation Selection Logic'),
266 _('Specifies the aggregation selection logic to use'));
267 o
.default = 'stable';
268 o
.value('stable', _('Aggregator: All slaves down or has no slaves (stable, 0)'));
269 o
.value('bandwidth', _('Aggregator: Slave added/removed or state changes (bandwidth, 1)'));
270 o
.value('count', _('Aggregator: Chosen by the largest number of ports + slave added/removed or state changes (count, 2)'));
271 o
.depends('bonding_policy', '802.3ad');
273 o
= s
.taboption('advanced', form
.ListValue
, 'lacp_rate',
275 _('Specifies the rate in which the link partner will be asked to transmit LACPDU packets'));
277 o
.value('slow', _('Every 30 seconds (slow, 0)'));
278 o
.value('fast', _('Every second (fast, 1)'));
279 o
.depends('bonding_policy', '802.3ad');
281 o
= s
.taboption('advanced', form
.Value
, 'packets_per_slave',
282 _('Packets To Transmit Before Moving To Next Slave'),
283 _("Specifies the number of packets to transmit through a slave before moving to the next one"));
284 o
.datatype
= 'range(0,65535)';
287 o
.depends('bonding_policy', 'balance-rr');
289 o
= s
.taboption('advanced', form
.Value
, 'lp_interval',
290 _('Interval For Sending Learning Packets'),
291 _("Specifies the number of seconds between instances where the bonding driver sends learning packets to each slaves peer switch"));
292 o
.datatype
= 'range(1,2147483647)';
295 o
.depends('bonding_policy', 'balance-tlb');
296 o
.depends('bonding_policy', 'balance-alb');
298 o
= s
.taboption('advanced', form
.ListValue
, 'tlb_dynamic_lb',
299 _('Enable Dynamic Shuffling Of Flows'),
300 _('Specifies whether to shuffle active flows across slaves based on the load'));
302 o
.value('1', _('Yes'));
303 o
.value('0', _('No'));
304 o
.depends('bonding_policy', 'balance-tlb');
306 o
= s
.taboption('advanced', form
.ListValue
, 'fail_over_mac',
307 _('Set same MAC Address to all slaves'),
308 _('Specifies whether active-backup mode should set all slaves to the same MAC address at enslavement'));
310 o
.value('none', _('Yes (none, 0)'));
311 o
.value('active', _('Set to currently active slave (active, 1)'));
312 o
.value('follow', _('Set to first slave added to the bond (follow, 2)'));
313 o
.depends('bonding_policy', 'active-backup');
315 o
= s
.taboption('advanced', form
.Value
, 'num_grat_arp__num_unsol_na',
316 _('Number of peer notifications after failover event'),
317 _("Specifies the number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements) to be issued after a failover event"));
318 o
.datatype
= 'range(0,255)';
321 o
.depends('bonding_policy', 'active-backup');
323 o
= s
.taboption('advanced', form
.ListValue
, 'xmit_hash_policy',
324 _('Transmit Hash Policy'),
325 _('Selects the transmit hash policy to use for slave selection'));
326 o
.default = 'layer2';
327 o
.value('layer2', _('Use XOR of hardware MAC addresses (layer2)'));
328 o
.value('layer2+3', _('Use XOR of hardware MAC addresses and IP addresses (layer2+3)'));
329 o
.value('layer3+4', _('Use upper layer protocol information (layer3+4)'));
330 o
.value('encap2+3', _('Use XOR of hardware MAC addresses and IP addresses, rely on skb_flow_dissect (encap2+3)'));
331 o
.value('encap3+4', _('Use upper layer protocol information, rely on skb_flow_dissect (encap3+4)'));
332 o
.depends('bonding_policy', 'balance-xor');
333 o
.depends('bonding_policy', 'balance-alb');
334 o
.depends('bonding_policy', 'balance-tlb');
335 o
.depends('bonding_policy', '802.3ad');
337 o
= s
.taboption('advanced', form
.Value
, 'resend_igmp',
338 _('Number of IGMP membership reports'),
339 _("Specifies the number of IGMP membership reports to be issued after a failover event in 200ms intervals"));
340 o
.datatype
= 'range(0,255)';
343 o
.depends('bonding_policy', 'balance-tlb');
344 o
.depends('bonding_policy', 'balance-alb');
346 o
= s
.taboption('advanced', form
.ListValue
, 'all_slaves_active',
347 _('Drop Duplicate Frames'),
348 _('Specifies that duplicate frames (received on inactive ports) should be dropped or delivered'));
350 o
.value('0', _('Yes'));
351 o
.value('1', _('No'));
353 o
= s
.taboption('advanced', form
.ListValue
, 'link_monitoring',
354 _('Link Monitoring'),
355 _('Method of link monitoring'));
357 o
.value('off', _('Off'));
358 o
.value('arp', _('ARP'));
359 o
.value('mii', _('MII'));
360 o
.validate
= validate_arp_policy
;
362 o
= s
.taboption('advanced', form
.Value
, 'arp_interval',
364 _("Specifies the ARP link monitoring frequency in milliseconds"));
365 o
.datatype
= 'uinteger';
368 o
.depends('link_monitoring', 'arp');
370 o
= s
.taboption('advanced', form
.DynamicList
, 'arp_ip_target',
372 _('Specifies the IP addresses to use for ARP monitoring'));
373 o
.datatype
= 'ipaddr';
375 o
.depends('link_monitoring', 'arp');
376 o
.validate
= validate_arp_ip_targets
;
378 o
= s
.taboption('advanced', form
.ListValue
, 'arp_all_targets',
379 _('ARP mode to consider a slave as being up'),
380 _('Specifies the quantity of ARP IP targets that must be reachable'));
382 o
.value('any', _('Consider the slave up when any ARP IP target is reachable (any, 0)'));
383 o
.value('all', _('Consider the slave up when all ARP IP targets are reachable (all, 1)'));
384 o
.depends({link_monitoring
: 'arp', bonding_policy
: 'active-backup'});
386 o
= s
.taboption('advanced', form
.ListValue
, 'arp_validate',
388 _('Specifies whether ARP probes and replies should be validated or non-ARP traffic should be filtered for link monitoring'));
389 o
.default = 'filter';
390 o
.value('none', _('No validation or filtering'));
391 o
.value('active', _('Validation only for active slave'));
392 o
.value('backup', _('Validation only for backup slaves'));
393 o
.value('all', _('Validation for all slaves'));
394 o
.value('filter', _('Filtering for all slaves, no validation'));
395 o
.value('filter_active', _('Filtering for all slaves, validation only for active slave'));
396 o
.value('filter_backup', _('Filtering for all slaves, validation only for backup slaves'));
397 o
.depends('link_monitoring', 'arp');
399 o
= s
.taboption('advanced', form
.Value
, 'miimon',
401 _("Specifies the MII link monitoring frequency in milliseconds"));
402 o
.datatype
= 'uinteger';
405 o
.depends('link_monitoring', 'mii');
407 o
= s
.taboption('advanced', form
.Value
, 'downdelay',
409 _("Specifies the time in milliseconds to wait before disabling a slave after a link failure detection"));
410 o
.datatype
= 'uinteger';
413 o
.depends('link_monitoring', 'mii');
415 o
= s
.taboption('advanced', form
.Value
, 'updelay',
417 _("Specifies the time in milliseconds to wait before enabling a slave after a link recovery detection"));
418 o
.datatype
= 'uinteger';
421 o
.depends('link_monitoring', 'mii');
423 o
= s
.taboption('advanced', form
.ListValue
, 'use_carrier',
424 _('Method to determine link status'),
425 _('Specifies whether or not miimon should use MII or ETHTOOL ioctls vs. netif_carrier_ok()'));
427 o
.value('0', _('MII / ETHTOOL ioctls'));
428 o
.value('1', _('netif_carrier_ok()'));
429 o
.depends('link_monitoring', 'mii');