};
function to_mask(bits, v6) {
- let m = [];
+ let m = [], n = false;
- if (bits < 0 || bits > (v6 ? 128 : 32))
+ if (bits < 0) {
+ n = true;
+ bits = -bits;
+ }
+
+ if (bits > (v6 ? 128 : 32))
return null;
for (let i = 0; i < (v6 ? 16 : 4); i++) {
let b = (bits < 8) ? bits : 8;
- m[i] = (0xff << (8 - b)) & 0xff;
+ m[i] = (n ? ~(0xff << (8 - b)) : (0xff << (8 - b))) & 0xff;
bits -= b;
}
switch (t) {
case 'ipv4_addr':
- fields[i] = `ip ${dir}saddr`;
+ fields[i] = `ip ${dir}addr`;
break;
case 'ipv6_addr':
- fields[i] = `ip6 ${dir}saddr`;
+ fields[i] = `ip6 ${dir}addr`;
break;
case 'ether_addr':
return fields;
}
-function determine_device_type(devname) {
- let uevent = fs.open(`/sys/class/net/${devname}/uevent`),
- devtype = null;
-
- if (uevent) {
- let line;
-
- while ((line = uevent.read('line')) != null) {
- let m = match(line, /^DEVTYPE=(\w+)/);
-
- if (m) {
- devtype = m[1];
- break;
- }
- }
-
- uevent.close();
- }
+function resolve_lower_devices(devstatus, devname, require_hwoffload) {
+ let dir = fs.opendir(`/sys/class/net/${devname}`);
+ let devs = [];
- return devtype;
-}
-
-function resolve_lower_devices(devname) {
- switch (determine_device_type(devname)) {
- case null:
- return [];
-
- case 'vlan':
- case 'bridge':
- let dir = fs.opendir(`/sys/class/net/${devname}`);
- let lower = [];
-
- if (dir) {
+ if (dir) {
+ switch (devstatus[devname]?.devtype) {
+ case 'vlan':
+ case 'bridge':
let e;
while ((e = dir.read()) != null)
if (index(e, "lower_") === 0)
- push(lower, ...resolve_lower_devices(substr(e, 6)));
+ push(devs, ...resolve_lower_devices(devstatus, substr(e, 6), require_hwoffload));
- dir.close();
- }
+ break;
- return lower;
+ default:
+ if (!require_hwoffload || devstatus[devname]?.["hw-tc-offload"])
+ push(devs, devname);
- default:
- return [ devname ];
+ break;
+ }
+
+ dir.close();
}
+
+ return devs;
}
function nft_json_command(...args) {
},
resolve_offload_devices: function() {
+ if (!this.default_option("flow_offloading"))
+ return [];
+
+ let devstatus = null;
let devices = [];
+ let bus = ubus.connect();
+
+ if (bus) {
+ devstatus = bus.call("network.device", "status") || {};
+ bus.disconnect();
+ }
- if (this.default_option("flow_offloading")) {
+ if (this.default_option("flow_offloading_hw")) {
for (let zone in this.zones())
for (let device in zone.related_physdevs)
- push(devices, ...resolve_lower_devices(device));
+ push(devices, ...resolve_lower_devices(devstatus, device, true));
- if (length(devices)) {
- devices = sort(uniq(devices));
+ devices = sort(uniq(devices));
- if (this.default_option("flow_offloading_hw") && !nft_try_hw_offload(devices)) {
- this.warn('Hardware flow offloading unavailable, falling back to software offloading');
- this.state.defaults.flow_offloading_hw = false;
- }
- }
+ if (length(devices) && nft_try_hw_offload(devices))
+ return devices;
+
+ this.warn('Hardware flow offloading unavailable, falling back to software offloading');
+ this.state.defaults.flow_offloading_hw = false;
+
+ devices = [];
}
- return devices;
+ for (let zone in this.zones())
+ for (let device in zone.related_physdevs)
+ push(devices, ...resolve_lower_devices(devstatus, device, false));
+
+ return sort(uniq(devices));
},
check_set_types: function() {
return null;
m = to_mask(b, length(a) == 16);
+ b = max(-1, b);
}
return [{
},
parse_date: function(val) {
- let m = match(val, /^([0-9-]+)T([0-9:]+)$/);
- let d = m ? match(m[1], /^([0-9]{1,4})(-([0-9]{1,2})(-([0-9]{1,2}))?)?$/) : null;
- let t = this.parse_time(m[2]);
-
- d[3] ||= 1;
- d[5] ||= 1;
+ let d = match(val, /^([0-9]{4})(-([0-9]{1,2})(-([0-9]{1,2})(T([0-9:]+))?)?)?$/);
- if (d == null || d[1] < 1970 || d[1] > 2038 || d[3] < 1 || d[3] > 12 || d[5] < 1 || d[5] > 31)
+ if (d == null || d[1] < 1970 || d[1] > 2038 || d[3] > 12 || d[5] > 31)
return null;
- if (m[2] && !t)
+ let t = this.parse_time(d[7] ?? "0");
+
+ if (t == null)
return null;
return {
year: +d[1],
- month: +d[3],
- day: +d[5],
- hour: t ? +t[1] : 0,
- min: t ? +t[3] : 0,
- sec: t ? +t[5] : 0
+ month: +d[3] || 1,
+ day: +d[5] || 1,
+ ...t
};
},
case 'ipv6_addr':
ip = filter(this.parse_subnet(values[i]), a => (a.family == 6));
- switch(length(ip)) {
+ switch (length(ip) ?? 0) {
case 0: return null;
case 1: break;
case 2: this.warn("Set entry '%s' resolves to multiple addresses, using first one", values[i]);
return sprintf('"%04d-%02d-%02d"', stamp.year, stamp.month, stamp.day);
},
+ datestamp: function(stamp) {
+ return exists(stamp, 'hour') ? this.datetime(stamp) : this.date(stamp);
+ },
+
time: function(stamp) {
return sprintf('"%02d:%02d:%02d"', stamp.hour, stamp.min, stamp.sec);
},
this.warn_section(data, "is disabled, ignoring section");
return;
}
- else if (zone.helper && !zone.helper.available) {
- this.warn_section(data, `uses unavailable ct helper '${zone.helper.name}', ignoring section`);
- return;
+
+ for (let helper in zone.helper) {
+ if (!helper.available) {
+ this.warn_section(data, `uses unavailable ct helper '${zone.helper.name}'`);
+ }
}
if (zone.mtu_fix && this.kernel < 0x040a0000) {
push(related_ubus_networks, { invert: false, device: name });
}
- for (let e in [ ...to_array(zone.network), ...related_ubus_networks ]) {
+ zone.network = [ ...to_array(zone.network), ...related_ubus_networks ];
+
+ for (let e in zone.network) {
if (exists(this.state.networks, e.device)) {
let net = this.state.networks[e.device];