Commit 50233e20 authored by 's avatar
Browse files

Added support for Napatech NT-series cards


git-svn-id: file:///home/svn/mapi/trunk@1447 8d5bb341-7cf1-0310-8cf6-ba355fef3186
parent 18335c4c
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <pthread.h>
#include <pcap.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <netinet/in.h>
#include "mapi.h"
#include "mapidrv.h"
#include "mapidlib.h"
#include "mapidevices.h"
#include "flist.h"
#include "debug.h"
#include "mapi_errors.h"
#ifdef PRECLASSIFICATION
#include "mapidflib.h"
#include "parseconf.h"
#include "printfstring.h"
#include "bpfcompiler.h"
#endif
#define bool_t int
/* The NTCommonInterface.h header provides the interface definitions
* * for the Napatech NTCI library */
#include <NTCommonInterface.h>
/* These headers are needed when capturing traffic */
#include <packetfeedstructure.h>
#include <packetdescriptor.h>
#include <NTCI_packetfeed.h>
#include <NTCI_errorcode.h>
#include <NTCI_capabilities.h>
#include <capabilitiesstructure.h>
#include <NTCI_packetclassification.h>
#include <packetclassificationstructure.h>
#include <extendeddescriptor05.h>
typedef struct napatech_instance {
pthread_attr_t th_attr;
pthread_t th_proc;
handle_t napatechhandle;
uint32_t packetfeedhandle;
uint32_t channelsBitmask;
FeedBufferInformationType1_t bufferInfo;
int eventset;
short skip;
void *buf;
int file;
char *name;
int id;
mapi_offline_device_status_t *offline_status;
mapid_hw_info_t hwinfo;
mapidlib_instance_t mapidlib;
u_int8_t *gpp_base;
} napatech_instance_t;
__attribute__ ((constructor)) void init ();
__attribute__ ((destructor)) void fini ();
static flist_t *devlist;
/* for mapidlib errorcode */
int
mapidrv_get_errno(int devid,int fd)
{
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_get_errno"));
napatech_instance_t *i=flist_get(devlist,devid);
return mapid_get_errno(&i->mapidlib,fd);
}
#ifdef WITH_AUTHENTICATION
int mapidrv_authenticate(int devid, int fd, char *vo)
{
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_authenticate"));
napatech_instance_t *i = flist_get(devlist, devid);
return mapid_authenticate(&i->mapidlib, fd, vo);
}
#endif
int
mapidrv_apply_function (int devid,int fd, int flags, char* function, mapiFunctArg *fargs)
{
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_apply_function"));
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_apply_function; devid = %d; fd = %d; function = %s", devid, fd, function));
napatech_instance_t *i=flist_get(devlist,devid);
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_apply_function; &i = %x", (int)i));
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_apply_function; &i->mapidlib = %x", (int)(&i->mapidlib)));
int _flags = flags;
return mapid_apply_function(&i->mapidlib, fd, function, fargs, _flags);
}
int mapidrv_add_device(const char *devname, int file,int devid, global_function_list_t *gflist,void *olstatus)
{
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_add_device"));
napatech_instance_t *i=malloc(sizeof(napatech_instance_t));
i->napatechhandle = NULL;
i->packetfeedhandle = 0;
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_add_device; devname: %s", devname));
i->name=strdup(devname);
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_add_device; i->name: %s", i->name));
i->id=devid;
// i->dagfd=-1;
i->file=file;
// i->th_proc=0;
i->hwinfo.offline=0;
i->hwinfo.devfd=i->napatechhandle;
i->hwinfo.gflist=gflist;
i->hwinfo.pkt_drop=0;
i->offline_status = olstatus;
if(devid<0)
i->hwinfo.offline = 1;
DEBUG_CMD(Debug_Message("Added device %d: %s", devid, devname));
flist_append(devlist,devid,i);
mapid_init(&i->mapidlib);
return 0;
}
int mapidrv_delete_device(int devid)
{
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_delete_device"));
napatech_instance_t *i=flist_remove(devlist,devid);
uint32_t result;
if (i!=NULL) {
int err=0;
if (i->th_proc && pthread_equal(i->th_proc, pthread_self())==0) {
DEBUG_CMD(Debug_Message("Calling thread != th_proc (%lu != %lu), cancelling", i->th_proc, pthread_self()));
fflush(stdout);
if ((err=pthread_cancel(i->th_proc))!=0) {
if (!(i->hwinfo.offline==1 && err==ESRCH)) {
DEBUG_CMD(Debug_Message("WARNING: Could not cancel thread for devid %d (%s)", devid, strerror(err)));
fflush(stdout);
}
}
}
if(i->napatechhandle != NULL) {
if((result = NTCI_DestroyPacketFeed(i->napatechhandle, i->packetfeedhandle)) != NTCI_ERRCODE_SUCCESS) {
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_delete_device; Failed to destroy packet feed! (%i)\n", result));
}
NTCI_CloseCard(i->napatechhandle);
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_delete_device; Napatech device closed"));
}
mapid_destroy(&i->mapidlib);
free(i->name);
if(i->offline_status != NULL)
*(i->offline_status) = DEVICE_DELETED;
free(i);
}
return 0;
}
static unsigned
// process_pkts(void *buf,unsigned len, napatech_instance_t *i)
process_pkts(BufferInformationSectionType1_t* bufferInformation, napatech_instance_t *i)
{
/* DEBUG_CMD(Debug_Message("napatechdrv: process_pkts"));
DEBUG_CMD(Debug_Message("napatechdrv: process_pkts; packet count: %d", bufferInformation->numDescriptorsAvailable)); */
mapid_pkthdr_t mhdr;
uint32_t packet = 0;
uint8_t *frame = NULL;
PacketDescriptorType2_t *descriptor = (PacketDescriptorType2_t *)(((uint8_t*)(i->bufferInfo.bufferBaseAddress)) + bufferInformation->sectionOffset);
// pNetFlow->flowStat.uiTotalDropped+=bufferInformation.numDroppedFrames;
if(descriptor->ExtensionFormat == EXTENDED_DESCRIPTOR_05_TYPE) {
for(packet=0; packet < bufferInformation->numDescriptorsAvailable; packet++) {
i->hwinfo.pkts++;
PacketExtDescriptorType05_t *pExtDescr = (PacketExtDescriptorType05_t*)(((uint8_t*)descriptor) + sizeof(PacketDescriptorType2_t));
frame = ((uint8_t*)descriptor) + sizeof(PacketDescriptorType2_t) + (descriptor->ExtensionLength << 3);
mhdr.ts = descriptor->Timestamp;
mhdr.ifindex = 0; // ?
mhdr.caplen = descriptor->StoredLength;
mhdr.wlen = descriptor->WireLength;
// ? TODO - modify third argument to pass test_packet_read
mapid_process_pkt(&i->mapidlib, (unsigned char*)frame, frame + (descriptor->StoredLength - descriptor->WireLength), &mhdr);
/* Avance to the next packet. */
descriptor = (PacketDescriptorType2_t*)((uint8_t*)descriptor + descriptor->StoredLength);
}
} else {
for(packet=0; packet < bufferInformation->numDescriptorsAvailable; packet++) {
i->hwinfo.pkts++;
frame = ((uint8_t*)descriptor) + sizeof(PacketDescriptorType2_t);
mhdr.ts = descriptor->Timestamp;
mhdr.ifindex = 0; // ?
mhdr.caplen = descriptor->StoredLength;
mhdr.wlen = descriptor->WireLength;
// ? TODO - modify third argument to pass test_packet_read
mapid_process_pkt(&i->mapidlib, (unsigned char*)frame, frame + (descriptor->StoredLength - descriptor->WireLength), &mhdr);
/* Avance to the next packet. */
descriptor = (PacketDescriptorType2_t*)((uint8_t*)descriptor + descriptor->StoredLength);
}
}
return 0;
}
static unsigned
process_pkts_offline(void *buf,unsigned len, napatech_instance_t *i)
{
DEBUG_CMD(Debug_Message("napatechdrv: process_pkts_offline"));
/* TODO */
return 0;
}
static void
mapidrv_offline_proc_loop(void *arg)
{
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_offline_proc_loop"));
/* TODO */
}
static void
mapidrv_proc_loop (void *arg)
{
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_proc_loop"));
int devid = *(int *)arg;
napatech_instance_t *i=flist_get(devlist,devid);
int err;
BufferRequestSampledType2_t request;
// BufferInformationSectionType6_t bufferInformation;
BufferInformationSectionType1_t bufferInformation;
uint32_t result;
request.common.waitTimeoutMS=GET_NEXT_BUFFER_INFINITE_WAIT;
if ((err=pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) != 0) {
DEBUG_CMD(Debug_Message("ERROR: pthread_setcanceltype failed (%s)",strerror(err)));
return;
}
if ((err=pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)) != 0) {
DEBUG_CMD(Debug_Message("ERROR: pthread_setcancelstate (%s) failed", strerror(err)));
return;
}
while (1)
{
// DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_proc_loop; i->napatechhandle: %d; i->packetfeedhandle: %d", i->napatechhandle, i->packetfeedhandle));
result = NTCI_GetNextBuffer(i->napatechhandle,
i->packetfeedhandle,
STID_BUFFER_REQUEST_SAMPLED_TYPE2,
&request,
STID_BUFFER_INFORMATION_SECTION_TYPE1,
&bufferInformation);
if(result == NTCI_ERRCODE_SUCCESS) {
if(bufferInformation.numDescriptorsAvailable > 0) process_pkts(&bufferInformation, i);
NTCI_ReleaseBuffer(i->napatechhandle,
i->packetfeedhandle,
STID_BUFFER_INFORMATION_SECTION_TYPE1,
&bufferInformation);
} else if(result != NTCI_STATUSCODE_NO_PACKETS_AVAILABLE) {
DEBUG_CMD(Debug_Message("Failed to get buffers. Error code %d\n", result)); //stderr
break;
}
}
}
int
mapidrv_read_results (int devid,int fd, int fid, mapid_result_t** result)
{
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_read_results"));
napatech_instance_t *i=flist_get(devlist,devid);
return mapid_read_results(&i->mapidlib,fd,fid,result);
}
mapid_funct_info_t* mapidrv_get_flow_functions(int devid,int fd)
{
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_get_flow_functions"));
napatech_instance_t *i=flist_get(devlist,devid);
return mapid_get_flow_functions(&i->mapidlib,fd);
}
int mapidrv_get_flow_info(int devid,int fd,mapi_flow_info_t *info) {
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_get_flow_info"));
napatech_instance_t *i=flist_get(devlist,devid);
return mapid_get_flow_info(&i->mapidlib,fd,info);
}
int
mapidrv_create_offline_flow (int devid, int format,int fd,char **devtype)
{
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_create_offline_flow"));
napatech_instance_t *i=flist_get(devlist,devid);
/* TODO */
return 0;
}
int
mapidrv_create_flow (int devid, int fd, char **devtype)
{
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_create_flow"));
napatech_instance_t *i;
uint32_t result=0;
uint32_t feedPriorities[] = { 1 };
FeedConfigSampledType2_t feedConfig;
// BufferInformationSectionType6_t bufferInformation;
// FeedBufferInformationType1_t bufferInfo;
// BufferRequestSampledType2_t request;
CardHardwareCapabilitiesType1_t cardCapabilities;
uint32_t channelsBitmask=0;
CardHardwareVersionCapabilitiesType3_t data3;
if(devid < 0)
{
napatech_instance_t *inst=flist_get(devlist,devid);
*devtype=MAPI_DEVICE_NAPATECH;
inst->hwinfo.offline=1;
inst->hwinfo.cap_length=1500;
inst->hwinfo.devtype=MAPI_DEVICE_NAPATECH;
inst->hwinfo.devid=inst->id;
inst->hwinfo.pkts=0;
DEBUG_CMD(Debug_Message("Reading from trace file: %s", inst->name));
return mapid_add_flow(&inst->mapidlib,fd,&inst->hwinfo,NULL);
}
i=flist_get(devlist,devid);
i->hwinfo.offline=0;
*devtype=MAPI_DEVICE_NAPATECH;
//Open device if it is not already open
if (i->napatechhandle == NULL)
{
/* Open the correct card. */
DEBUG_CMD(Debug_Message("mapinapatechdrv: mapidrv_create_flow; Trying to open NTCI based adapter #%d\n", i->name[strlen(i->name) - 1] - '0'));
if(strstr(i->name, "xyxs") != NULL) {
/* X card series. */
DEBUG_CMD(Debug_Message("mapinapatechdrv: mapidrv_create_flow; Opening X card series."));
i->napatechhandle = NTCI_OpenCard(NTCI_CARD_TYPE_ANY, i->name[strlen(i->name) - 1] - '0');
} else if(strstr(i->name, "ntx") != NULL) {
DEBUG_CMD(Debug_Message("mapinapatechdrv: mapidrv_create_flow; Opening ntxc card series."));
i->napatechhandle = NTCI_OpenCard(NTCI_ANY_NAPATECH_CARD_TYPE, i->name[strlen(i->name) - 1] - '0');
}
if(i->napatechhandle==NULL) {
DEBUG_CMD(Debug_Message("mapinapatechdrv: mapidrv_create_flow; Failed to open adapter.\n"));
return NTCI_ERRCODE_NO_DEVICE_OPEN; // TODO
}
i->hwinfo.devfd = (int)i->napatechhandle;
DEBUG_CMD(Debug_Message("mapinapatechdrv: mapidrv_create_flow; NTCI_CardIdentification() = %d", NTCI_CardIdentification(i->napatechhandle)));
if((result = NTCI_GetCapabilities(i->napatechhandle,
CAPID_HARDWARE,
NOT_SUB_CAPABILITIES,
STID_CARD_HARDWARE_CAPABILITIES_TYPE1,
&cardCapabilities)) != NTCI_ERRCODE_SUCCESS) {
DEBUG_CMD(Debug_Message(stderr, "Error finding adapter capabilities: %i\n", result));
}
channelsBitmask = cardCapabilities.totalChannelsBitmask;
/* Check if we need to use NTPL to set up feeds. */
if((result = NTCI_GetCapabilities(i->napatechhandle,
CAPID_VERSION,
NOT_SUB_CAPABILITIES,
STID_CARD_HARDWARE_VERSION_CAPABILITIES_TYPE3,
&data3)) != NTCI_ERRCODE_SUCCESS) {
DEBUG_CMD(Debug_Message(stderr, "Error finding HW capabilities: %i\n", result));
}
switch (data3.AdapterCard.dwInfoType) {
case 1:
if((uint16_t)((data3.AdapterCard.u.InfoType1.qwFpgaId>>8)&0xFF) >= 32) {
if(system("grep \"#disableMultiFeed\" /opt/napatech/config/default.cfg > /dev/null") != 0) {
if(system("grep disableMultiFeed /opt/napatech/config/default.cfg | grep 0 > /dev/null") == 0) {
channelsBitmask = 0;
}
} else {
channelsBitmask = 0;
}
}
break;
case 2:
if((uint16_t)((data3.AdapterCard.u.InfoType2.qwFpgaId>>8)&0xFF) >= 32) {
if(system("grep \"#disableMultiFeed\" /opt/napatech/config/default.cfg > /dev/null") != 0) {
if(system("grep disableMultiFeed /opt/napatech/config/default.cfg | grep 0 > /dev/null") == 0) {
channelsBitmask = 0;
}
} else {
channelsBitmask = 0;
}
}
break;
default:
// DEBUG_MSG(Debug_Message("Unsupported FPGA!")); // ?
return;
}
i->hwinfo.devtype=MAPI_DEVICE_NAPATECH;
i->hwinfo.devid=i->id;
i->hwinfo.pkts=0;
/* Set up the packet feed engine for a single feed.
*
* The feedPriorities array is used to assign the
* priorities of different feeds when creating multiple
* simultaneous feeds; in this example it is redundant
* as only one entry is required */
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_create_flow; NTCI_SetupPacketFeedEngine(%d, %d, %d)", i->napatechhandle, 1, feedPriorities[0]));
if((result = NTCI_SetupPacketFeedEngine(i->napatechhandle, 1, feedPriorities)) != NTCI_ERRCODE_SUCCESS) {
DEBUG_CMD(Debug_Message("Failed to initialise packet feed engine (%i)\n", result)); //stderr
NTCI_CloseCard(i->napatechhandle);
return -1;
}
if(channelsBitmask == 0) {
PassFilter_t command;
command.WriteHW = TRUE;
sprintf(command.achFilterString, "Capture[Priority=0;Feed=0]=ALL");
/* TODO - preclasification ^^^ */
if((result = NTCI_PacketClassification(i->napatechhandle,
STID_PASS_FILTER,
&command)) != NTCI_ERRCODE_SUCCESS) {
FilterError_t error;
result = NTCI_PacketClassification(i->napatechhandle,
STID_GET_FILTER_ERROR,
&error);
DEBUG_CMD(Debug_Message("%s\n",error.achFilterError1)); // stderr
DEBUG_CMD(Debug_Message("%s\n",error.achFilterError2)); // stderr
DEBUG_CMD(Debug_Message("%s\n",error.achFilterError3)); // stderr
NTCI_CloseCard(i->napatechhandle);
return -1;
}
}
/* Create the packet feed.
*
* First, initialise the feedConfig structure */
/* provide packets in sections */
feedConfig.bufferType = BUFFER_SECTION;
/* hardware native timestamps */
feedConfig.timestampType = TIMESTAMP_NATIVE;
/* do not deliver corrupted packets */
feedConfig.dropErroredPacketsFlag = 0;
/* slicing is disabled */
feedConfig.sliceLength = 0;
/* large samples are used: these better handle network
* traffic fluctuations */
feedConfig.bufferBehaviour = SMALL_REGULAR_SAMPLES;
/* Create the packet feed.
*
* PACKET_FEED_SOURCE_SAMPLED is used to specify real time
* sampling of network traffic. */
if((result = NTCI_CreatePacketFeed(i->napatechhandle,
0,
channelsBitmask,
PACKET_FEED_SOURCE_SAMPLED,
PACKET_FEED_DESTINATION_EXTERNAL,
STID_FEED_CONFIG_SAMPLED_TYPE2,
&feedConfig,
&i->packetfeedhandle)) != NTCI_ERRCODE_SUCCESS) {
DEBUG_CMD(Debug_Message("Failed to create a packet feed (%i)\n", result)); //stderr
NTCI_CloseCard(i->napatechhandle);
return -1;
}
// i->packetfeedhandle = packetFeedHandle;
/* find the location of the feed buffer where new
* data will be stored */
if((result = NTCI_GetPacketFeedBuffers(i->napatechhandle,
i->packetfeedhandle,
STID_FEED_BUFFER_INFORMATION_TYPE1,
&i->bufferInfo)) != NTCI_ERRCODE_SUCCESS) {
DEBUG_CMD(Debug_Message("Unable to retrieve the location of the feed buffer.\n")); // stderr
NTCI_CloseCard(i->napatechhandle);
return -1;
}
if((result = NTCI_StartPacketFeed(i->napatechhandle, i->packetfeedhandle)) != NTCI_ERRCODE_SUCCESS) {
DEBUG_CMD(Debug_Message("Error while starting packet feed (%i)\n", result)); // stderr
NTCI_CloseCard(i->napatechhandle);
return -1;
}
//Start processing thread
if (pthread_attr_init (&i->th_attr) != 0)
{
DEBUG_CMD(Debug_Message("ERROR: pthread_attr_init failed"));
return DAGDRV_PTHR_ERR; // TODO
}
if (pthread_create(&i->th_proc, &i->th_attr, (void *) mapidrv_proc_loop, (void *) &(i->id)) != 0)
{
DEBUG_CMD(Debug_Message("ERROR: pthread_create failed"));
return DAGDRV_PTHR_ERR; // TODO
}
}
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_create_flow_; i->napatechhandle: %d; i->packetfeedhandle: %d", i->napatechhandle, i->packetfeedhandle));
return mapid_add_flow(&i->mapidlib,fd,&i->hwinfo,NULL);
}
int
mapidrv_connect (int devid,int fd)
{
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_connect"));
int ret;
napatech_instance_t *i=flist_get(devlist,devid);
if(i == NULL)
return -1;
ret=mapid_connect(&i->mapidlib,fd);
if(i->hwinfo.offline==4) {
if (pthread_attr_init (&i->th_attr) != 0)
{
DEBUG_CMD(Debug_Message("ERROR: pthread_attr_init failed"));
return NICDRV_PTHR_ERR;
}
if (pthread_create
(&i->th_proc, &i->th_attr, (void *) mapidrv_offline_proc_loop, (void *) &(i->id)) != 0)
{
DEBUG_CMD(Debug_Message("ERROR: pthread_create failed"));
return NICDRV_PTHR_ERR;
}
}
return ret;
}
int
mapidrv_start_offline_device( int devid)
{
DEBUG_CMD(Debug_Message("napatechdrv: mapidrv_start_offline_device"));
napatech_instance_t *i = flist_get(devlist,devid);