Skip to content

Latest commit

 

History

History
318 lines (273 loc) · 16.6 KB

BaseNetworkModel.md

File metadata and controls

318 lines (273 loc) · 16.6 KB

Base Network Model

The Part 22 runtime publishes provider-supplied network state through the standard Server/Resources/Communication entry points. Applications can expose physical and layered interfaces, priority mappings, Time Sensitive Networking (TSN) streams and Link Layer Discovery Protocol (LLDP) observations without coupling the SDK to an operating-system driver or switch.

ReferenceNetworkModelProvider is an in-memory simulator. Its mapping methods change its own state only; an accepted method call does not configure the host, reserve bandwidth or establish a real TSN stream. Production adapters implement INetworkModelProvider and supply the deployment's acquisition, persistence and network-control behavior.

Host the model

Use the existing Opc.Ua.Server and Opc.Ua.Client packages; no additional network-model package or packet-capture library is required.

using Microsoft.Extensions.DependencyInjection;
using Opc.Ua;
using Opc.Ua.Server.Network;

var provider = new NetworkModelBuilder()
    .AddMappingTable(new NetworkMappingTableSnapshot("default")
    {
        CanEdit = true,
        Entries = []
    })
    .AddInterface(new NetworkInterfaceSnapshot("physical", "eth0")
    {
        AdminStatus = InterfaceAdminStatus.Up,
        OperStatus = InterfaceOperStatus.Up,
        Speed = 1_000_000_000,
        Ethernet = new NetworkEthernetSnapshot(1000, Duplex.Full, 1522),
        MappingTableId = "default"
    })
    .AddInterface(new NetworkInterfaceSnapshot("vlan", "eth0.2")
    {
        AdminStatus = InterfaceAdminStatus.Up,
        OperStatus = InterfaceOperStatus.Up,
        Speed = 1_000_000_000,
        VlanId = 2,
        LowerLayerIds = ["physical"]
    })
    .Build(DateTime.UtcNow, StatusCodes.Good);

services.AddOpcUa()
    .AddServer(options =>
    {
        options.ApplicationName = "NetworkModelServer";
        options.EndpointUrls.Add("opc.tcp://localhost:62588/NetworkModelServer");
    })
    .AddNetworkModel(provider);

Mapping changes are denied by default. Pass an explicit authorizeMappingEdits policy to AddNetworkModel to permit them for the appropriate caller. The server evaluates that policy for each invocation, independently of the table's CanEdit capability. A production policy must check the session's authenticated identity and the application's authorization rules; configuring an editable table does not grant permission.

For direct server construction, register a NetworkModelNodeManagerFactory(provider, authorizeMappingEdits) with StandardServer.AddNodeManager. Both registration paths use the same manager. The manager references the namespace-zero Resources tree rather than creating an application-specific replacement. DiagnosticsNodeManager retains ownership of these entry points, including LLDP's existing local-system and port container nodes; the network manager updates local-system values and attaches provider instances beneath them.

To resolve a deployment provider through dependency injection, register INetworkModelProvider with the application's lifetime and pass services => services.GetRequiredService<INetworkModelProvider>() to AddNetworkModel. The factory runs when the server starts, after its service container is available.

Supply acquisitions and own their lifetime

INetworkModelProvider.ReadAsync returns a coherent acquisition. WatchAsync yields an initial acquisition and subsequent complete revisions; it may coalesce intermediate revisions. EditPriorityMappingAsync reports success only after the provider has accepted the mutation. Providers must serialize acquisition and edits so that an older read cannot overwrite an accepted edit.

The application owns the provider and its persistence. Stop the server before disposing provider-owned drivers or connections. The server cancels its observation on shutdown. The reference provider retains no state across process restart unless the application explicitly saves a snapshot and supplies it to the next instance.

Snapshots use stable application-owned IDs for interfaces, tables, streams, ports and neighbors. IfName becomes the interface BrowseName. Removing an instance from a subsequent acquisition removes its published nodes; clients must rediscover removed instances rather than keeping their old NodeIds. Adding or removing an optional capability preserves retained nodes and their monitored items. Removing a capability deletes only its nodes and references; restoring it does not require clients to recreate monitored items on the interface's unchanged mandatory parameters. Mapping and lower-layer relationships remain browsable in both directions as acquisitions change.

The application or provider is responsible for making StreamId unique within its related TSN network and StreamName unique within the network segment, as required by Part 22 §5.2.7. The SDK reports the supplied identifiers; its snapshot model does not identify the complete network or segment scope, and the server does not allocate these identifiers or enforce global uniqueness across snapshot entries.

The reference provider and server require SR-class identifiers to be unique within each interface and stream-interface identifiers to be unique within each stream. An SR-class ID may recur on another interface, and a stream-interface ID may recur on another stream.

