Skip to content

Commit aa01330

Browse files
committed
[nxos] Include LLDP adjacencies in Interface GetStatus
Retrieve LLDP neighbor information while fetching interface status. As of now, this is only performed on physical interfaces with the use case of cabling validation in mind. The GetStatus response now includes a slice of adjacencies with a subset of the Cisco model for NXOS [1]. [1] https://pubhub.devnetcloud.com/media/dme-docs-10-4-3/docs/Discovery%20Protocols/lldp%3AAdjEp/
1 parent b87564c commit aa01330

3 files changed

Lines changed: 84 additions & 7 deletions

File tree

internal/provider/cisco/nxos/lldp.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,27 @@ func (*LLDPOper) IsListItem() {}
4141
func (*LLDPOper) XPath() string {
4242
return "System/fm-items/lldp-items"
4343
}
44+
45+
// LLDPAdjacencyItems represents the LLDP neighbor information for a single interface.
46+
type LLDPAdjacencyItems struct {
47+
// ID is the identifier of the interface for which the LLDP neighbor information is being retrieved, e.g., "eth1/1".
48+
ID string `json:"-"`
49+
AdjItems struct {
50+
AdjEpList []struct {
51+
ChassisIdT uint8 `json:"chassisIdT"`
52+
ChassisIdV string `json:"chassisIdV"`
53+
PortIdT uint8 `json:"portIdT"`
54+
PortIdV string `json:"portIdV"`
55+
PortDesc string `json:"portDesc,omitempty"`
56+
SysName string `json:"sysName,omitempty"`
57+
SysDesc string `json:"sysDesc,omitempty"`
58+
TTL int32 `json:"ttl"`
59+
} `json:"AdjEp-list,omitzero"`
60+
} `json:"adj-items,omitzero"`
61+
}
62+
63+
func (p *LLDPAdjacencyItems) XPath() string {
64+
return "System/lldp-items/inst-items/if-items/If-list[id=" + p.ID + "]"
65+
}
66+
67+
func (*LLDPAdjacencyItems) IsListItem() {}

internal/provider/cisco/nxos/lldp_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33

44
package nxos
55

6+
import (
7+
"testing"
8+
)
9+
610
func init() {
711
lldp := &LLDP{
812
HoldTime: NewOption(uint16(200)),
@@ -22,3 +26,32 @@ func init() {
2226

2327
Register("lldp", lldp)
2428
}
29+
30+
func TestLLDPAdjacencyItems_XPath(t *testing.T) {
31+
tests := []struct {
32+
name string
33+
id string
34+
want string
35+
}{
36+
{
37+
name: "ethernet interface 1/1",
38+
id: "eth1/1",
39+
want: "System/lldp-items/inst-items/if-items/If-list[id=eth1/1]",
40+
},
41+
{
42+
name: "ethernet interface 1/48",
43+
id: "eth1/48",
44+
want: "System/lldp-items/inst-items/if-items/If-list[id=eth1/48]",
45+
},
46+
}
47+
48+
for _, tt := range tests {
49+
t.Run(tt.name, func(t *testing.T) {
50+
adj := &LLDPAdjacencyItems{ID: tt.id}
51+
got := adj.XPath()
52+
if got != tt.want {
53+
t.Errorf("LLDPAdjacencyItems.XPath() = %v, want %v", got, tt.want)
54+
}
55+
})
56+
}
57+
}

internal/provider/cisco/nxos/provider.go

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,18 +1138,35 @@ func (p *Provider) GetInterfaceStatus(ctx context.Context, req *provider.Interfa
11381138
}
11391139

11401140
var (
1141-
operSt OperSt
1142-
operMsg string
1141+
operSt OperSt
1142+
operMsg string
1143+
lldpAdjacencies []provider.LLDPAdjacency
11431144
)
11441145
switch req.Interface.Spec.Type {
11451146
case v1alpha1.InterfaceTypePhysical:
11461147
phys := new(PhysIfOperItems)
11471148
phys.ID = name
1148-
if err := p.client.GetState(ctx, phys); err != nil && !errors.Is(err, gnmiext.ErrNil) {
1149+
lldpAdj := new(LLDPAdjacencyItems)
1150+
lldpAdj.ID = name
1151+
if err := p.client.GetState(ctx, phys, lldpAdj); err != nil && !errors.Is(err, gnmiext.ErrNil) {
11491152
return provider.InterfaceStatus{}, err
11501153
}
11511154
operSt = phys.OperSt
11521155

1156+
for _, adj := range lldpAdj.AdjItems.AdjEpList {
1157+
neighbor := provider.LLDPAdjacency{
1158+
ChassisID: adj.ChassisIdV,
1159+
ChassisIDType: adj.ChassisIdT,
1160+
PortID: adj.PortIdV,
1161+
PortIDType: adj.PortIdT,
1162+
PortDescription: adj.PortDesc,
1163+
SysName: adj.SysName,
1164+
SysDescription: adj.SysDesc,
1165+
TTL: uint32(adj.TTL), // #nosec G115
1166+
}
1167+
lldpAdjacencies = append(lldpAdjacencies, neighbor)
1168+
}
1169+
11531170
case v1alpha1.InterfaceTypeLoopback:
11541171
lb := new(LoopbackOperItems)
11551172
lb.ID = name
@@ -1179,10 +1196,13 @@ func (p *Provider) GetInterfaceStatus(ctx context.Context, req *provider.Interfa
11791196
return provider.InterfaceStatus{}, fmt.Errorf("unsupported interface type: %s", req.Interface.Spec.Type)
11801197
}
11811198

1182-
return provider.InterfaceStatus{
1183-
OperStatus: operSt == OperStUp,
1184-
OperMessage: operMsg,
1185-
}, nil
1199+
status := provider.InterfaceStatus{
1200+
OperStatus: operSt == OperStUp,
1201+
OperMessage: operMsg,
1202+
LLDPAdjacencies: lldpAdjacencies,
1203+
}
1204+
1205+
return status, nil
11861206
}
11871207

11881208
var ErrInterfaceNotFound = errors.New("one or more interfaces do not exist")

0 commit comments

Comments
 (0)