Utility Library libntutil

Reference Documentation

Intel® PAC
Napatech SmartNIC
Reference Information
Napatech Software Suite: Utility Library libntutil
Utility Library libntutil


The utility library has a C language interface and provides a software implementation of the hashing algorithms provided by Napatech adapters. The software implementation of the hashing algorithms enables application programmers to calculate the hash value and destination stream number for a set of input data. What can be provided as input data depends on the adapter type and the chosen hash mode, and the calculated hash value and destination stream number depend on the actual input to the hashing algorithm. This documentation will use the term hash result when it is not significant whether it is the hash value or the destination stream number that is important.

The libntutil library is a stand-alone library that does not require a Napatech adapter be installed in the host computer, nor does it require that the Napatech driver is up and running. This allows the library to be used in an application that needs to calculate the hash value or the destination stream number for a given set of input. However, the library can also be used with a program that uses a Napatech adapter to read incoming packets and needs to calculate the hash value on the fly.


The libntutil library is installed together with the Napatech 3GD driver suite. The library consists of a header file named ntutil.h and the library in binary format and named either libntutil.so (FreeBSD and Linux) or libntutil.dll (Windows.)

Carry out the following steps to interface to and link with the library.

  • Include the header file named ntutil.h
  • Link with the library named libntutil.so (FreeBSD and Linux) or libntutil.dll (Windows).

Napatech provides an example program calc_single_hash.c that illustrates how to access and use the library. It is also possible to use the library with a C++ program.


The library operates with three concepts each represented with a C language struct: (1) a hash mode configuration expressed by the NtHashRefConfig_t type, (2) input to the hashing implementations expressed by the NtHashRefInput_t type, and (3) the result of the hash calculation expressed by the type named NtHashRefResult_t.

An application calls NT_HashRefOpen with a NtHashRefConfig_t to obtain a handle to a specific hash mode configuration. The application then (repeatedly) calls NT_HashRefCalc to calculate the hash values for specific input and uses the hash result, until it calls NT_HashRefClose to release resources used by the library uses to store information about the hash mode configuration.

Configuration Type

The configuration type NtHashRefConfig_t identifies the adapter type type and its associated fpgaid together with hash mode configuration parameters hash mode, hash mask, number of streams to distribute calculated hash values over, and hash seed. The library requires the adapter type and fpgaid because the hashing implementations vary between adapter types.

NtHashRefConfig_t is defined in a way that allows Napatech to provide newer version of the library and still be backward-compatible. The current edition of the library provides a single configuration structure named NtHashRefConfig_v0_t:

