| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | package l2topology |
| 4 | |
| 5 | import "fmt" |
| 6 | |
| 7 | const ( |
| 8 | fdbStatusLearned = "learned" |
| 9 | fdbStatusSelf = "self" |
| 10 | fdbStatusIgnored = "ignored" |
| 11 | ) |
| 12 | |
| 13 | // BuildL2ResultFromObservations converts normalized L2 observations into a |
| 14 | // deterministic engine result. Callers that need a stable timestamp should set |
| 15 | // DiscoverOptions.CollectedAt explicitly. |
| 16 | func BuildL2ResultFromObservations(observations []L2Observation, opts DiscoverOptions) (Result, error) { |
| 17 | if len(observations) == 0 { |
| 18 | return Result{}, fmt.Errorf("%w: at least one observation is required", ErrInvalidRequest) |
| 19 | } |
| 20 | if !opts.EnableLLDP && !opts.EnableCDP && !opts.EnableBridge && !opts.EnableARP && !opts.EnableSTP { |
| 21 | opts.EnableLLDP = true |
| 22 | opts.EnableCDP = true |
| 23 | } |
| 24 | |
| 25 | state := newL2BuildState(len(observations)) |
| 26 | if err := state.registerObservations(observations); err != nil { |
| 27 | return Result{}, err |
| 28 | } |
| 29 | if opts.EnableLLDP { |
| 30 | state.applyLLDP(observations) |
| 31 | } |
| 32 | if opts.EnableCDP { |
| 33 | state.applyCDP(observations) |
| 34 | } |
| 35 | if opts.EnableSTP { |
| 36 | state.applySTP(observations) |
| 37 | } |
| 38 | if opts.EnableBridge { |
| 39 | state.applyBridge(observations) |
| 40 | } |
| 41 | if opts.EnableARP { |
| 42 | state.applyARP(observations) |
| 43 | } |
| 44 | |
| 45 | identityAliasStats := reconcileDeviceIdentityAliases(state.devices, state.interfaces, state.enrichments) |
| 46 | state.markManagedDevices() |
| 47 | |
| 48 | return state.buildResult(identityAliasStats, opts.CollectedAt), nil |
| 49 | } |