A NVMf library for Java
Switch branches/tags
Nothing to show
Clone or download
PepperJo DiSNI 2.0 changes package names
DiSNI 2.0 drops rdma in package name.

Signed-off-by: Jonas Pfefferle <pepperjo@japf.ch>
Latest commit 7594095 Nov 9, 2018
Type Name Latest commit message Commit time
Failed to load latest commit information.
pom.xml New DiSNI version 2.0 Nov 9, 2018


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 or higher. 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= -Dnqn=nqn.2017-06.io.crail:cnode4420 -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.0-jar-with-dependencies.jar:target/jnvmf-1.0-tests.jar com.ibm.jnvmf.benchmark.NvmfClientBenchmark --help

to shows the available arguments.

For example:

java -cp target/jnvmf-1.0-jar-with-dependencies.jar:target/jnvmf-1.0-tests.jar com.ibm.jnvmf.benchmark.NvmfClientBenchmark -a -p 4420 -g 4096 -i 3 -m RANDOM -n 10 -nqn nqn.2016-06.io.spdk:cnode1 -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 nqn.2016-06.io.spdk:cnode1
  • 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

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("nqn.2016-06.io.spdk:cnode1"));
/* 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:


or email: zrlio-users@googlegroups.com