Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time

jNVMf: A NVMe over Fabrics library for Java

jNVMf is a Java library for remote access to NVMe storage. It implements client side of the NVMe over Fabrics (NVMf) specification. jNVMf has been tested to work with SPDK, Linux and Mellanox offloading targets. Futhermore it supports advanced NVMe/f features like fused operations, incapsule data and dataset management.

Building jNVMf

Building the source requires Apache Maven and a Java JDK with Java version 8. jNVMf depends on DiSNI while the java dependecy is automatically picked up from maven central you need to download and compile the native library of DiSNI. Check the DiSNI README for instructions on how to build the native library. To build jNVMf use:

mvn -DskipTests package or mvn -DskipTests install

Run Unit tests

To run the unit tests make sure the LD_LIBRARY_PATH contains libdisni (see above) and execute:

mvn test -Prdma -DargLine="-DdestinationAddress= -DlocalAddress= -Dport=4420"

where destinationAddress is the target IP address, localAddress is the local IP of the RDMA device, nqn the NVMe qualified name of the controller you want to connect to and port the port of the target.

Run benchmark

jNVMf provides a small benchmark tool. Run:

java -cp target/jnvmf-1.7-jar-with-dependencies.jar:target/jnvmf-1.7-tests.jar --help

to shows the available arguments.

For example:

java -cp target/jnvmf-1.7-jar-with-dependencies.jar:target/jnvmf-1.7-tests.jar -a -p 4420 -g 4096 -i 3 -m RANDOM -n 10 -nqn -o bench.csv -qd 1 -rw read -s 4096 -qs 64 -H -I

  • executes a -m RANDOM -rw read test
  • to a target at -a, -p 4420 with controller -nqn
  • all accesses are aligned to -g 4096 bytes
  • statistics are printed every -i 3 seconds -n 10 times
  • output is written to -o bench.csv in csv format
  • queue depth -qd 1
  • transfer size -s 4096 bytes
  • queue size -qs 64 entries
  • histogram -H
  • RDMA inline data -I

Run diagnostics

jNVMf offers a tool to run diagnostics. Print help with:

java -cp target/jnvmf-1.7-jar-with-dependencies.jar:target/jnvmf-1.7-tests.jar --help


java -Djnvmf.legacy=true -cp jnvmf-1.7-jar-with-dependencies.jar:jnvmf-1.7-tests.jar -a -p 4420 -nqn -t asyncevent

  • executes -t asyncevent test
  • to a target at -a, -p 4420 with controller -nqn

Example API usage

Sample usage of the jNVMf API to perform a read operation:

Nvme nvme = new Nvme();
/* target ip and port we want to connect to */
InetSocketAddress socketAddress = new InetSocketAddress("", 4420);
/* controller NVMe qualified name */
NvmfTransportId tid = new NvmfTransportId(socketAddress,
                new NvmeQualifiedName(""));
/* connect to controller */
Controller controller = nvme.connect(tid);
/* enable controller */
/* create a io queue pair with submission queue size 64 */
IoQueuePair queuePair = controller.createIoQueuePair(64);
/* allocate and register buffer to be used for transfer */
ByteBuffer buffer = ByteBuffer.allocateDirect(4096);
KeyedNativeBuffer registeredBuffer = queuePair.registerMemory(buffer);
/* create a new read command */
NvmReadCommand command = new NvmReadCommand(queuePair);
/* create a response */
Response<NvmResponseCapsule> response = command.newResponse();
/* set buffer */
NvmIOCommandCapsule commandCapsule = command.getCommandCapsule();
/* set length, LBA and namespace identifier */
NvmIoCommandSqe sqe = commandCapsule.getSubmissionQueueEntry();
/* read one block*/
sqe.setNamespaceIdentifier(new NamespaceIdentifier(1));
volatile boolean done = false;
/* set callback */
command.setCallback(new OperationCallback() {
      public void onStart() {

      public void onComplete() {
          System.out.println("command completed");
          /* check response */
          NvmCompletionQueueEntry cqe = response.getResponseCapsule().getCompletionQueueEntry();
          StatusCode.Value statusCode = cqe.getStatusCode();
          if (!statusCode.equals(GenericStatusCode.getInstance().SUCCESS)) {
              System.out.println("Command not successful");
          done = true;

      public void onFailure(RdmaException e) {
          System.out.println("There was an RDMA error when executing the command");
          done = true;
/* wait until command is done */
while (!done);


PRs are always welcome. Please fork, and make necessary modifications, and let us know.


If you have questions or suggestions, feel free to post at:!forum/zrlio-users

or email: