Skip to content

Commit 1cadee0

Browse files
committed
[NXOS] LLDP provider implementation
* Enables/disables LLDP feature and configures global and per-interface settings on Cisco NX-OS switches.
1 parent 5427955 commit 1cadee0

11 files changed

Lines changed: 612 additions & 5 deletions

File tree

cmd/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ import (
4040
_ "github.com/ironcore-dev/network-operator/internal/provider/cisco/nxos"
4141
_ "github.com/ironcore-dev/network-operator/internal/provider/openconfig"
4242

43+
// Import provider-specific config validators.
44+
_ "github.com/ironcore-dev/network-operator/internal/providerconfig/cisco/nx"
45+
4346
nxv1alpha1 "github.com/ironcore-dev/network-operator/api/cisco/nx/v1alpha1"
4447
"github.com/ironcore-dev/network-operator/api/core/v1alpha1"
4548
nxcontroller "github.com/ironcore-dev/network-operator/internal/controller/cisco/nx"

docs/api-reference/index.md

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ SPDX-License-Identifier: Apache-2.0
2424
- [EVPNInstance](#evpninstance)
2525
- [ISIS](#isis)
2626
- [Interface](#interface)
27+
- [LLDP](#lldp)
2728
- [ManagementAccess](#managementaccess)
2829
- [NTP](#ntp)
2930
- [NetworkVirtualizationEdge](#networkvirtualizationedge)
@@ -136,6 +137,8 @@ _Appears in:_
136137
- [DNSSpec](#dnsspec)
137138
- [ISISSpec](#isisspec)
138139
- [InterfaceSpec](#interfacespec)
140+
- [LLDPInterface](#lldpinterface)
141+
- [LLDPSpec](#lldpspec)
139142
- [NTPSpec](#ntpspec)
140143
- [NetworkVirtualizationEdgeSpec](#networkvirtualizationedgespec)
141144
- [OSPFSpec](#ospfspec)
@@ -1367,6 +1370,59 @@ _Appears in:_
13671370
| `Passive` | LACPModePassive indicates that LACP is in passive mode.<br /> |
13681371

13691372

1373+
#### LLDP
1374+
1375+
1376+
1377+
LLDP is the Schema for the lldps API
1378+
1379+
1380+
1381+
1382+
1383+
| Field | Description | Default | Validation |
1384+
| --- | --- | --- | --- |
1385+
| `apiVersion` _string_ | `networking.metal.ironcore.dev/v1alpha1` | | |
1386+
| `kind` _string_ | `LLDP` | | |
1387+
| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | |
1388+
| `spec` _[LLDPSpec](#lldpspec)_ | | | Required: \{\} <br /> |
1389+
| `status` _[LLDPStatus](#lldpstatus)_ | | | Optional: \{\} <br /> |
1390+
1391+
1392+
#### LLDPSpec
1393+
1394+
1395+
1396+
LLDPSpec defines the desired state of LLDP
1397+
1398+
1399+
1400+
_Appears in:_
1401+
- [LLDP](#lldp)
1402+
1403+
| Field | Description | Default | Validation |
1404+
| --- | --- | --- | --- |
1405+
| `deviceRef` _[LocalObjectReference](#localobjectreference)_ | DeviceName is the name of the Device this object belongs to. The Device object must exist in the same namespace.<br />Immutable. | | Required: \{\} <br /> |
1406+
| `providerConfigRef` _[TypedLocalObjectReference](#typedlocalobjectreference)_ | ProviderConfigRef is a reference to a resource holding the provider-specific configuration for this LLDP.<br />If not specified the provider applies the target platform's default settings. | | Optional: \{\} <br /> |
1407+
| `adminState` _[AdminState](#adminstate)_ | AdminState indicates whether LLDP is system-wide administratively up or down. | | Enum: [Up Down] <br />Required: \{\} <br /> |
1408+
1409+
1410+
#### LLDPStatus
1411+
1412+
1413+
1414+
LLDPStatus defines the observed state of LLDP.
1415+
1416+
1417+
1418+
_Appears in:_
1419+
- [LLDP](#lldp)
1420+
1421+
| Field | Description | Default | Validation |
1422+
| --- | --- | --- | --- |
1423+
| `conditions` _[Condition](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#condition-v1-meta) array_ | conditions represent the current state of the LLDP resource.<br />Each condition has a unique type and reflects the status of a specific aspect of the resource.<br />Standard condition types include:<br />- "Available": the resource is fully functional<br />- "Progressing": the resource is being created or updated<br />- "Degraded": the resource failed to reach or maintain its desired state<br />The status of each condition is one of True, False, or Unknown. | | Optional: \{\} <br /> |
1424+
1425+
13701426
#### LocalObjectReference
13711427

13721428

@@ -1395,6 +1451,8 @@ _Appears in:_
13951451
- [InterfaceSpec](#interfacespec)
13961452
- [InterfaceStatus](#interfacestatus)
13971453
- [KeepAlive](#keepalive)
1454+
- [LLDPInterface](#lldpinterface)
1455+
- [LLDPSpec](#lldpspec)
13981456
- [ManagementAccessSpec](#managementaccessspec)
13991457
- [NTPSpec](#ntpspec)
14001458
- [NetworkVirtualizationEdgeSpec](#networkvirtualizationedgespec)
@@ -2717,6 +2775,7 @@ _Appears in:_
27172775
- [EVPNInstanceSpec](#evpninstancespec)
27182776
- [ISISSpec](#isisspec)
27192777
- [InterfaceSpec](#interfacespec)
2778+
- [LLDPSpec](#lldpspec)
27202779
- [ManagementAccessSpec](#managementaccessspec)
27212780
- [NTPSpec](#ntpspec)
27222781
- [NetworkVirtualizationEdgeSpec](#networkvirtualizationedgespec)
@@ -2931,6 +2990,7 @@ Package v1alpha1 contains API Schema definitions for the nx.cisco.networking.met
29312990
### Resource Types
29322991
- [BorderGateway](#bordergateway)
29332992
- [InterfaceConfig](#interfaceconfig)
2993+
- [LLDPConfig](#lldpconfig)
29342994
- [ManagementAccessConfig](#managementaccessconfig)
29352995
- [NetworkVirtualizationEdgeConfig](#networkvirtualizationedgeconfig)
29362996
- [System](#system)
@@ -3186,7 +3246,62 @@ _Appears in:_
31863246
| --- | --- | --- | --- |
31873247
| `destination` _string_ | Destination is the destination IP address of the vPC's domain peer keepalive interface.<br />This is the IP address the local switch will send keepalive messages to. | | Format: ipv4 <br />Required: \{\} <br /> |
31883248
| `source` _string_ | Source is the source IP address for keepalive messages.<br />This is the local IP address used to send keepalive packets to the peer. | | Format: ipv4 <br />Required: \{\} <br /> |
3189-
| `vrfRef` _[LocalObjectReference](#localobjectreference)_ | VRFRef is an optional reference to a VRF resource, e.g., the management VRF.<br />If specified, the switch sends keepalive packets throughout this VRF.<br />If omitted, the management VRF is used. | | Optional: \{\} <br /> |
3249+
| `vrfName` _string_ | The name of the vrf used to send keepalive packets to the peer.<br />Mutually exclusive with VrfRef. | | MaxLength: 63 <br />MinLength: 1 <br />Optional: \{\} <br /> |
3250+
| `vrfRef` _[LocalObjectReference](#localobjectreference)_ | The reference to a VRF resource used to send keepalive packets to the peer.<br />Mutually exclusive with VrfName. | | Optional: \{\} <br /> |
3251+
3252+
3253+
#### LLDPConfig
3254+
3255+
3256+
3257+
LLDPConfig is the Schema for the LLDPConfig API
3258+
3259+
3260+
3261+
3262+
3263+
| Field | Description | Default | Validation |
3264+
| --- | --- | --- | --- |
3265+
| `apiVersion` _string_ | `nx.cisco.networking.metal.ironcore.dev/v1alpha1` | | |
3266+
| `kind` _string_ | `LLDPConfig` | | |
3267+
| `metadata` _[ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#objectmeta-v1-meta)_ | Refer to Kubernetes API documentation for fields of `metadata`. | | |
3268+
| `spec` _[LLDPConfigSpec](#lldpconfigspec)_ | spec defines the desired state of LLDP | | Required: \{\} <br /> |
3269+
3270+
3271+
#### LLDPConfigSpec
3272+
3273+
3274+
3275+
LLDPConfig defines the Cisco-specific configuration of an LLDP object.
3276+
3277+
3278+
3279+
_Appears in:_
3280+
- [LLDPConfig](#lldpconfig)
3281+
3282+
| Field | Description | Default | Validation |
3283+
| --- | --- | --- | --- |
3284+
| `initDelay` _integer_ | InitDelay defines the delay in seconds before LLDP starts sending packets after interface comes up. | 2 | Maximum: 10 <br />Minimum: 1 <br />Optional: \{\} <br /> |
3285+
| `holdTime` _integer_ | HoldTime defines the time in seconds that the receiving device should hold the LLDP information before discarding it. | 120 | Maximum: 255 <br />Minimum: 1 <br />Optional: \{\} <br /> |
3286+
| `interfaceRefs` _[LLDPInterface](#lldpinterface) array_ | InterfaceRefs is a list of interfaces and their LLDP configuration. | | Optional: \{\} <br /> |
3287+
3288+
3289+
#### LLDPInterface
3290+
3291+
3292+
3293+
3294+
3295+
3296+
3297+
_Appears in:_
3298+
- [LLDPConfigSpec](#lldpconfigspec)
3299+
3300+
| Field | Description | Default | Validation |
3301+
| --- | --- | --- | --- |
3302+
| `name` _string_ | Name of the referent.<br />More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names | | MaxLength: 63 <br />MinLength: 1 <br />Required: \{\} <br /> |
3303+
| `adminRxState` _[AdminState](#adminstate)_ | AdminRxState defines the administrative state for receiving LLDP PDUs on the interface. | Up | Enum: [Up Down] <br />Optional: \{\} <br /> |
3304+
| `adminTxState` _[AdminState](#adminstate)_ | AdminTxState defines the administrative state for transmitting LLDP PDUs on the interface. | Up | Enum: [Up Down] <br />Optional: \{\} <br /> |
31903305

31913306

31923307
#### ManagementAccessConfig

internal/controller/core/lldp_controller.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/ironcore-dev/network-operator/internal/conditions"
3535
"github.com/ironcore-dev/network-operator/internal/deviceutil"
3636
"github.com/ironcore-dev/network-operator/internal/provider"
37+
"github.com/ironcore-dev/network-operator/internal/providerconfig"
3738
"github.com/ironcore-dev/network-operator/internal/resourcelock"
3839
)
3940

@@ -201,6 +202,8 @@ type lldpScope struct {
201202
Provider provider.LLDPProvider
202203
// ProviderConfig is the resource referenced by LLDP.Spec.ProviderConfigRef, if any.
203204
ProviderConfig *provider.ProviderConfig
205+
// ProviderConfigScope is the scope with the resources referenced in ProviderConfig, if applicable.
206+
ProviderConfigScope *providerconfig.Scope
204207
}
205208

206209
func (r *LLDPReconciler) reconcile(ctx context.Context, s *lldpScope) (_ ctrl.Result, reterr error) {
@@ -240,9 +243,17 @@ func (r *LLDPReconciler) reconcile(ctx context.Context, s *lldpScope) (_ ctrl.Re
240243
}()
241244

242245
// Ensure the LLDP is realized on the remote device.
246+
// Convert providerconfig.Scope to provider.ProviderConfigScope.
247+
// These are separate types to decouple the validation layer (which uses k8s client)
248+
// from the provider layer (which should not depend on k8s client).
249+
var providerScope *provider.ProviderConfigScope
250+
if s.ProviderConfigScope != nil {
251+
providerScope = provider.NewProviderConfigScope(s.ProviderConfigScope.Raw())
252+
}
243253
err = s.Provider.EnsureLLDP(ctx, &provider.LLDPRequest{
244-
LLDP: s.LLDP,
245-
ProviderConfig: s.ProviderConfig,
254+
LLDP: s.LLDP,
255+
ProviderConfig: s.ProviderConfig,
256+
ProviderConfigScope: providerScope,
246257
})
247258

248259
cond := conditions.FromError(err)
@@ -321,6 +332,24 @@ func (r *LLDPReconciler) validateProviderConfigRef(ctx context.Context, s *lldpS
321332
return nil, reconcile.TerminalError(fmt.Errorf("unsupported ProviderConfigRef Kind %q on this provider", gv))
322333
}
323334

335+
// if a provider-specific validator is registered, use it
336+
if validator, ok := providerconfig.GetValidator(gvk); ok {
337+
reader := r.APIReader
338+
if reader == nil {
339+
// fall back to the cached client if APIReader is not set
340+
reader = r.Client
341+
}
342+
s.ProviderConfigScope, err = validator(ctx, reader, s.LLDP, s.LLDP.Spec.ProviderConfigRef)
343+
if err != nil {
344+
conditions.Set(s.LLDP, metav1.Condition{
345+
Type: v1alpha1.ConfiguredCondition,
346+
Status: metav1.ConditionFalse,
347+
Reason: v1alpha1.IncompatibleProviderConfigRef,
348+
Message: fmt.Sprintf("ProviderConfigRef validation failed: %v", err),
349+
})
350+
return nil, reconcile.TerminalError(fmt.Errorf("configuration error in provider config ref %w", err))
351+
}
352+
}
324353
return cfg, nil
325354
}
326355

0 commit comments

Comments
 (0)