blob: 25f435744aa3760254d8a077116afe2f842a2c96 [file] [log] [blame]
/*
*
* (C) 2005-12 - Luca Deri <deri@ntop.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* VLAN support courtesy of Vincent Magnin <vincent.magnin@ci.unil.ch>
*
*/
#define _GNU_SOURCE
#include <signal.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/poll.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <net/ethernet.h> /* the L2 protocols */
#include <sys/time.h>
#include <time.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <locale.h>
#ifdef ENABLE_BPF
#include <pcap/pcap.h>
#include <pcap/bpf.h>
//#include <linux/filter.h>
#endif
#include "pfring.h"
#include "pfutils.c"
#define ALARM_SLEEP 1
#define DEFAULT_SNAPLEN 128
#define MAX_NUM_THREADS 64
#define DEFAULT_DEVICE "eth0"
#define NO_ZC_BUFFER_LEN 9000
pfring *pd;
int verbose = 0, num_threads = 1;
pfring_stat pfringStats;
pthread_rwlock_t statsLock;
static struct timeval startTime;
unsigned long long numPkts[MAX_NUM_THREADS] = { 0 }, numBytes[MAX_NUM_THREADS] = { 0 };
#ifdef ENABLE_BPF
unsigned long long numPktsFiltered[MAX_NUM_THREADS] = { 0 };
struct bpf_program filter;
u_int8_t userspace_bpf = 0;
#endif
u_int8_t wait_for_packet = 1, do_shutdown = 0, add_drop_rule = 0;
u_int8_t use_extended_pkt_header = 0, touch_payload = 0, enable_hw_timestamp = 0, dont_strip_timestamps = 0;
/* ******************************** */
void print_stats() {
pfring_stat pfringStat;
struct timeval endTime;
double deltaMillisec;
static u_int8_t print_all;
static u_int64_t lastPkts = 0;
static u_int64_t lastBytes = 0;
double diff, bytesDiff;
static struct timeval lastTime;
char buf[256], buf1[64], buf2[64], buf3[64], timebuf[128];
u_int64_t deltaMillisecStart;
if(startTime.tv_sec == 0) {
gettimeofday(&startTime, NULL);
print_all = 0;
} else
print_all = 1;
gettimeofday(&endTime, NULL);
deltaMillisec = delta_time(&endTime, &startTime);
if(pfring_stats(pd, &pfringStat) >= 0) {
double thpt;
int i;
unsigned long long nBytes = 0, nPkts = 0;
#ifdef ENABLE_BPF
unsigned long long nPktsFiltered = 0;
#endif
for(i=0; i < num_threads; i++) {
nBytes += numBytes[i];
nPkts += numPkts[i];
#ifdef ENABLE_BPF
nPktsFiltered += numPktsFiltered[i];
#endif
}
deltaMillisecStart = delta_time(&endTime, &startTime);
snprintf(buf, sizeof(buf),
"Duration: %s\n"
"Packets: %lu\n"
"Dropped: %lu\n"
#ifdef ENABLE_BPF
"Filtered: %lu\n"
#endif
"Bytes: %lu\n",
sec2dhms((deltaMillisecStart/1000), timebuf, sizeof(timebuf)),
(long unsigned int) pfringStat.recv,
(long unsigned int) pfringStat.drop,
#ifdef ENABLE_BPF
(long unsigned int) nPktsFiltered,
#endif
(long unsigned int) nBytes);
pfring_set_application_stats(pd, buf);
thpt = ((double)8*nBytes)/(deltaMillisec*1000);
fprintf(stderr, "=========================\n"
"Absolute Stats: [%u pkts rcvd]"
#ifdef ENABLE_BPF
"[%u pkts filtered]"
#endif
"[%u pkts dropped]\n"
"Total Pkts=%u/Dropped=%.1f %%\n",
(unsigned int)pfringStat.recv,
#ifdef ENABLE_BPF
(unsigned int)nPktsFiltered,
#endif
(unsigned int)pfringStat.drop,
(unsigned int)(pfringStat.recv+pfringStat.drop),
pfringStat.recv == 0 ? 0 :
(double)(pfringStat.drop*100)/(double)(pfringStat.recv+pfringStat.drop));
fprintf(stderr, "%s pkts - %s bytes",
pfring_format_numbers((double)nPkts, buf1, sizeof(buf1), 0),
pfring_format_numbers((double)nBytes, buf2, sizeof(buf2), 0));
if(print_all)
fprintf(stderr, " [%s pkt/sec - %s Mbit/sec]\n",
pfring_format_numbers((double)(nPkts*1000)/deltaMillisec, buf1, sizeof(buf1), 1),
pfring_format_numbers(thpt, buf2, sizeof(buf2), 1));
else
fprintf(stderr, "\n");
if(print_all && (lastTime.tv_sec > 0)) {
deltaMillisec = delta_time(&endTime, &lastTime);
diff = nPkts-lastPkts;
bytesDiff = nBytes - lastBytes;
bytesDiff /= (1000*1000*1000)/8;
snprintf(buf, sizeof(buf),
"Actual Stats: %llu pkts [%s ms][%s pps/%s Gbps]",
(long long unsigned int)diff,
pfring_format_numbers(deltaMillisec, buf1, sizeof(buf1), 1),
pfring_format_numbers(((double)diff/(double)(deltaMillisec/1000)), buf2, sizeof(buf2), 1),
pfring_format_numbers(((double)bytesDiff/(double)(deltaMillisec/1000)), buf3, sizeof(buf3), 1));
fprintf(stderr, "=========================\n%s\n", buf);
}
lastPkts = nPkts, lastBytes = nBytes;
}
lastTime.tv_sec = endTime.tv_sec, lastTime.tv_usec = endTime.tv_usec;
fprintf(stderr, "=========================\n\n");
}
/* ******************************** */
void drop_packet_rule(const struct pfring_pkthdr *h) {
const struct pkt_parsing_info *hdr = &h->extended_hdr.parsed_pkt;
static int rule_id=0;
if(add_drop_rule == 1) {
hash_filtering_rule rule;
memset(&rule, 0, sizeof(hash_filtering_rule));
rule.rule_id = rule_id++;
rule.vlan_id = hdr->vlan_id;
rule.proto = hdr->l3_proto;
rule.rule_action = dont_forward_packet_and_stop_rule_evaluation;
rule.host4_peer_a = hdr->ip_src.v4, rule.host4_peer_b = hdr->ip_dst.v4;
rule.port_peer_a = hdr->l4_src_port, rule.port_peer_b = hdr->l4_dst_port;
if(pfring_handle_hash_filtering_rule(pd, &rule, 1 /* add_rule */) < 0)
fprintf(stderr, "pfring_add_hash_filtering_rule(1) failed\n");
else
printf("Added filtering rule %d\n", rule.rule_id);
} else {
filtering_rule rule;
int rc;
memset(&rule, 0, sizeof(rule));
rule.rule_id = rule_id++;
rule.rule_action = dont_forward_packet_and_stop_rule_evaluation;
rule.core_fields.proto = hdr->l3_proto;
rule.core_fields.shost.v4 = hdr->ip_src.v4, rule.core_fields.shost_mask.v4 = 0xFFFFFFFF;
rule.core_fields.sport_low = rule.core_fields.sport_high = hdr->l4_src_port;
rule.core_fields.dhost.v4 = hdr->ip_dst.v4, rule.core_fields.dhost_mask.v4 = 0xFFFFFFFF;
rule.core_fields.dport_low = rule.core_fields.dport_high = hdr->l4_dst_port;
if((rc = pfring_add_filtering_rule(pd, &rule)) < 0)
fprintf(stderr, "pfring_add_hash_filtering_rule(2) failed\n");
else
printf("Rule %d added successfully...\n", rule.rule_id);
}
}
/* ******************************** */
void sigproc(int sig) {
static int called = 0;
fprintf(stderr, "Leaving...\n");
if(called) return; else called = 1;
do_shutdown = 1;
print_stats();
pfring_breakloop(pd);
}
/* ******************************** */
void my_sigalarm(int sig) {
if(do_shutdown)
return;
print_stats();
alarm(ALARM_SLEEP);
signal(SIGALRM, my_sigalarm);
}
/* ****************************************************** */
static char hex[] = "0123456789ABCDEF";
char* etheraddr_string(const u_char *ep, char *buf) {
u_int i, j;
char *cp;
cp = buf;
if((j = *ep >> 4) != 0)
*cp++ = hex[j];
else
*cp++ = '0';
*cp++ = hex[*ep++ & 0xf];
for(i = 5; (int)--i >= 0;) {
*cp++ = ':';
if((j = *ep >> 4) != 0)
*cp++ = hex[j];
else
*cp++ = '0';
*cp++ = hex[*ep++ & 0xf];
}
*cp = '\0';
return (buf);
}
/* ****************************************************** */
/*
* A faster replacement for inet_ntoa().
*/
char* _intoa(unsigned int addr, char* buf, u_short bufLen) {
char *cp, *retStr;
u_int byte;
int n;
cp = &buf[bufLen];
*--cp = '\0';
n = 4;
do {
byte = addr & 0xff;
*--cp = byte % 10 + '0';
byte /= 10;
if(byte > 0) {
*--cp = byte % 10 + '0';
byte /= 10;
if(byte > 0)
*--cp = byte + '0';
}
*--cp = '.';
addr >>= 8;
} while (--n > 0);
/* Convert the string to lowercase */
retStr = (char*)(cp+1);
return(retStr);
}
/* ************************************ */
char* intoa(unsigned int addr) {
static char buf[sizeof "ff:ff:ff:ff:ff:ff:255.255.255.255"];
return(_intoa(addr, buf, sizeof(buf)));
}
/* ************************************ */
inline char* in6toa(struct in6_addr addr6) {
static char buf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"];
char *ret = (char*)inet_ntop(AF_INET6, &addr6, buf, sizeof(buf));
if(ret == NULL) {
printf("Internal error (buffer too short)");
buf[0] = '\0';
}
return(ret);
}
/* ****************************************************** */
char* proto2str(u_short proto) {
static char protoName[8];
switch(proto) {
case IPPROTO_TCP: return("TCP");
case IPPROTO_UDP: return("UDP");
case IPPROTO_ICMP: return("ICMP");
case IPPROTO_GRE: return("GRE");
default:
snprintf(protoName, sizeof(protoName), "%d", proto);
return(protoName);
}
}
/* ****************************************************** */
#ifdef ENABLE_BPF
int parse_bpf_filter(char *filter_buffer, u_int caplen) {
if(pcap_compile_nopcap(caplen, /* snaplen_arg */
DLT_EN10MB, /* linktype_arg */
&filter, /* program */
filter_buffer, /* const char *buf */
0, /* optimize */
0 /* mask */
) == -1) {
return -1;
}
if(filter.bf_insns == NULL)
return -1;
return 0;
}
#endif
/* ****************************************************** */
static int32_t thiszone;
void dummyProcesssPacket(const struct pfring_pkthdr *h,
const u_char *p, const u_char *user_bytes) {
long threadId = (long)user_bytes;
numPkts[threadId]++, numBytes[threadId] += h->len+24 /* 8 Preamble + 4 CRC + 12 IFG */;
#ifdef ENABLE_BPF
if (userspace_bpf && bpf_filter(filter.bf_insns, p, h->caplen, h->len) == 0)
return; /* rejected */
numPktsFiltered[threadId]++;
#endif
if(touch_payload) {
volatile int __attribute__ ((unused)) i;
i = p[12] + p[13];
}
if(verbose) {
struct ether_header *ehdr;
char buf1[32], buf2[32];
int s;
uint usec;
uint nsec=0;
if(h->ts.tv_sec == 0) {
memset((void*)&h->extended_hdr.parsed_pkt, 0, sizeof(struct pkt_parsing_info));
pfring_parse_pkt((u_char*)p, (struct pfring_pkthdr*)h, 5, 1, 1);
}
s = (h->ts.tv_sec + thiszone) % 86400;
if(h->extended_hdr.timestamp_ns) {
if (pd->dna.dna_dev.mem_info.device_model != intel_igb_82580 /* other than intel_igb_82580 */)
s = ((h->extended_hdr.timestamp_ns / 1000000000) + thiszone) % 86400;
/* "else" intel_igb_82580 has 40 bit ts, using gettimeofday seconds:
* be careful with drifts mixing sys time and hw timestamp */
usec = (h->extended_hdr.timestamp_ns / 1000) % 1000000;
nsec = h->extended_hdr.timestamp_ns % 1000;
} else {
usec = h->ts.tv_usec;
}
printf("%02d:%02d:%02d.%06u%03u ",
s / 3600, (s % 3600) / 60, s % 60,
usec, nsec);
ehdr = (struct ether_header *) p;
if(use_extended_pkt_header) {
printf("%s[if_index=%d]",
h->extended_hdr.rx_direction ? "[RX]" : "[TX]",
h->extended_hdr.if_index);
printf("[%s -> %s] ",
etheraddr_string(h->extended_hdr.parsed_pkt.smac, buf1),
etheraddr_string(h->extended_hdr.parsed_pkt.dmac, buf2));
if(h->extended_hdr.parsed_pkt.offset.vlan_offset)
printf("[vlan %u] ", h->extended_hdr.parsed_pkt.vlan_id);
if (h->extended_hdr.parsed_pkt.eth_type == 0x0800 /* IPv4*/ || h->extended_hdr.parsed_pkt.eth_type == 0x86DD /* IPv6*/) {
if(h->extended_hdr.parsed_pkt.eth_type == 0x0800 /* IPv4*/ ) {
printf("[IPv4][%s:%d ", intoa(h->extended_hdr.parsed_pkt.ipv4_src), h->extended_hdr.parsed_pkt.l4_src_port);
printf("-> %s:%d] ", intoa(h->extended_hdr.parsed_pkt.ipv4_dst), h->extended_hdr.parsed_pkt.l4_dst_port);
} else {
printf("[IPv6][%s:%d ", in6toa(h->extended_hdr.parsed_pkt.ipv6_src), h->extended_hdr.parsed_pkt.l4_src_port);
printf("-> %s:%d] ", in6toa(h->extended_hdr.parsed_pkt.ipv6_dst), h->extended_hdr.parsed_pkt.l4_dst_port);
}
printf("[l3_proto=%s]", proto2str(h->extended_hdr.parsed_pkt.l3_proto));
if(h->extended_hdr.parsed_pkt.tunnel.tunnel_id != NO_TUNNEL_ID) {
printf("[TEID=0x%08X][tunneled_proto=%s]",
h->extended_hdr.parsed_pkt.tunnel.tunnel_id,
proto2str(h->extended_hdr.parsed_pkt.tunnel.tunneled_proto));
if(h->extended_hdr.parsed_pkt.eth_type == 0x0800 /* IPv4*/ ) {
printf("[IPv4][%s:%d ",
intoa(h->extended_hdr.parsed_pkt.tunnel.tunneled_ip_src.v4),
h->extended_hdr.parsed_pkt.tunnel.tunneled_l4_src_port);
printf("-> %s:%d] ",
intoa(h->extended_hdr.parsed_pkt.tunnel.tunneled_ip_dst.v4),
h->extended_hdr.parsed_pkt.tunnel.tunneled_l4_dst_port);
} else {
printf("[IPv6][%s:%d ",
in6toa(h->extended_hdr.parsed_pkt.tunnel.tunneled_ip_src.v6),
h->extended_hdr.parsed_pkt.tunnel.tunneled_l4_src_port);
printf("-> %s:%d] ",
in6toa(h->extended_hdr.parsed_pkt.tunnel.tunneled_ip_dst.v6),
h->extended_hdr.parsed_pkt.tunnel.tunneled_l4_dst_port);
}
}
printf("[hash=%u][tos=%d][tcp_seq_num=%u]",
h->extended_hdr.pkt_hash,
h->extended_hdr.parsed_pkt.ipv4_tos,
h->extended_hdr.parsed_pkt.tcp.seq_num);
} else {
if(h->extended_hdr.parsed_pkt.eth_type == 0x0806 /* ARP */)
printf("[ARP]");
else
printf("[eth_type=0x%04X]", h->extended_hdr.parsed_pkt.eth_type);
}
printf(" [caplen=%d][len=%d][parsed_header_len=%d][eth_offset=%d][l3_offset=%d][l4_offset=%d][payload_offset=%d]\n",
h->caplen, h->len, h->extended_hdr.parsed_header_len,
h->extended_hdr.parsed_pkt.offset.eth_offset,
h->extended_hdr.parsed_pkt.offset.l3_offset,
h->extended_hdr.parsed_pkt.offset.l4_offset,
h->extended_hdr.parsed_pkt.offset.payload_offset);
} else {
printf("[%s -> %s][eth_type=0x%04X][caplen=%d][len=%d] (use -m for details)\n",
etheraddr_string(ehdr->ether_shost, buf1),
etheraddr_string(ehdr->ether_dhost, buf2),
ntohs(ehdr->ether_type),
h->caplen, h->len);
}
}
if(verbose == 2) {
int i;
for(i = 0; i < h->caplen; i++)
printf("%02X ", p[i]);
printf("\n");
}
if(unlikely(add_drop_rule)) {
if(h->ts.tv_sec == 0)
pfring_parse_pkt((u_char*)p, (struct pfring_pkthdr*)h, 4, 0, 1);
drop_packet_rule(h);
}
}
/* *************************************** */
int32_t gmt2local(time_t t) {
int dt, dir;
struct tm *gmt, *loc;
struct tm sgmt;
if(t == 0)
t = time(NULL);
gmt = &sgmt;
*gmt = *gmtime(&t);
loc = localtime(&t);
dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
(loc->tm_min - gmt->tm_min) * 60;
/*
* If the year or julian day is different, we span 00:00 GMT
* and must add or subtract a day. Check the year first to
* avoid problems when the julian day wraps.
*/
dir = loc->tm_year - gmt->tm_year;
if(dir == 0)
dir = loc->tm_yday - gmt->tm_yday;
dt += dir * 24 * 60 * 60;
return (dt);
}
/* *************************************** */
void printHelp(void) {
printf("pfcount - (C) 2005-13 ntop.org\n\n");
printf("-h Print this help\n");
printf("-i <device> Device name. Use:\n"
" - ethX@Y for channels\n"
" - dnaX for DNA-based adapters\n"
" - dnacluster:X for DNA cluster Id X\n"
#ifdef HAVE_DAG
" - dag:dagX:Y for Endace DAG cards\n"
#endif
);
printf("-n <threads> Number of polling threads (default %d)\n", num_threads);
printf("-f <filter> [BPF filter]\n");
printf("-c <cluster id> cluster id\n");
printf("-e <direction> 0=RX+TX, 1=RX only, 2=TX only\n");
printf("-l <len> Capture length\n");
printf("-g <core_id> Bind this app to a core\n");
printf("-d <device> Device on which incoming packets are copied (e.g. userspace:usr0 or dna1)\n");
printf("-w <watermark> Watermark\n");
printf("-p <poll wait> Poll wait (msec)\n");
printf("-b <cpu %%> CPU pergentage priority (0-99)\n");
printf("-a Active packet wait\n");
printf("-m Long packet header (with PF_RING extensions)\n");
printf("-r Rehash RSS packets\n");
printf("-s Enable hw timestamping\n");
printf("-S Do not strip hw timestamps (if present)\n");
printf("-t Touch payload (for force packet load on cache)\n");
#ifdef ENABLE_QAT_PM
printf("-x <string> Search string on payload. You can specify this option multiple times.\n");
#endif
printf("-u <1|2> For each incoming packet add a drop rule (1=hash, 2=wildcard rule)\n");
printf("-v <mode> Verbose [1: verbose, 2: very verbose (print packet payload)]\n");
exit(0);
}
/* *************************************** */
void* packet_consumer_thread(void* _id) {
long thread_id = (long)_id;
u_int numCPU = sysconf( _SC_NPROCESSORS_ONLN );
u_char buffer[NO_ZC_BUFFER_LEN];
u_char *buffer_p = buffer;
u_long core_id = thread_id % numCPU;
struct pfring_pkthdr hdr;
/* printf("packet_consumer_thread(%lu)\n", thread_id); */
if((num_threads > 1) && (numCPU > 1)) {
if(bind2core(core_id) == 0)
printf("Set thread %lu on core %lu/%u\n", thread_id, core_id, numCPU);
}
memset(&hdr, 0, sizeof(hdr));
while(1) {
int rc;
u_int len;
if(do_shutdown) break;
if((rc = pfring_recv(pd, &buffer_p, NO_ZC_BUFFER_LEN, &hdr, wait_for_packet)) > 0) {
if(do_shutdown) break;
dummyProcesssPacket(&hdr, buffer, (u_char*)thread_id);
#ifdef TEST_SEND
buffer[0] = 0x99;
buffer[1] = 0x98;
buffer[2] = 0x97;
pfring_send(pd, buffer, hdr.caplen);
#endif
} else {
if(wait_for_packet == 0) sched_yield();
}
if(0) {
struct simple_stats {
u_int64_t num_pkts, num_bytes;
};
struct simple_stats stats;
len = sizeof(stats);
rc = pfring_get_filtering_rule_stats(pd, 5, (char*)&stats, &len);
if(rc < 0)
fprintf(stderr, "pfring_get_filtering_rule_stats() failed [rc=%d]\n", rc);
else {
printf("[Pkts=%u][Bytes=%u]\n",
(unsigned int)stats.num_pkts,
(unsigned int)stats.num_bytes);
}
}
}
return(NULL);
}
/* *************************************** */
#define MAX_NUM_STRINGS 32
int main(int argc, char* argv[]) {
char *device = NULL, c, buf[32], path[256] = { 0 }, *reflector_device = NULL;
#ifdef ENABLE_QAT_PM
char *to_search[MAX_NUM_STRINGS] = { NULL };
u_int num_strings_to_search = 0;
#endif
u_char mac_address[6] = { 0 };
int promisc, snaplen = DEFAULT_SNAPLEN, rc;
u_int clusterId = 0;
u_int32_t flags = 0;
int bind_core = -1;
packet_direction direction = rx_and_tx_direction;
u_int16_t watermark = 0, poll_duration = 0,
cpu_percentage = 0, rehash_rss = 0;
#ifdef ENABLE_BPF
char *bpfFilter = NULL;
#endif
#if 0
struct sched_param schedparam;
/* mlockall(MCL_CURRENT|MCL_FUTURE); */
schedparam.sched_priority = 50;
if(sched_setscheduler(0, SCHED_FIFO, &schedparam) == -1) {
printf("error while setting the scheduler, errno=%i\n", errno);
exit(1);
}
#undef TEST_PROCESSOR_AFFINITY
#ifdef TEST_PROCESSOR_AFFINITY
{
unsigned long new_mask = 1;
unsigned int len = sizeof(new_mask);
unsigned long cur_mask;
pid_t p = 0; /* current process */
int ret;
ret = sched_getaffinity(p, len, NULL);
printf(" sched_getaffinity = %d, len = %u\n", ret, len);
ret = sched_getaffinity(p, len, &cur_mask);
printf(" sched_getaffinity = %d, cur_mask = %08lx\n", ret, cur_mask);
ret = sched_setaffinity(p, len, &new_mask);
printf(" sched_setaffinity = %d, new_mask = %08lx\n", ret, new_mask);
ret = sched_getaffinity(p, len, &cur_mask);
printf(" sched_getaffinity = %d, cur_mask = %08lx\n", ret, cur_mask);
}
#endif
#endif
startTime.tv_sec = 0;
thiszone = gmt2local(0);
while((c = getopt(argc,argv,"hi:c:d:l:v:ae:n:w:p:b:rg:u:mtsS"
#ifdef ENABLE_QAT_PM
"x:"
#endif
#ifdef ENABLE_BPF
"f:"
#endif
)) != '?') {
if((c == 255) || (c == -1)) break;
switch(c) {
case 'h':
printHelp();
return(0);
break;
case 'a':
wait_for_packet = 0;
break;
case 'e':
switch(atoi(optarg)) {
case rx_and_tx_direction:
case rx_only_direction:
case tx_only_direction:
direction = atoi(optarg);
break;
}
break;
case 'c':
clusterId = atoi(optarg);
break;
case 'd':
reflector_device = strdup(optarg);
break;
case 'l':
snaplen = atoi(optarg);
break;
case 'i':
device = strdup(optarg);
break;
case 'n':
num_threads = atoi(optarg);
break;
case 'v':
if(optarg[0] == '1')
verbose = 1;
else if(optarg[0] == '2')
verbose = 2;
else
printHelp();
break;
#ifdef ENABLE_BPF
case 'f':
bpfFilter = strdup(optarg);
break;
#endif
case 'w':
watermark = atoi(optarg);
break;
case 'b':
cpu_percentage = atoi(optarg);
break;
case 'm':
use_extended_pkt_header = 1;
break;
case 'p':
poll_duration = atoi(optarg);
break;
case 'r':
rehash_rss = 1;
break;
case 't':
touch_payload = 1;
break;
case 's':
enable_hw_timestamp = 1;
break;
case 'S':
dont_strip_timestamps = 1;
break;
case 'g':
bind_core = atoi(optarg);
break;
case 'u':
switch(add_drop_rule = atoi(optarg)) {
case 1:
printf("Adding hash filtering rules\n");
break;
default:
printf("Adding wildcard filtering rules\n");
add_drop_rule = 2;
break;
}
#ifdef ENABLE_QAT_PM
case 'x':
if(num_strings_to_search >= MAX_NUM_STRINGS) {
printf("Too many strings specified (-x): maximum %u\n", MAX_NUM_STRINGS);
} else
to_search[num_strings_to_search++] = strdup(optarg);
break;
#endif
}
}
if(verbose) watermark = 1;
if(device == NULL) device = DEFAULT_DEVICE;
if(num_threads > MAX_NUM_THREADS) num_threads = MAX_NUM_THREADS;
/* hardcode: promisc=1, to_ms=500 */
promisc = 1;
if(num_threads > 0)
pthread_rwlock_init(&statsLock, NULL);
if(wait_for_packet && (cpu_percentage > 0)) {
if(cpu_percentage > 99) cpu_percentage = 99;
pfring_config(cpu_percentage);
}
if(num_threads > 1) flags |= PF_RING_REENTRANT;
if(use_extended_pkt_header) flags |= PF_RING_LONG_HEADER;
if(promisc) flags |= PF_RING_PROMISC;
if(enable_hw_timestamp) flags |= PF_RING_HW_TIMESTAMP;
if(!dont_strip_timestamps) flags |= PF_RING_STRIP_HW_TIMESTAMP;
flags |= PF_RING_DNA_SYMMETRIC_RSS; /* Note that symmetric RSS is ignored by non-DNA drivers */
//printf("flags: %d\n", flags);
pd = pfring_open(device, snaplen, flags);
if(pd == NULL) {
fprintf(stderr, "pfring_open error [%s] (pf_ring not loaded or perhaps you use quick mode and have already a socket bound to %s ?)\n",
strerror(errno), device);
return(-1);
} else {
u_int32_t version;
pfring_set_application_name(pd, "pfcount");
pfring_version(pd, &version);
printf("Using PF_RING v.%d.%d.%d\n",
(version & 0xFFFF0000) >> 16,
(version & 0x0000FF00) >> 8,
version & 0x000000FF);
}
if(strstr(device, "dnacluster:")) {
printf("Capturing from %s\n", device);
} else {
if(pfring_get_bound_device_address(pd, mac_address) != 0)
fprintf(stderr, "Unable to read the device address\n");
else {
int ifindex = -1;
pfring_get_bound_device_ifindex(pd, &ifindex);
printf("Capturing from %s [%s][ifIndex: %d]\n",
device, etheraddr_string(mac_address, buf),
ifindex);
}
}
printf("# Device RX channels: %d\n", pfring_get_num_rx_channels(pd));
printf("# Polling threads: %d\n", num_threads);
if (enable_hw_timestamp) {
struct timespec ltime;
/* Setting current clock */
if (clock_gettime(CLOCK_REALTIME, &ltime) != 0 ||
pfring_set_device_clock(pd, &ltime) < 0)
fprintf(stderr, "Error setting device clock\n");
}
#ifdef ENABLE_BPF
if(bpfFilter != NULL) {
if (pd->dna.dna_mapped_device) {
if (parse_bpf_filter(bpfFilter, snaplen) == 0) {
userspace_bpf = 1;
printf("Successfully set BPF filter '%s'\n", bpfFilter);
} else
printf("Error compiling BPF filter '%s'\n", bpfFilter);
} else {
rc = pfring_set_bpf_filter(pd, bpfFilter);
if(rc != 0)
printf("pfring_set_bpf_filter(%s) returned %d\n", bpfFilter, rc);
else
printf("Successfully set BPF filter '%s'\n", bpfFilter);
#if 0
rc = pfring_remove_bpf_filter(pd);
if(rc != 0)
printf("pfring_remove_bpf_filter() returned %d\n", rc);
else
printf("Successfully removed BPF filter '%s'\n", bpfFilter);
#endif
}
}
#endif
#ifdef ENABLE_QAT_PM
if(num_strings_to_search > 0) {
int i;
for(i=0; i<num_strings_to_search; i++) {
rc = pfring_search_payload(pd, to_search[i]);
if(rc < 0)
printf("pfring_search_payload() returned %d\n", rc);
else
printf("Successfully added string to search '%s'\n", to_search[i]);
}
}
#endif
if(clusterId > 0) {
rc = pfring_set_cluster(pd, clusterId, cluster_round_robin);
printf("pfring_set_cluster returned %d\n", rc);
}
if((rc = pfring_set_direction(pd, direction)) != 0)
; //fprintf(stderr, "pfring_set_direction returned %d (perhaps you use a direction other than rx only with DNA ?)\n", rc);
if((rc = pfring_set_socket_mode(pd, recv_only_mode)) != 0)
fprintf(stderr, "pfring_set_socket_mode returned [rc=%d]\n", rc);
if(watermark > 0) {
if((rc = pfring_set_poll_watermark(pd, watermark)) != 0)
fprintf(stderr, "pfring_set_poll_watermark returned [rc=%d][watermark=%d]\n", rc, watermark);
}
if(reflector_device != NULL) {
rc = pfring_set_reflector_device(pd, reflector_device);
if(rc == 0) {
/* printf("pfring_set_reflector_device(%s) succeeded\n", reflector_device); */
} else
fprintf(stderr, "pfring_set_reflector_device(%s) failed [rc: %d]\n", reflector_device, rc);
}
if(rehash_rss)
pfring_enable_rss_rehash(pd);
if(poll_duration > 0)
pfring_set_poll_duration(pd, poll_duration);
signal(SIGINT, sigproc);
signal(SIGTERM, sigproc);
signal(SIGINT, sigproc);
if(!verbose) {
signal(SIGALRM, my_sigalarm);
alarm(ALARM_SLEEP);
}
if(0) {
filtering_rule rule;
int rc;
#define DUMMY_PLUGIN_ID 1
memset(&rule, 0, sizeof(rule));
rule.rule_id = 5;
rule.rule_action = forward_packet_and_stop_rule_evaluation;
rule.core_fields.proto = 6 /* tcp */;
// rule.plugin_action.plugin_id = DUMMY_PLUGIN_ID; /* Dummy plugin */
// rule.extended_fields.filter_plugin_id = DUMMY_PLUGIN_ID; /* Enable packet parsing/filtering */
if((rc = pfring_add_filtering_rule(pd, &rule)) < 0)
fprintf(stderr, "pfring_add_filtering_rule(2) failed\n");
else
printf("Rule added successfully...\n");
}
if(0) {
filtering_rule rule;
char *sgsn = "1.2.3.4";
char *ggsn = "1.2.3.5";
/* ************************************* */
memset(&rule, 0, sizeof(rule));
rule.rule_id = 1;
rule.rule_action = forward_packet_and_stop_rule_evaluation;
rule.core_fields.proto = 17 /* UDP */;
rule.core_fields.shost.v4 = ntohl(inet_addr(sgsn)),rule.core_fields.shost_mask.v4 = 0xFFFFFFFF;
rule.core_fields.dhost.v4 = ntohl(inet_addr(ggsn)), rule.core_fields.dhost_mask.v4 = 0xFFFFFFFF;
rule.extended_fields.tunnel.tunnel_id = 0x0000a2b6;
if((rc = pfring_add_filtering_rule(pd, &rule)) < 0)
fprintf(stderr, "pfring_add_filtering_rule(id=%d) failed: rc=%d\n", rule.rule_id, rc);
else
printf("Rule %d added successfully...\n", rule.rule_id );
/* ************************************* */
memset(&rule, 0, sizeof(rule));
rule.rule_id = 2;
rule.rule_action = forward_packet_and_stop_rule_evaluation;
rule.core_fields.proto = 17 /* UDP */;
rule.core_fields.shost.v4 = ntohl(inet_addr(ggsn)), rule.core_fields.dhost_mask.v4 = 0xFFFFFFFF;
rule.core_fields.dhost.v4 = ntohl(inet_addr(sgsn)), rule.core_fields.shost_mask.v4 = 0xFFFFFFFF;
rule.extended_fields.tunnel.tunnel_id = 0x776C0000;
if((rc = pfring_add_filtering_rule(pd, &rule)) < 0)
fprintf(stderr, "pfring_add_filtering_rule(id=%d) failed: rc=%d\n", rule.rule_id, rc);
else
printf("Rule %d added successfully...\n", rule.rule_id );
/* ************************************** */
/* Signaling (Up) */
memset(&rule, 0, sizeof(rule));
rule.rule_id = 3;
rule.rule_action = forward_packet_and_stop_rule_evaluation;
rule.core_fields.proto = 17 /* UDP */;
rule.core_fields.sport_low = rule.core_fields.sport_high = 2123;
rule.extended_fields.tunnel.tunnel_id = NO_TUNNEL_ID; /* Ignore the tunnel */
if((rc = pfring_add_filtering_rule(pd, &rule)) < 0)
fprintf(stderr, "pfring_add_filtering_rule(id=%d) failed: rc=%d\n", rule.rule_id, rc);
else
printf("Rule %d added successfully...\n", rule.rule_id );
memset(&rule, 0, sizeof(rule));
/* ************************************** */
/* Signaling (Down) */
memset(&rule, 0, sizeof(rule));
rule.rule_id = 4;
rule.rule_action = forward_packet_and_stop_rule_evaluation;
rule.core_fields.proto = 17 /* UDP */;
rule.core_fields.dport_low = rule.core_fields.dport_high = 2123;
rule.extended_fields.tunnel.tunnel_id = NO_TUNNEL_ID; /* Ignore the tunnel */
if((rc = pfring_add_filtering_rule(pd, &rule)) < 0)
fprintf(stderr, "pfring_add_filtering_rule(id=%d) failed: rc=%d\n", rule.rule_id, rc);
else
printf("Rule %d added successfully...\n", rule.rule_id );
memset(&rule, 0, sizeof(rule));
/* ************************************** */
pfring_toggle_filtering_policy(pd, 0); /* Default to drop */
}
pfring_set_application_stats(pd, "Statistics not yet computed: please try again...");
if(pfring_get_appl_stats_file_name(pd, path, sizeof(path)) != NULL)
fprintf(stderr, "Dumping statistics on %s\n", path);
if (pfring_enable_ring(pd) != 0) {
printf("Unable to enable ring :-(\n");
pfring_close(pd);
return(-1);
}
if (num_threads <= 1) {
if(bind_core >= 0)
bind2core(bind_core);
pfring_loop(pd, dummyProcesssPacket, (u_char*)NULL, wait_for_packet);
//packet_consumer_thread(0);
} else {
pthread_t my_thread;
long i;
for(i=0; i<num_threads; i++)
pthread_create(&my_thread, NULL, packet_consumer_thread, (void*)i);
for(i=0; i<num_threads; i++)
pthread_join(my_thread, NULL);
}
sleep(1);
pfring_close(pd);
return(0);
}