I tried tcpdump/tcpreplay to do multicast replay.
# snaplen = maximum udp payload size + udp header size + ip header size + ethernet header size # need to tune -B -s carefully for packet lossless tcpdump -B 10240 -s 2112 -tt -vv -i eth4 -w eth4.pcap multicast tcpreplay -t -i lo eth4.pcap
However, tcpdump could capture packets from tcpreplay, my program failed to subscribe. I tried to tcpedit MAC per [Tcpreplay-users] Could not replay a multicast, but still did not work. After search for a while, I decided to write my own tcpreplay.
#include <err.h>
#include <pcap.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
// ethernet headers are always exactly 14 bytes [1]
#define SIZE_ETHERNET 14 // http://www.tcpdump.org/pcap.html
void replayOnePcap(pcap_t* pcap, long offset, int fd)
{
struct sockaddr_in addr;
bzero((char *)&addr, sizeof(addr));
addr.sin_family = AF_INET;
struct pcap_pkthdr header;
const u_char* packet;
long num = 0;
long vol = 0;
time_t lastReportTm;
while ((packet = pcap_next(pcap, &header)) != NULL) {
const struct ip* ip = (struct ip*)(packet + SIZE_ETHERNET);
if (*((const u_char*)ip + 16) < 224) // check if it is multicast
continue;
assert(ip->ip_p == IPPROTO_UDP);
timeval now;
time_t t;
for (;;) {
gettimeofday(&now, NULL);
t = now.tv_sec+offset;
if (header.ts.tv_sec < t ||
(header.ts.tv_sec == t && header.ts.tv_usec <= now.tv_usec))
break;
//usleep(1);
}
int size_ip = (ip->ip_hl)*4;
const struct udphdr* udp = (struct udphdr*)(packet + SIZE_ETHERNET + size_ip);
int n = SIZE_ETHERNET + size_ip + sizeof(udphdr);
const u_char* payload = packet + n;
addr.sin_addr.s_addr = ip->ip_dst.s_addr;
addr.sin_port = udp->dest;
++num;
vol += sizeof(header) + header.len;
::sendto(fd, payload, header.len - n, 0, (struct sockaddr*)&addr, sizeof(addr));
if (now.tv_sec - lastReportTm >= 10) {
lastReportTm = now.tv_sec;
LOG_INFO('#' << num/1e+6 << "M " << vol/1e+6 << "M : " <<
header.ts.tv_usec << "us " << asctime(localtime(&header.ts.tv_sec)));
LOG_INFO("expect: " << asctime(localtime(&t)));
}
}
}
No comments:
Post a Comment