The reference provider copies mutable generated structures and backing arrays on input and output. Each read and watch item carries the current revision. Publish accepts a complete replacement only when its revision matches the provider's current revision; it checks that condition under the same lock used for mapping edits. A publish or accepted edit advances the revision, so an acquisition read before either change cannot replace the resulting state, even when its timestamp is equal or later. A current-revision publish still replaces the complete acquisition rather than merging it. The provider also rejects a timestamp earlier than its current acquisition timestamp. Mapping edits retain that timestamp because they do not represent a new hardware acquisition.

Supply UTC acquisition timestamps and meaningful quality. A failed acquisition must carry a bad status, rather than Good values copied from a healthy default. Snapshot construction requires explicit quality, acquisition time, interface states and speed, and stream state and identity; omitted fields cannot silently become an operational interface or stream. The provider contract covers every optional capability in the supported Part 22 interface, mapping, TSN and LLDP models. Supply each value the acquisition supports; the server publishes it through the standard node or generated structure, and the typed client can read it through the standard proxies. Omit unsupported or unavailable optional values. This includes interface physical addresses and lower-layer relationships, mapping methods, TSN observations and per-interface offsets, and LLDP statistics, local capabilities, port management-address transmit settings and remote-system observations. The model distinguishes IETF interface speed in bit/s from IEEE Ethernet-port speed in Mbit/s. Stream identifiers have eight bytes, MAC-address arrays have six bytes, and traffic intervals have a nonzero denominator.

The server validates each provider acquisition before publishing it. It rejects an initial acquisition or newer revision whose timestamp kind is not UTC with BadInvalidArgument before building entities; stale revisions remain ignored. Present enumeration values must be defined by their OPC UA data type. Interface VLAN identifiers and SR-class VIDs must be in the range 0-4094; SR-class IDs and priorities must be in the range 0-7. A TSN VLAN tag has a separate domain: VlanId may be 0-4095 and PriorityCodePoint may be 0-7. Each priority-mapping entry must have nonblank MappingUri and PriorityLabel values, a PCP value from 0-7 or 255, and a DSCP value from 0-63 or UInt32.MaxValue; the (MappingUri, PriorityLabel) pair must be unique within its table. Part 22 defines the TSN VLAN-tag and mapping-entry value domains in §5.2.14 and §5.3.2.1. The reference provider and server also apply the nonblank-key and per-table uniqueness checks. Repeated SR-class IDs within an interface and repeated stream-interface IDs within a stream reject the acquisition with BadInvalidArgument. An invalid enum or network value rejects the acquisition with BadOutOfRange; an invalid mapping entry also rejects it with BadInvalidArgument. The server retains the previous values and timestamps while marking their quality bad. A later valid acquisition restores the published quality. Unsupported optional values remain absent.

If provider observation throws, the server retains the last values and their acquisition timestamps but publishes bad quality and retries observation. It retains those values internally; a read with Bad quality returns a null payload under the stack's standard DataValue read behavior. Clients must use the status and timestamp to identify unavailable acquisitions rather than expecting the last payload on the wire. The server uses the provider's bad ServiceResultException status, or BadCommunicationError for other exceptions. A newer valid revision restores the acquisition's supplied quality; reconnecting alone does not turn retained data into a new acquisition. The server rejects a higher revision with an older timestamp before changing the address space. If observation ends before cancellation, the server marks retained values BadCommunicationError and starts observation again. An initial read failure also marks the standard LLDP local-system values bad rather than leaving their startup quality unchanged.

Discover and use the typed client

The client borrows its session and subscription. It does not dispose them or replay mapping methods after reconnecting.

using Opc.Ua.Client.Network;

services.AddOpcUa()
    .AddClient(options => options.ApplicationName = "NetworkModelClient")
    .AddNetworkModelClient();

// session is an already-connected, caller-owned ISessionClient.
NetworkModelClient client =
    serviceProvider.GetRequiredService<NetworkModelClientFactory>().Create(session);

ArrayOf<NodeId> interfaces = await client.DiscoverInterfacesAsync(ct);
for (int index = 0; index < interfaces.Count; index++)
{
    NetworkInterfaceValues values = await client.ReadInterfaceAsync(interfaces[index], ct);
    if (StatusCode.IsGood(values.Speed.DataValue.StatusCode) &&
        values.Speed.DataValue.WrappedValue.TryGetValue(out ulong bitsPerSecond))
    {
        Console.WriteLine(bitsPerSecond);
    }

    ArrayOf<NodeId> tables =
        await client.GetEffectiveMappingTablesAsync(interfaces[index], ct);
}

Direct construction uses new NetworkModelClient(session, telemetry) or session.GetNetworkModelClient(telemetry). GetInterface, GetMappingTable and GetLldp return the source-generated standard model proxies.

