This source file is an example of how to write an IP fragment re-assembling code, using the Napatech FPGA IPFMode feature. It accelerates IP re-assembling by making it possible to load balance using a 5 tuple hash algoritm instead of a 2 tuple hash algorithm. This is done for fragments by learning from the first fragment and use this knowledge to calculate the 5 tuple for belonging fragments. The complexing case is the situation where the FPGA was not able to learn and identify a fragment and therefore it is sent to one of the un-matching streams. In this situation the code needs to exchange the un-matched packet and deliver it to the right re-assembling thread.
A Napatech capture accelerator is needed to run this example with IPFMode support. The ntservice.ini file must have enough HostBuffersRx defined to honor the requested streams needed when running this demo application. Below is an example of a minimum ini-file. It will create 20 64MB RX hostbuffer from NUMA node 0.
Note that the PacketDescriptor is set to Ext9, This is needed to run IPFMode at all. If anything less is specified, then the IPFMode will not be used and it will revert into a Hash2Tuple mode.
Note2 that the TimeSyncReferencePriority is set to OsTime. This is critical, when using a fragtimeout value (default), because the timestamp of each packet is used to calculate its timeout.
************************* Overview of the algorithm used ******************************
The FPGA enables you to match IP fragments and distribute them using a multi CPU buffer splitting scheme based on a 5-tuple hash algorithm when using the IPFMode feature. If a multi CPU splitting scheme based on a 2-tuple hash algorithm gives good enough distribution, then the IPFMode feature in the FPGA should not be used. All belonging fragments will end up in same stream using a 2-tuple hash algorithm. IPFMode: how it works:
Unmatched threads – variable number (N) – number of unmatched streams to use (2-tuple hash cpu-splitting)
Each unmatched thread receives the unmatched fragments. When a fragment is received, it is checked in the DOI tables to find a datagram ID match. If a match is found, the NetBuf containing the fragment is send to that reassembling Msg box FIFO, of which the DOI table belongs to. Otherwise, if no match found (yet), the fragment is temporarily put into a wait list. The wait list is periodically checked against the DOI tables.
Reassembling threads – variable number (M) – number of streams to use (5-tuple hash cpu-splitting)
When each reassembling thread receives IP fragments, it collects them into complete datagrams. If all fragments are received in order, or at least the first fragment is received first, then the need for unmatched fragment collection is not needed and all datagrams are reassembled in the reassembling threads. When the reassembling thread receives a first fragment, it then stores that fragment in its local collection hash table (tbl) and makes that datagram ID available for the specific unmatched thread to inform about its interest in fragments belonging to this datagram, using the specific DOI table connecting the reassembling thread with the unmatched thread. When all fragments are received for a datagram, they are all released and the DOI table entry is cleared. Each reassembling thread first reads from the Msg box for a NetBuf, and if none found, then it reads the NTAPI stream for a NetBuf. If any fragments are received from here, they are put into the collection table (tbl).
Used by Unmatched threads to send unmatched fragments to the reassembling threads. [[[unm1 Msgbox],[ unm2 Msgbox],…[ unmN Msgbox]], [[unm1 Msgbox],[ unm2 Msgbox],…[ unmN Msgbox]]…M times] reasm1 reasm2 …reasmM
The Msg boxes are built as FIFOs and are used by the unmatched threads to send the NetBuf of a received datagram fragment to the belonging reassembling thread.
Used by Reassmbling threads to send unmatched-fragment NetBufs back to the unmatched threads originally received them. [[[reasm1 Msgbox],[ reasm2 Msgbox],…[ reasmM Msgbox]], [[reasm1 Msgbox],[ reasm2 Msgbox],…[ reasmN Msgbox]]…N times] unm1 unm2 …unmN
This FIFO is only needed to make the complete algorithm lockless. The NTAPI cannot handle multi-threaded access to the packet interface without serialization.
The DOI tables are a set of hash tables containing a list of datagram IDs that the reassembling threads are interested in.
The FPGA specifies the unmatched stream ID together with the reception of the first fragment. This information is used by the reassembling threads to inform the specific unmatched thread about where to send unmatched fragments matching the first fragments datagram ID.
Each reassembling thread has one DOI table allocated for each unmatched thread, thus M*N DOI hash tables are used. This way each reassembling thread has exclusive write access to one table for each unmatched tread. [[[reasm1 tbl],[reasm2 tbl],…[reasmM tbl]], [[reasm1 tbl],[reasm2 tbl],…[reasmM tbl]]…N times] Unmatched1 Unmatched2 …UnmatchedN
Each unmatched thread only reads information from the DOI tables. When an unmatched fragment matches an entry in the DOI table, then this fragment is send to the reassembling thread using the dedicated Msg box FIFO.
The fragments belonging to a datagram are identified by the calculated datagram ID: It consists of information from 4 fields in the IP header (source IP, destination IP, Identification and protocol).
#if defined(__linux__) || defined(__FreeBSD__)
#include <unistd.h>
#include <signal.h>
#include <assert.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <sys/time.h>
#elif defined(WIN32) || defined (WIN64)
#include <winsock2.h>
#include <time.h>
#include <sys/timeb.h>
#include <process.h>
#endif
#if defined(WIN32) || defined (WIN64)
#define snprintf(a, b, c, d) _snprintf_s((a), _countof(a), (b), (c), (d))
void sleep(int time)
{
Sleep(time * 1000);
}
void usleep(unsigned long usec)
{
Sleep(usec / 1000);
}
struct timezone {
int tz_minuteswest;
int tz_dsttime;
};
int gettimeofday(struct timeval *tv, struct timezone *tz)
{
struct __timeb64 timebuffer;
_ftime64_s(&timebuffer);
tv->tv_sec = (long)timebuffer.time;
tv->tv_usec = timebuffer.millitm * 1000;
return 0;
}
typedef HANDLE pthread_t;
typedef unsigned (__stdcall *start_address_t)(void *parameter);
int pthread_create(HANDLE *thread, DWORD *attr, start_address_t start_routine, void *parameter)
{
HANDLE handle = (HANDLE)_beginthreadex(
NULL, 0, start_routine, parameter, 0,
NULL);
if (handle == 0)
{
fprintf(stderr, "pthread_create() fail with error: 0x%x\n", status);
return status | NT_SYSTEM_ERRORS;
}
*thread = handle;
return NT_SUCCESS;
}
int pthread_join(HANDLE thread, void **value_ptr)
{
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
return NT_SUCCESS;
}
#endif
#pragma pack(push, 1)
uint8_t ipHlen:4;
uint8_t ipVer:4;
uint8_t tos;
uint16_t ipTotlen;
uint16_t Id;
#define FRAG_OFFS_MASK 0x1FFF
#define LAST_FRAG_BITS 0x00E0
uint16_t fragOffs;
uint8_t ttl;
uint8_t prot;
uint16_t csum;
uint32_t srcAddr;
uint32_t dstAddr;
#pragma pack(pop)
#define L3_ADDR(_NetBuf_) ((uint8_t *)NT_NET_GET_PKT_L2_PTR(_NetBuf_)+NT_NET_GET_PKT_L3_OFFSET(_NetBuf_))
#define IPVERSION(_NetBuf_) (((iphdr_t *)L3_ADDR(_NetBuf_))->ipVer)
#define IPV4_HDR_LENGTH(_NetBuf_) ((uint8_t)(((iphdr_t *)L3_ADDR(_NetBuf_))->ipHlen)<<2)
#define IPV4_TOT_LEN(_NetBuf_) (ntohs(((iphdr_t *)L3_ADDR(_NetBuf_))->ipTotlen))
#define IPV4_FRAGMENT_ID(_NetBuf_) (ntohs(((iphdr_t *)L3_ADDR(_NetBuf_))->Id))
#define IPV4_FRAGMENT_OFFSET(_NetBuf_) ((ntohs(((iphdr_t *)L3_ADDR(_NetBuf_))->fragOffs)&FRAG_OFFS_MASK)<<3)
#define IPV4_LAST_FRAG(_NetBuf_) (((((iphdr_t *)L3_ADDR(_NetBuf_))->fragOffs)&LAST_FRAG_BITS)==0)
#define IPV4_SRC_ADDR(_NetBuf_) (((iphdr_t *)L3_ADDR(_NetBuf_))->srcAddr)
#define IPV4_DST_ADDR(_NetBuf_) (((iphdr_t *)L3_ADDR(_NetBuf_))->dstAddr)
#define IPV4_PROTOCOL(_NetBuf_) (((iphdr_t *)L3_ADDR(_NetBuf_))->prot)
#define IPV4_GET_DGRAM_ID(_NetBuf_, _src_, _dst_, _id_, _prot_) \
do {iphdr_t *_ip_=(iphdr_t *)L3_ADDR(_NetBuf_);_src_=_ip_->srcAddr;_dst_=_ip_->dstAddr;\
_id_=_ip_->Id;_prot_=_ip_->prot;}while(0)
#define IPV4_DATA_LEN(_NetBuf_) (IPV4_TOT_LEN(_NetBuf_)-IPV4_HDR_LENGTH(_NetBuf_))
volatile uint64_t src_id;
struct {
volatile uint32_t src;
volatile uint32_t id;
};
#define MAX_SRC_ID 8
#define DOI_FRAG_TBL_SIZE 8081
#define DOI_HASH_GET_KEY(_entry_, _src_, _id_) (_entry_ = (_src_+_id_)%DOI_FRAG_TBL_SIZE)
uint16_t offset;
uint16_t size;
uint8_t firstFrag;
uint8_t lastFrag;
};
#define MAX_FRAG_CNT 18
#define REASSEMBLY_HASH_TBL_SIZE 1021
#define INITIAL_HASH_TBL_ENTRY_CNT 1024
uint64_t id1;
uint64_t id2;
volatile uint64_t *pDOI_Src_id;
volatile uint64_t *pDOI_Dst_pr;
uint16_t fragCnt;
struct frag_s aFrag[MAX_FRAG_CNT];
#define LOOKUP_ENTRY(_tbl_base_, _tbl_entry_type_, _tbl_size_, _id1_, _id2_, _tbl_entry_) \
{ \
uint32_t _key_ = (uint32_t)((_id1_ ^ _id2_) % _tbl_size_); \
_tbl_entry_type_ *_tbl_; \
_tbl_ = _tbl_base_[_key_]; \
while (_tbl_ && (_tbl_->id1 != _id1_ || _tbl_->id2 != _id2_)) { \
_tbl_ = _tbl_->pNext; \
} \
_tbl_entry_=_tbl_; \
}
#define GET_NEW_TBL_ENTRY(_tbl_free_, _tbl_entry_type_, _tbl_entry_) \
{ \
if (!_tbl_free_) { \
int __o__; \
_tbl_entry_type_ *__plm__; \
for (__o__ = 0; __o__ < 64; __o__++) { \
__plm__ = calloc(1, sizeof(_tbl_entry_type_)); \
if (!__plm__) assert(0); \
__plm__->pNext = _tbl_free_; \
_tbl_free_ = __plm__; \
} \
} \
_tbl_entry_ = _tbl_free_; \
_tbl_free_ = _tbl_free_->pNext; \
tbl_entry->pNext = NULL; \
}
#define RELEASE_TBL_ENTRY(_tbl_free_, _tbl_entry_) \
{ \
_tbl_entry_->pNext = _tbl_free_; \
_tbl_free_ = _tbl_entry_; \
}
#define ADD_ENTRY_TO_TBL(_tbl_base_, _tbl_entry_type_, _tbl_size_, _tbl_entry_) \
{ \
uint32_t _key_ = (uint32_t)((_tbl_entry_->id1 ^ _tbl_entry_->id2) % _tbl_size_); \
_tbl_entry_type_ *_tbl_; \
_tbl_ = _tbl_base_[_key_]; \
while (_tbl_ && (_tbl_->id1 != _tbl_entry_->id1 || _tbl_->id2 != _tbl_entry_->id2)) { \
_tbl_ = _tbl_->pNext; \
} \
if (_tbl_ == NULL) { \
_tbl_entry_->pNext = _tbl_base_[_key_]; \
_tbl_base_[_key_] = _tbl_entry_; \
} \
else { \
assert(_tbl_==_tbl_entry_); \
} \
}
#define DEL_ENTRY_FROM_TBL(_tbl_base_, _tbl_entry_type_, _tbl_size_, _tbl_entry_) \
{ \
uint32_t _key_ = (uint32_t)((_tbl_entry_->id1 ^ _tbl_entry_->id2) % _tbl_size_); \
_tbl_entry_type_ *_tbl_, *_prev_ = NULL; \
_tbl_ = _tbl_base_[_key_]; \
while (_tbl_ && (_tbl_->id1 != _tbl_entry_->id1 || _tbl_->id2 != _tbl_entry_->id2)) { \
_prev_ = _tbl_;_tbl_ = _tbl_->pNext; \
} \
if (_tbl_) { \
if (_prev_) { \
_prev_->pNext = _tbl_->pNext; \
} \
else { \
_tbl_base_[_key_] = _tbl_->pNext; \
} \
} \
else { \
assert(0); \
} \
}
#if defined(__linux__) || defined(__FreeBSD__)
#define compiler_barrier() __asm__ __volatile__("":::"memory")
#elif defined(WIN32) || defined (WIN64)
#define compiler_barrier()
#endif
#define MSG_BOX_DEPTH 0x2000
volatile uint32_t rdIdx;
volatile uint32_t wrIdx;
#define MSG_BOX_EMPTY(_fifo_) ((_fifo_)->wrIdx==(_fifo_)->rdIdx)
#define MSG_BOX_FULL(_fifo_) (((_fifo_)->wrIdx-(_fifo_)->rdIdx) >= MSG_BOX_DEPTH)
#define MSG_BOX_GET(_fifo_) (_fifo_)->data[(_fifo_)->rdIdx&(MSG_BOX_DEPTH-1)]; compiler_barrier(); (_fifo_)->rdIdx++
#define MSG_BOX_PUT(_fifo_, _elem_) \
do { \
(_fifo_)->data[(_fifo_)->wrIdx&(MSG_BOX_DEPTH-1)]=_elem_; \
compiler_barrier(); \
(_fifo_)->wrIdx++; \
} while (0)
#define MAX_WAIT_ELEM 1024
pthread_t thread;
int streamId;
ipDefrag_t *pIpDefrag;
int fragRecv;
int fragsDeleted;
pthread_t thread;
int idx;
int streamId;
ipDefrag_t *pIpDefrag;
int datagramCompleted;
int fragmentsTimedout;
int firstFragRcv;
int nonFragments;
int Src_IdClash;
int msgboxPackets;
int Running;
int unmCnt;
int unmStart;
int reasmCnt;
int reasmStart;
uint64_t fragTimeout;
int ExtDescrType;
int allReasmClosed;
};
#define NO_OPTIONS 0
#define OPTION_HELP (1<<1)
#define OPTION_ADAPTER (1<<2)
#define OPTION_NUM_REASM (1<<3)
#define OPTION_NUM_UNM (1<<4)
#define OPTION_TIMEOUT (1<<5)
#define OPTION_TABLE_PERSIST (1<<6)
#define OPTION_TABLE_TIMEOUT (1<<7)
OPT_INTEGER(
'r',
"reasm", &
opt_reasm,
"Number of concurrent IP fragments re-assembling streams/threads",
NULL, 0, 0,
"number"),
OPT_INTEGER(
'f',
"fragtimeout", &
opt_frag,
"How old fragments may get before they are deleted from tables (ms)",
NULL, 0, 0,
"ms"),
};
"Syntax:\n"
"\n"
"ipfdemo_example [-a <adapter number>] [-r <number>] [-u <number>] [-f <ms>] [-p <timeout|lastfragment>] [-t <value>]\n"
"\nCommands:\n",
{
struct timeval tv;
return (uint64_t) (tv.tv_sec * 1000000 + tv.tv_usec);
}
{
int32_t entry;
uint32_t src, dst;
uint8_t prot;
uint16_t id;
int idx;
idx=0;
if (pTbl[entry].aSrc_id[idx] == val.
src_id &&
return 1;
} else {
return 0;
}
}
idx++;
}
}
return 0;
}
#if defined(__linux__) || defined(__FreeBSD__)
static void *_UnMatchedThread(void *arg)
#elif defined(WIN32) || defined (WIN64)
static unsigned __stdcall _UnMatchedThread(void *arg)
#endif
{
}
fprintf(stderr,
"[%i] NT_NetRxOpen() failed: %s\n", pUnm->
streamId, errorBuffer);
#if defined(__linux__) || defined(__FreeBSD__)
#elif defined(WIN32) || defined (WIN64)
{ _endthreadex(0); return 0; }
#endif
}
}
}
if (checkTimeout) {
}
while (pWaitFrag) {
if (!deleteIt && checkTimeout) {
deleteIt=1;
}
}
if (deleteIt) {
if (pWaitFrag->hNetBuf) {
pWaitFrag->hNetBuf =
NULL;
}
if (pUnm->
pWait == pWaitFrag) {
} else
if (pPrev) {
}
pWaitFrag = pNxt;
} else {
pPrev = pWaitFrag;
pWaitFrag = pWaitFrag->
pNext;
}
}
}
if ((status =
NT_NetRxGet(hNetRx, &hNetBuf, 1)) != NT_SUCCESS) {
if ((status == NT_STATUS_TIMEOUT) || (status == NT_STATUS_TRYAGAIN)) {
continue;
}
fprintf(stderr,
"[%i] NT_NetRxGet() failed: %s\n", pUnm->
streamId, errorBuffer);
#if defined(__linux__) || defined(__FreeBSD__)
#elif defined(WIN32) || defined (WIN64)
{ _endthreadex(0); return 0; }
#endif
}
}
invalidPkt = 1;
NT_NET_GET_PKT_L3_FRAGMENTED(hNetBuf)) {
if (NT_NET_GET_PKT_DESCRIPTOR_FORMAT(hNetBuf) == 9) {
if (NT_NET_GET_PKT_L3_FIRST_FRAG(hNetBuf)) {
fprintf(stderr,
"[%i] ERROR un-matched streams may never receive first fragment\n", pUnm->
streamId);
exit(0);
}
invalidPkt = 0;
usleep(1);
} else {
}
}
}
}
}
if (invalidPkt && !NT_NET_GET_PKT_L3_FRAGMENTED(hNetBuf)) {
fprintf(stderr,
"[%i] ERROR, invalid non-ipv4-fragment received on one un-matched fragment stream\n", pUnm->
streamId);
exit(0);
}
}
while (pWait) {
}
usleep(1000);
}
}
}
fprintf(stderr,
"[%i] Un-matched: NT_NetRxGet() failed: %s\n", pUnm->
streamId, errorBuffer);
}
#if defined(__linux__) || defined(__FreeBSD__)
#elif defined(WIN32) || defined (WIN64)
{ _endthreadex(0); return 0; }
#endif
}
{
int waitCnt;
waitCnt=0;
while (waitCnt < 100) {
usleep(1000);
waitCnt++;
} else {
break;
}
};
if (waitCnt == 100) {
fprintf(stderr,
"[%i] Return Msg Box full - failed to put element.\n", pReasm->
streamId);
}
}
{
for (i = 0; i < tbl_entry->
fragCnt; i++) {
} else {
}
}
}
}
}
{
int fstFrag = -1;
int lstFrag = -1;
}
}
if (fstFrag >= 0 && lstFrag >= 0) {
return 1;
}
}
return 0;
}
#if defined(__linux__) || defined(__FreeBSD__)
static void *_ReassemblyThread(void *arg)
#elif defined(WIN32) || defined (WIN64)
static unsigned __stdcall _ReassemblyThread(void *arg)
#endif
{
fprintf(stderr,
"[%i] NT_NetRxOpen() failed: %s\n", pReasm->
streamId, errorBuffer);
#if defined(__linux__) || defined(__FreeBSD__)
#elif defined(WIN32) || defined (WIN64)
{ _endthreadex(0); return 0; }
#endif
}
timeoutChkCnt = 0;
fromUnm=1;
unmIndex = (uint8_t)i;
break;
}
}
if ((status =
NT_NetRxGet(hNetRx, &hNetBuf, 1)) != NT_SUCCESS) {
if ((status == NT_STATUS_TIMEOUT) || (status == NT_STATUS_TRYAGAIN)) {
if (++timeoutChkCnt >= 100) {
while (tbl_entry) {
deleteIt = 0;
for (ii = 0; ii < tbl_entry->
fragCnt; ii++) {
deleteIt=1;
break;
}
}
if (deleteIt) {
tbl_entry = pNxt;
} else {
tbl_entry = tbl_entry->
pNext;
}
}
}
}
timeoutChkCnt = 0;
}
}
continue;
}
fprintf(stderr,
"[%i] NT_NetRxGet() failed: %s\n", pReasm->
streamId, errorBuffer);
goto EXIT;
}
fromUnm = 0;
unmIndex = 0;
}
timeoutChkCnt = 0;
NT_NET_GET_PKT_L3_FRAGMENTED(hNetBuf)) {
uint32_t unmEntry;
uint32_t src, dst;
uint8_t prot;
uint16_t id;
int offset;
if (NT_NET_GET_PKT_L3_FIRST_FRAG(hNetBuf)) pReasm->
firstFragRcv++;
}
if (tbl_entry->
id1 == 0) {
} else {
fprintf(stderr,
"[%i] ERROR - MAX frag cnt reached\n", pReasm->
streamId);
exit(0);
}
}
} else {
}
if (NT_NET_GET_PKT_DESCRIPTOR_FORMAT(hNetBuf) == 9) {
if (NT_NET_GET_PKT_L3_FIRST_FRAG(hNetBuf)) {
int idx=-1;
offset = NT_NET_GET_PKT_IPF_UNMATCHED_STREAMID(hNetBuf) - pReasm->
pIpDefrag->
unmStart;
if (unmTbl[unmEntry].aSrc_id[i] == val.
src_id &&
break;
}
if (idx < 0 && unmTbl[unmEntry].aSrc_id[i] == 0) {
}
}
if (idx >= 0) {
} else {
fprintf(stderr,
"[%i] Too many clashes in DOI (more than %i - raise MAX_SRC_ID)\n", pReasm->
streamId, MAX_SRC_ID);
exit(0);
}
}
}
}
} else {
fprintf(stderr,
"[%i] NT_NetRxRelease() failed: %s\n", pReasm->
streamId , errorBuffer);
goto EXIT;
}
}
}
EXIT:
while (pTbl) {
for (ii = 0; ii < pTbl->
fragCnt; ii++) {
} else {
}
}
}
}
}
}
fprintf(stderr,
"[%i] Re-asm thread: NT_NetRxGet() failed: %s\n", pReasm->
streamId, errorBuffer);
}
#if defined(__linux__) || defined(__FreeBSD__)
#elif defined(WIN32) || defined (WIN64)
{ _endthreadex(0); return 0; }
#endif
}
#if defined(WIN32) || defined (WIN64)
#else
#endif
{
#ifdef WIN32
return TRUE;
#else
if (sig == SIGINT)
#endif
}
#define INPUT_ADAPTER 0
#define FRAGMENT_TIMEOUT 2000 // mSec
#define NUM_STREAMS 4
#define NUM_UNM_STREAMS 4
#define TABLE_TIMEOUT 125
#define TABLE_PERSIST_TIMEOUT 0
int main(
int argc,
const char *argv[])
{
int inp_1, inp_2;
int hashTblFreed;
int waitTblFreed;
int msgboxElmFreed;
int tablePersistTimeout;
int tableTimeout;
#define NUM_NTPL 3
{"Assign[streamid=(%i..%i)]=port==(%i..%i)",
"HashMode=Hash%iTuple",
"IPFMode[StreamId=(%i..%i);timeout=%i;TablePersist=%s]=port==(%i..%i)"};
#if defined(WIN32) || defined (WIN64)
#else
struct sigaction newaction;
memset(&newaction, 0, sizeof(newaction));
if (sigaction(SIGINT, &newaction,
NULL) < 0) {
fprintf(stderr, "Failed to register sigaction.\n");
exit(1);
}
#endif
memset(&IpDefrag, 0 ,
sizeof(
struct _ipDefrag));
}
}
}
}
tablePersistTimeout = 1;
}
}
}
fprintf(stderr, "NT_Init() failed: %s\n", errorBuffer);
return -1;
}
if ((status =
NT_InfoOpen(&hInfoStream,
"IPFExample")) != NT_SUCCESS) {
fprintf(stderr, "NT_InfoOpen() failed: %s\n", errorBuffer);
return -1;
}
fprintf(stderr, "NT_InfoRead() failed: %s\n", errorBuffer);
return -1;
}
} else {
fprintf(stderr, "The packet descriptor is not Ext9. Please set 'PacketDescriptor = Ext9' in ntservice.ini file for the selected adapter.\n");
return -1;
}
fprintf(stderr, "Failed to read timesync info: %s\n", errorBuffer);
return -1;
}
fprintf(stderr, "The timesync reference clock on the selected adapter is not OS. Please set TimeSyncReferencePriority=OsTime in ntservice.ini file for the selected adapter\n");
return -1;
}
}
fprintf(stderr, "NT_InfoClose() failed: %s\n", errorBuffer);
return -1;
}
if ((status =
NT_ConfigOpen(&hCfgStream,
"IPFExample")) != NT_SUCCESS) {
fprintf(stderr, "NT_ConfigOpen() failed: %s\n", errorBuffer);
return -1;
}
switch (i) {
case 1:
snprintf(tmpBuffer,
sizeof(tmpBuffer), ntplExpr[i], (IpDefrag.
ExtDescrType == 9)?5:2);
break;
case 2:
if (tablePersistTimeout) {
snprintf(tmpBuffer,
sizeof(tmpBuffer), ntplExpr[i], IpDefrag.
unmStart, IpDefrag.
unmStart + IpDefrag.
unmCnt - 1, tableTimeout,
"TimeoutOnly", inp_1, inp_2);
} else {
snprintf(tmpBuffer,
sizeof(tmpBuffer), ntplExpr[i], IpDefrag.
unmStart, IpDefrag.
unmStart + IpDefrag.
unmCnt - 1, tableTimeout,
"LastFragment", inp_1, inp_2);
}
} else {
continue;
}
break;
default:
strncpy(tmpBuffer, ntplExpr[i], sizeof(tmpBuffer) - 1);
break;
}
fprintf(stderr, "ERROR --> %s\n", tmpBuffer);
fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
return -1;
}
}
fprintf(stderr, "Memory allocation failed\n");
return -1;
}
fprintf(stderr, "Memory allocation failed\n");
return -1;
}
for (i = 0; i < IpDefrag.
reasmCnt; i++) {
if (tbl) {
}
}
fprintf(stderr, "Unable to create Unmatched stream thread");
}
}
fprintf(stderr, "Memory allocation failed\n");
return -1;
}
for (i = 0; i < IpDefrag.
unmCnt; i++) {
fprintf(stderr, "Unable to create Unmatched stream thread");
}
}
}
int sum1,sum2,sum3,sum4,sum5;
printf("Parameters:\n");
printf(
"Adapter number to run on %i\n", IpDefrag.
adapterNo);
printf(
"Number of streams/threads %i\n", IpDefrag.
reasmCnt);
printf(
"Number of un-matched streams/threads %i\n", IpDefrag.
unmCnt);
printf(
"Fragment timeout (ms) %i\n", (
int)(IpDefrag.
fragTimeout/100000));
printf("IPFMode table timeout (ms) %i\n", tableTimeout/10);
printf("IPFMode TablePersist ");
if (tablePersistTimeout) {
printf("TimeoutOnly\n");
} else {
printf("LastFragment\n");
}
printf(
"\nRunning with extended descriptor %i\n", IpDefrag.
ExtDescrType);
printf("-------------------------------------------------------------------\n");
printf("Re-assembling streams:\n");
printf(" # Completed First frag Deleted partial Non-fragmented Id\n");
printf(" (timed out) packets clashes\n");
sum1 = sum2 = sum3 = sum4 = sum5 = 0;
for (i = 0; i < IpDefrag.
reasmCnt; i++) {
}
printf("sum:%7d, %8d, %10d, %14d, %12d\n", sum1,sum2,sum3,sum4,sum5);
printf("Un-matched fragment streams:\n");
printf(" # Fragments Deleted frags\n");
printf(" received (timed out)\n");
for (i = 0; i< IpDefrag.
unmCnt; i++) {
}
}
printf("\n-------------------------------------------------------------------\n");
fflush(stdout);
sleep(2);
}
hashTblFreed = 0;
waitTblFreed = 0;
msgboxElmFreed = 0;
for (i = 0; i < IpDefrag.
reasmCnt; i++) {
}
hashTblFreed++;
}
}
}
for (i = 0; i < IpDefrag.
unmCnt; i++) {
}
for (i = 0; i < IpDefrag.
unmCnt; i++) {
while (pWait) {
waitTblFreed++;
}
}
if (msgboxElmFreed || hashTblFreed || waitTblFreed) {
printf("\n----------------------------------------------------------");
if (hashTblFreed) {
printf("\n%i entries remained in hash table on exit", hashTblFreed);
}
if (waitTblFreed) {
printf("\n%i entries remained in un-matched fragments wait-table on exit", waitTblFreed);
}
if (msgboxElmFreed) {
printf("\n%i entries remained in msg boxes on exit", msgboxElmFreed);
}
printf("\n----------------------------------------------------------\n");
}
fprintf(stderr, "NT_NTPL() failed: %s\n", errorBuffer);
return -1;
}
fprintf(stderr, "NT_ConfigClose() failed: %s\n", errorBuffer);
return -1;
}
return 0;
}