OpenNFS.Client
0.1.0
dotnet add package OpenNFS.Client --version 0.1.0
NuGet\Install-Package OpenNFS.Client -Version 0.1.0
<PackageReference Include="OpenNFS.Client" Version="0.1.0" />
<PackageVersion Include="OpenNFS.Client" Version="0.1.0" />
<PackageReference Include="OpenNFS.Client" />
paket add OpenNFS.Client --version 0.1.0
#r "nuget: OpenNFS.Client, 0.1.0"
#:package OpenNFS.Client@0.1.0
#addin nuget:?package=OpenNFS.Client&version=0.1.0
#tool nuget:?package=OpenNFS.Client&version=0.1.0
OpenNFS
OpenNFS is a native C# implementation effort for ONC RPC and NFS. Current scope, support-bar notes, and release gates are tracked in this README and in docs/release-checklist.md.
Alpha Status
OpenNFS is an ALPHA repository.
- The current package/version line is
v0.1.0, but that is not a stability or support claim. - Public APIs, runtime behavior, interoperability coverage, CI workflows, and documentation are all subject to change without notice.
- Only very limited compatibility testing has been done relative to the eventual support bar. Passing local suites, direct-peer tests, Linux peer checks, or archived subset conformance runs does not imply broad protocol, platform, kernel, or client/server compatibility.
Current status
This repository is in active implementation and remains alpha.
OpenNFS.ServerandOpenNFS.Clientare the intended public packages.- No protocol version is yet claimed as supported on a release branch.
- NFSv3 plus MOUNT v3 is now the first working and testable end-to-end protocol surface in this repository.
- That NFSv3-era surface currently passes direct
OpenNFS.Client -> OpenNFS.Server,OpenNFS.Client -> Sample.OpenNfsServer,OpenNFS.Client -> Linux userspace NFS server,OpenNFS.Client -> Linux kernel NFS server,Linux kernel client -> OpenNFS.Server, andLinux kernel client -> Sample.OpenNfsServervalidation. The currentknfsdclient case combines successful browse and transfer coverage with a missing-entry negative lookup assertion on the same live peer, and the shared recovery suites now also cover dropped-reply reconnect replay plus forced-disconnect variants on the current public client/server path. - NFSv4.0 is now the second working and testable direct-peer protocol surface in this repository.
- That NFSv4.0 surface currently passes direct
OpenNFS.Client -> OpenNFS.Server,OpenNFS.Client -> Sample.OpenNfsServer,OpenNFS.Client -> nfs-ganesha, andOpenNFS.Client -> knfsdvalidation for root discovery, browse/read flows, statefulWRITE/COMMITtransfer, namespace mutation, stateful open/confirm/close, and positive and negative state-handling variants on the current interop harness, including explicit lease-expiry re-registration recovery and stale-state cleanup coverage on the shared raw and grouped suites. - The current NFSv4.0 surface also has working and testable positive and negative lock coverage where the configured host surface exposes locking, delegation grant plus
DELEGRETURNon hosts that exposeINfsDelegations, plusSECINFOdiscovery, owner and owner-group attribute mapping, ACLGETATTR/SETATTR,PUTPUBFH,VERIFY,NVERIFY, and explicit capability-gatedOPENATTR,DELEGPURGE, andRELEASE_LOCKOWNERresults. Those paths are covered with positive and negative raw and grouped validation, with directOpenNFS.Client -> OpenNFS.Servervalidation on the currently host-backed paths. - NFSv4.1 session-management is now in place.
EXCHANGE_ID,CREATE_SESSION,DESTROY_SESSION,BIND_CONN_TO_SESSION, andSEQUENCEhave typed handlers, a wire-level COMPOUND-over-RPC dispatcher (Nfs41CompoundService), an RFC 8881 §18.46.3 slot table with replay caching plus exactly-once handling, and a TCP host (OpenNfsTcpNfs41ServerHost). The public client surface shipsOpenNfsV41ClientSession.EstablishAsync/SendCompoundAsync/TrySendCompoundAsync/ReconnectAsync/DisposeAsyncwith auto-reconnect-and-retry on transport failure, server-owner trunking comparison, partial-success result envelopes (OpenNfsV41CompoundResult.IsFullSuccess/HasPartialResults/ReachedServer), and a typedOpenNfsV41StatusExceptioncarrying nativenfsstat4plus normalizedOpenNfsErrorCategory. The typedOpenNfsV41CallbackHandler+OpenNfsV41CallbackDispatcherplusNfs41CallbackInvokerexercise full bidirectional CB_COMPOUND wire flow (serverCB_RECALL→ client handler → reply round-trip). - NFSv4.2 capability-gated operation surface is now wired at the typed processor level.
INfsSparseandINfsCopyCloneare real host capability contracts withSeekAsync/AllocateAsync/DeallocateAsync/ReadSparseAsyncandCopyAsync/CloneAsync. The typedNfs42SparseFileProcessor,Nfs42CopyCloneProcessor, andNfs42AdvisoryOperationsProcessorroute every advertised v4.2 op in scope (SEEK,ALLOCATE,DEALLOCATE,READ_PLUS,COPY,CLONE,IO_ADVISE,OFFLOAD_CANCEL,OFFLOAD_STATUS,WRITE_SAME,COPY_NOTIFY) to the host capability or surface a standards-compliantNFS4ERR_NOTSUPPwhen the host has not opted in. This is not an NFSv4.2 release-support claim until live peer interop and applicablepynfscoverage pass. - RPCSEC_GSS credential / context / sequence / wrap-unwrap / verifier handling is wired end-to-end through a real Kerberos provider.
OpenNfsKerberosMechanism(inOpenNFS.Rpc/Security/Kerberos/) implementsIRpcSecGssMechanismoverSystem.Net.Security.NegotiateAuthenticationwithPackage = "Kerberos". The repository ships a self-contained Dockerized MIT KDC with three principals and exported keytabs, plus aRun-Probe.ps1runner that exercises the provider end-to-end against the live KDC. The named acceptance Touchstone gatesKrb5ReadWrite,Krb5iDetectsTamper,Krb5pEncryptsPayload,RpcSecGssContextEstablishment,RpcSecGssSequenceWindow, andRpcSecGssIntegrityFailureRejectedall pass. See the RPCSEC_GSS / Kerberos setup section for the full bootstrap. - The repository is multi-targeted
net8.0;net10.0.krb5p(privacy viaWrap/Unwrap) works on both target frameworks.krb5andkrb5i(which needGSS_GetMIC/GSS_VerifyMIC) require thenet10.0build because those APIs land in net10 only. - No protocol version is yet claimed as supported on a release branch.
- Archived real conformance evidence now exists for
pjdfstestNFSv3core, Connectathongeneral,pynfsNFSv4.0, and an initialpynfsNFSv4.1 session-management subset. This is still not a release-support claim: broader optional surfaces such as v3 locking and v4.1 callback scenarios are not yet part of the passing release bar, and the privileged CI / release-branch enforcement path is still administrative rather than code-complete. - Release-readiness automation now includes a formal release checklist, source-level skipped-test enforcement, a repository-honesty validator, vendored conformance harnesses for
pjdfstest, Connectathon, andpynfs, and workflow scaffolding for hosted and privileged interop. The release gate validates fresh non-synthetic conformance manifests, but no protocol version is described as supported until every applicable checklist item is enforced on the release branch with evidence. - The current additive compatibility pass introduces
WithServer(...),ConnectAsync(...)/DisconnectAsync(...),MountAsync(...), explicit MOUNT endpoint configuration for NFSv3, groupedExportshelpers that honor that bootstrap endpoint for export enumeration and mount flows,OpenNfsMountSessionfor path-first mounted-export work, and the server-sideOpenNfsServerBuilder.BuildApplication()/OpenNfsServerApplicationwrapper for the default runnable server journey.ConnectAsync(...)is now explicitly a lifetime-open step rather than an eager reachability probe, and the raw planning/execution entry points remain available as explicitly advanced members in the public API surface. - The primary client path now also has a bounded OpenCIFS-aligned typed error and non-throwing result layer:
TryConnectAsync(...),TryDisconnectAsync(...),TryMountAsync(...), and the newExports.Try...Async(...)bootstrap helpers returnOpenNfsClientResult/OpenNfsClientResult<T>, while the throwing path now surfaces typedOpenNfsClientStateException,OpenNfsClientProtocolException,OpenNfsClientIoException,OpenNfsMountV3StatusException, andOpenNfsV3StatusExceptionfailures with normalizedOpenNfsErrorCategoryvalues. Broader grouped/server parity and NFSv4 partial-success envelopes remain open. - The managed server lifecycle now also has a bounded OpenCIFS-aligned non-throwing layer:
OpenNfsServerApplication.TryRunAsync(...),TryStartAsync(...), andTryStopAsync(...)returnOpenNfsServerResultand preserve typedOpenNfsServerStateExceptionfailures for duplicate starts, bind conflicts, and disposed-application misuse. - The current server surface now also exposes local export introspection consistently across
OpenNfsServerBuilder,OpenNfsServer, andOpenNfsServerApplicationthroughGetExportsAsync(...), which keeps the managed server path closer to the equivalent OpenCIFS local-share snapshot flow without exposing protocol host types. - The current NFSv4.0 path now also has a bounded identity service:
OpenNfsClient.Identityexposes owner/group read and update helpers, andIOpenNfsClientIdentityPolicyplusOpenNfsLinuxStyleIdentityPolicylet consumers normalize server-returned owner strings into local display names without rewriting the underlying wire values. Direct peer and sample-artifact coverage now passes owner/group round-trips and restart persistence on the managed path, and the sharedIdMapSuitesnow also proves real Linux-kernel-mountedstat/chownbehavior againstSample.OpenNfsServer. OpenNFS.Servernow includes a built-in disk-backedUseLocalFileSystem()path, so a consumer can stand up a real export without first implementingINfsFileSystem.OpenNFS.Servernow also exposesOpenNfsServerApplicationas the primary runnable host surface, and the shared suites now validate both direct and clean-package-consumer server startup over real NFSv3 and NFSv4.0 traffic.Sample.OpenNfsServernow also consumes the shippedappsettings.sample.jsonthrough--config, so the documented sample bootstrap path is a real runtime path rather than a stale illustrative file.Sample.OpenNfsServernow has first-class sample acceptance coverage for config-file startup, Linux kernel mount/read/write, denied mounts, persistent filehandle behavior across restart, and direct NFSv4.0 capability validation for ACLs, owner/group mapping, delegations, conflicting locks, and ACL persistence across restart. The Kerberos provider works end-to-end against the test KDC at the GSS level; the remainingSampleServerSuites/KerberosMountgate (Linux kernelmount -o sec=krb5against the sample artifact) needs the sample's MOUNT v3 + NFSv3 dispatchers to validate per-call verifier MICs through the registered mechanism on every RPC, which is the next sample-server integration slice.- The public package story is now validated from clean temp consumer apps, not just from project references inside this repository. Shared client and server surface suites pack both public packages to a local feed, restore them into clean console apps, and execute positive and negative variants outside this solution. That clean-consumer matrix now includes
OpenNFS.Server -> Linux kernel clientandOpenNFS.Client -> Sample.OpenNfsServer,OpenNFS.Client -> knfsd, andOpenNFS.Client -> nfs-ganesha. Both public packages now produce.nupkgand.snupkgartifacts, and both carry the internal runtime implementation assemblies they need instead of depending on non-public NuGet packages. - The repository now also includes
OpenNFS.TestClientandOpenNFS.TestServer: menu-driven console tools for manually exercising the current public client and server surfaces. The client can configure explicitAUTH_SYSmachine, uid, gid, and supplementary group values, list exports, mount an export, browse and mutate files, inspect metadata, and upload or download content. The server can stand up a temporary disk-backed export with configurable ports, export path, read-only mode, and mount-denial behavior so other NFS clients can connect to it directly. - The repository currently provides:
- a buildable multi-project solution under
src/ - package and build governance files under
src/ - a public client configuration, lifetime, low-level raw request-planning and raw v3 request-execution surface, raw NFSv4 COMPOUND planning and execution surface, grouped convenience API surface, typed NFSv3 and NFSv4.0 file, directory, state/session, lock, ACL, delegation, and security-discovery reply models, typed MOUNT v3 reply decoding helpers, typed NFSv4.0 root-discovery helpers, and grouped NFSv3 plus MOUNT v3 execution paths over TCP with v3-era UDP fallback, with transport policy, primary and alternate endpoints, endpoint selection mode, retry policy, authentication flavor, timeout configuration, cancellation-aware open/close/dispose behavior, explicit ONC RPC program/version binding for v3-era raw calls, validated NFSv3 procedure request/plan/reply models, validated NFSv4 COMPOUND request/plan/reply models, grouped
Directories,Files,Exports,Locks,Sessions, andAdministrationhelpers, typedGETATTR/ACCESS/LOOKUP/READ/READLINK/READDIR/READDIRPLUS/FSSTAT/FSINFO/PATHCONF/WRITE/COMMIT/CREATE/MKDIR/REMOVE/RMDIR/RENAME/SYMLINK/LINKgrouped NFSv3 helpers, typed NFSv4.0PUTROOTFH/GETATTR/ACCESS/LOOKUP/LOOKUPP/SECINFO/READ/WRITE/COMMIT/READLINK/READDIR/CREATE/REMOVE/RENAME/LINK/ACL grouped helpers, caller-selected NFSv4.0 groupedGETATTRrequests for owner, owner-group, ACL, and ACL-support attribute mapping, typed NFSv4.0SETCLIENTID/SETCLIENTID_CONFIRM/OPEN/OPEN_CONFIRM/OPEN_DOWNGRADE/RENEW/CLOSE/LOCKT/LOCK/LOCKU/DELEGRETURNgrouped helpers and reply models, typed NLM v4TEST/LOCK/CANCEL/UNLOCKgrouped lock helpers and reply models, grouped NLM v4 execution over the real TCP NLM listener, executable NFSv3/MOUNT v3/NLM v4NULLprobes on the grouped administrative surface, typedMNT/EXPORT/DUMPMOUNT v3 decode models plusUMNT/UMNTALLreply validation, and idempotency-aware retry, timeout, and reply-validation infrastructure for current grouped and raw v3 plus raw v4 client execution, alongside a public server construction surface withOpenNfsServer,OpenNfsServerBuilder, direct export configuration, a mandatoryINfsFileSystemhost contract, and capability-composed optional host seams - an additive compatibility-oriented client layer with
WithServer(...)builder aliases, optionalWithMountEndpoint(...)/WithMountPort(...)NFSv3 bootstrap configuration,ConnectAsync(...)/DisconnectAsync(...)lifecycle aliases,MountAsync(...),TryConnectAsync(...),TryDisconnectAsync(...),TryMountAsync(...), export bootstrapTry...Asynchelpers returningOpenNfsClientResult/OpenNfsClientResult<T>, typedOpenNfsClientExceptionsubclasses for state, protocol, transport, MOUNT v3, and NFSv3 path failures, a groupedIdentityhelper with pluggableIOpenNfsClientIdentityPolicymapping for the current NFSv4.0 owner and owner-group surface, and export-scopedOpenNfsMountSessionpath-firstFiles,Directories, andMetadatahelpers over the current NFSv3 mounted-export flow while the exact raw and handle-based APIs remain available as explicitly advanced members - public server-side filehandle contracts with intrinsic and persistent mapping providers, including host-supplied stable identities for rename-safe mappings, a public
OpenNfsServerApplicationwrapper surfaced throughOpenNfsServerBuilder.BuildApplication()for the default runnable host journey, a public mount-authorization seam for host-driven export filtering and mount allow/deny decisions, a built-inLocalNfsFileSystembackend surfaced throughOpenNfsServerBuilder.UseLocalFileSystem(), and a runnable sample provider that now exercises the currently advertised optional host seams for ACLs, id mapping, delegations, and locking over a real disk-backed export - typed request and response context models for every current host-facing server operation, covering export discovery, path-info resolution, child lookup, directory enumeration, file reads, symbolic-link reads, file writes, file commit, path create/delete/rename, symbolic-link create, hard-link create, filehandle create/resolve, and protocol-neutral lock flows
- vendored RFC/XDR source material under
specs/xdr/, including extracted RPC and NFSv4.xinputs plus normalizednfs3.x,mount3.x,nlm3.x,nlm4.x, andnsm.x - an
OpenNFS.XdrGentool that validates the XDR generation manifest, parses vendored.xentry points into AST documents with contextual errors, regenerates checked-inGenerated/*.g.csmodel and codec files for the internal RPC and protocol projects, and verifies output drift in--checkmode - low-level
OpenNFS.Rpc.Xdrreader and writer primitives for scalar values, opaque and string payloads, arrays, discriminated unions, bounded decode failures, and generated-code integration support OpenNFS.Rpc.RpcMessagesandOpenNFS.Rpc.RecordMarkinghelpers for ONC RPC call/reply envelopes,AUTH_NONEandAUTH_SYScontainers, accepted and rejected reply shaping, and RFC 5531 record-marking encode/decodeOpenNFS.Rpc.Transportabstractions for stream-backed TCP framing, datagram-backed UDP flows, transport timeouts, and explicit v3-era UDP policy gatingOpenNFS.Rpc.RpcBindprimitives for in-memory portmap v2 and rpcbind v3/v4 registration, lookup, unregister, and RPC envelope dispatch flows over the generated corpusOpenNFS.Rpc.Replayprimitives for expiring reply caches and deterministic request-correlation keysOpenNFS.Protocol.V3core procedure metadata, the first NFSv3 server dispatcher foundation, a dispatcher-level duplicate-request cache for retry-safe v3 replay, filesystem-backed handlers forGETATTR,LOOKUP,ACCESS,READ,READLINK,WRITE,CREATE,MKDIR,SYMLINK,REMOVE,RMDIR,RENAME,LINK,COMMIT,READDIR,READDIRPLUS,FSSTAT,FSINFO, andPATHCONF, plus explicit standards-compliant rejection paths forSETATTRandMKNODwhile the corresponding host seams remain unimplemented, the first MOUNT v3 server-side dispatcher forMNT,DUMP,UMNT,UMNTALL, andEXPORT, the first NLM v4 server-side dispatcher for synchronousTEST/LOCK/CANCEL/UNLOCKplus fire-and-forget message/result procedure handling over the public locking seam, and the first NSM server-side dispatcher forSM_STAT,SM_MON,SM_UNMON,SM_UNMON_ALL,SM_SIMU_CRASH, andSM_NOTIFY, including blocked-waiter tracking, unlock-triggered wakeup, in-process granted-callback dispatch, NSM monitor and callback registration state, simulated restart state transitions, grace-period gating for NLM reclaim flows, transport-aware requester identity for replay correlation, and reusable TCP host listeners for MOUNT v3, NFSv3, NLM v4, and NSM, alongside validated export lookup, root filehandle issuance, in-memory mount tracking, host-driven export filtering and mount authorization, deterministic synthetic metadata, real child-path, directory-enumeration, byte-range read, symbolic-link target read, byte-range write, symbolic-link creation, hard-link creation over the current host seam, cross-directory rename and replacement flows, reboot-sensitive per-server write verifiers, requestedUNSTABLE/DATA_SYNC/FILE_SYNCwrite handling, weak cache consistency timestamp and size reporting, cookie-verifier and resumable-directory-read handling, stale-handle, blocked-lock, denied-lock, grace-period, duplicate-replay, and unknown-entry mapping, RPCGARBAGE_ARGShandling, malformedAUTH_SYSrejection, and explicitPROC_UNAVAILpaths forSETATTR,MKNOD,SHARE,UNSHARE,FREE_ALL, and other non-core work that remains outside the current implementation surfaceOpenNFS.Protocol.V40the first NFSv4.0 COMPOUND server foundation, including minor-version mismatch handling, current and saved filehandle state,OP_ILLEGALshaping, partial attribute encoding forSUPPORTED_ATTRS/TYPE/CHANGE/SIZE/FILEHANDLEplus owner and owner-group identity strings when the host exposes id mapping and ACL plus ACL-support attribute handling when the host exposesINfsAcls, the current namespace plus mutation slice over the public host contracts (PUTROOTFH,PUTPUBFH,PUTFH,SAVEFH,RESTOREFH,GETFH,GETATTR,SETATTRfor ACL replacement,ACCESS,VERIFY,NVERIFY,LOOKUP,LOOKUPP,SECINFO,READ,READDIR,READLINK,CREATEfor directory and symbolic-link objects,LINK,RENAME, and genericREMOVE), explicit capability-gatedOPENATTR,DELEGPURGE, andRELEASE_LOCKOWNERresponses for the current advertised feature set, the first in-memory stateful-open slice withSETCLIENTID,SETCLIENTID_CONFIRM,OPEN,OPEN_CONFIRM,OPEN_DOWNGRADE,RENEW, andCLOSE, the first stateful transfer slice withWRITEandCOMMITvalidated against open and lock stateids with reboot-sensitive write verifiers, the first byte-range locking plus simulated grace-period reclaim slice withLOCKT,LOCK,LOCKU,CLAIM_PREVIOUSreclaim open, reclaim-awareLOCK, clientid confirmation, lease refresh, share reservations, open-owner and lock-owner seqids, lock-owner tables,GRACE/NO_GRACE/RECLAIM_BADhandling, and stateid tracking, plus the first delegation slice with host-backed grant, conflict-driven recall notification,NFS4ERR_DELAYconflict shaping, andDELEGRETURN, alongside a reusable TCPOpenNfsTcpNfs40ServerHostfor the current NFSv4.0 wire surfaceOpenNFS.Serverexport-resolution validation over the public host contracts, including static and provider-backed export composition, host-driven mount authorization and export visibility decisions, stable capability discovery for locking, ACLs, delegations, copy/clone, sparse files, and identity mapping, a protocol-neutralINfsLockingrequest/response seam for advisory byte-range locks, typed host operation contexts, plus default and persistent filehandle policy surfaces- a runnable
Sample.OpenNfsServerartifact that seeds a minimal export tree by default, serves the current TCP MOUNT v3, NFSv3, and NFSv4.0 surfaces through the publicOpenNfsServerApplicationwrapper over the internal protocol hosts, supports persistent filehandle mappings, persistent ACL state, configurable owner and owner-group identity mapping, the current delegation and locking baseline, consumes the shipped config file through--configwith config-relative source and state paths, and can be exercised by bothOpenNFS.Clientand real Linux clients in the shared interop suite - Touchstone runners and shared suite descriptors for baseline repository, XDR runtime, RPC envelope and record-marking behavior, transport framing and timeout behavior, rpcbind and portmap registration flows, replay-cache behavior, NFSv3 duplicate-request replay behavior, generated model round-trips, parser, generated-output validation, filehandle persistence behavior, server operation-context cancellation behavior, the first NFSv3 procedure-catalog, dispatcher, metadata-handler, directory-enumeration, MOUNT v3 server foundation, the full currently advertised NFSv4.0 COMPOUND core-operation binding surface, the first NFSv4.0 stateful-open foundation, the first NFSv4.0 grouped write and stateful transfer foundation, the first NFSv4.0 locking and grace-period reclaim foundation, the first NFSv4.0 security-discovery, identity-attribute, ACL, and delegation foundation, NLM v4 locking foundation, and NSM monitor/restart-recovery coverage, including explicit positive and negative duplicate-write replay, blocking-wakeup, granted-callback, NSM monitor/notify, restart-reclaim, NFSv4.0 raw COMPOUND execution, raw NFSv4.0 advanced core-op fidelity, raw NFSv4.0 lock and reclaim cases, raw
SECINFO, owner/owner_group, ACL attribute, and delegation recall cases, NFSv4.0 grouped read-only client cases, NFSv4.0 grouped mutation client cases, NFSv4.0 grouped stateful-open client cases, NFSv4.0 grouped write client cases, NFSv4.0 grouped lock client cases, NFSv4.0 grouped recovery client cases, NFSv4.0 grouped security-discovery, identity-mapping, ACL, and delegation client cases, and real TCP NLM-listener execution coverage, host-driven mount authorization/filtering, plus client configuration, lifetime, raw request-planning, raw v3 execution, raw v4 execution, grouped convenience API, typed NFSv3 and NFSv4.0 file, directory, stateful, lock, reclaim, ACL, delegation, and security-discovery decode and execution, typed MOUNT v3 reply decoding, typed grouped NLM v4 lock execution and decode, grouped MOUNT v3 execution with v3-era UDP fallback, internal transport-pipeline behavior, and Docker-backedInteropSuitescoverage that auto-runs when the local Docker daemon is reachable and exercisesOpenNFS.Client -> OpenNFS.Server,OpenNFS.Client -> Sample.OpenNfsServer,OpenNFS.Client -> Linux userspace NFS server,OpenNFS.Client -> Linux kernel NFS server,Linux kernel client -> OpenNFS.Server, andLinux kernel client -> Sample.OpenNfsServerover NFSv3-era flows, plus directOpenNFS.Client -> OpenNFS.Server,OpenNFS.Client -> Sample.OpenNfsServer,OpenNFS.Client -> nfs-ganesha, andOpenNFS.Client -> knfsdvalidation for the current NFSv4.0 browse, mutation, stateful-open, confirm, close, transfer, state-error, public-root, verify, and capability-gated paths, with current host-backed security-discovery coverage and current host-backed delegation grant plus return coverage, and explicit positive and negative variants
- a buildable multi-project solution under
Out of scope:
- pNFS layout protocols, layout advertisement, and data-server flows. OpenNFS does not implement pNFS. There is no plan to add it; this is an explicit non-goal, not a deferral.
- RDMA transport
RDMA remains out of scope for the current release line and may be evaluated as a separate feature line in a later phase. pNFS stays a permanent non-goal: OpenNFS targets server-and-client over standard ONC RPC transports, not the layout-and-data-server split that pNFS introduces.
Repository layout
.
|-- .github/
| `-- workflows/
|-- docs/
|-- scripts/
|-- specs/
| `-- xdr/
|-- src/
| |-- Directory.Build.props
| |-- Directory.Build.targets
| |-- Directory.Packages.props
| |-- OpenNFS.sln
| |-- OpenNFS.Client/
| |-- OpenNFS.Protocol.V3/
| |-- OpenNFS.Protocol.V40/
| |-- OpenNFS.Protocol.V41/
| |-- OpenNFS.Protocol.V42/
| |-- OpenNFS.Rpc/
| |-- OpenNFS.Server/
| |-- OpenNFS.TestClient/
| |-- OpenNFS.TestServer/
| |-- OpenNFS.XdrGen/
| |-- Sample.OpenNfsServer/
| |-- Test.Automated/
| |-- Test.Nunit/
| |-- Test.Shared/
| `-- Test.Xunit/
|-- CHANGELOG.md
|-- LICENSE.md
`-- README.md
Build and validation
dotnet build src/OpenNFS.sln -c Release
powershell -ExecutionPolicy Bypass -File .\scripts\Generate-Xdr.ps1
powershell -ExecutionPolicy Bypass -File .\scripts\Generate-Xdr.ps1 -Check
powershell -ExecutionPolicy Bypass -File .\scripts\release\Assert-NoSkippedTests.ps1
powershell -ExecutionPolicy Bypass -File .\scripts\release\Assert-ReleaseChecklist.ps1
powershell -ExecutionPolicy Bypass -File .\scripts\release\Assert-RepositoryHonesty.ps1
powershell -ExecutionPolicy Bypass -File .\scripts\release\Invoke-ReleaseValidation.ps1 -PlanOnly -IncludePack
dotnet run --project src\Test.Automated\Test.Automated.csproj -- --results artifacts\touchstone-results.json
dotnet run --project src\Test.Automated\Test.Automated.csproj -- --suite IdMapSuites --suite SampleServerSuites --suite InteropSuites --results artifacts\touchstone-targeted.json
dotnet test src\Test.Xunit\Test.Xunit.csproj -c Release
dotnet test src\Test.Nunit\Test.Nunit.csproj -c Release
When the local Docker daemon is reachable, the shared runners also execute the Docker-backed InteropSuites. When Docker is unavailable, those cases are skipped with an explicit reason instead of failing unrelated validation.
Test.Automated is the exhaustive runner. It executes the full shared Touchstone catalog, including Docker-backed interop, packaged-consumer validation, and other heavyweight matrix cases. Test.Xunit and Test.Nunit are now adapter-smoke projects over the unit-tagged subset of that catalog so the same heavy matrix is not rerun three times.
Test.Automated now also accepts repeated --suite <SuiteId> filters for targeted validation when you only need the suites touched by a slice instead of the full matrix.
The formal support-claim gate is tracked in docs/release-checklist.md. The release scripts now validate that checklist, ban explicit skipped-test markers in source, validate that the repo still carries the required no-overclaim disclaimers and no placeholder markers in implementation code, and require fresh non-synthetic conformance manifests for pjdfstest, Connectathon, and pynfs before a support claim can advance.
The shared compatibility coverage also compiles the canonical README client and server snippets against clean packaged consumer apps, while the packaged-consumer and sample/interop suites execute the equivalent runtime flows against real peers.
Interactive test tools
The repo now ships two menu-driven console tools for manual exercise of the current public API surface.
Start the temporary test server:
dotnet run --project src/OpenNFS.TestServer/OpenNFS.TestServer.csproj -c Release
Typical server flow:
startto bind the MOUNT v3, NFSv3, and NFSv4.0 listenersshowto review the bound ports and backing-store pathtree,mkdir,write, anddeleteto manipulate the temporary backing directoryreadonly on|off,denymounts on|off,v3 on|off, andv40 on|offto change the exposed behavior beforestart
Start the menu client:
dotnet run --project src/OpenNFS.TestClient/OpenNFS.TestClient.csproj -c Release
Typical client flow:
server localhost 2049and optionallymountendpoint localhost 20048authsys myhost 501 20 10,11to set the currentAUTH_SYSmachine, uid, gid, and supplementary gidsconnectexportsto enumerate available exportsmount /exports/testls,cd,stat,cat,write,mkdir,rm,rmdir,put, andgetto exercise the mounted-session surface
These tools are for manual integration work and debugging. They are anchored to the best-covered public paths in the repo today: mounted-session NFSv3 for the test client, and the public OpenNfsServerApplication host path for the test server.
Usage examples
These examples are intentionally anchored to the best-covered paths in the repo today: NFSv3 plus MOUNT v3 for full browse/read/write flows, and direct-peer NFSv4.0 for root discovery, namespace, stateful-open, and WRITE/COMMIT transfer flows.
Client example
For NFSv3, many servers expose separate MOUNT and NFS endpoints. The additive happy path now supports that directly on one client: configure the NFS endpoint, optionally configure a dedicated MOUNT endpoint, connect once, and call MountAsync(...) to get an export-scoped OpenNfsMountSession.
ConnectAsync(...) intentionally opens only the client lifetime. It does not perform eager server reachability checks, version negotiation, or mount bootstrap RPCs; those happen when you issue the first real protocol operation.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Text;
using OpenNFS.Client;
CancellationToken cancellationToken = CancellationToken.None;
await using OpenNfsClient client = new OpenNfsClientBuilder()
.WithServer("nfs.example.net", 2049)
.WithMountEndpoint("nfs.example.net", 20048)
.WithAuthSysCredentials("nfs-client", 1001, 1001, new uint[] { 1001, 1002 })
.WithUdpForNfsV3(true)
.Build();
await client.ConnectAsync(cancellationToken);
IReadOnlyList<OpenNfsExportV3Entry> availableExports = await client.Exports.ListExportsV3Async(cancellationToken);
await using OpenNfsMountSession session = await client.MountAsync("/data", cancellationToken);
IReadOnlyList<OpenNfsV3DirectoryEntry> rootEntries = await session.Directories.ListAsync("/", cancellationToken);
byte[] bytes = await session.Files.ReadAllBytesAsync("/docs/readme.txt", cancellationToken);
OpenNfsV3Attributes attributes = await session.Metadata.GetAttributesAsync("/docs/readme.txt", cancellationToken);
await session.Directories.CreateFileAsync("/docs/notes.txt", failIfExists: true, cancellationToken);
await session.Files.WriteAllBytesAsync(
"/docs/notes.txt",
Encoding.UTF8.GetBytes("updated from OpenNFS.Client\n"),
OpenNfsWriteStability.FileSync,
cancellationToken);
await session.Directories.DeleteFileAsync("/docs/notes.txt", cancellationToken);
await client.DisconnectAsync(cancellationToken);
If the server uses the same endpoint for both MOUNT and NFS, omit WithMountEndpoint(...) and MountAsync(...) will reuse the primary endpoint.
If you prefer the aligned non-throwing path for expected bootstrap negatives, the current primary client surface now also exposes bounded Try...Async companions:
using System.Collections.Generic;
using System.Threading;
using OpenNFS.Client;
CancellationToken cancellationToken = CancellationToken.None;
await using OpenNfsClient client = new OpenNfsClientBuilder()
.WithServer("nfs.example.net", 2049)
.WithMountEndpoint("nfs.example.net", 20048)
.Build();
OpenNfsClientResult connectResult = await client.TryConnectAsync(cancellationToken);
connectResult.EnsureSuccess();
OpenNfsClientResult<IReadOnlyList<OpenNfsExportV3Entry>> exportsResult =
await client.Exports.TryListExportsV3Async(cancellationToken);
exportsResult.EnsureSuccess();
OpenNfsClientResult<OpenNfsMountSession> mountResult =
await client.TryMountAsync("/data", cancellationToken);
if (!mountResult.IsSuccess)
{
Console.WriteLine(mountResult.ErrorCategory + ": " + mountResult.Exception?.Message);
return;
}
await using OpenNfsMountSession session = mountResult.GetValueOrThrow();
OpenNfsClientResult disconnectResult = await client.TryDisconnectAsync(cancellationToken);
disconnectResult.EnsureSuccess();
The current mounted-session contract is intentionally narrow and explicit:
- Resolution is scoped to the mounted export root.
- Paths are re-resolved on each operation; there is no local handle cache.
- Same-session create, write, rename, and delete operations are immediately visible through that same session.
- One session is safe for concurrent path operations on the current tested NFSv3 mounted-export path.
- No cross-session coherence guarantee is implied.
- Relative navigation segments such as
.and..are rejected.
NFSv4.0 client example
The current grouped NFSv4.0 surface starts with root discovery rather than a mounted-session wrapper. The example below connects to a dedicated NFSv4.0 listener, resolves an export path from the pseudo-root, checks SECINFO, reads owner and owner-group strings when the server exposes id mapping, reads ACLs when the server exposes ACL capability, reads a file, and performs a minimal stateful open / confirm / WRITE / COMMIT / close cycle. Some peers require the current filehandle to be set explicitly for OPEN_CONFIRM and CLOSE; the handle-aware overloads below are the most interoperable form:
using System;
using System.Text;
using System.Threading;
using OpenNFS.Client;
CancellationToken cancellationToken = CancellationToken.None;
await using OpenNfsClient client = new OpenNfsClientBuilder()
.WithServer("nfs40.example.net", 3049)
.Build();
await client.ConnectAsync(cancellationToken);
OpenNfsV40LookupResult pseudoRoot = await client.Directories.GetRootV40Async(cancellationToken);
OpenNfsV40LookupResult dataDirectory = await client.Directories.LookupV40Async(
pseudoRoot.ObjectFileHandle.ToArray(),
"data",
cancellationToken);
OpenNfsV40SecurityInfoResult securityInfo = await client.Directories.GetSecurityInfoV40Async(
dataDirectory.ObjectFileHandle.ToArray(),
"readme.txt",
cancellationToken);
OpenNfsV40LookupResult readmeFile = await client.Directories.LookupV40Async(
dataDirectory.ObjectFileHandle.ToArray(),
"readme.txt",
cancellationToken);
OpenNfsV40GetAttributesResult identityAttributes = await client.Files.GetAttributesV40Async(
readmeFile.ObjectFileHandle.ToArray(),
new[]
{
OpenNfsV40AttributeKind.Type,
OpenNfsV40AttributeKind.Owner,
OpenNfsV40AttributeKind.OwnerGroup,
},
cancellationToken);
OpenNfsV40GetIdentityResult mappedIdentity = await client.Identity.GetOwnerAndGroupV40Async(
readmeFile.ObjectFileHandle.ToArray(),
cancellationToken);
OpenNfsV40GetAclResult aclResult = await client.Files.GetAclV40Async(
readmeFile.ObjectFileHandle.ToArray(),
cancellationToken);
OpenNfsV40ReadResult readResult = await client.Files.ReadV40Async(
readmeFile.ObjectFileHandle.ToArray(),
0,
4096,
cancellationToken);
byte[] clientVerifier = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
OpenNfsV40SetClientIdResult setClientId = await client.Sessions.SetClientIdV40Async(
"example-client",
clientVerifier,
cancellationToken);
OpenNfsV40SessionResult confirmClientId = await client.Sessions.ConfirmClientIdV40Async(
setClientId.ClientId,
setClientId.ConfirmationVerifier.ToArray(),
cancellationToken);
OpenNfsV40OpenResult openResult = await client.Files.OpenExistingV40Async(
dataDirectory.ObjectFileHandle.ToArray(),
setClientId.ClientId,
"owner-a",
"readme.txt",
OpenNfsV40ShareAccess.Both,
OpenNfsV40ShareDeny.None,
1,
cancellationToken);
OpenNfsV40StateIdResult openConfirm = await client.Files.ConfirmOpenV40Async(
readmeFile.ObjectFileHandle.ToArray(),
openResult.StateId!,
2,
cancellationToken);
OpenNfsV40WriteResult writeResult = await client.Files.WriteV40Async(
readmeFile.ObjectFileHandle.ToArray(),
openConfirm.StateId!,
0,
OpenNfsWriteStability.FileSync,
Encoding.UTF8.GetBytes("updated via NFSv4.0\n"),
cancellationToken);
OpenNfsV40CommitResult commitResult = await client.Files.CommitV40Async(
readmeFile.ObjectFileHandle.ToArray(),
0,
writeResult.Count,
cancellationToken);
OpenNfsV40SetIdentityResult setIdentityResult = await client.Identity.SetOwnerAndGroupV40Async(
readmeFile.ObjectFileHandle.ToArray(),
"docs-owner@example.test",
"docs-group@example.test",
cancellationToken);
OpenNfsV40ReadResult verifyRead = await client.Files.ReadV40Async(
readmeFile.ObjectFileHandle.ToArray(),
0,
4096,
cancellationToken);
OpenNfsV40StateIdResult closeResult = await client.Files.CloseV40Async(
readmeFile.ObjectFileHandle.ToArray(),
openConfirm.StateId!,
3,
cancellationToken);
await client.DisconnectAsync(cancellationToken);
When the host exposes INfsDelegations, OpenExistingV40Async(...) may also populate openResult.Delegation; the current grouped client can release that state with ReturnDelegationV40Async(...), and the shared suites cover the conflicting-open recall path.
When the host exposes INfsIdMapper, client.Identity.GetOwnerAndGroupV40Async(...) and SetOwnerAndGroupV40Async(...) provide a higher-level owner/group surface over the raw attribute bits. By default those helpers preserve the server-returned strings verbatim. If you want Linux-style display names such as alice from server strings such as alice@example.test, configure OpenNfsLinuxStyleIdentityPolicy on the builder.
Server example
The aligned public server journey now lives in OpenNFS.Server itself through BuildApplication() and OpenNfsServerApplication:
using System;
using System.Threading;
using System.Threading.Tasks;
using OpenNFS.Server;
using OpenNFS.Server.FileHandles;
CancellationToken cancellationToken = CancellationToken.None;
await using OpenNfsServerApplication app = new OpenNfsServerBuilder()
.WithServerName("Example OpenNFS Server")
.WithListenerAddress("0.0.0.0")
.UseLocalFileSystem()
.UseFileHandleProvider(new PersistentMappingHandleProvider(@"C:\OpenNfsState\filehandles.json"))
.AddExport("/data", @"D:\Exports\Data")
.BuildApplication(new OpenNfsServerApplicationOptions
{
MountPort = 20048,
NfsPort = 2049,
Nfs40Port = 3049,
});
await app.RunAsync(cancellationToken);
If you need the bound ports before entering the long-running wait, call StartAsync(...) directly and read MountPort, NfsPort, and Nfs40Port from the started OpenNfsServerApplication.
If you prefer the aligned non-throwing managed lifecycle path, OpenNfsServerApplication now also exposes TryRunAsync(...), TryStartAsync(...), and TryStopAsync(...), each returning OpenNfsServerResult.
If you also register UseDelegations(...), the current NFSv4.0 surface can grant delegations, surface recall notifications to the host, and accept DELEGRETURN from clients on the tested path.
OpenNFS.Server now includes LocalNfsFileSystem.cs as a built-in disk-backed backend, and UseLocalFileSystem() is the preferred first setup path for real host-local exports. It already covers browse, read, write, commit, create, delete, rename, and symbolic-link operations against real disk paths on the tested path. For current NFSv3-era mount compatibility, pair it with PersistentMappingHandleProvider.cs so root filehandles stay within the MOUNT v3 wire-size limit and survive restart predictably.
If you need to serve something other than the local filesystem, implement INfsFileSystem.cs directly. The built-in backend is intentionally just the first-class default, not the only hosting model.
Server capability baseline
The current backend contract splits into mandatory and optional pieces:
- Mandatory:
INfsFileSystemor the built-inUseLocalFileSystem()path, plus at least one configured export. - Strongly recommended on the current NFSv3-mounted path:
PersistentMappingHandleProviderfor restart-safe, MOUNT-compatible filehandles. - Optional capability seams:
INfsMountAuthorization,INfsLocking,INfsAcls,INfsDelegations,INfsIdMapper,INfsSparse, andINfsCopyClone.
If an optional capability is absent, the current server surface leaves it unadvertised or returns standards-compliant capability-gated failures on the covered protocol paths. Backend authors do not need every optional capability just to serve browse, read, write, and directory-management traffic.
OpenCIFS Parity
The intended high-level consumer flow is deliberately converging with OpenCIFS:
- Build immutable settings with
OpenNfsClientBuilder. - Create
OpenNfsClient. - Call
ConnectAsync(...). - Open a protocol-named namespace session with
MountAsync(...). - Use grouped path-first APIs on the session:
Files,Directories,Metadata,Locks. - Call
DisconnectAsync(...)when the client lifetime is done.
The protocol-specific nouns stay honest to NFS, but the public journey is meant to mirror OpenCIFS structurally wherever that does not hide NFS behavior.
The current primary client path also now mirrors OpenCIFS on bounded error-handling shape: the happy path remains throwing MethodAsync(...), while the aligned lifecycle and bootstrap helpers also expose TryMethodAsync(...) companions that return OpenNfsClientResult / OpenNfsClientResult<T> with typed client exceptions and normalized OpenNfsErrorCategory values.
Advanced Surface
The normal happy path is the mounted-session surface shown above. The following members are intentionally still available for exact protocol control, but they are secondary:
OpenNfsClient.OpenAsync(...)andCloseAsync(...)OpenNfsClient.CreateMountSession(...)OpenNfsClient.PrepareV3ProcedureAsync(...)andExecuteV3ProcedureAsync(...)OpenNfsClient.PrepareCompoundAsync(...)andExecuteCompoundAsync(...)
Those members are marked as advanced or non-primary in the public API surface so IntelliSense favors the path-first flow first while preserving full protocol fidelity when you need it.
The shared client and server suites now also exercise raw NFSv4.0 PUTPUBFH, VERIFY, NVERIFY, and the current explicit capability-gated OPENATTR, DELEGPURGE, and RELEASE_LOCKOWNER paths directly, so the advanced COMPOUND surface is not limited to the grouped convenience APIs.
Sample quick start
The fastest documented way to stand up a testable server today is the sample artifact with its shipped config file:
dotnet run --project src/Sample.OpenNfsServer/Sample.OpenNfsServer.csproj -c Release -- --config src/Sample.OpenNfsServer/appsettings.sample.json
The shipped appsettings.sample.json is now live: relative sourcePath and mappingPath values resolve from the config file directory, so the sample seeds src/Sample.OpenNfsServer/sample-data/export and stores persistent handles under src/Sample.OpenNfsServer/sample-state/.
The sample config also now accepts owner and ownerGroup values for the current NFSv4.0 owner and owner-group attribute path, and the sample persists ACL updates in a sidecar state file next to the filehandle mapping file.
The current shared suites now verify this sample path directly in four ways:
- config-file startup plus public
OpenNfsClient.MountAsync(...) - Linux kernel NFSv3 mount/read/write
- denied-mount behavior
- persistent filehandle reuse across restart when the mapping file is preserved
From a Linux client, the current shortest tested mount path is NFSv3 plus MOUNT v3:
sudo mkdir -p /mnt/opennfs-sample
sudo mount -t nfs -o vers=3,tcp,port=2049,mountport=20048 localhost:/exports/sample /mnt/opennfs-sample
ls /mnt/opennfs-sample
cat /mnt/opennfs-sample/hello.txt
sudo umount /mnt/opennfs-sample
If you need ephemeral local ports for side-by-side development runs, keep the same config file and override only the listeners on the command line:
dotnet run --project src/Sample.OpenNfsServer/Sample.OpenNfsServer.csproj -c Release -- --config src/Sample.OpenNfsServer/appsettings.sample.json --mount-port 0 --nfs-port 0 --nfs40-port 0
RPCSEC_GSS / Kerberos setup
The OpenNFS Kerberos provider (OpenNfsKerberosMechanism) plugs into IRpcSecGssMechanism and uses System.Net.Security.NegotiateAuthentication with Package = "Kerberos". On Windows .NET this delegates to SSPI; on Linux .NET it delegates to GSSAPI. The repository ships a self-contained Kerberos test fixture so contributors can exercise krb5, krb5i, and krb5p without any external KDC.
Stand up the test KDC
cd scripts/interop/kerberos
docker compose up -d --build
powershell -ExecutionPolicy Bypass -File Verify-Kdc.ps1
The Verify-Kdc.ps1 script drives a real kinit + kvno round-trip and verifies both a TGT and a service ticket land. Once the KDC is healthy:
- The realm is
EXAMPLE.TEST. - The KDC is reachable at
kdc.example.test:88from thekerberos_defaultDocker network and at127.0.0.1:8888from the host. - Three principals are provisioned at first boot:
nfs/sample.example.test@EXAMPLE.TEST— the sample server's service principalalice@EXAMPLE.TEST— a regular user (passwordalice-password)bob@EXAMPLE.TEST— a second regular user (passwordbob-password)
- Keytabs land at
scripts/interop/kerberos/keytabs/sample.keytab,alice.keytab,bob.keytab. - The
krb5.confclients should use lives atscripts/interop/kerberos/krb5.conf.
Run the Kerberos probe end-to-end
The probe app OpenNFS.KerberosProbe builds and runs in a Linux Docker container, authenticates as alice via the keytab, drives the full token exchange through OpenNfsKerberosMechanism, and exercises a bidirectional Wrap/Unwrap (krb5p) plus MIC-tamper-detection (krb5i) round-trip:
powershell -ExecutionPolicy Bypass -File scripts/interop/kerberos/probe/Run-Probe.ps1
The Touchstone cases SecuritySuites/Krb5ReadWrite, SecuritySuites/Krb5iDetectsTamper, SecuritySuites/Krb5pEncryptsPayload, SecuritySuites/RpcSecGssContextEstablishment, and SecuritySuites/RpcSecGssIntegrityFailureRejected invoke the same runner from the automated test pipeline and gate on the KDC container being healthy through KerberosProbeEnvironment. With the KDC up, these cases run in the standard dotnet run --project src/Test.Automated/Test.Automated.csproj --framework net8.0 -- --suite SecuritySuites flow with no further setup.
Wiring a host to use the provider
Any consumer that wants to register the Kerberos mechanism with their RPCSEC_GSS server-side authenticator does so by passing an OpenNfsKerberosMechanism instance built from OpenNfsKerberosMechanismOptions:
var options = new OpenNfsKerberosMechanismOptions(targetSpn: "nfs/sample.example.test@EXAMPLE.TEST");
using var mechanism = new OpenNfsKerberosMechanism(options);
krb5p (privacy) is supported on both net8.0 and net10.0. krb5 and krb5i (which need MIC compute/verify) require the net10.0 build because System.Net.Security.NegotiateAuthentication.ComputeIntegrityCheck/VerifyIntegrityCheck are net10-only APIs. The provider surfaces a clear CryptographicException when MIC operations are invoked on the net8 build.
Stop / reset the KDC
cd scripts/interop/kerberos
docker compose down # stop, keep DB + keytabs
docker compose down -v # stop + drop the DB (next start re-creates principals)
rm -f keytabs/*.keytab # drop keytabs only
Packaging
Only the following projects are configured as packable public packages:
OpenNFS.ServerOpenNFS.Client
The internal protocol, RPC, test, and tooling projects are intentionally non-packable.
OpenNFS.Client currently bundles the internal runtime assemblies it needs for real execution, including OpenNFS.Rpc, OpenNFS.Protocol.V3, OpenNFS.Protocol.V40, and OpenNFS.Server, because those are implementation details rather than separate public NuGet packages.
OpenNFS.Server now does the same for its runnable application surface. The public package includes OpenNFS.Rpc, OpenNFS.Protocol.V3, and OpenNFS.Protocol.V40, which is what allows BuildApplication() to start the current internal wire hosts without asking consumers to reference non-public packages directly.
The shared package-consumer acceptance coverage now validates both public packages from a clean local-feed restore path:
ServerSurfaceSuitespacksOpenNFS.Server, restores it into a temp console app, starts a real server throughBuildApplication(), and exercises positive and negative protocol flows from outside this solution.ClientSurfaceSuitespacksOpenNFS.Client, restores it into a temp console app, and exercises positive and negative client execution and lifetime flows.ReleaseReadinessSuitesnow extends that clean-consumer proof to real peers: a packagedOpenNFS.Serveris mounted and used by a Linux kernel client, and a packagedOpenNFS.Clientexecutes positive and negative flows against the sample server,knfsd, andnfs-ganesha.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 172 | 5/18/2026 |