CPU_STRINGS = (
### AMD ###
# APU
+ (r"AMD (Sempron)\(tm\) (\d+) APU with Radeon\(tm\) R\d+", r"AMD \1 \2 APU"),
(r"AMD ([\w\-]+) APU with Radeon\(tm\) HD Graphics", r"AMD \1 APU"),
+ (r"AMD ([\w\-]+) Radeon R\d+, \d+ Compute Cores \d+C\+\d+G", r"AMD \1 APU"),
# Athlon
(r"AMD Athlon.* II X2 ([a-z0-9]+).*", r"AMD Athlon X2 \1"),
(r"AMD Athlon\(tm\) 64 Processor (\w+)", r"AMD Athlon64 \1"),
# Geode
(r"Geode\(TM\) Integrated Processor by AMD PCS", r"AMD Geode"),
(r"(Geode).*", r"\1"),
+ # Mobile
+ (r"Mobile AMD (Athlon|Sempron)\(tm\) Processor (\d+\+?)", r"AMD \1-M \2"),
# Intel
(r"Intel\(R\) (Atom|Celeron).*CPU\s*([A-Z0-9]+) .*", r"Intel \1 \2"),
except KeyError:
return self.data.vendor
+ @property
+ def family(self):
+ return self.data.family
+
@property
def model(self):
return self.data.model
+ @property
+ def stepping(self):
+ return self.data.stepping
+
@property
def model_string(self):
s = self.data.model_string.split()
return flag in self.flags
def uses_ht(self):
+ if self.vendor == "Intel" and self.family == 6 and self.model in (15, 55, 76, 77):
+ return False
+
return self.has_flag("ht")
@property
if location:
self.set_location(location)
+ self.log_profile_update()
+
+ def log_profile_update(self):
+ # Log that an update was performed for this profile id
+ self.db.execute("INSERT INTO fireinfo_profiles_log(public_id) \
+ VALUES(%s)", self.public_id)
+
def expired(self, when=None):
self.db.execute("UPDATE fireinfo_profiles \
SET time_valid = then_or_now(%s) WHERE id = %s", when, self.id)
def appliance_id(self):
if not hasattr(self, "_appliance_id"):
appliances = (
+ ("fountainnetworks-duo-box", self._appliance_test_fountainnetworks_duo_box),
("fountainnetworks-prime", self._appliance_test_fountainnetworks_prime),
+ ("lightningwirelabs-eco-plus", self._appliance_test_lightningwirelabs_eco_plus),
("lightningwirelabs-eco", self._appliance_test_lightningwirelabs_eco),
)
@property
def appliance(self):
- if self.appliance_id == "fountainnetworks-prime":
+ if self.appliance_id == "fountainnetworks-duo-box":
+ return "Fountain Networks - IPFire Duo Box"
+
+ elif self.appliance_id == "fountainnetworks-prime":
return "Fountain Networks - IPFire Prime Box"
+ elif self.appliance_id == "lightningwirelabs-eco-plus":
+ return "Lightning Wire Labs - IPFire Eco Plus Appliance"
+
elif self.appliance_id == "lightningwirelabs-eco":
return "Lightning Wire Labs - IPFire Eco Appliance"
+ def _appliance_test_fountainnetworks_duo_box(self):
+ if not self.processor.vendor == "Intel":
+ return False
+
+ if not self.processor.model_string == "Intel(R) Celeron(R) 2957U @ 1.40GHz":
+ return False
+
+ if not self.count_device("pci", "10ec", "8168") == 2:
+ return False
+
+ # WiFi module
+ if self.count_device("usb", "148f", "5572") < 1:
+ return False
+
+ return True
+
def _appliance_test_fountainnetworks_prime(self):
if not self.system in (("SECO", None), ("SECO", "0949")):
return False
if not network_adapters_count == 4:
return False
- # 4GB of memory
- if not self.memory >= 4230823936 * 0.95:
+ return True
+
+ def _appliance_test_lightningwirelabs_eco_plus(self):
+ if not self.system_vendor == "ASUS":
+ return False
+
+ if not self.system_model.startswith("P9A-I/2550"):
+ return False
+
+ # Must have four Intel network adapters
+ network_adapters_count = self.count_device("pci", "8086", "1f41")
+ if not network_adapters_count == 4:
return False
return True
# Remove the arch bit
if release:
r = [e for e in release.split() if e]
- for s in ("(i586)", "(armv5tel)"):
+ for s in ("(x86_64)", "(i586)", "(armv5tel)"):
try:
r.remove(s)
break
return False
- def can_update_profile(self, public_id, private_id, when=None):
- res = self.db.get("SELECT 1 FROM fireinfo_profiles \
- WHERE public_id = %s AND private_id = %s \
- AND time_updated + INTERVAL '60 minutes' <= then_or_now(%s) \
- AND time_valid >= then_or_now(%s) ORDER BY time_updated DESC LIMIT 1",
- public_id, private_id, when, when)
+ def profile_rate_limit_active(self, public_id, when=None):
+ res = self.db.get("SELECT COUNT(*) AS count FROM fireinfo_profiles_log \
+ WHERE public_id = %s AND ts >= then_or_now(%s) - INTERVAL '60 minutes'",
+ public_id, when)
- if res:
+ if res and res.count >= 10:
return True
return False
+ def is_private_id_change_permitted(self, public_id, private_id, when=None):
+ # Check if a profile exists with a different private id that is still valid
+ res = self.db.get("SELECT 1 FROM fireinfo_profiles \
+ WHERE public_id = %s AND NOT private_id = %s \
+ AND time_valid >= then_or_now(%s) LIMIT 1", public_id, private_id, when)
+
+ if res:
+ return False
+
+ return True
+
def get_profile(self, public_id, private_id=None, when=None):
res = self.db.get("SELECT * FROM fireinfo_profiles \
WHERE public_id = %s AND \
(CASE WHEN %s IS NULL THEN TRUE ELSE private_id = %s END) AND \
- (CASE WHEN %s IS NULL THEN TRUE ELSE \
- then_or_now(%s) BETWEEN time_created AND time_valid END) \
- ORDER BY time_updated DESC LIMIT 1", public_id,
- private_id, private_id, when, when)
+ then_or_now(%s) BETWEEN time_created AND time_valid \
+ ORDER BY time_updated DESC LIMIT 1",
+ public_id, private_id, private_id, when)
+
+ if res:
+ return Profile(self.backend, res.id, res)
+
+ def get_profile_with_data(self, public_id, when=None):
+ res = self.db.get("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id) \
+ SELECT * FROM profiles JOIN fireinfo_profiles ON profiles.id = fireinfo_profiles.id \
+ WHERE public_id = %s ORDER BY time_updated DESC LIMIT 1", when, public_id)
if res:
return Profile(self.backend, res.id, res)
public_id, private_id, when, when, when, valid)
if res:
- return Profile(self.backend, res.id)
+ p = Profile(self.backend, res.id)
+ p.log_profile_update()
+
+ return p
# Devices
profile = self.fireinfo.get_profile(public_id, private_id=private_id, when=when)
# Check if the update can actually be updated
- if profile and not self.fireinfo.can_update_profile(public_id, private_id, when=when):
- logging.warning("Profile not updated because private ID does not"
- " match or last update is too recent: %s" % public_id)
+ if profile and self.fireinfo.profile_rate_limit_active(public_id, when=when):
+ logging.warning("There were too many updates for this profile in the last hour: %s" % public_id)
+ return
+
+ elif not self.is_private_id_change_permitted(public_id, private_id, when=when):
+ logging.warning("Changing private id is not permitted for profile: %s" % public_id)
return
# Parse the profile
MAX(fireinfo_profiles_processors.clock_speed) AS max FROM profiles \
LEFT JOIN fireinfo_profiles_processors ON profiles.id = fireinfo_profiles_processors.profile_id \
WHERE NOT fireinfo_profiles_processors.processor_id IS NULL \
- AND fireinfo_profiles_processors.clock_speed > 0", when)
+ AND fireinfo_profiles_processors.clock_speed > 0 \
+ AND fireinfo_profiles_processors.clock_speed < fireinfo_profiles_processors.bogomips \
+ AND fireinfo_profiles_processors.bogomips <= %s", when, 10000)
if res:
return (res.avg or 0, res.stddev or 0, res.min or 0, res.max or 0)
flags = (
"aes", "avx", "avx2", "lm", "mmx", "mmxext", "nx", "pae",
"pni", "popcnt", "sse", "sse2", "rdrand", "ssse3", "sse4a",
- "sse4_1", "sse4_2"
+ "sse4_1", "sse4_2", "sha", "pclmulqdq", "rdseed",
)
else:
return