neighbor improvements

This commit is contained in:
Graham McIntire 2026-01-16 16:25:49 -06:00
parent dcd4588304
commit a7ed057976
No known key found for this signature in database
3 changed files with 60 additions and 39 deletions

View file

@ -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)

View file

@ -5,6 +5,26 @@
active_page="equipment"
>
<div class="mb-6">
<!-- Breadcrumbs -->
<nav class="flex mb-4" aria-label="Breadcrumb">
<ol class="inline-flex items-center space-x-1 text-sm text-zinc-600 dark:text-zinc-400">
<li class="inline-flex items-center">
<.link
navigate={~p"/orgs/#{@current_organization.slug}/sites/#{@equipment.site.id}"}
class="hover:text-zinc-900 dark:hover:text-zinc-200"
>
{@equipment.site.name}
</.link>
</li>
<li aria-current="page">
<div class="flex items-center">
<.icon name="hero-chevron-right" class="h-4 w-4 mx-1" />
<span class="text-zinc-900 dark:text-zinc-100 font-medium">{@equipment.name}</span>
</div>
</li>
</ol>
</nav>
<div class="flex items-center justify-between mb-4">
<div>
<h1 class="text-2xl font-bold text-zinc-900 dark:text-zinc-100">{@equipment.name}</h1>
@ -489,7 +509,7 @@
<thead class="bg-zinc-50 dark:bg-zinc-900">
<tr class="text-xs text-zinc-600 dark:text-zinc-400">
<th class="px-4 py-3 text-left font-medium">Protocol</th>
<th class="px-4 py-3 text-left font-medium">Local Interface</th>
<th class="px-4 py-3 text-left font-medium">Local Port</th>
<th class="px-4 py-3 text-left font-medium">Remote Device</th>
<th class="px-4 py-3 text-left font-medium">Remote Port</th>
<th class="px-4 py-3 text-left font-medium">Platform</th>
@ -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 @@
</.link>
<% else %>
<div class="text-zinc-900 dark:text-zinc-100">
{neighbor.remote_system_name || "Unknown"}
<%= if neighbor.remote_system_name do %>
{neighbor.remote_system_name |> String.split("/") |> List.first()}
<% else %>
Unknown
<% end %>
</div>
<% end %>
</td>
<td class="px-4 py-3">
<%= if neighbor.matched_equipment do %>
<div class="text-zinc-900 dark:text-zinc-100">
{neighbor.remote_system_name || "-"}
<div class="text-zinc-900 dark:text-zinc-100">
{neighbor.remote_port_id || "-"}
</div>
<%= if !neighbor.matched_equipment && neighbor.remote_chassis_id do %>
<div class="text-xs font-mono text-zinc-500 dark:text-zinc-400">
{neighbor.remote_chassis_id}
</div>
<%= if neighbor.remote_port_description do %>
<div class="text-xs text-zinc-500 dark:text-zinc-400">
{neighbor.remote_port_description}
</div>
<% end %>
<% else %>
<div class="text-zinc-900 dark:text-zinc-100">
{neighbor.remote_port_id || "-"}
</div>
<%= if neighbor.remote_chassis_id && neighbor.remote_chassis_id != neighbor.remote_port_id do %>
<div class="text-xs font-mono text-zinc-500 dark:text-zinc-400">
{neighbor.remote_chassis_id}
</div>
<% end %>
<% end %>
</td>
<td class="px-4 py-3 text-xs text-zinc-600 dark:text-zinc-400">

View file

@ -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)