@@ -29,7 +29,22 @@ extern "C" {
29
29
#include <inttypes.h>
30
30
#include <arpa/inet.h>
31
31
#include <netdb.h>
32
+
33
+ #if HAVE_BYTESWAP_H
32
34
#include <byteswap.h>
35
+ #else
36
+ #define bswap_16 (value ) \
37
+ ((((value) & 0xff) << 8) | ((value) >> 8))
38
+
39
+ #define bswap_32 (value ) \
40
+ (((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | \
41
+ (uint32_t)bswap_16((uint16_t)((value) >> 16)))
42
+
43
+ #define bswap_64 (value ) \
44
+ (((uint64_t)bswap_32((uint32_t)((value) & 0xffffffff)) << 32) | \
45
+ (uint64_t)bswap_32((uint32_t)((value) >> 32)))
46
+ #endif
47
+
33
48
#include <getopt.h>
34
49
35
50
#include "sflow.h" /* sFlow v5 */
@@ -202,11 +217,14 @@ typedef struct _SFConfig {
202
217
char * readPcapFileName ;
203
218
FILE * readPcapFile ;
204
219
struct pcap_file_header readPcapHdr ;
220
+ struct pcap_pkthdr pcapPktHdr ;
205
221
int pcapSwap ;
222
+ uint64_t pcapStart_mS ;
223
+ uint64_t pcapNext_mS ;
224
+ uint64_t pcapStartOffset_mS ;
206
225
/* sFlow-from-pcap generator */
207
226
uint32_t pcapSamplingN ;
208
227
SFDDgram * sFlowDatagram ;
209
- uint64_t pcap_uS ;
210
228
double playback ;
211
229
uint32_t output_sample_pool ;
212
230
uint32_t output_sample_seqNo ;
@@ -5971,38 +5989,55 @@ static int pcapOffsetToSFlow(uint8_t *start, int len)
5971
5989
}
5972
5990
5973
5991
/*_________________---------------------------__________________
5974
- _________________ readPcapPacket __________________
5992
+ _________________ readPcapPacketHeader __________________
5975
5993
-----------------___________________________------------------
5976
5994
*/
5977
5995
5978
- static int readPcapPacket (FILE * file )
5996
+ static int readPcapPacketHdr (FILE * file , struct pcap_pkthdr * hdr , uint64_t * pcap_uS )
5979
5997
{
5980
- uint8_t buf [SA_MAX_PCAP_PKT ];
5981
- struct pcap_pkthdr hdr ;
5982
- SFSample sample ;
5983
- int skipBytes = 0 ;
5984
-
5985
- if (fread (& hdr , sizeof (hdr ), 1 , file ) != 1 ) {
5998
+ if (fread (hdr , sizeof (* hdr ), 1 , file ) != 1 ) {
5986
5999
if (feof (file )) return 0 ;
5987
6000
fprintf (ERROUT , "unable to read pcap packet header from %s : %s\n" , sfConfig .readPcapFileName , strerror (errno ));
5988
6001
exit (-32 );
5989
6002
}
5990
6003
5991
6004
if (sfConfig .pcapSwap ) {
5992
- hdr . ts_sec = bswap_32 (hdr . ts_sec );
5993
- hdr . ts_usec = bswap_32 (hdr . ts_usec );
5994
- hdr . caplen = bswap_32 (hdr . caplen );
5995
- hdr . len = bswap_32 (hdr . len );
6005
+ hdr -> ts_sec = bswap_32 (hdr -> ts_sec );
6006
+ hdr -> ts_usec = bswap_32 (hdr -> ts_usec );
6007
+ hdr -> caplen = bswap_32 (hdr -> caplen );
6008
+ hdr -> len = bswap_32 (hdr -> len );
5996
6009
}
5997
6010
5998
6011
/* Protect against possible buffer overrun from corrupted pcap file.
5999
6012
Thanks to Naoki Ogawa for spotting this. */
6000
- if (hdr . caplen > SA_MAX_PCAP_PKT ) {
6001
- fprintf (ERROUT , "pcap %s : capture-len (%u) too long for read buffer\n" , sfConfig .readPcapFileName , hdr . caplen );
6013
+ if (hdr -> caplen > SA_MAX_PCAP_PKT ) {
6014
+ fprintf (ERROUT , "pcap %s : capture-len (%u) too long for read buffer\n" , sfConfig .readPcapFileName , hdr -> caplen );
6002
6015
return 0 ;
6003
6016
}
6004
6017
6005
- if (fread (buf , hdr .caplen , 1 , file ) != 1 ) {
6018
+ if (pcap_uS ) {
6019
+ // tell caller where we are (in pcap uS time)
6020
+ uint64_t t_uS = hdr -> ts_sec ;
6021
+ t_uS *= 1000000 ;
6022
+ t_uS += hdr -> ts_usec ;
6023
+ * pcap_uS = t_uS ;
6024
+ }
6025
+
6026
+ return 1 ;
6027
+ }
6028
+
6029
+ /*_________________---------------------------__________________
6030
+ _________________ readPcapPacket __________________
6031
+ -----------------___________________________------------------
6032
+ */
6033
+
6034
+ static int readPcapPacket (FILE * file , struct pcap_pkthdr * hdr )
6035
+ {
6036
+ uint8_t buf [SA_MAX_PCAP_PKT ];
6037
+ SFSample sample ;
6038
+ int skipBytes = 0 ;
6039
+
6040
+ if (fread (buf , hdr -> caplen , 1 , file ) != 1 ) {
6006
6041
fprintf (ERROUT , "unable to read pcap packet from %s : %s\n" , sfConfig .readPcapFileName , strerror (errno ));
6007
6042
exit (-34 );
6008
6043
}
@@ -6026,9 +6061,9 @@ static int readPcapPacket(FILE *file)
6026
6061
sfd_xdr_enc_int32 (pktsmp , 1 ); // number of elements
6027
6062
sfd_xdr_start_tlv (pktsmp , SFLFLOW_HEADER );
6028
6063
sfd_xdr_enc_int32 (pktsmp , SFLHEADER_ETHERNET_ISO8023 ); // header protocol - TODO: learn from pcap
6029
- sfd_xdr_enc_int32 (pktsmp , hdr . len + 4 ); // frame_length
6064
+ sfd_xdr_enc_int32 (pktsmp , hdr -> len + 4 ); // frame_length
6030
6065
sfd_xdr_enc_int32 (pktsmp , 4 ); // stripped (FCS)
6031
- uint32_t caplen = hdr . caplen ;
6066
+ uint32_t caplen = hdr -> caplen ;
6032
6067
if (caplen > SFL_DEFAULT_HEADER_SIZE )
6033
6068
caplen = SFL_DEFAULT_HEADER_SIZE ;
6034
6069
sfd_xdr_enc_int32 (pktsmp , caplen ); // header len
@@ -6038,40 +6073,61 @@ static int readPcapPacket(FILE *file)
6038
6073
SFDAddSample (sfConfig .sFlowDatagram , pktsmp );
6039
6074
}
6040
6075
6041
- if (sfConfig .playback < 100 ) {
6042
- uint64_t pcap_uS = (hdr .ts_sec * 1000000 ) + hdr .ts_usec ;
6043
- if (sfConfig .pcap_uS ) {
6044
- // apply playback-speed time compression factor
6045
- uint64_t wait_uS = (pcap_uS - sfConfig .pcap_uS ) / sfConfig .playback ;
6046
- if ((now_mS (NULL ) - SFDLastSend_mS (sfConfig .sFlowDatagram )) > 500
6047
- || wait_uS > 500000 )
6048
- SFDSend (sfConfig .sFlowDatagram ); // flush before sleep
6049
- usleep (wait_uS );
6050
- }
6051
- sfConfig .pcap_uS = pcap_uS ;
6052
- }
6076
+ /* TODO: check this logic - should perhaps be happening in select loop? */
6077
+ if ((now_mS (NULL ) - SFDLastSend_mS (sfConfig .sFlowDatagram )) > 500 )
6078
+ SFDSend (sfConfig .sFlowDatagram );
6053
6079
}
6054
6080
else {
6055
6081
// reading full sFlow datagrams from pcap file
6056
- if (hdr . caplen < hdr . len ) {
6082
+ if (hdr -> caplen < hdr -> len ) {
6057
6083
fprintf (ERROUT , "incomplete datagram (pcap snaplen too short)\n" );
6058
6084
}
6059
6085
else {
6060
6086
/* need to skip over the encapsulation in the captured packet.
6061
6087
-- should really do this by checking for 802.2, IP options etc. but
6062
6088
for now we just assume ethernet + IP + UDP */
6063
- skipBytes = pcapOffsetToSFlow (buf , hdr . caplen );
6089
+ skipBytes = pcapOffsetToSFlow (buf , hdr -> caplen );
6064
6090
memset (& sample , 0 , sizeof (sample ));
6065
6091
sample .rawSample = buf + skipBytes ;
6066
- sample .rawSampleLen = hdr . caplen - skipBytes ;
6067
- sample .pcapTimestamp = hdr . ts_sec ;
6092
+ sample .rawSampleLen = hdr -> caplen - skipBytes ;
6093
+ sample .pcapTimestamp = hdr -> ts_sec ;
6068
6094
receiveSFlowDatagram (& sample );
6069
6095
}
6070
6096
}
6071
6097
return 1 ;
6072
6098
}
6073
6099
6074
6100
6101
+ /*_________________---------------------------__________________
6102
+ _________________ initPcapPlayback __________________
6103
+ -----------------___________________________------------------
6104
+ */
6105
+
6106
+ static int initPcapPlayback (void ) {
6107
+ /* tee up the time-regulated infinite playback */
6108
+ uint64_t pcap_uS = 0 ;
6109
+ int found = readPcapPacketHdr (sfConfig .readPcapFile , & sfConfig .pcapPktHdr , & pcap_uS );
6110
+ if (found ) {
6111
+ sfConfig .pcapStart_mS = pcap_uS / 1000 ;
6112
+ sfConfig .pcapStartOffset_mS = now_mS (NULL ) - sfConfig .pcapStart_mS ;
6113
+ sfConfig .pcapNext_mS = sfConfig .pcapStart_mS ;
6114
+ }
6115
+ return found ;
6116
+ }
6117
+
6118
+ /*_________________---------------------------__________________
6119
+ _________________ pcapPlaybackNextSend_mS __________________
6120
+ -----------------___________________________------------------
6121
+ */
6122
+
6123
+ static uint64_t pcapPlaybackNextSend_mS (void ) {
6124
+ double pcap_rel_mS = (double )(sfConfig .pcapNext_mS - sfConfig .pcapStart_mS );
6125
+ double pcap_rel_scaled_mS = pcap_rel_mS / sfConfig .playback ;
6126
+ return sfConfig .pcapStartOffset_mS
6127
+ + sfConfig .pcapStart_mS
6128
+ + (uint64_t ) pcap_rel_scaled_mS ;
6129
+ }
6130
+
6075
6131
/*_________________---------------------------__________________
6076
6132
_________________ parseVlanFilter __________________
6077
6133
-----------------___________________________------------------
@@ -6504,7 +6560,9 @@ static void process_command_line(int argc, char *argv[])
6504
6560
break ;
6505
6561
case 'P' :
6506
6562
sfConfig .playback = atof (optarg );
6507
- if (sfConfig .playback <= 000001 )
6563
+ if (sfConfig .playback <= 0 )
6564
+ sfConfig .playback = 0 ;
6565
+ else if (sfConfig .playback <= 0.00001 )
6508
6566
sfConfig .playback = 0.00001 ;
6509
6567
break ;
6510
6568
case 'x' : sfConfig .removeContent = YES ; break ;
@@ -6659,21 +6717,26 @@ int main(int argc, char *argv[])
6659
6717
if (sfConfig .outputFormat == SFLFMT_PCAP
6660
6718
|| sfConfig .outputFormat == SFLFMT_PCAP_DISCARD )
6661
6719
writePcapHeader ();
6662
- if (sfConfig .readPcapFile ) {
6663
- /* just use a blocking read */
6664
- #ifdef SFL_PCAP_LOOP
6720
+
6721
+ if (sfConfig .readPcapFile
6722
+ && sfConfig .playback == 0 ) {
6723
+ /* just read flat out until done */
6665
6724
for (;;) {
6666
- uint32_t pcount ;
6667
- while (readPcapPacket (sfConfig .readPcapFile ))
6668
- pcount ++ ;
6669
- fprintf (ERROUT , "%" PRIu64 ":%u\n" , now_mS (NULL ), pcount );
6670
- fseek (sfConfig .readPcapFile , sizeof (struct pcap_file_header ), SEEK_SET );
6725
+ if (!readPcapPacketHdr (sfConfig .readPcapFile , & sfConfig .pcapPktHdr , NULL ))
6726
+ break ;
6727
+ if (!readPcapPacket (sfConfig .readPcapFile , & sfConfig .pcapPktHdr ))
6728
+ break ;
6671
6729
}
6672
- #else
6673
- while (readPcapPacket (sfConfig .readPcapFile ));
6674
- #endif
6675
6730
}
6676
6731
else {
6732
+ /* use select loop */
6733
+
6734
+ if (sfConfig .readPcapFile
6735
+ && sfConfig .playback != 0 ) {
6736
+ /* tee up the time-regulated infinite playback */
6737
+ initPcapPlayback ();
6738
+ }
6739
+
6677
6740
fd_set readfds ;
6678
6741
/* set the select mask */
6679
6742
FD_ZERO (& readfds );
@@ -6715,6 +6778,40 @@ int main(int argc, char *argv[])
6715
6778
if (soc4 != -1 && FD_ISSET (soc4 , & readfds )) readPacket (soc4 );
6716
6779
if (soc6 != -1 && FD_ISSET (soc6 , & readfds )) readPacket (soc6 );
6717
6780
}
6781
+
6782
+ if (sfConfig .pcapStartOffset_mS ) {
6783
+ /* in monotonic time, when should the next packet go out? */
6784
+ uint64_t send_mS = pcapPlaybackNextSend_mS ();
6785
+ uint64_t now = now_mS (NULL );
6786
+ int atEOF = 0 ;
6787
+ // printf("now=%lu, send_mS=%lu\n", now, send_mS);
6788
+ /* keep sending pcap packets until we catch up to monotonic "now" */
6789
+ while (now > send_mS ) {
6790
+ uint64_t pcap_uS = 0 ;
6791
+ if (readPcapPacket (sfConfig .readPcapFile , & sfConfig .pcapPktHdr ) == 0
6792
+ || readPcapPacketHdr (sfConfig .readPcapFile , & sfConfig .pcapPktHdr , & pcap_uS ) == 0 ) {
6793
+ atEOF = 1 ;
6794
+ break ;
6795
+ }
6796
+ else {
6797
+ uint64_t pcap_mS = pcap_uS / 1000 ;
6798
+ /* insist that pcapNext_mS must never go backwards */
6799
+ if (pcap_mS >= sfConfig .pcapNext_mS )
6800
+ sfConfig .pcapNext_mS = pcap_mS ;
6801
+ send_mS = pcapPlaybackNextSend_mS ();
6802
+ // printf("now=%lu, pcap_mS=%lu pcapNext_mS=%lu send_mS=%lu\n",
6803
+ // now, pcap_mS, sfConfig.pcapNext_mS, send_mS);
6804
+ }
6805
+ }
6806
+ if (atEOF ) {
6807
+ /* seek back to start of file */
6808
+ fseek (sfConfig .readPcapFile , sizeof (struct pcap_file_header ), SEEK_SET );
6809
+ /* and restart the playback */
6810
+ initPcapPlayback ();
6811
+ }
6812
+
6813
+ }
6814
+
6718
6815
}
6719
6816
}
6720
6817
return 0 ;
0 commit comments