From a7ed057976cfa1e475758e1729f37aa086dcfdb8 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Fri, 16 Jan 2026 16:25:49 -0600 Subject: [PATCH] neighbor improvements --- lib/towerops/snmp/neighbor_discovery.ex | 26 +++++---- .../live/equipment_live/show.html.heex | 53 ++++++++++++------- .../towerops/snmp/neighbor_discovery_test.exs | 20 +++---- 3 files changed, 60 insertions(+), 39 deletions(-) diff --git a/lib/towerops/snmp/neighbor_discovery.ex b/lib/towerops/snmp/neighbor_discovery.ex index 1e2795c7..c2f96ea5 100644 --- a/lib/towerops/snmp/neighbor_discovery.ex +++ b/lib/towerops/snmp/neighbor_discovery.ex @@ -92,15 +92,16 @@ defmodule Towerops.Snmp.NeighborDiscovery do build_neighbor_record("lldp", neighbor_map, interfaces, neighbor_map[:local_port]) end - defp parse_lldp_field("4", value, _oid, acc), do: Map.put(acc, :remote_chassis_id, format_chassis_id(value)) + # LLDP Remote Table field mappings (LLDP-MIB) + defp parse_lldp_field("5", value, _oid, acc), do: Map.put(acc, :remote_chassis_id, format_chassis_id(value)) - defp parse_lldp_field("5", value, _oid, acc), do: Map.put(acc, :remote_port_id, format_port_id(value)) + defp parse_lldp_field("7", value, _oid, acc), do: Map.put(acc, :remote_port_id, format_port_id(value)) - defp parse_lldp_field("6", value, _oid, acc), do: Map.put(acc, :remote_port_description, to_string_safe(value)) + defp parse_lldp_field("8", value, _oid, acc), do: Map.put(acc, :remote_port_description, to_string_safe(value)) - defp parse_lldp_field("7", value, _oid, acc), do: Map.put(acc, :remote_system_name, to_string_safe(value)) + defp parse_lldp_field("9", value, _oid, acc), do: Map.put(acc, :remote_system_name, to_string_safe(value)) - defp parse_lldp_field("8", value, _oid, acc), do: Map.put(acc, :remote_system_description, to_string_safe(value)) + defp parse_lldp_field("10", value, _oid, acc), do: Map.put(acc, :remote_system_description, to_string_safe(value)) defp parse_lldp_field("12", value, _oid, acc), do: Map.put(acc, :remote_capabilities, parse_lldp_capabilities(value)) @@ -237,10 +238,17 @@ defmodule Towerops.Snmp.NeighborDiscovery do end defp format_chassis_id(value) when is_binary(value) do - value - |> :binary.bin_to_list() - |> Enum.map_join(":", &String.pad_leading(Integer.to_string(&1, 16), 2, "0")) - |> String.downcase() + # LLDP Chassis ID has subtype byte + value + # If it's a printable string (subtype 4 = MAC as text, 7 = local), use it directly + if String.valid?(value) and String.printable?(value) do + String.trim(value) + else + # Otherwise convert binary to hex MAC format + value + |> :binary.bin_to_list() + |> Enum.map_join(":", &String.pad_leading(Integer.to_string(&1, 16), 2, "0")) + |> String.downcase() + end end defp format_chassis_id(value), do: to_string_safe(value) diff --git a/lib/towerops_web/live/equipment_live/show.html.heex b/lib/towerops_web/live/equipment_live/show.html.heex index 0899e850..a9c87cbd 100644 --- a/lib/towerops_web/live/equipment_live/show.html.heex +++ b/lib/towerops_web/live/equipment_live/show.html.heex @@ -5,6 +5,26 @@ active_page="equipment" >
+ + +

{@equipment.name}

@@ -489,7 +509,7 @@ Protocol - Local Interface + Local Port Remote Device Remote Port Platform @@ -518,7 +538,7 @@ <%= if neighbor.matched_equipment do %> <.link navigate={ - ~p"/orgs/#{@equipment.site.organization_id}/equipment/#{neighbor.matched_equipment.id}" + ~p"/orgs/#{@current_organization.slug}/equipment/#{neighbor.matched_equipment.id}" } class="font-medium text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300" > @@ -526,29 +546,22 @@ <% else %>
- {neighbor.remote_system_name || "Unknown"} + <%= if neighbor.remote_system_name do %> + {neighbor.remote_system_name |> String.split("/") |> List.first()} + <% else %> + Unknown + <% end %>
<% end %> - <%= if neighbor.matched_equipment do %> -
- {neighbor.remote_system_name || "-"} +
+ {neighbor.remote_port_id || "-"} +
+ <%= if !neighbor.matched_equipment && neighbor.remote_chassis_id do %> +
+ {neighbor.remote_chassis_id}
- <%= if neighbor.remote_port_description do %> -
- {neighbor.remote_port_description} -
- <% end %> - <% else %> -
- {neighbor.remote_port_id || "-"} -
- <%= if neighbor.remote_chassis_id && neighbor.remote_chassis_id != neighbor.remote_port_id do %> -
- {neighbor.remote_chassis_id} -
- <% end %> <% end %> diff --git a/test/towerops/snmp/neighbor_discovery_test.exs b/test/towerops/snmp/neighbor_discovery_test.exs index dc2868ed..558486d6 100644 --- a/test/towerops/snmp/neighbor_discovery_test.exs +++ b/test/towerops/snmp/neighbor_discovery_test.exs @@ -82,16 +82,16 @@ defmodule Towerops.Snmp.NeighborDiscoveryTest do expect(SnmpMock, :walk, fn _, _, _ -> {:ok, [ - # LLDP remote chassis ID (field 4) for timemark.1.1 - %{oid: "1.0.8802.1.1.2.1.4.1.1.4.0.1.1", value: <<0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF>>}, - # LLDP remote port ID (field 5) - %{oid: "1.0.8802.1.1.2.1.4.1.1.5.0.1.1", value: "Gi0/1"}, - # LLDP remote port description (field 6) - %{oid: "1.0.8802.1.1.2.1.4.1.1.6.0.1.1", value: "GigabitEthernet0/1"}, - # LLDP remote system name (field 7) - %{oid: "1.0.8802.1.1.2.1.4.1.1.7.0.1.1", value: "neighbor-switch"}, - # LLDP remote system description (field 8) - %{oid: "1.0.8802.1.1.2.1.4.1.1.8.0.1.1", value: "Cisco IOS Software"} + # LLDP remote chassis ID (field 5) for timemark.1.1 + %{oid: "1.0.8802.1.1.2.1.4.1.1.5.0.1.1", value: <<0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF>>}, + # LLDP remote port ID (field 7) + %{oid: "1.0.8802.1.1.2.1.4.1.1.7.0.1.1", value: "Gi0/1"}, + # LLDP remote port description (field 8) + %{oid: "1.0.8802.1.1.2.1.4.1.1.8.0.1.1", value: "GigabitEthernet0/1"}, + # LLDP remote system name (field 9) + %{oid: "1.0.8802.1.1.2.1.4.1.1.9.0.1.1", value: "neighbor-switch"}, + # LLDP remote system description (field 10) + %{oid: "1.0.8802.1.1.2.1.4.1.1.10.0.1.1", value: "Cisco IOS Software"} ]} end)