diff --git a/lib/towerops/gaiia/device_subscriber_link.ex b/lib/towerops/gaiia/device_subscriber_link.ex index 7678876e..3cf1376f 100644 --- a/lib/towerops/gaiia/device_subscriber_link.ex +++ b/lib/towerops/gaiia/device_subscriber_link.ex @@ -39,7 +39,7 @@ defmodule Towerops.Gaiia.DeviceSubscriberLink do :subscriber_mac ]) |> validate_required([:organization_id, :device_id, :gaiia_account_id, :match_method, :confidence]) - |> validate_inclusion(:match_method, ~w(arp_ip arp_mac subnet site_fallback)) + |> validate_inclusion(:match_method, ~w(wireless_mac wireless_ip arp_ip arp_mac subnet site_fallback)) |> validate_inclusion(:confidence, ~w(high medium low)) |> unique_constraint([:device_id, :gaiia_account_id]) |> foreign_key_constraint(:organization_id) diff --git a/lib/towerops/gaiia/subscriber_matching.ex b/lib/towerops/gaiia/subscriber_matching.ex index 2d98bb27..b156c6c3 100644 --- a/lib/towerops/gaiia/subscriber_matching.ex +++ b/lib/towerops/gaiia/subscriber_matching.ex @@ -69,6 +69,9 @@ defmodule Towerops.Gaiia.SubscriberMatching do # Load all wireless client entries for this org's devices wireless_clients = load_wireless_clients(organization_id) + # Load account lookup once for all phases (performance optimization) + account_lookup = load_account_id_lookup(organization_id) + # Build lookup maps arp_by_ip = Map.new(arp_entries, fn e -> {e.ip_address, e} end) arp_by_mac = Map.new(arp_entries, fn e -> {normalize_mac(e.mac_address), e} end) @@ -76,26 +79,28 @@ defmodule Towerops.Gaiia.SubscriberMatching do wc_by_ip = wireless_clients |> Enum.filter(& &1.ip_address) |> Map.new(fn w -> {w.ip_address, w} end) # Phase 1: Wireless client MAC match (highest confidence) - {wc_mac_matched, wc_mac_links} = match_by_wireless_mac(items, wc_by_mac, organization_id, now) + {wc_mac_matched, wc_mac_links} = match_by_wireless_mac(items, wc_by_mac, account_lookup, organization_id, now) # Phase 2: Wireless client IP match (high confidence) remaining_after_wc_mac = Enum.reject(items, &MapSet.member?(wc_mac_matched, &1.id)) - {wc_ip_matched, wc_ip_links} = match_by_wireless_ip(remaining_after_wc_mac, wc_by_ip, organization_id, now) + + {wc_ip_matched, wc_ip_links} = + match_by_wireless_ip(remaining_after_wc_mac, wc_by_ip, account_lookup, organization_id, now) # Phase 3: ARP IP match (medium confidence) matched_so_far = MapSet.union(wc_mac_matched, wc_ip_matched) remaining_after_wc = Enum.reject(items, &MapSet.member?(matched_so_far, &1.id)) - {ip_matched, ip_links} = match_by_arp_ip(remaining_after_wc, arp_by_ip, organization_id, now) + {ip_matched, ip_links} = match_by_arp_ip(remaining_after_wc, arp_by_ip, account_lookup, organization_id, now) # Phase 4: ARP MAC match (medium confidence) matched_so_far = MapSet.union(matched_so_far, ip_matched) remaining_after_ip = Enum.reject(items, &MapSet.member?(matched_so_far, &1.id)) - {mac_matched, mac_links} = match_by_arp_mac(remaining_after_ip, arp_by_mac, organization_id, now) + {mac_matched, mac_links} = match_by_arp_mac(remaining_after_ip, arp_by_mac, account_lookup, organization_id, now) # Phase 5: Site fallback (low confidence) matched_ids = MapSet.union(matched_so_far, mac_matched) remaining = Enum.reject(items, &MapSet.member?(matched_ids, &1.id)) - site_links = match_by_site_fallback(remaining, organization_id, now) + site_links = match_by_site_fallback(remaining, account_lookup, organization_id, now) all_links = wc_mac_links ++ wc_ip_links ++ ip_links ++ mac_links ++ site_links @@ -259,9 +264,7 @@ defmodule Towerops.Gaiia.SubscriberMatching do |> Map.new() end - defp match_by_wireless_mac(items, wc_by_mac, org_id, now) do - account_lookup = load_account_id_lookup(org_id) - + defp match_by_wireless_mac(items, wc_by_mac, account_lookup, org_id, now) do {matched_ids, links} = Enum.reduce(items, {MapSet.new(), []}, fn item, {matched, acc} -> normalized = normalize_mac(item.mac_address) @@ -292,9 +295,7 @@ defmodule Towerops.Gaiia.SubscriberMatching do {matched_ids, Enum.reverse(links)} end - defp match_by_wireless_ip(items, wc_by_ip, org_id, now) do - account_lookup = load_account_id_lookup(org_id) - + defp match_by_wireless_ip(items, wc_by_ip, account_lookup, org_id, now) do {matched_ids, links} = Enum.reduce(items, {MapSet.new(), []}, fn item, {matched, acc} -> wc = if item.ip_address, do: Map.get(wc_by_ip, item.ip_address) @@ -324,9 +325,7 @@ defmodule Towerops.Gaiia.SubscriberMatching do {matched_ids, Enum.reverse(links)} end - defp match_by_arp_ip(items, arp_by_ip, org_id, now) do - account_lookup = load_account_id_lookup(org_id) - + defp match_by_arp_ip(items, arp_by_ip, account_lookup, org_id, now) do {matched_ids, links} = Enum.reduce(items, {MapSet.new(), []}, fn item, {matched, acc} -> arp = if item.ip_address, do: Map.get(arp_by_ip, item.ip_address) @@ -356,9 +355,7 @@ defmodule Towerops.Gaiia.SubscriberMatching do {matched_ids, Enum.reverse(links)} end - defp match_by_arp_mac(items, arp_by_mac, org_id, now) do - account_lookup = load_account_id_lookup(org_id) - + defp match_by_arp_mac(items, arp_by_mac, account_lookup, org_id, now) do {matched_ids, links} = Enum.reduce(items, {MapSet.new(), []}, fn item, {matched, acc} -> normalized = normalize_mac(item.mac_address) @@ -389,9 +386,7 @@ defmodule Towerops.Gaiia.SubscriberMatching do {matched_ids, Enum.reverse(links)} end - defp match_by_site_fallback(items, org_id, now) do - account_lookup = load_account_id_lookup(org_id) - + defp match_by_site_fallback(items, account_lookup, org_id, now) do # Load network site -> TowerOps site mappings site_mappings = NetworkSite