typedef struct NtHashRefConfig_v0_s {
enum NtAdapterType_e adapterType; //!< The adapter type
union Ntfpgaid_u fpgaid; //!< FPGA ID to emulate
enum NtHashRefHashMode_e hashmode;//!< Hash mode
uint32_t hashmask[10]; //!< Hash mask, adapter default is all 0xFF values
uint32_t streams; //!< Number of streams to distribute to
uint32_t seed; //!< Hash seed, adapter default is 0xFFFFFFFF

It is the programmer's responsibility to initialize the NtHashRefConfig_v0_t structure correctly before using it with NT_HashRefOpen. In a stand-alone scenario, the programmer may hardcode the values based on the set of adapters otherwise available. In an online scenario, where the driver is up and running, a programmer may get some of the information, adapter type and fpgaid, from the configuration stream.

An adapter by default uses a hash mask consisting of all 0xFF values, which causes the adapter to consider all input when it calculates the hash value. A programmer uses the array hashmask to set the hash mask.

The member field streams defines the number of streams to distribute over. An adapter uses the calculated hash value and the number of streams to calculate the target stream number. It is legal to set the number of streams equal to zero, which causes the library to not calculate the target stream number.

The member field seed defines the initial seed used by the hashing algorithm. An adapter uses a default value of 0xFFFFFFFF.

It is legal to set the hash mask to all zeros, but this results in the same hash value and target stream number regardless of the input to the hashing algorithm.

It is possible, and necessary, for an application to create multiple configuration types when the application needs to use multiple hashing modes, adapter types, or other things that differ in an instance of NtHashRefConfig_t.

The library validates the config structure when an application calls NT_HashRefOpen, and if valid, returns a valid handle that an application must subsequently use when calculating the hash value.

It is the application's responsibility to use the proper handle together with a valid input data type (see Input Type), and the library returns EINVAL if an application uses an illegal combination.

Input Type

The library uses the hash input type NtHashRefInput_t type for the data that goes into the hash algorithm. The NtHashRefInput_t is a structure that contains a union, and an application must denote which structure type of the union that is used to provide the hash input. An excerpt is shown below:

typedef struct {
enum NtHashRefInputType_e inputType; /* Denotes the used structure */
union NtHashRefInput_u {
struct NtLastMplsLabel_s {
uint32_t label; //!< 20-bit MPLS label
} lastMplsLabel;
struct NtTuple2IPv4_s {
uint32_t srcIP; //!< 32-bit IPv4 address in network order
uint32_t dstIP; //!< 32-bit IPv4 address in network order
} tuple2IPv4;
struct NtTuple2IPv6_s {
uint8_t srcIP[16]; //!< 128-bit IPv6 address in network order
uint8_t dstIP[16]; //!< 128-bit IPv6 address in network order
} tuple2IPv6;
} u;

Each hash mode supports a subset of the input types. For instance, the 2-tuple hash mode supports input types that provide a source and destination IP address, both IPv4 and IPv6 addresses. Section Valid Combinations of Hash Modes and Input Types lists the supported combinations.

If an application uses an unsupported combination of hashing algorithm and input type, the library returns the error code EINVAL.

Result Type

The result type NtHashRefResult_t contains the output from a succesful call to NT_HashRefCalc.

typedef struct NtHashRefResult_s {
uint32_t hashvalue; //!< 24-bit calculated hash value
uint32_t stream; //!< Destination stream

The result provides the hash value and the destination stream number.

There are a few characteristics that pertain to the destination stream number.

  • The library calculates the stream number if the application specifies a positive (non-zero) number of streams in the NtHashRefConfig_t structure; otherwise the library sets the stream number in the result to zero.
  • An application must map the resulting stream number to a final stream number in case the preferred hash (1) set-up does not start with stream number zero or (2) is noncontiguous.

    As an example, suppose an application wants to map the hash value to streams four through eleven (eight streams), the application must set the number of streams to eight, and map the result's stream number to the final stream number by adding the stream offset value of four.

    As an example of a noncontiguous range of streams, suppose an application wants to map the hash value to streams one, three, five, and seven (four streams), the application should set the number of streams to four, and map the result's stream number to the final stream number by multiplying it by two and adding one.

Valid Combinations of Hash Modes and Input Types

The table Hash Modes and Input Types documents which input types to use for the different hash modes.

The Hash Mode column is the hash mode. Multiple entries in the same cell means that information to the right (of the cell) pertains to all hash mode entries. The InputType column is the input type. The Struct Type column is the structure type to use in the union (part of NtHashRefInput_t) to use to provide input to the hash algorithm. The Struct Member column is the member variable to use to refer to the structure that contains the input to the hash algorithm.

Hash Modes and Input Types
Hash Mode Input Type Struct Type Struct Member

As an example of how to read the table, the hash mode NT_HASHREF_HASHMODE_LAST_MPLS_LABEL supports the input type NT_HASHREF_INPUT_TYPE_LAST_MPLS_LABEL, which in turn denotes the struct member lastMplsLabel of type NtLastMplsLabel_s in NtHashRefInput_t.

To illustrate how to apply the information in a program that uses hash mode NT_HASHREF_HASHMODE_LAST_MPLS_LABEL:

The following code snippet maps the two steps into C code:

NtHashRefConfig config;
config.config_v0.hashmode = NT_HASHREF_HASHMODE_LAST_MPLS_LABEL;
/* Need to set up remaining config_v0 members and call NT_HashRefOpen */
NtHashRefInput_t input;
input.u.lastMplsLabel.label = htonl(1234);
/* Call NT_HashRefCalc */

Multi-threaded Programs

It is safe to use the library concurrently from multiple threads. In particular, it is legal to call NT_HashRefCalc concurrently with the same handle.

However, calling NT_HashRefClose concurrently with the same handle is undefined behavior.

Resource Release

A hashref handle must be closed (released) once with a single call to NT_HashRefClose. A memory leak is the result if an application does not close a handle. Once a handle is released, it is undefined behavior to call NT_HashRefCalc or NT_HashRefClose with that handle. It is safe to reuse a released handle in a call to NT_HashRefOpen.

Big-Endian (Network order) Input

The hash reference implementation library requires input that goes into the hash algorithm be in network order (big-endian format). To be more specific, the requirement is that the contents of the NtHashRefInput_u union be stored in network order.

The requirement only pertains to NtHashRefInput_u.
Endianness is only an issue for values that are larger than eight bits (one byte).

The decision to require network order in NtHashRefInput_u is to ensure that it is possible to copy the values of IPv4 and IPv6 addresses and port numbers from network packets to the input structures when calling NT_HashRefCalc, as well as to increase consistency.

Always use the helper functions htonl and htons around literal values when setting values in NtHashRefInput_u.

Return Values

The library's functions return zero on success, and a non-zero value in case of errors.

The library may return one of the following error codes: EINVAL and ENOMEM. Their meaning are indicated below:

  • EINVAL A wrong parameter, or an invalid combination of parameters, is supplied.
  • ENOMEM It is not possible to allocate heap memory.


There are no known limitations.


  • Make sure that input supplied to NT_HashRefCalc via NtHashRefInput_u union is in network order.
  • Further to the item above, use helper functions htonl and htons to set literal 16- and 32-bit values, respectively.


Also refer to the example program calc_single_hash.c that illustrates how to calculate the hash values for a set of fixed IP addresses.

An application wants to use the hashref library to calculate the 2-tuple hash value for a pair of IP addresses consisting of a source and destination IP address.

The application must perform the following steps:

NtHasRefConfig_t config;
config.config = NtHashRefConfig_v0;
config.u.config_v0.adapterType = NT_ADAPTER_TYPE_NT20E2;
config.u.config_v0.fpgaid.s.item = 200;
config.u.config_v0.fpgaid.s.product = 9220;
config.u.config_v0.fpgaid.s.ver = 50;
config.u.config_v0.fpgaid.s.rev = 3;
config.u.config_v0.fpgaid.s.build = 0;
config.u.config_v0.hashmode = NT_HASHREF_HASHMODE_2_TUPLE;
config.u.config_v0.streams = 8; /* distribute to eight streams */
config.u.config_v0.seed = 0xffffffff; /* default hash seed value */
memset(&config.u.config_v0.hashmask, 0xff, sizeof(config.u.config_v0.hashmask);
int rc = NT_hashRefOpen(&href, &config);
if (rc) {
/* An error occurred */
} else {
/* It went fine */
  • Populate an input structure and set the proper input data type and call NT_HashRefCalc:
struct NtTuple2IPv4_s *hinput = &input.u.tuple2IPv4;
/* network input must use network order */
hinput->srcIP = htonl(0x0a0a0a0a); /* IP V4: */
hinput->dstIP = htonl(0xc0a80101); /* IP V4: */
rc = NT_HashRefCalc(href, &input, &result);
if (rc) {
(void)fprintf(stderr, "Cannot calculate hash value\n");
return rc;
printf("2-tuple hash of (src =, dst =\n"
"\tvalue = 0x%x, stream number = %d\n",
result.hashvalue, result.stream);
  • Release the resources used by the hashref library before closing the application: