Files
infix/src/webui/internal/handlers/lldp.go
T
Joachim Wiberg d07c8a9b5e webui: styling and cleanup
Vendor a Lucide icon set under static/img/icons/ and partial:ize the
inline SVGs across base, login, firmware, sidebar, and yang-tree.

Reorganize the sidebar with mirrored Status/Configure section labels.
Rename NACM to Users & Groups and Firmware to Software; swap Routes and
Routing between Status and Configure.

Split Configure > System into General, NTP Client, and DNS Client pages,
which opens up for relocating the Set Time RPC from the Maintenance
section to a new Date & Time card in the System General config page.

Update browser tab title on htmx navigation via an HX-Trigger
setPageTitle event; encode the payload as 7-bit ASCII so the middle
dot in "Page · Context" survives header transit.

Add missing hover-help ⓘ icons to bridge port configuration, and adjust
their alignment slightly.  While in interface configuration:
 - fix the annoying Save => collapse so one can edit multiple
   interface sections without having to re-expand the iface
 - add missing dhcpv4 settings
 - add missing custom mac (use advanced view for other settings)
 - clean up Save button mess (consolidate)

Rename Firmware -> Software everywhere in the Maintenance section and
fix "Install progress stuck at 10%" issue.

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
2026-06-15 19:45:21 +02:00

133 lines
4.2 KiB
Go

// SPDX-License-Identifier: MIT
package handlers
import (
"context"
"encoding/json"
"html/template"
"log"
"net/http"
"strings"
"infix/webui/internal/restconf"
)
// ─── LLDP types ──────────────────────────────────────────────────────────────
// LLDPNeighbor is a remote system seen via LLDP.
type LLDPNeighbor struct {
LocalPort string
ChassisID string
SystemName string
PortID string
PortDesc string
SystemDesc string
Capabilities string // comma-separated
MgmtAddress string
}
// ─── Page data ───────────────────────────────────────────────────────────────
type lldpPageData struct {
PageData
Neighbors []LLDPNeighbor
Error string
}
// ─── Handler ─────────────────────────────────────────────────────────────────
// LLDPHandler serves the LLDP neighbors page.
type LLDPHandler struct {
Template *template.Template
RC *restconf.Client
}
// Overview renders the LLDP page (GET /lldp).
func (h *LLDPHandler) Overview(w http.ResponseWriter, r *http.Request) {
data := lldpPageData{
PageData: newPageData(w, r, "lldp", "LLDP"),
}
ctx := context.WithoutCancel(r.Context())
var raw struct {
LLDP struct {
Port []struct {
Name string `json:"name"`
DestMACAddress string `json:"dest-mac-address"`
RemoteSystemsData []struct {
ChassisID string `json:"chassis-id"`
PortID string `json:"port-id"`
PortDesc string `json:"port-desc"`
SystemName string `json:"system-name"`
SystemDescription string `json:"system-description"`
SystemCapabilitiesEnabled json.RawMessage `json:"system-capabilities-enabled"`
ManagementAddress []struct {
Address string `json:"address"`
} `json:"management-address"`
} `json:"remote-systems-data"`
} `json:"port"`
} `json:"ieee802-dot1ab-lldp:lldp"`
}
if err := h.RC.Get(ctx, "/data/ieee802-dot1ab-lldp:lldp", &raw); err != nil {
log.Printf("restconf lldp: %v", err)
data.Error = "Failed to fetch LLDP data"
} else {
for _, port := range raw.LLDP.Port {
for _, rs := range port.RemoteSystemsData {
mgmt := ""
if len(rs.ManagementAddress) > 0 {
mgmt = rs.ManagementAddress[0].Address
}
data.Neighbors = append(data.Neighbors, LLDPNeighbor{
LocalPort: port.Name,
ChassisID: rs.ChassisID,
SystemName: rs.SystemName,
PortID: rs.PortID,
PortDesc: rs.PortDesc,
SystemDesc: rs.SystemDescription,
Capabilities: parseLLDPCapabilities(rs.SystemCapabilitiesEnabled),
MgmtAddress: mgmt,
})
}
}
}
tmplName := "lldp.html"
if r.Header.Get("HX-Request") == "true" {
tmplName = "content"
}
if err := h.Template.ExecuteTemplate(w, tmplName, data); err != nil {
log.Printf("template error: %v", err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
}
}
// ─── Helpers ─────────────────────────────────────────────────────────────────
// parseLLDPCapabilities turns the YANG system-capabilities-enabled bits
// value into a readable comma-separated string.
func parseLLDPCapabilities(raw json.RawMessage) string {
if len(raw) == 0 {
return ""
}
// Try plain string first (some implementations encode as "bridge router")
var s string
if json.Unmarshal(raw, &s) == nil {
parts := strings.Fields(s)
return strings.Join(parts, ", ")
}
// Try array of strings
var arr []string
if json.Unmarshal(raw, &arr) == nil {
return strings.Join(arr, ", ")
}
// Fallback: return raw minus braces
trimmed := strings.TrimSpace(string(raw))
if trimmed == "{}" || trimmed == "null" || trimmed == "[]" {
return ""
}
return trimmed
}