| /* |
| * |
| * (C) 2005-13 - ntop.org |
| * |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU Lessed General Public License as published by |
| * the Free Software Foundation; either version 3 of the License, or |
| * (at your option) any later version. |
| * |
| * |
| */ |
| |
| #define __USE_XOPEN2K |
| #include <sys/types.h> |
| #include <pthread.h> |
| |
| #include "pfring.h" |
| #include <net/ethernet.h> |
| |
| // #define RING_DEBUG |
| |
| #define EXTRA_SAFE 1 |
| |
| /* ********************************* */ |
| |
| #include "pfring_mod.h" |
| #include "pfring_mod_stack.h" |
| #include "pfring_mod_usring.h" |
| |
| #ifdef HAVE_DAG |
| #include "pfring_mod_dag.h" |
| #endif |
| |
| #ifdef HAVE_DNA |
| #include "pfring_mod_dna.h" |
| #endif |
| |
| #ifdef HAVE_VIRTUAL |
| #include "pfring_mod_virtual.h" |
| #endif |
| |
| static pfring_module_info pfring_module_list[] = { |
| { /* usually you don't need to specify this */ |
| .name = "default", |
| .open = pfring_mod_open, |
| }, |
| { |
| .name = "stack", |
| .open = pfring_mod_stack_open, |
| }, |
| #ifdef HAVE_VIRTUAL |
| { /* vPF_RING (guest-side) */ |
| .name = "host", |
| .open = pfring_virtual_open, |
| }, |
| #endif |
| #ifdef HAVE_DAG |
| { |
| .name = "dag", |
| .open = pfring_dag_open, |
| }, |
| #endif |
| #ifdef HAVE_DNA |
| #ifdef HAVE_ZERO |
| { |
| .name = "dnacl", /* using dnacl* as dnacluster is too long */ |
| .open = pfring_dna_cluster_open, |
| }, |
| #endif |
| { |
| .name = "dna", |
| .open = pfring_dna_open, |
| }, |
| #endif |
| { |
| .name = "userspace", |
| .open = pfring_mod_usring_open, |
| }, |
| {0} |
| }; |
| |
| /* **************************************************** */ |
| |
| pfring* pfring_open(const char *device_name, u_int32_t caplen, u_int32_t flags) { |
| int i = -1; |
| int mod_found = 0; |
| int ret; |
| char *str, *str1; |
| pfring *ring; |
| |
| #ifdef RING_DEBUG |
| printf("[PF_RING] Attempting to pfring_open(%s)\n", device_name); |
| #endif |
| |
| ring = (pfring*)malloc(sizeof(pfring)); |
| if(ring == NULL) |
| return NULL; |
| |
| memset(ring, 0, sizeof(pfring)); |
| |
| ring->promisc = (flags & PF_RING_PROMISC) ? 1 : 0; |
| ring->caplen = caplen; |
| ring->reentrant = (flags & PF_RING_REENTRANT) ? 1 : 0; |
| ring->direction = rx_and_tx_direction; |
| ring->mode = send_and_recv_mode; |
| ring->long_header = (flags & PF_RING_LONG_HEADER) ? 1 : 0; |
| ring->rss_mode = (flags & PF_RING_DNA_SYMMETRIC_RSS) ? PF_RING_DNA_SYMMETRIC_RSS : ( |
| (flags & PF_RING_DNA_FIXED_RSS_Q_0) ? PF_RING_DNA_FIXED_RSS_Q_0 : 0); |
| ring->force_timestamp = (flags & PF_RING_TIMESTAMP) ? 1 : 0; |
| ring->strip_hw_timestamp = (flags & PF_RING_STRIP_HW_TIMESTAMP) ? 1 : 0; |
| ring->hw_ts.enable_hw_timestamp = (flags & PF_RING_HW_TIMESTAMP) ? 1 : 0; |
| ring->tx.enabled_rx_packet_send = (flags & PF_RING_RX_PACKET_BOUNCE) ? 1 : 0; |
| ring->disable_parsing = (flags & PF_RING_DO_NOT_PARSE) ? 1 : 0; |
| ring->disable_timestamp = (flags & PF_RING_DO_NOT_TIMESTAMP) ? 1 : 0; |
| |
| #ifdef RING_DEBUG |
| printf("pfring_open: device_name=%s\n", device_name); |
| #endif |
| /* modules */ |
| |
| if(device_name) { |
| ret = -1; |
| ring->device_name = NULL; |
| |
| while (pfring_module_list[++i].name) { |
| str = str1 = NULL; |
| #ifdef HAVE_DNA |
| u_int8_t is_dna = 0; |
| if(strcmp(pfring_module_list[i].name, "dna") == 0) { |
| /* DNA module: check proc for renamed interfaces */ |
| FILE *proc_net_pfr; |
| char line[256]; |
| snprintf(line, sizeof(line), "/proc/net/pf_ring/dev/%s/info", device_name); |
| proc_net_pfr = fopen(line, "r"); |
| if(proc_net_pfr != NULL) { |
| const char *str_mode = "Polling Mode:"; |
| while(fgets(line, sizeof(line), proc_net_pfr) != NULL) { |
| char *p = &line[0]; |
| if (!strncmp(p, str_mode, strlen(str_mode))) { |
| p += strlen(str_mode); |
| is_dna = (strstr(p, "DNA") != NULL); |
| break; |
| } |
| } |
| } |
| } |
| |
| if (!is_dna) /* if already recognized as dna do not check module prefix */ |
| #endif |
| if(!(str = strstr(device_name, pfring_module_list[i].name))) continue; |
| if(!pfring_module_list[i].open) continue; |
| mod_found = 1; |
| #ifdef RING_DEBUG |
| printf("pfring_open: found module %s\n", pfring_module_list[i].name); |
| #endif |
| |
| if (str != NULL) { |
| str1 = strchr(str, ':'); |
| if (str1 != NULL) str1++; |
| } |
| |
| ring->device_name = str1 ? strdup(str1) : strdup(device_name); |
| ret = pfring_module_list[i].open(ring); |
| break; |
| } |
| } |
| |
| /* default */ |
| if(!mod_found) { |
| ring->device_name = strdup(device_name ? device_name : "any"); |
| |
| ret = pfring_mod_open(ring); |
| } |
| |
| if(ret < 0) { |
| if(ring->device_name) free(ring->device_name); |
| free(ring); |
| return NULL; |
| } |
| |
| if(unlikely(ring->reentrant)) { |
| pthread_rwlock_init(&ring->rx_lock, PTHREAD_PROCESS_PRIVATE); |
| pthread_rwlock_init(&ring->tx_lock, PTHREAD_PROCESS_PRIVATE); |
| } |
| |
| ring->socket_default_accept_policy = 1; /* Accept (default) */ |
| |
| ring->rdi.device_id = ring->rdi.port_id = -1; /* Default */ |
| |
| ring->mtu_len = pfring_get_mtu_size(ring); |
| if(ring->mtu_len == 0) ring->mtu_len = 9000 /* Jumbo MTU */; |
| ring->mtu_len += sizeof(struct ether_header); |
| |
| ring->initialized = 1; |
| |
| #ifdef RING_DEBUG |
| printf("[PF_RING] Successfully open pfring_open(%s)\n", device_name); |
| #endif |
| |
| return ring; |
| } |
| |
| /* **************************************************** */ |
| |
| pfring* pfring_open_consumer(const char *device_name, u_int32_t caplen, u_int32_t flags, |
| u_int8_t consumer_plugin_id, |
| char* consumer_data, u_int consumer_data_len) { |
| pfring *ring = pfring_open(device_name, caplen, flags); |
| |
| if(ring) { |
| if(consumer_plugin_id > 0) { |
| int rc; |
| |
| ring->kernel_packet_consumer = consumer_plugin_id; |
| rc = pfring_set_packet_consumer_mode(ring, consumer_plugin_id, |
| consumer_data, consumer_data_len); |
| if(rc < 0) { |
| pfring_close(ring); |
| return(NULL); |
| } |
| } |
| } |
| |
| return ring; |
| } |
| |
| /* **************************************************** */ |
| |
| u_int8_t pfring_open_multichannel(const char *device_name, u_int32_t caplen, |
| u_int32_t flags, |
| pfring* ring[MAX_NUM_RX_CHANNELS]) { |
| u_int8_t num_channels, i, num = 0; |
| char *at; |
| char base_device_name[32]; |
| |
| snprintf(base_device_name, sizeof(base_device_name), "%s", device_name); |
| at = strchr(base_device_name, '@'); |
| if(at != NULL) |
| at[0] = '\0'; |
| |
| /* Count how many RX channel the specified device supports */ |
| ring[0] = pfring_open(base_device_name, caplen, flags); |
| |
| if(ring[0] == NULL) |
| return(0); |
| else |
| num_channels = pfring_get_num_rx_channels(ring[0]); |
| |
| pfring_close(ring[0]); |
| |
| if(num_channels > MAX_NUM_RX_CHANNELS) |
| num_channels = MAX_NUM_RX_CHANNELS; |
| |
| /* Now do the real job */ |
| for(i=0; i<num_channels; i++) { |
| char dev[32]; |
| |
| snprintf(dev, sizeof(dev), "%s@%d", base_device_name, i); |
| ring[i] = pfring_open(dev, caplen, flags); |
| |
| if(ring[i] == NULL) |
| return(num); |
| else |
| num++; |
| } |
| |
| return(num); |
| } |
| |
| /* **************************************************** */ |
| |
| void pfring_close(pfring *ring) { |
| if(!ring) |
| return; |
| |
| pfring_shutdown(ring); |
| |
| if(ring->close) |
| ring->close(ring); |
| |
| if(unlikely(ring->reentrant)) { |
| pthread_rwlock_destroy(&ring->rx_lock); |
| pthread_rwlock_destroy(&ring->tx_lock); |
| } |
| |
| free(ring->device_name); |
| free(ring); |
| } |
| |
| /* **************************************************** */ |
| |
| void pfring_shutdown(pfring *ring) { |
| if (!ring) |
| return; |
| |
| ring->is_shutting_down = ring->break_recv_loop = 1; |
| |
| if(ring->shutdown) |
| ring->shutdown(ring); |
| } |
| |
| /* **************************************************** */ |
| |
| void pfring_config(u_short cpu_percentage) { |
| static u_int pfring_initialized = 0; |
| |
| if(!pfring_initialized) { |
| struct sched_param schedparam; |
| |
| /*if(cpu_percentage >= 50) mlockall(MCL_CURRENT|MCL_FUTURE); */ |
| |
| pfring_initialized = 1; |
| schedparam.sched_priority = cpu_percentage; |
| if(sched_setscheduler(0, SCHED_FIFO, &schedparam) == -1) { |
| printf("error while setting the scheduler, errno=%i\n", errno); |
| exit(1); |
| } |
| } |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_reflector_device(pfring *ring, char *device_name) { |
| if((device_name == NULL) || ring->reflector_socket) |
| return(-1); |
| |
| ring->reflector_socket = pfring_open(device_name, ring->caplen, PF_RING_PROMISC); |
| |
| if(ring->reflector_socket != NULL) { |
| pfring_set_socket_mode(ring->reflector_socket, send_only_mode); |
| pfring_enable_ring(ring->reflector_socket); |
| return(0); |
| } else |
| return(-1); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_loop(pfring *ring, pfringProcesssPacket looper, |
| const u_char *user_bytes, u_int8_t wait_for_packet) { |
| u_char *buffer = NULL; |
| struct pfring_pkthdr hdr; |
| int rc = 0; |
| |
| memset(&hdr, 0, sizeof(hdr)); |
| ring->break_recv_loop = 0; |
| |
| if((! ring) |
| || ring->is_shutting_down |
| || (! ring->recv) |
| || ring->mode == send_only_mode) |
| return -1; |
| |
| while(!ring->break_recv_loop) { |
| rc = ring->recv(ring, &buffer, 0, &hdr, wait_for_packet); |
| |
| if(rc < 0) |
| break; |
| else if(rc > 0) { |
| hdr.caplen = min_val(hdr.caplen, ring->caplen); |
| |
| looper(&hdr, buffer, user_bytes); |
| } else { |
| /* if(!wait_for_packet) usleep(1); */ |
| } |
| } |
| |
| return(rc); |
| } |
| |
| /* **************************************************** */ |
| |
| void pfring_breakloop(pfring *ring) { |
| if(!ring) |
| return; |
| |
| ring->break_recv_loop = 1; |
| } |
| |
| /* **************************************************** */ |
| |
| void pfring_bundle_init(pfring_bundle *bundle, bundle_read_policy p) { |
| memset(bundle, 0, sizeof(pfring_bundle)); |
| bundle->policy = p; |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_bundle_add(pfring_bundle *bundle, pfring *ring) { |
| if(bundle->num_sockets >= (MAX_NUM_BUNDLE_ELEMENTS-1)) |
| return(-1); |
| |
| bundle->sockets[bundle->num_sockets] = ring; |
| bundle->pfd[bundle->num_sockets].fd = pfring_get_selectable_fd(ring); |
| bundle->num_sockets++; |
| |
| pfring_enable_ring(ring); |
| |
| return(0); |
| } |
| |
| /* **************************************************** */ |
| |
| /* Returns the first bundle socket with something to read */ |
| int pfring_bundle_poll(pfring_bundle *bundle, u_int wait_duration) { |
| int i; |
| |
| for(i=0; i<bundle->num_sockets; i++) { |
| pfring_sync_indexes_with_kernel(bundle->sockets[i]); |
| bundle->pfd[i].events = POLLIN /* | POLLERR */; |
| bundle->pfd[i].revents = 0; |
| } |
| |
| errno = 0; |
| return poll(bundle->pfd, bundle->num_sockets, wait_duration); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_bundle_read(pfring_bundle *bundle, |
| u_char** buffer, u_int buffer_len, |
| struct pfring_pkthdr *hdr, |
| u_int8_t wait_for_incoming_packet) { |
| int i, sock_id = -1, found, rc, empty_rings, scans; |
| struct timespec ts = { 0 }; |
| struct timespec tmpts; |
| u_int8_t founds[32] = { 0 }; |
| |
| redo_pfring_bundle_read: |
| |
| switch(bundle->policy) { |
| case pick_round_robin: |
| for(i=0; i<bundle->num_sockets; i++) { |
| rc = pfring_recv(bundle->sockets[bundle->last_read_socket], buffer, buffer_len, hdr, 0); |
| if(++bundle->last_read_socket == bundle->num_sockets) bundle->last_read_socket = 0; |
| if(rc > 0) return(rc); |
| } |
| break; |
| |
| case pick_fifo: |
| found = 0; |
| empty_rings = 0; |
| scans = 0; |
| |
| sockets_scan: |
| scans++; |
| for(i=0; i<bundle->num_sockets; i++) { |
| if(founds[i] == 0) { |
| pfring *ring = bundle->sockets[i]; |
| |
| rc = pfring_next_pkt_time(ring, &tmpts); |
| |
| if(rc == 0) { |
| if(!found || timespec_is_before(&tmpts, &ts)) { |
| memcpy(&ts, &tmpts, sizeof(struct timespec)); |
| found = 1, founds[i] = 1; |
| sock_id = i; |
| } |
| } else if (rc == PF_RING_ERROR_NO_PKT_AVAILABLE) { |
| empty_rings = 1; |
| } else { |
| /* error */ |
| } |
| } |
| } |
| |
| if(found) { |
| #ifdef EXTRA_SAFE |
| if(empty_rings && (scans == 1)) |
| goto sockets_scan; /* scanning ring twice (safety check) */ |
| #endif |
| |
| return(pfring_recv(bundle->sockets[sock_id], buffer, buffer_len, hdr, 0)); |
| } |
| break; |
| } |
| |
| if(wait_for_incoming_packet) { |
| rc = pfring_bundle_poll(bundle, bundle->sockets[0]->poll_duration); |
| |
| if(rc > 0) goto redo_pfring_bundle_read; |
| else return(rc); |
| } |
| |
| return(0); |
| } |
| |
| /* **************************************************** */ |
| |
| void pfring_bundle_destroy(pfring_bundle *bundle) { |
| int i; |
| |
| for(i=0; i<bundle->num_sockets; i++) { |
| pfring_disable_ring(bundle->sockets[i]); |
| } |
| |
| memset(bundle, 0, sizeof(pfring_bundle)); |
| } |
| |
| /* **************************************************** */ |
| |
| void pfring_bundle_close(pfring_bundle *bundle) { |
| int i; |
| |
| for(i=0; i<bundle->num_sockets; i++) { |
| pfring_close(bundle->sockets[i]); |
| } |
| |
| memset(bundle, 0, sizeof(pfring_bundle)); |
| } |
| |
| /* **************************************************** */ |
| /* Module-specific functions */ |
| /* **************************************************** */ |
| |
| int pfring_stats(pfring *ring, pfring_stat *stats) { |
| if(ring && ring->stats) |
| return(ring->stats(ring, stats)); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_recv(pfring *ring, u_char** buffer, u_int buffer_len, |
| struct pfring_pkthdr *hdr, |
| u_int8_t wait_for_incoming_packet) { |
| if(likely((ring |
| && ring->enabled |
| && ring->recv |
| && (ring->mode != send_only_mode)))) { |
| int rc; |
| |
| /* Reentrancy is not compatible with zero copy */ |
| if(unlikely((buffer_len == 0) && ring->reentrant)) |
| return(PF_RING_ERROR_INVALID_ARGUMENT); |
| |
| ring->break_recv_loop = 0; |
| rc = ring->recv(ring, buffer, buffer_len, hdr, wait_for_incoming_packet); |
| hdr->caplen = min_val(hdr->caplen, ring->caplen); |
| |
| if(unlikely(ring->reflector_socket != NULL)) { |
| if (rc > 0) |
| pfring_send(ring->reflector_socket, (char *) *buffer, hdr->caplen, 0 /* flush */); |
| } |
| |
| return rc; |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_recv_parsed(pfring *ring, u_char** buffer, u_int buffer_len, |
| struct pfring_pkthdr *hdr, u_int8_t wait_for_incoming_packet, |
| u_int8_t level /* 1..4 */, u_int8_t add_timestamp, u_int8_t add_hash) { |
| int rc = pfring_recv(ring, buffer, buffer_len, hdr, wait_for_incoming_packet); |
| |
| if(rc > 0) |
| rc = pfring_parse_pkt(*buffer, hdr, level, add_timestamp, add_hash); |
| |
| return rc; |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_poll_watermark(pfring *ring, u_int16_t watermark) { |
| if(ring && ring->set_poll_watermark) |
| return ring->set_poll_watermark(ring, watermark); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_poll_duration(pfring *ring, u_int duration) { |
| if(ring && ring->set_poll_duration) |
| return ring->set_poll_duration(ring, duration); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_tx_watermark(pfring *ring, u_int16_t watermark) { |
| if(ring && ring->set_tx_watermark) |
| return ring->set_tx_watermark(ring, watermark); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_add_hw_rule(pfring *ring, hw_filtering_rule *rule) { |
| if(ring && ring->add_hw_rule) |
| return ring->add_hw_rule(ring, rule); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_remove_hw_rule(pfring *ring, u_int16_t rule_id) { |
| if(ring && ring->remove_hw_rule) |
| return ring->remove_hw_rule(ring, rule_id); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_channel_id(pfring *ring, u_int32_t channel_id) { |
| if(ring && ring->set_channel_id) |
| return ring->set_channel_id(ring, channel_id); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_channel_mask(pfring *ring, u_int32_t channel_mask) { |
| if(ring && ring->set_channel_mask) |
| return ring->set_channel_mask(ring, channel_mask); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_application_name(pfring *ring, char *name) { |
| if(ring && ring->set_application_name) |
| return ring->set_application_name(ring, name); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_application_stats(pfring *ring, char *stats) { |
| if(ring && ring->set_application_stats) |
| return ring->set_application_stats(ring, stats); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| char* pfring_get_appl_stats_file_name(pfring *ring, char *path, u_int path_len) { |
| if(ring && ring->get_appl_stats_file_name) |
| return ring->get_appl_stats_file_name(ring, path, path_len); |
| |
| return(NULL); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_bind(pfring *ring, char *device_name) { |
| if(ring && ring->bind) |
| return ring->bind(ring, device_name); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_send(pfring *ring, char *pkt, u_int pkt_len, u_int8_t flush_packet) { |
| int rc = -1; |
| |
| if(unlikely(pkt_len > ring->mtu_len)) |
| return(PF_RING_ERROR_INVALID_ARGUMENT); /* Packet too long */ |
| |
| if(likely(ring |
| && ring->enabled |
| && (!ring->is_shutting_down) |
| && ring->send |
| && (ring->mode != recv_only_mode))) { |
| |
| if(unlikely(ring->reentrant)) |
| pthread_rwlock_wrlock(&ring->tx_lock); |
| |
| rc = ring->send(ring, pkt, pkt_len, flush_packet); |
| |
| if(unlikely(ring->reentrant)) |
| pthread_rwlock_unlock(&ring->tx_lock); |
| } |
| |
| return rc; |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_send_ifindex(pfring *ring, char *pkt, u_int pkt_len, u_int8_t flush_packet, int if_index) { |
| int rc = -1; |
| |
| if(unlikely(pkt_len > ring->mtu_len)) |
| return(PF_RING_ERROR_INVALID_ARGUMENT); /* Packet too long */ |
| |
| if(likely(ring |
| && ring->enabled |
| && (!ring->is_shutting_down) |
| && ring->send_ifindex |
| && (ring->mode != recv_only_mode))) { |
| |
| if(unlikely(ring->reentrant)) |
| pthread_rwlock_wrlock(&ring->tx_lock); |
| |
| rc = ring->send_ifindex(ring, pkt, pkt_len, flush_packet, if_index); |
| |
| if(unlikely(ring->reentrant)) |
| pthread_rwlock_unlock(&ring->tx_lock); |
| } |
| |
| return rc; |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_send_parsed(pfring *ring, char *pkt, struct pfring_pkthdr *hdr, u_int8_t flush_packet) { |
| int rc = -1; |
| |
| if(likely(ring |
| && ring->enabled |
| && (!ring->is_shutting_down) |
| && ring->send_parsed |
| && (ring->mode != recv_only_mode))) { |
| |
| if(unlikely(ring->reentrant)) |
| pthread_rwlock_wrlock(&ring->tx_lock); |
| |
| rc = ring->send_parsed(ring, pkt, hdr, flush_packet); |
| |
| if(unlikely(ring->reentrant)) |
| pthread_rwlock_unlock(&ring->tx_lock); |
| |
| return rc; |
| } |
| |
| if(ring && !ring->send_parsed) |
| rc = PF_RING_ERROR_NOT_SUPPORTED; |
| |
| return rc; |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_send_get_time(pfring *ring, char *pkt, u_int pkt_len, struct timespec *ts) { |
| int rc = -1; |
| |
| if(likely(ring |
| && ring->enabled |
| && (!ring->is_shutting_down) |
| && ring->send_get_time |
| && (ring->mode != recv_only_mode))) { |
| |
| if(unlikely(ring->reentrant)) |
| pthread_rwlock_wrlock(&ring->tx_lock); |
| |
| rc = ring->send_get_time(ring, pkt, pkt_len, ts); |
| |
| if(unlikely(ring->reentrant)) |
| pthread_rwlock_unlock(&ring->tx_lock); |
| |
| return rc; |
| } |
| |
| if(ring && !ring->send_get_time) |
| rc = PF_RING_ERROR_NOT_SUPPORTED; |
| |
| return rc; |
| } |
| |
| /* **************************************************** */ |
| |
| u_int8_t pfring_get_num_rx_channels(pfring *ring) { |
| if(ring && ring->get_num_rx_channels) |
| return ring->get_num_rx_channels(ring); |
| |
| return 1; |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_sampling_rate(pfring *ring, u_int32_t rate /* 1 = no sampling */) { |
| if(ring && ring->set_sampling_rate) { |
| int rc; |
| |
| rc = ring->set_sampling_rate(ring, rate); |
| |
| if (rc == 0) |
| ring->sampling_rate = rate; |
| |
| return(rc); |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_get_selectable_fd(pfring *ring) { |
| if(ring && ring->get_selectable_fd) |
| return ring->get_selectable_fd(ring); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_direction(pfring *ring, packet_direction direction) { |
| if(ring && ring->set_direction) { |
| int rc; |
| |
| if(ring->enabled) |
| return -1; /* direction must be set before pfring_enable() */ |
| |
| rc = ring->set_direction(ring, direction); |
| |
| if(rc == 0) |
| ring->direction = direction; |
| |
| return(rc); |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_socket_mode(pfring *ring, socket_mode mode) { |
| if(ring && ring->set_socket_mode) { |
| int rc; |
| |
| if(ring->enabled) |
| return -1; /* direction must be set before pfring_enable() */ |
| |
| rc = ring->set_socket_mode(ring, mode); |
| |
| if(rc == 0) |
| ring->mode = mode; |
| |
| return(rc); |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_cluster(pfring *ring, u_int clusterId, cluster_type the_type) { |
| if(ring && ring->set_cluster) |
| return ring->set_cluster(ring, clusterId, the_type); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_remove_from_cluster(pfring *ring) { |
| if(ring && ring->remove_from_cluster) |
| return ring->remove_from_cluster(ring); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_master_id(pfring *ring, u_int32_t master_id) { |
| if(ring && ring->set_master_id) |
| return ring->set_master_id(ring, master_id); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_master(pfring *ring, pfring *master) { |
| if(ring && ring->set_master) |
| return ring->set_master(ring, master); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| u_int16_t pfring_get_ring_id(pfring *ring) { |
| if(ring && ring->get_ring_id) |
| return ring->get_ring_id(ring); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| u_int32_t pfring_get_num_queued_pkts(pfring *ring) { |
| if(ring && ring->get_num_queued_pkts) |
| return ring->get_num_queued_pkts(ring); |
| |
| return 0; |
| } |
| |
| /* **************************************************** */ |
| |
| u_int8_t pfring_get_packet_consumer_mode(pfring *ring) { |
| if(ring && ring->get_packet_consumer_mode) |
| return ring->get_packet_consumer_mode(ring); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_packet_consumer_mode(pfring *ring, u_int8_t plugin_id, |
| char *plugin_data, u_int plugin_data_len) { |
| if(ring && ring->set_packet_consumer_mode) |
| return ring->set_packet_consumer_mode(ring, plugin_id, plugin_data, plugin_data_len); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_get_hash_filtering_rule_stats(pfring *ring, hash_filtering_rule* rule, |
| char* stats, u_int *stats_len) { |
| if(ring && ring->get_hash_filtering_rule_stats) |
| return ring->get_hash_filtering_rule_stats(ring, rule, stats, stats_len); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_handle_hash_filtering_rule(pfring *ring, hash_filtering_rule* rule_to_add, |
| u_char add_rule) { |
| if(ring && ring->handle_hash_filtering_rule) |
| return ring->handle_hash_filtering_rule(ring, rule_to_add, add_rule); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_purge_idle_hash_rules(pfring *ring, u_int16_t inactivity_sec) { |
| if(ring && ring->purge_idle_hash_rules) |
| return ring->purge_idle_hash_rules(ring, inactivity_sec); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_purge_idle_rules(pfring *ring, u_int16_t inactivity_sec) { |
| if(ring && ring->purge_idle_rules) |
| return ring->purge_idle_rules(ring, inactivity_sec); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_add_filtering_rule(pfring *ring, filtering_rule* rule_to_add) { |
| if(ring && ring->add_filtering_rule) |
| return ring->add_filtering_rule(ring, rule_to_add); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_remove_filtering_rule(pfring *ring, u_int16_t rule_id) { |
| if(ring && ring->remove_filtering_rule) |
| return ring->remove_filtering_rule(ring, rule_id); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_get_filtering_rule_stats(pfring *ring, u_int16_t rule_id, |
| char* stats, u_int *stats_len) { |
| if(ring && ring->get_filtering_rule_stats) |
| return ring->get_filtering_rule_stats(ring, rule_id, stats, stats_len); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_toggle_filtering_policy(pfring *ring, u_int8_t rules_default_accept_policy) { |
| if (ring && ring->toggle_filtering_policy) |
| return ring->toggle_filtering_policy(ring, rules_default_accept_policy); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_enable_rss_rehash(pfring *ring) { |
| if(ring && ring->enable_rss_rehash) |
| return ring->enable_rss_rehash(ring); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_poll(pfring *ring, u_int wait_duration) { |
| if(likely((ring && ring->poll))) |
| return ring->poll(ring, wait_duration); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_version(pfring *ring, u_int32_t *version) { |
| if(ring && ring->version) |
| return ring->version(ring, version); |
| |
| *version = RING_VERSION_NUM; |
| return 0;/*PF_RING_ERROR_NOT_SUPPORTED*/; |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_get_bound_device_address(pfring *ring, u_char mac_address[6]) { |
| if(ring && ring->get_bound_device_address) |
| return ring->get_bound_device_address(ring, mac_address); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_get_bound_device_ifindex(pfring *ring, int *if_index) { |
| if(ring && ring->get_bound_device_ifindex) |
| return ring->get_bound_device_ifindex(ring, if_index); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_get_device_ifindex(pfring *ring, char *device_name, int *if_index) { |
| if(ring && ring->get_device_ifindex) |
| return ring->get_device_ifindex(ring, device_name, if_index); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| u_int16_t pfring_get_slot_header_len(pfring *ring) { |
| if(ring && ring->get_slot_header_len) |
| return ring->get_slot_header_len(ring); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_virtual_device(pfring *ring, virtual_filtering_device_info *info) { |
| if(ring && ring->set_virtual_device) |
| return ring->set_virtual_device(ring, info); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_loopback_test(pfring *ring, char *buffer, u_int buffer_len, u_int test_len) { |
| if(ring && ring->loopback_test) |
| return ring->loopback_test(ring, buffer, buffer_len, test_len); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_enable_ring(pfring *ring) { |
| if(ring && ring->enable_ring) { |
| int rc; |
| |
| if(ring->enabled) return(0); |
| |
| rc = ring->enable_ring(ring); |
| if(rc == 0) ring->enabled = 1; |
| |
| return rc; |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_disable_ring(pfring *ring) { |
| if(ring && ring->disable_ring) { |
| int rc; |
| |
| if(!ring->enabled) return(0); |
| |
| rc = ring->disable_ring(ring); |
| if(rc == 0) ring->enabled = 0; |
| |
| return rc; |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_is_pkt_available(pfring *ring) { |
| if(ring && ring->is_pkt_available) { |
| return ring->is_pkt_available(ring); |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_next_pkt_time(pfring *ring, struct timespec *ts) { |
| if(ring && ring->next_pkt_time) { |
| return ring->next_pkt_time(ring, ts); |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_next_pkt_raw_timestamp(pfring *ring, u_int64_t *ts) { |
| if(ring && ring->next_pkt_raw_timestamp) { |
| return ring->next_pkt_raw_timestamp(ring, ts); |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_bpf_filter(pfring *ring, char *filter_buffer) { |
| if(ring && ring->set_bpf_filter) { |
| return ring->set_bpf_filter(ring, filter_buffer); |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_remove_bpf_filter(pfring *ring) { |
| if(ring && ring->remove_bpf_filter) { |
| return ring->remove_bpf_filter(ring); |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| void pfring_sync_indexes_with_kernel(pfring *ring) { |
| if(ring && ring->sync_indexes_with_kernel) |
| ring->sync_indexes_with_kernel(ring); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_send_last_rx_packet(pfring *ring, int tx_interface_id) { |
| /* |
| We can't send the last packet with multithread as the concept of "last" |
| does not apply here having threads that compete for packets |
| */ |
| if(unlikely(ring->reentrant || (!ring->long_header))) |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| |
| if(ring && ring->send_last_rx_packet) |
| return(ring->send_last_rx_packet(ring, tx_interface_id)); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_filtering_mode(pfring *ring, filtering_mode mode) { |
| if(!ring) |
| return -1; |
| |
| ring->ft_mode = mode; |
| return 0; |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_get_device_clock(pfring *ring, struct timespec *ts) { |
| if(ring && ring->get_device_clock) { |
| return ring->get_device_clock(ring, ts); |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_device_clock(pfring *ring, struct timespec *ts) { |
| if(ring && ring->set_device_clock) { |
| return ring->set_device_clock(ring, ts); |
| } |
| |
| return PF_RING_ERROR_NOT_SUPPORTED; |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_adjust_device_clock(pfring *ring, struct timespec *offset, int8_t sign) { |
| if(ring && ring->adjust_device_clock) { |
| return ring->adjust_device_clock(ring, offset, sign); |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| u_int pfring_get_num_tx_slots(pfring* ring) { |
| if(ring && ring->dna_get_num_tx_slots) { |
| return ring->dna_get_num_tx_slots(ring); |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| u_int pfring_get_num_rx_slots(pfring* ring) { |
| if(ring && ring->dna_get_num_rx_slots) { |
| return ring->dna_get_num_rx_slots(ring); |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_copy_tx_packet_into_slot(pfring* ring, |
| u_int16_t tx_slot_id, char* buffer, u_int len) { |
| if(ring && ring->dna_copy_tx_packet_into_slot) |
| return ring->dna_copy_tx_packet_into_slot(ring, tx_slot_id, buffer, len); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| u_char* pfring_get_pkt_buff_data(pfring *ring, pfring_pkt_buff *pkt_handle) { |
| if(ring && ring->get_pkt_buff_data) |
| return ring->get_pkt_buff_data(ring, pkt_handle); |
| |
| return NULL; |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_pkt_buff_len(pfring *ring, pfring_pkt_buff *pkt_handle, u_int32_t len) { |
| if(ring && ring->set_pkt_buff_len) |
| return ring->set_pkt_buff_len(ring, pkt_handle, len); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_set_pkt_buff_ifindex(pfring *ring, pfring_pkt_buff *pkt_handle, int if_index) { |
| if(ring && ring->set_pkt_buff_ifindex) |
| return ring->set_pkt_buff_ifindex(ring, pkt_handle, if_index); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_register_zerocopy_tx_ring(pfring *ring, pfring *tx_ring) { |
| if(ring && ring->register_zerocopy_tx_ring) |
| return ring->register_zerocopy_tx_ring(ring, tx_ring); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_add_pkt_buff_ifindex(pfring *ring, pfring_pkt_buff *pkt_handle, int if_index) { |
| if(ring && ring->add_pkt_buff_ifindex) |
| return ring->add_pkt_buff_ifindex(ring, pkt_handle, if_index); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| pfring_pkt_buff* pfring_alloc_pkt_buff(pfring *ring) { |
| if(ring && ring->alloc_pkt_buff) |
| return ring->alloc_pkt_buff(ring); |
| |
| return NULL; |
| } |
| |
| /* **************************************************** */ |
| |
| void pfring_release_pkt_buff(pfring *ring, pfring_pkt_buff *pkt_handle) { |
| if(ring && ring->release_pkt_buff) |
| ring->release_pkt_buff(ring, pkt_handle); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_recv_pkt_buff(pfring *ring, pfring_pkt_buff *pkt_handle, struct pfring_pkthdr *hdr, u_int8_t wait_for_incoming_packet) { |
| /* Note: this function fills the buffer pointed by pkt_handle */ |
| |
| if(ring && ring->recv_pkt_buff) |
| return ring->recv_pkt_buff(ring, pkt_handle, hdr, wait_for_incoming_packet); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_send_pkt_buff(pfring *ring, pfring_pkt_buff *pkt_handle, u_int8_t flush_packet) { |
| /* Note: this function reset the buffer pointed by pkt_handle */ |
| |
| if(ring && ring->send_pkt_buff) |
| return ring->send_pkt_buff(ring, pkt_handle, flush_packet); |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_flush_tx_packets(pfring *ring) { |
| if(ring && ring->flush_tx_packets) { |
| ring->flush_tx_packets(ring); |
| return(0); |
| } |
| |
| return(PF_RING_ERROR_NOT_SUPPORTED); |
| } |
| |
| /* **************************************************** */ |
| |
| int pfring_search_payload(pfring *ring, char *string_to_search) { |
| if (!ring) |
| return(-1); |
| |
| return(-2); |
| } |
| |