/** * loop over the DataTemplateInfo (fieldinfo,datainfo) to get the IPFIX values to store in database */ char* getRecData(IpfixDbWriter* ipfixDbWriter,Table* table, SourceID* sourceID, DataTemplateInfo* dataTemplateInfo,uint16_t length, FieldData* data) { int i ,j, k, n; uint64_t intdata = 0; uint32_t flowstartsec = 0; /**begin query string for insert statement*/ char insert[STARTLEN+(table->countCol * INS_WIDTH)]; strcpy(insert,"INSERT INTO "); /**make string for the column names*/ char ColNames[table->countCol * INS_WIDTH]; strcpy(ColNames," ("); /**make string for the values given by the IPFIX_TYPEID stored in the record*/ char ColValues[table->countCol * INS_WIDTH]; strcpy(ColValues," VALUES ("); char stringtmp[INS_WIDTH];// needed to cast from char to string /**loop over the columname and loop over the IPFIX_TYPEID of the record to get the corresponding */ /**data to store and make insert statement*/ for( i=0; i < table->countCol; i++) { for( j=0; strcmp(identify[j].cname,"END") != 0; j++) { if(columnsNames[i] == identify[j].cname) { int notfound = 1; strncat(ColValues,"'",sizeof(char)+1); strncat(ColNames,columnsNames[i],strlen(columnsNames[i])+1); if( i != table->countCol-1) strncat(ColNames,",",sizeof(char)+1); if( i == table->countCol-1) strncat(ColNames,") ",(2*sizeof(char))+1); if(dataTemplateInfo->fieldCount > 0) { for(k=0; k < dataTemplateInfo->fieldCount; k++) { if(dataTemplateInfo->fieldInfo[k].type.id == identify[j].ipfixId) { notfound = 0; intdata = getdata(dataTemplateInfo->fieldInfo[k].type,(data+dataTemplateInfo->fieldInfo[k].offset)); sprintf(stringtmp,"%Lu",(uint64_t)intdata); strncat(ColValues,stringtmp,strlen(stringtmp)+1); strncat(ColValues,"'",sizeof(char)+1); if(identify[j].ipfixId == IPFIX_TYPEID_flowStartSeconds) { flowstartsec = intdata; } if( i != table->countCol-1) strncat(ColValues,",",sizeof(char)+1); if( i == table->countCol-1) strncat(ColValues,")",sizeof(char)+1); break; } } } if( dataTemplateInfo->dataCount > 0 && notfound) { for(n=0; n < dataTemplateInfo->dataCount; n++) { if(dataTemplateInfo->dataInfo[n].type.id == identify[j].ipfixId) { notfound = 0; intdata = getdata(dataTemplateInfo->dataInfo[n].type,(dataTemplateInfo->data+dataTemplateInfo->dataInfo[n].offset)); sprintf(stringtmp,"%Lu",(uint64_t)intdata); strncat(ColValues,stringtmp,strlen(stringtmp)+1); strncat(ColValues,"'",sizeof(char)+1); if( i != table->countCol-1) strncat(ColValues,",",sizeof(char)+1); if( i == table->countCol-1) strncat(ColValues,")",sizeof(char)+1); break; } } } if(notfound) { if(identify[j].ipfixId == EXPORTERID) { /**lookup exporter buffer to get exporterID from sourcID and expIp**/ uint32_t expID = getExporterID(ipfixDbWriter, table, sourceID); sprintf(stringtmp,"%u",(uint32_t)expID); strncat(ColValues,stringtmp,strlen(stringtmp)+1); strncat(ColValues,"'",sizeof(char)+1); } else { intdata = getdefaultIPFIXdata(identify[j].ipfixId); sprintf(stringtmp,"%Lu",(uint64_t)intdata); strncat(ColValues,stringtmp,strlen(stringtmp)+1); strncat(ColValues,"'",sizeof(char)+1); } if( i != table->countCol-1) strncat(ColValues,",",sizeof(char)+1); if( i == table->countCol-1) strncat(ColValues,")",sizeof(char)+1); } } } } /**make hole query string for the insert statement*/ char tablename[TABLE_WIDTH] ; char* tablen = getTableName(ipfixDbWriter, table, flowstartsec); strcpy(tablename, tablen); /** Insert statement = INSERT INTO + tablename + Columnsname + Values of record*/ strncat(insert, tablename,strlen(tablename)+1); strncat(insert,ColNames,strlen(ColNames)+1); strncat(insert,ColValues, strlen(ColValues)+1); char* insertTableStr = (char*) malloc((strlen(insert)+1)*sizeof(char)); strcpy(insertTableStr,insert); return insertTableStr; }
/** * loop over properties and template to get the IPFIX values in correct order to store in database * The result is written to BSON Object, and flowstart is returned */ mongo::BSONObj IpfixDbWriterMongo::getInsertObj(const IpfixRecord::SourceID& sourceID, TemplateInfo& dataTemplateInfo,uint16_t length, IpfixRecord::Data* data) { uint64_t intdata = 0; uint64_t intdata2 = 0; uint32_t k; bool notfound, notfound2; mongo::BSONObjBuilder obj; time_t flowstartsec = 0; if (!allProp) { /** loop over a subset of elements (selected properties) and loop over the IPFIX_TYPEID of the record * to get the corresponding data to store and make insert statement */ for(vector<Property>::iterator prop = documentProperties.begin(); prop != documentProperties.end(); prop++) { if (prop->ipfixId == EXPORTERID) { // if this is the same source ID as last time, we get the exporter id from currentExporter if ((currentExporter != NULL) && equalExporter(sourceID, currentExporter->sourceID)) { DPRINTF("Exporter is same as last time (ODID=%d, id=%d)", sourceID.observationDomainId, currentExporter->id); intdata = (uint64_t)currentExporter->id; } else { // lookup exporter buffer to get exporterID from sourcID and expIp intdata = (uint64_t)getExporterID(sourceID); } } else { notfound = true; // try to gather data required for the field if(dataTemplateInfo.fieldCount > 0) { // look inside the ipfix record for(k=0; k < dataTemplateInfo.fieldCount; k++) { if( dataTemplateInfo.fieldInfo[k].type.enterprise == prop->enterprise && dataTemplateInfo.fieldInfo[k].type.id == prop->ipfixId) { notfound = false; intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)); DPRINTF("IpfixDbWriterMongo::getData: really saw ipfix id %d in packet with intdata %llX, type %d, length %d and offset %X", prop->ipfixId, intdata, dataTemplateInfo.fieldInfo[k].type.id, dataTemplateInfo.fieldInfo[k].type.length, dataTemplateInfo.fieldInfo[k].offset); break; } } } if( dataTemplateInfo.dataCount > 0 && notfound) { // look in static data fields of template for data for(k=0; k < dataTemplateInfo.dataCount; k++) { if(dataTemplateInfo.fieldInfo[k].type.enterprise == prop->enterprise && dataTemplateInfo.dataInfo[k].type.id == prop->ipfixId) { notfound = false; intdata = getData(dataTemplateInfo.dataInfo[k].type,(dataTemplateInfo.data+dataTemplateInfo.dataInfo[k].offset)); break; } } } if(notfound) { notfound2 = true; // for some Ids, we have an alternative if(prop->enterprise == 0) { switch (prop->ipfixId) { case IPFIX_TYPEID_flowStartSeconds: if(dataTemplateInfo.fieldCount > 0) { for(k=0; k < dataTemplateInfo.fieldCount; k++) { // look for alternative (flowStartMilliseconds/1000) if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowStartMilliseconds) { intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000; notfound = false; break; } // if no flow start time is available, maybe this is is from a netflow from Cisco // then - as a last alternative - use flowStartSysUpTime as flow start time if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowStartSysUpTime) { intdata2 = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)); notfound2 = false; } } if(notfound && !notfound2) { intdata = intdata2; notfound = false; } } break; case IPFIX_TYPEID_flowEndSeconds: if(dataTemplateInfo.fieldCount > 0) { for(k=0; k < dataTemplateInfo.fieldCount; k++) { // look for alternative (flowEndMilliseconds/1000) if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowEndMilliseconds) { intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000; notfound = false; break; } // if no flow end time is available, maybe this is from a netflow from Cisco // then use flowEndSysUpTime as flow start time if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowEndSysUpTime) { intdata2 = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)); notfound2 = false; } } if(notfound && !notfound2) { intdata = intdata2; notfound = false; } } break; } } else if (prop->enterprise==IPFIX_PEN_reverse) { switch (prop->ipfixId) { case IPFIX_TYPEID_flowStartSeconds: // look for alternative (revFlowStartMilliseconds/1000) if(dataTemplateInfo.fieldCount > 0) { for(k=0; k < dataTemplateInfo.fieldCount; k++) { if(dataTemplateInfo.fieldInfo[k].type == InformationElement::IeInfo(IPFIX_TYPEID_flowStartMilliseconds, IPFIX_PEN_reverse)) { intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000; notfound = false; break; } } } break; case IPFIX_TYPEID_flowEndSeconds: // look for alternative (revFlowEndMilliseconds/1000) if(dataTemplateInfo.fieldCount > 0) { for(k=0; k < dataTemplateInfo.fieldCount; k++) { if(dataTemplateInfo.fieldInfo[k].type == InformationElement::IeInfo(IPFIX_TYPEID_flowEndMilliseconds, IPFIX_PEN_reverse)) { intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000; notfound = false; break; } } } break; } } // if still not found, get default value if(notfound) intdata = prop->defaultValue; } // we need extra treatment for timing related fields if(prop->enterprise == 0 ) { switch (prop->ipfixId) { case IPFIX_TYPEID_flowStartSeconds: // save time for table access if (flowstartsec==0) flowstartsec = intdata; break; case IPFIX_TYPEID_flowEndSeconds: break; case IPFIX_TYPEID_flowStartMilliseconds: // if flowStartSeconds is not stored in one of the columns, but flowStartMilliseconds is, // then we use flowStartMilliseconds for table access // This is realized by storing this value only if flowStartSeconds has not yet been seen. // A later appearing flowStartSeconds will override this value. if (flowstartsec==0) flowstartsec = intdata/1000; case IPFIX_TYPEID_flowEndMilliseconds: // in the database the millisecond entry is counted from last second intdata %= 1000; break; } } else if (prop->enterprise==IPFIX_PEN_reverse) switch (prop->ipfixId) { case IPFIX_TYPEID_flowStartMilliseconds: case IPFIX_TYPEID_flowEndMilliseconds: // in the database the millisecond entry is counted from last second intdata %= 1000; break; } } msg(MSG_DEBUG, "saw ipfix id %s (element ID %d) in packet with intdata %llX", prop->propertyName, prop->ipfixId, static_cast<int64_t>(intdata)); if (beautyProp) obj << prop->propertyName << static_cast<long long int>(intdata); else obj << boost::lexical_cast<std::string>(prop->ipfixId).c_str() << static_cast<long long int>(intdata); if (flowstartsec == 0) { msg(MSG_ERROR, "IpfixDbWriterMongo: Failed to get timing data from record. Will be saved in default table."); } } } else { /* Dump all elements to DB */ if(dataTemplateInfo.fieldCount > 0) { // look in ipfix records for(int k=0; k < dataTemplateInfo.fieldCount; k++) { intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)); DPRINTF("IpfixDbWriterMongo::getData: dumping from packet intdata %llX, type %d, length %d and offset %X", intdata, dataTemplateInfo.fieldInfo[k].type.id, dataTemplateInfo.fieldInfo[k].type.length, dataTemplateInfo.fieldInfo[k].offset); obj << boost::lexical_cast<std::string>(dataTemplateInfo.fieldInfo[k].type.id).c_str() << static_cast<long long int>(intdata); } } if( dataTemplateInfo.dataCount > 0) { // look in static data fields of template for data for(int k=0; k < dataTemplateInfo.dataCount; k++) { intdata = getData(dataTemplateInfo.dataInfo[k].type,(dataTemplateInfo.data+dataTemplateInfo.dataInfo[k].offset)); obj << boost::lexical_cast<std::string>(dataTemplateInfo.fieldInfo[k].type.id).c_str() << static_cast<long long int>(intdata); } } } return obj.obj(); }
/** * loop over the IpfixRecord::DataTemplateInfo (fieldinfo,datainfo) to get the IPFIX values to store in database * The result is written into statemStr which must have sufficient space! */ char* IpfixDbWriter::getInsertStatement(char* statemStr, IpfixRecord::SourceID* sourceID, IpfixRecord::DataTemplateInfo* dataTemplateInfo,uint16_t length, IpfixRecord::Data* data, char** locks, int maxlocks) { int j, k; uint64_t intdata = 0; uint32_t flowstartsec = 0; /**begin query string for insert statement*/ strcpy(statemStr,"INSERT INTO "); /**make string for the column names*/ char ColNames[numberOfColumns * INS_WIDTH]; strcpy(ColNames," ("); /**make string for the values given by the IPFIX_TYPEID stored in the record*/ char ColValues[numberOfColumns * INS_WIDTH]; strcpy(ColValues," VALUES ("); /**loop over the columname and loop over the IPFIX_TYPEID of the record to get the corresponding data to store and make insert statement*/ for( j=0; identify[j].cname != 0; j++) { bool notfound = true; if (identify[j].ipfixId == EXPORTERID) { /**lookup exporter buffer to get exporterID from sourcID and expIp**/ uint32_t expID = getExporterID(sourceID); intdata = expID; notfound = false; } else { // try to gather data required for the field if(dataTemplateInfo->fieldCount > 0) { // look inside the ipfix data packet for(k=0; k < dataTemplateInfo->fieldCount; k++) { if(dataTemplateInfo->fieldInfo[k].type.id == identify[j].ipfixId) { notfound = false; intdata = getdata(dataTemplateInfo->fieldInfo[k].type,(data+dataTemplateInfo->fieldInfo[k].offset)); DPRINTF("IpfixDbWriter::getRecData: really saw ipfix id %d in packet with intdata %llX, type %d, length %d and offset %X", identify[j].ipfixId, intdata, dataTemplateInfo->fieldInfo[k].type.id, dataTemplateInfo->fieldInfo[k].type.length, dataTemplateInfo->fieldInfo[k].offset); } } } if( dataTemplateInfo->dataCount > 0 && notfound) { // look in static data fields of template for data for(k=0; k < dataTemplateInfo->dataCount; k++) { if(dataTemplateInfo->dataInfo[k].type.id == identify[j].ipfixId) { notfound = false; intdata = getdata(dataTemplateInfo->dataInfo[k].type,(dataTemplateInfo->data+dataTemplateInfo->dataInfo[k].offset)); } } } if(notfound) { // for some Ids, we have an alternative switch (identify[j].ipfixId) { case IPFIX_TYPEID_flowStartSeconds: // look for alternative (flowStartMilliSeconds/1000) if(dataTemplateInfo->fieldCount > 0) { for(k=0; k < dataTemplateInfo->fieldCount; k++) { if(dataTemplateInfo->fieldInfo[k].type.id == IPFIX_TYPEID_flowStartMilliSeconds) { intdata = getdata(dataTemplateInfo->fieldInfo[k].type,(data+dataTemplateInfo->fieldInfo[k].offset)) / 1000; notfound = false; break; } } } break; case IPFIX_ETYPEID_revFlowStartSeconds: // look for alternative (revFlowStartMilliSeconds/1000) if(dataTemplateInfo->fieldCount > 0) { for(k=0; k < dataTemplateInfo->fieldCount; k++) { if(dataTemplateInfo->fieldInfo[k].type.id == IPFIX_ETYPEID_revFlowStartMilliSeconds) { intdata = getdata(dataTemplateInfo->fieldInfo[k].type,(data+dataTemplateInfo->fieldInfo[k].offset)) / 1000; notfound = false; break; } } } break; case IPFIX_TYPEID_flowEndSeconds: // look for alternative (flowEndMilliSeconds/1000) if(dataTemplateInfo->fieldCount > 0) { for(k=0; k < dataTemplateInfo->fieldCount; k++) { if(dataTemplateInfo->fieldInfo[k].type.id == IPFIX_TYPEID_flowEndMilliSeconds) { intdata = getdata(dataTemplateInfo->fieldInfo[k].type,(data+dataTemplateInfo->fieldInfo[k].offset)) / 1000; notfound = false; break; } } } break; case IPFIX_ETYPEID_revFlowEndSeconds: // look for alternative (revFlowEndMilliSeconds/1000) if(dataTemplateInfo->fieldCount > 0) { for(k=0; k < dataTemplateInfo->fieldCount; k++) { if(dataTemplateInfo->fieldInfo[k].type.id == IPFIX_ETYPEID_revFlowEndMilliSeconds) { intdata = getdata(dataTemplateInfo->fieldInfo[k].type,(data+dataTemplateInfo->fieldInfo[k].offset)) / 1000; notfound = false; break; } } } break; } // if still not found, get default value if(notfound) intdata = getdefaultIPFIXdata(identify[j].ipfixId); } // we need extra treatment for timing related fields switch (identify[j].ipfixId) { case IPFIX_TYPEID_flowStartSeconds: // save time for table access printf("intdata (seconds): %llu\n", intdata); if (flowstartsec==0) flowstartsec = intdata; break; case IPFIX_TYPEID_flowStartMilliSeconds: // if flowStartSeconds is not stored in one of the columns, but flowStartMilliSeconds is, // the we use flowStartMilliSeconds for table access // This is realized by storing this value only if flowStartSeconds has not yet been seen. // A later appearing flowStartSeconds will override this value. printf("intdata (milliseconds): %llu\n", intdata); if (flowstartsec==0) flowstartsec = intdata/1000; // in the database the millisecond entry is counted from last second intdata %= 1000; break; case IPFIX_TYPEID_flowEndMilliSeconds: case IPFIX_ETYPEID_revFlowStartMilliSeconds: case IPFIX_ETYPEID_revFlowEndMilliSeconds: // in the database the millisecond entry is counted from last second intdata %= 1000; break; } } DPRINTF("saw ipfix id %d in packet with intdata %llX", identify[j].ipfixId, intdata); addColumnEntry(ColNames, identify[j].cname, false, j==numberOfColumns-1); addColumnEntry(ColValues, intdata, true, j==numberOfColumns-1); } printf("colnames: '%s', colvals: '%s'\n", ColNames, ColValues); if (flowstartsec == 0) { printf("failed to get timing data\n"); //THROWEXCEPTION("failed to get timing data from ipfix packet. this is a critical error at the moment, as no valid table can be determined. Aborting"); return ""; } /**make whole query string for the insert statement*/ char tablename[TABLE_WIDTH]; DPRINTF("flowstartsec: %d", flowstartsec); const char* tablen = getTableName(flowstartsec); strcpy(tablename, tablen); /** Insert statement = INSERT INTO + tablename + Columnsname + Values of record*/ strcat(statemStr, tablename); strcat(statemStr, ColNames); strcat(statemStr, ColValues); /* insert table name into locks if necessary */ for(j=0; j < maxlocks; j++) { if(locks[j][0] == '\0') { /* empty slot, i.e. no more table names. insert the current one */ strcpy(locks[j], tablename); break; } else if(strncmp(tablename, locks[j], TABLE_WIDTH) == 0) /* found tablename */ break; } return statemStr; }
/** * loop over table columns and template to get the IPFIX values in correct order to store in database * The result is written into row, the firstSwitched time is returned in flowstartsec */ string& IpfixDbWriter::getInsertString(string& row, time_t& flowstartsec, const IpfixRecord::SourceID& sourceID, TemplateInfo& dataTemplateInfo,uint16_t length, IpfixRecord::Data* data) { uint64_t intdata = 0; uint64_t intdata2 = 0; uint32_t k; bool notfound, notfound2; bool first = true; ostringstream rowStream(row); flowstartsec = 0; rowStream << "("; /**loop over the columname and loop over the IPFIX_TYPEID of the record to get the corresponding data to store and make insert statement*/ for(vector<Column>::iterator col = tableColumns.begin(); col != tableColumns.end(); col++) { if (col->ipfixId == EXPORTERID) { // if this is the same source ID as last time, we get the exporter id from currentExporter if ((currentExporter != NULL) && equalExporter(sourceID, currentExporter->sourceID)) { DPRINTF("Exporter is same as last time (ODID=%d, id=%d)", sourceID.observationDomainId, currentExporter->id); intdata = (uint64_t)currentExporter->id; } else { // lookup exporter buffer to get exporterID from sourcID and expIp intdata = (uint64_t)getExporterID(sourceID); } } else { notfound = true; // try to gather data required for the field if(dataTemplateInfo.fieldCount > 0) { // look inside the ipfix record for(k=0; k < dataTemplateInfo.fieldCount; k++) { if(dataTemplateInfo.fieldInfo[k].type.enterprise == col->enterprise && dataTemplateInfo.fieldInfo[k].type.id == col->ipfixId) { notfound = false; intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)); DPRINTF("IpfixDbWriter::getData: really saw ipfix id %d in packet with intdata %llX, type %d, length %d and offset %X", col->ipfixId, intdata, dataTemplateInfo.fieldInfo[k].type.id, dataTemplateInfo.fieldInfo[k].type.length, dataTemplateInfo.fieldInfo[k].offset); break; } } } if( dataTemplateInfo.dataCount > 0 && notfound) { // look in static data fields of template for data for(k=0; k < dataTemplateInfo.dataCount; k++) { if(dataTemplateInfo.fieldInfo[k].type.enterprise == col->enterprise && dataTemplateInfo.dataInfo[k].type.id == col->ipfixId) { notfound = false; intdata = getData(dataTemplateInfo.dataInfo[k].type,(dataTemplateInfo.data+dataTemplateInfo.dataInfo[k].offset)); break; } } } if(notfound) { notfound2 = true; // for some Ids, we have an alternative if(col->enterprise == 0) { switch (col->ipfixId) { case IPFIX_TYPEID_flowStartSeconds: if(dataTemplateInfo.fieldCount > 0) { for(k=0; k < dataTemplateInfo.fieldCount; k++) { // look for alternative (flowStartMilliSeconds/1000) if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowStartMilliSeconds) { intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000; notfound = false; break; } // if no flow start time is available, maybe this is is from a netflow from Cisco // then - as a last alternative - use flowStartSysUpTime as flow start time if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowStartSysUpTime) { intdata2 = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)); notfound2 = false; } } if(notfound && !notfound2) { intdata = intdata2; notfound = false; } } break; //TODO: replace by enterprise number (Gerhard 12/2009) case IPFIX_ETYPEID_revFlowStartSeconds: // look for alternative (revFlowStartMilliSeconds/1000) if(dataTemplateInfo.fieldCount > 0) { for(k=0; k < dataTemplateInfo.fieldCount; k++) { if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_ETYPEID_revFlowStartMilliSeconds) { intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000; notfound = false; break; } } } break; case IPFIX_TYPEID_flowEndSeconds: if(dataTemplateInfo.fieldCount > 0) { for(k=0; k < dataTemplateInfo.fieldCount; k++) { // look for alternative (flowEndMilliSeconds/1000) if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowEndMilliSeconds) { intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000; notfound = false; break; } // if no flow end time is available, maybe this is is from a netflow from Cisco // then use flowEndSysUpTime as flow start time if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_TYPEID_flowEndSysUpTime) { intdata2 = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)); notfound2 = false; } } if(notfound && !notfound2) { intdata = intdata2; notfound = false; } } break; //TODO: replace by enterprise number (Gerhard 12/2009) case IPFIX_ETYPEID_revFlowEndSeconds: // look for alternative (revFlowEndMilliSeconds/1000) if(dataTemplateInfo.fieldCount > 0) { for(k=0; k < dataTemplateInfo.fieldCount; k++) { if(dataTemplateInfo.fieldInfo[k].type.id == IPFIX_ETYPEID_revFlowEndMilliSeconds) { intdata = getData(dataTemplateInfo.fieldInfo[k].type,(data+dataTemplateInfo.fieldInfo[k].offset)) / 1000; notfound = false; break; } } } break; } } // if still not found, get default value if(notfound) intdata = col->defaultValue; } // we need extra treatment for timing related fields if(col->enterprise == 0 ) { switch (col->ipfixId) { case IPFIX_TYPEID_flowStartSeconds: // save time for table access if (flowstartsec==0) flowstartsec = intdata; break; case IPFIX_TYPEID_flowEndSeconds: break; case IPFIX_TYPEID_flowStartMilliSeconds: // if flowStartSeconds is not stored in one of the columns, but flowStartMilliSeconds is, // then we use flowStartMilliSeconds for table access // This is realized by storing this value only if flowStartSeconds has not yet been seen. // A later appearing flowStartSeconds will override this value. if (flowstartsec==0) flowstartsec = intdata/1000; case IPFIX_TYPEID_flowEndMilliSeconds: //TODO: replace by enterprise number (Gerhard 12/2009) case IPFIX_ETYPEID_revFlowStartMilliSeconds: case IPFIX_ETYPEID_revFlowEndMilliSeconds: // in the database the millisecond entry is counted from last second intdata %= 1000; break; } } } DPRINTF("saw ipfix id %d in packet with intdata %llX", col->ipfixId, intdata); if(first) rowStream << intdata; else rowStream << "," << intdata; first = false; } rowStream << ")"; if (flowstartsec == 0) { msg(MSG_ERROR, "IpfixDbWriter: Failed to get timing data from record. Will be saved in default table."); } row = rowStream.str(); DPRINTF("Insert row: %s", row.c_str()); return row; }