Discovery matches standard types, vendor subtypes and HasInterface references. It resolves namespace URIs through the connected session, rather than assuming an instance namespace index. Mapping lookup follows HasLowerLayerInterface only when the current interface has no direct UsesPriorityMappingTable reference. A referenced table must expose exactly one HasTypeDefinition derived from PriorityMappingTableType; a missing or unrelated type definition produces BadTypeDefinitionInvalid. Aggregated lower layers can yield several tables; cycles, remote targets and ambiguous direct mappings produce errors. Traversal and browse-result limits bound malformed graphs.

ReadInterfaceAsync, ReadStreamAsync, ReadMappingTableAsync and ReadParametersAsync retain value quality and acquisition timestamps. Check each status before interpreting its payload. Missing mandatory parameters produce BadNotFound; omitted optional parameters produce BadNotSupported. ObserveAsync(variableId, streamingSubscription, ...) forwards data changes through an existing streaming subscription without taking ownership of it.

Mapping results

The table key is the combination of MappingUri and PriorityLabel. AddPriorityMappingEntryAsync and DeletePriorityMappingEntryAsync return the complete CallMethodResult, including input-argument diagnostics. Service-level failures throw ServiceResultException.

Condition Result
Caller rejected by the server policy BadUserAccessDenied
Reference provider rejects an edit to a read-only table BadNotSupported
Duplicate mapping key on add BadIndexRangeInvalid
Missing mapping key on delete BadBrowseNameInvalid
PCP outside 0-7, except sentinel 255 BadInvalidArgument
DSCP outside 0-63, except sentinel UInt32.MaxValue BadInvalidArgument
Unavailable reference-provider acquisition Acquisition's bad status

PCP 255 and DSCP UInt32.MaxValue mean that the field is unused. The standard variable BrowseName is spelled PriorityMapppingEntries; clients and servers retain that spelling for interoperability. The server publishes the optional add/delete methods only for editable tables. An omitted method is not an available configuration operation.

FailureSystemIdentifier uses a Byte matrix with eight columns. When no identifiers exist, the server retains the [0,8] shape in memory and declares the variable's dimensions, but the binary Variant carries an empty Byte array: OPC 10000-6 omits matrix dimensions when any dimension is zero. Nonempty acquisitions carry the matrix dimensions and identifier bytes again.

Run the simulated server/client scenario

dotnet run --project samples\Network\NetworkModelSample -- 62588

The sample starts a local server, connects a separate client over a secured OPC TCP endpoint, and discovers a physical interface and a layered VLAN interface. Both resolve to the physical interface's mapping table. It exercises an unauthorized edit, a permitted edit and an invalid edit, then observes stream configuration, operation, bandwidth failure and recovery through a subscription while an LLDP neighbor appears and disappears. The acquisition also supplies LLDP statistics, local capabilities, management addresses and an unknown TLV.

Its authorization switch is controlled by the local scenario, and its certificate configuration automatically accepts certificates for the local demonstration. Neither is a production authorization or trust policy. The sample stores generated certificates under the process temporary directory and never changes host networking.

Replace ReferenceNetworkModelProvider with an injected INetworkModelProvider implementation to connect an application-owned adapter. The snapshot records and standard wire model do not require a particular driver or switch API.

Specification and implementation coverage

The contract follows OPC 10000-22 version 1.05.04 and the namespace-zero declarations generated from tools/Opc.Ua.SourceGeneration.Core/Design/StandardTypes.xml. The published document names the following conformance units; this list does not invent corresponding profile URIs or establish product certification.

Published conformance units Runtime surface
BNM Entry Points; BNM Mapping Entry Points; BNM TSN Entry Points Standard Resources, Communication, interfaces, tables and stream entry points
BNM IETF Interface Base Info; BNM Ethernet Base Info IETF parameters and distinct IEEE Ethernet-port parameters with engineering units
BNM AutoNeg; BNM VLAN Capabilities; BNM IETF Interface Vlan Info Optional negotiation, VLAN capability and VLAN identity interfaces
BNM TSN Base Info; BNM TSN Config Talker/listener identity, state, traffic, status, MAC/VLAN and interface configuration
BNM Priority Mapping; BNM Priority Mapping2 Mapping references, lower-layer inheritance, entries and authorized table methods
BNM IEEE LLDP Info Local system, ports, remote statistics and neighbors, including optional capabilities, descriptions, management addresses and unknown TLVs

Provider invariants are exercised in ReferenceNetworkModelProviderTests, client service behavior in NetworkModelClientServiceTests, and real connections in NetworkModelIntegrationTests. The sample's deterministic acquisition source is compiled into the integration tests so its topology and transitions are exercised without a physical network dependency.

Production operating-system and switch adapters, physical TSN reservation and packet capture are outside this runtime. Optional MCP and UA Lens integrations are not included.