blob: 6c6078755f7cc88de44fdb1f023b229daf14abf7 [file] [log] [blame]
/*
* vPFRing - a vNPlug client (Virtual PF_RING)
*
* Authors:
*
* Alfredo Cardigliano <cardigliano@ntop.org>
*
* This work is licensed under the terms of the GNU GPL version 2.
*
*/
#include "vpfring.h"
//#define VPFRING_DEBUG
#ifdef VPFRING_DEBUG
#define VPFRING_DEBUG_PRINTF(fmt, ...) do {printf("[vPFRing] " fmt, ## __VA_ARGS__); } while (0)
#else
#define VPFRING_DEBUG_PRINTF(fmt, ...)
#endif
static QLIST_HEAD(vpfring_devices_head, vPFRingInfo) vpfring_devices =
QLIST_HEAD_INITIALIZER(vpfring_devices);
static struct vPFRingInfo *vpfring_device_by_id(uint32_t device_id)
{
struct vPFRingInfo *i;
QLIST_FOREACH(i, &vpfring_devices, list) {
if (i->dev_id == device_id){
VPFRING_DEBUG_PRINTF("vPFRing device %d found\n", device_id);
return i;
}
}
VPFRING_DEBUG_PRINTF("error: vPFRing device %d not found!\n", device_id);
return NULL;
}
/* ******************************************************************************************* */
uint32_t vpfring_io_readl(struct vNPlugDevClientInfo *client, target_phys_addr_t addr)
{
//struct vPFRingInfo *vpfri = client->priv;
//VPFRING_DEBUG_PRINTF("io_readl handler call for dev with id=%d\n", vpfri->dev_id);
return 0;
}
/* ******************************************************************************************* */
void vpfring_io_writel(struct vNPlugDevClientInfo *client, target_phys_addr_t addr, uint32_t val)
{
//struct vPFRingInfo *vpfri = client->priv;
//VPFRING_DEBUG_PRINTF("io_readl handler call for dev with id=%d\n", vpfri->dev_id);
}
/* ******************************************************************************************* */
static int vpfring_ring_add(struct vPFRingAddMsg *amsg, void *ret_message, uint32_t ret_size)
{
struct vPFRingInfo *vpfri;
struct vNPlugDevClientInfo *client;
char tmpstr[32];
int ret = -1;
vpfri = g_malloc0(sizeof(*vpfri));
if (!vpfri)
goto exit;
client = g_malloc0(sizeof(*client));
if (!client)
goto free_vpfri;
client->set_init_data_handler = vpfring_set_init_data;
client->pre_unplug_handler = vpfring_stop;
client->post_unplug_handler = vpfring_close_and_free;
client->io_readl_handler = vpfring_io_readl;
client->io_writel_handler = vpfring_io_writel;
client->priv = vpfri;
vpfri->vnplug_client = client;
VPFRING_DEBUG_PRINTF("opening ring\n");
vpfri->ring = pfring_open(
amsg->device_name,
amsg->caplen,
amsg->flags);
if (vpfri->ring == NULL)
goto free_client;
/* the dev_id will be set in the init_data handler, called from qdev_device_add */
vpfri->dev_id = 0xffffffff;
VPFRING_DEBUG_PRINTF("registering vPFRing device\n");
QLIST_INSERT_HEAD(&vpfring_devices, vpfri, list);
VPFRING_DEBUG_PRINTF("creating vNPlug device\n");
QemuOpts *opts;
opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
/* it's ugly but there is no other clean way.. */
qemu_opt_set(opts, "driver", "vnplug-dev");
qemu_opt_set(opts, "backend_events_n", "1");
qemu_opt_set(opts, "guest_events_n", "1");
snprintf(tmpstr, 32, "%u", vpfri->ring->slots_info->tot_mem);
qemu_opt_set(opts, "vma_size", tmpstr);
snprintf(tmpstr, 32, "%" PRIu64, (uint64_t) vpfri->ring->buffer);
qemu_opt_set(opts, "vma_ptr", tmpstr);
snprintf(tmpstr, 32, "%" PRIu64, (uint64_t) client);
qemu_opt_set(opts, "client_info_ptr", tmpstr);
vpfri->qdev = qdev_device_add(opts);
if (vpfri->qdev == NULL)
goto close_ring;
/* after qdev_device_add returns, dev_id should be updated to the correct value */
if (vpfri->dev_id != 0xffffffff){
VPFRING_DEBUG_PRINTF("vNPlug device created successfully [ id=%u, state=%d ]\n", vpfri->dev_id, vpfri->qdev->state);
} else {
fprintf(stderr, "[vPFRing] Error occurs while creating the vNPlug device: ID not set.\n");
goto unregister;
}
return vpfri->dev_id;
unregister:
QLIST_REMOVE(vpfri, list);
close_ring:
pfring_close(vpfri->ring);
free_client:
g_free(client);
free_vpfri:
g_free(vpfri);
exit:
return ret;
}
/* ******************************************************************************************* */
static void vpfring_ring_del(struct vPFRingInfo *vpfri)
{
Error *errp;
if (vpfri == NULL){
VPFRING_DEBUG_PRINTF("error deleting device (null)");
return;
}
VPFRING_DEBUG_PRINTF("deleting vPFRing device %d\n", vpfri->dev_id);
VPFRING_DEBUG_PRINTF("unplugging vNPlug device\n");
qdev_unplug(vpfri->qdev, &errp);
/* Note: this is called by qdev_unplug */
//qdev_free(vpfri->qdev);
/* Note: stop -> pre_unplug_handler
* close and free -> post_unplug_handler */
}
/* ******************************************************************************************* */
int vpfring_ctrl_message_rcv(void *message, uint32_t size, void *ret_message, uint32_t ret_size)
{
struct vPFRingMsg *msg = (struct vPFRingMsg *) message;
struct vPFRingInfo *vpfri = NULL;
int ret_val;
if (size != (sizeof(*msg) + msg->payload_len)){
VPFRING_DEBUG_PRINTF("vpfring_ctrl_message_rcv: wrong message size=%u. expected size=%lu!\n", size, sizeof(*msg) + msg->payload_len);
return -1;
}
if (msg->type != VPFRING_CTRL_MSG_DEVICE_ADD) {
if (!(vpfri = vpfring_device_by_id(msg->device_id))) {
fprintf(stderr, "[vPFRing] Error: vpfring_ctrl_message_rcv: Wrong device id=%u, device not found!\n", msg->device_id);
return -1;
}
}
switch (msg->type)
{
case VPFRING_CTRL_MSG_SET_DIRECTION:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_SET_DIRECTION received\n");
if (msg->payload_len != sizeof(struct vPFRingSetDirectionMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingSetClusterMsg with wrong size\n");
return -1;
}
return pfring_set_direction(vpfri->ring,
((struct vPFRingSetDirectionMsg *) msg->payload)->direction);
case VPFRING_CTRL_MSG_SET_SOCKET_MODE:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_SET_SOCKET_MODE received\n");
if (msg->payload_len != sizeof(struct vPFRingSetSocketModeMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingSetSocketModeMsg with wrong size\n");
return -1;
}
return pfring_set_socket_mode(vpfri->ring,
((struct vPFRingSetSocketModeMsg *) msg->payload)->mode);
case VPFRING_CTRL_MSG_SET_CLUSTER:
{
struct vPFRingSetClusterMsg *cmsg;
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_SET_CLUSTER received\n");
if (msg->payload_len != sizeof(struct vPFRingSetClusterMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingSetClusterMsg with wrong size\n");
return -1;
}
cmsg = (struct vPFRingSetClusterMsg *) msg->payload;
return pfring_set_cluster(vpfri->ring, cmsg->cluster_id, cmsg->cluster_type);
}
case VPFRING_CTRL_MSG_SET_MASTER_ID:
{
struct vPFRingSetMasterIdMsg *midmsg;
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_SET_MASTER_ID received\n");
if (msg->payload_len != sizeof(struct vPFRingSetMasterIdMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingSetMasterIdMsg with wrong size\n");
return -1;
}
midmsg = (struct vPFRingSetMasterIdMsg *) msg->payload;
return pfring_set_master_id(vpfri->ring, midmsg->master_id);
}
case VPFRING_CTRL_MSG_SET_CHANNEL_MASK:
{
struct vPFRingSetChannelMaskMsg *cidmsg;
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_SET_CHANNEL_ID received\n");
if (msg->payload_len != sizeof(struct vPFRingSetChannelMaskMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingSetChannelMaskMsg with wrong size\n");
return -1;
}
cidmsg = (struct vPFRingSetChannelMaskMsg *) msg->payload;
return pfring_set_channel_mask(vpfri->ring, cidmsg->channel_mask);
}
case VPFRING_CTRL_MSG_ADD_HW_RULE:
{
struct vPFRingAddHwRuleMsg *hwrmsg;
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_ADD_HW_RULE received\n");
if (msg->payload_len != sizeof(struct vPFRingAddHwRuleMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingAddHwRuleMsg with wrong size\n");
return -1;
}
hwrmsg = (struct vPFRingAddHwRuleMsg *) msg->payload;
return pfring_add_hw_rule(vpfri->ring, &hwrmsg->rule);
}
case VPFRING_CTRL_MSG_REMOVE_HW_RULE:
{
struct vPFRingRemoveHwRuleMsg *hwrmsg;
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_REMOVE_HW_RULE received\n");
if (msg->payload_len != sizeof(struct vPFRingRemoveHwRuleMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingRemoveHwRuleMsg with wrong size\n");
return -1;
}
hwrmsg = (struct vPFRingRemoveHwRuleMsg *) msg->payload;
return pfring_remove_hw_rule(vpfri->ring, hwrmsg->rule_id);
}
case VPFRING_CTRL_MSG_REMOVE_FROM_CLUSTER:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_REMOVE_FROM_CLUSTER received\n");
return pfring_remove_from_cluster(vpfri->ring);
case VPFRING_CTRL_MSG_PURGE_IDLE_HASH_RULES:
{
struct vPFRingPurgeIdleHashRulesMsg *pisrmsg;
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_PURGE_IDLE_HASH_RULES received\n");
if (msg->payload_len != sizeof(struct vPFRingPurgeIdleHashRulesMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingPurgeIdleHashRulesMsg with wrong size\n");
return -1;
}
pisrmsg = (struct vPFRingPurgeIdleHashRulesMsg *) msg->payload;
return pfring_purge_idle_hash_rules(vpfri->ring, pisrmsg->inactivity_sec);
}
case VPFRING_CTRL_MSG_PURGE_IDLE_RULES:
{
struct vPFRingPurgeIdleRulesMsg *pisrmsg;
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_PURGE_IDLE_RULES received\n");
if (msg->payload_len != sizeof(struct vPFRingPurgeIdleRulesMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingPurgeIdleRulesMsg with wrong size\n");
return -1;
}
pisrmsg = (struct vPFRingPurgeIdleRulesMsg *) msg->payload;
return pfring_purge_idle_hash_rules(vpfri->ring, pisrmsg->inactivity_sec);
}
case VPFRING_CTRL_MSG_SET_APPLICATION_NAME:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_SET_APPLICATION_NAME received\n");
if (msg->payload_len != sizeof(struct vPFRingSetApplicationNameMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingSetApplicationNameMsg with wrong size\n");
return -1;
}
return pfring_set_application_name(
vpfri->ring,
((struct vPFRingSetApplicationNameMsg *) msg->payload)->name);
case VPFRING_CTRL_MSG_DEVICE_ADD:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_DEVICE_ADD received\n");
if (msg->payload_len < sizeof(struct vPFRingAddMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingAddMsg with wrong size\n");
return -1;
}
return vpfring_ring_add((struct vPFRingAddMsg *) msg->payload, ret_message, ret_size);
case VPFRING_CTRL_MSG_BIND:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_BIND received\n");
if (msg->payload_len != sizeof(struct vPFRingBindMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingBindMsg with wrong size\n");
return -1;
}
return pfring_bind(
vpfri->ring,
((struct vPFRingBindMsg *) msg->payload)->device_name);
case VPFRING_CTRL_MSG_SET_POLL_WATERMARK:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_SET_POLL_WATERMARK received\n");
if (msg->payload_len != sizeof(struct vPFRingSetPollWatermarkMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingSetPollWatermarkMsg with wrong size\n");
return -1;
}
return pfring_set_poll_watermark(
vpfri->ring,
((struct vPFRingSetPollWatermarkMsg *) msg->payload)->watermark);
case VPFRING_CTRL_MSG_DEVICE_DEL:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_DEVICE_DEL received\n");
vpfring_ring_del(vpfri);
break;
case VPFRING_CTRL_MSG_GET_FILTERING_RULE_STATS:
{
struct vPFRingGetFilteringRuleStatsMsg *gfrsmsg;
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_VERSION received\n");
if (msg->payload_len != sizeof(struct vPFRingGetFilteringRuleStatsMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingGetFilteringRuleStatsMsg with wrong size\n");
return -1;
}
if (ret_message == NULL || ret_size <= 0){
VPFRING_DEBUG_PRINTF("skipping! return buffer not found or empty\n");
return -1;
}
gfrsmsg = (struct vPFRingGetFilteringRuleStatsMsg *) msg->payload;
if (gfrsmsg->stats_len != ret_size){
VPFRING_DEBUG_PRINTF("skipping! something wrong..\n");
return -1;
}
return pfring_get_filtering_rule_stats(vpfri->ring,
gfrsmsg->rule_id,
ret_message,
&gfrsmsg->stats_len);
}
case VPFRING_CTRL_MSG_GET_NUM_RX_CHANNELS:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_GET_NUM_RX_CHANNELS received\n");
return pfring_get_num_rx_channels(vpfri->ring);
case VPFRING_CTRL_MSG_GET_RING_ID:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_GET_RING_ID received\n");
return pfring_get_ring_id(vpfri->ring);
case VPFRING_CTRL_MSG_GET_PACKET_CONSUMER_MODE:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_GET_PACKET_CONSUMER_MODE received\n");
return pfring_get_packet_consumer_mode(vpfri->ring);
case VPFRING_CTRL_MSG_SET_PACKET_CONSUMER_MODE:
{
struct vPFRingSetPacketConsumerModeMsg *pcmmsg;
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_SET_PACKET_CONSUMER_MODE received\n");
if (msg->payload_len < sizeof(struct vPFRingSetPacketConsumerModeMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingSetPacketConsumerModeMsg with wrong size\n");
return -1;
}
pcmmsg = (struct vPFRingSetPacketConsumerModeMsg *) msg->payload;
return pfring_set_packet_consumer_mode(vpfri->ring, pcmmsg->plugin_id, pcmmsg->plugin_data, pcmmsg->plugin_data_len);
}
case VPFRING_CTRL_MSG_SET_VIRTUAL_DEVICE:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_SET_VIRTUAL_DEVICE received\n");
if (msg->payload_len != sizeof(virtual_filtering_device_info)){
VPFRING_DEBUG_PRINTF("skipping! payload with wrong size\n");
return -1;
}
return pfring_set_virtual_device(vpfri->ring, (virtual_filtering_device_info *) msg->payload);
case VPFRING_CTRL_MSG_GET_HASH_FILTERING_RULE_STATS:
{
struct vPFRingGetHashFilteringRuleStatsMsg *hfrsmsg;
uint32_t stats_len_c;
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_GET_HASH_FILTERING_RULE_STATS received\n");
if (msg->payload_len != sizeof(struct vPFRingGetHashFilteringRuleStatsMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingGetHashFilteringRuleStatsMsg with wrong size\n");
return -1;
}
hfrsmsg = (struct vPFRingGetHashFilteringRuleStatsMsg *) msg->payload;
if (ret_message == NULL || ret_size != hfrsmsg->stats_len ){
VPFRING_DEBUG_PRINTF("skipping! return buffer with wrong size\n");
return -1;
}
stats_len_c = hfrsmsg->stats_len;
return pfring_get_hash_filtering_rule_stats(vpfri->ring, &hfrsmsg->rule, (char *) ret_message, &stats_len_c);
}
case VPFRING_CTRL_MSG_ADD_FILTERING_RULE:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_ADD_FILTERING_RULE received\n");
if (msg->payload_len != sizeof(filtering_rule)){
VPFRING_DEBUG_PRINTF("skipping! payload with wrong size\n");
return -1;
}
return pfring_add_filtering_rule(vpfri->ring, (filtering_rule *) msg->payload);
case VPFRING_CTRL_MSG_HANDLE_HASH_FILTERING_RULE:
{
struct vPFRingHandleHashFilteringRuleMsg *hfrmsg;
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_HANDLE_HASH_FILTERING_RULE received\n");
if (msg->payload_len != sizeof(struct vPFRingHandleHashFilteringRuleMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingHandleHashFilteringRuleMsg with wrong size\n");
return -1;
}
hfrmsg = (struct vPFRingHandleHashFilteringRuleMsg *) msg->payload;
return pfring_handle_hash_filtering_rule(vpfri->ring, &hfrmsg->rule_to_add, hfrmsg->add_rule);
}
case VPFRING_CTRL_MSG_ENABLE_RING:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_ENABLE_RING received\n");
return pfring_enable_ring(vpfri->ring);
case VPFRING_CTRL_MSG_DISABLE_RING:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_DISABLE_RING received\n");
return pfring_disable_ring(vpfri->ring);
case VPFRING_CTRL_MSG_REMOVE_FILTERING_RULE:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_REMOVE_FILTERING_RULE received\n");
if (msg->payload_len != sizeof(struct vPFRingRemoveFilteringRuleMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingRemoveFilteringRuleMsg with wrong size\n");
return -1;
}
return pfring_remove_filtering_rule(
vpfri->ring,
((struct vPFRingRemoveFilteringRuleMsg *) msg->payload)->rule_id);
case VPFRING_CTRL_MSG_TOGGLE_FILTERING_POLICY:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_TOGGLE_FILTERING_POLICY received\n");
if (msg->payload_len != sizeof(struct vPFRingToggleFilteringPolicyMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingToggleFilteringPolicyMsg with wrong size\n");
return -1;
}
return pfring_toggle_filtering_policy(
vpfri->ring,
((struct vPFRingToggleFilteringPolicyMsg *) msg->payload)->rules_default_accept_policy);
case VPFRING_CTRL_MSG_VERSION:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_VERSION received\n");
if (ret_message == NULL || ret_size != sizeof(u_int32_t)){
VPFRING_DEBUG_PRINTF("skipping! return buffer with wrong size\n");
return -1;
}
ret_val = pfring_version(vpfri->ring, (u_int32_t *) ret_message);
VPFRING_DEBUG_PRINTF("PF_RING version is v.%d.%d.%d\n",
(*((u_int32_t *) ret_message) & 0xFFFF0000) >> 16,
(*((u_int32_t *) ret_message) & 0x0000FF00) >> 8,
*((u_int32_t *) ret_message) & 0x000000FF);
return ret_val;
case VPFRING_CTRL_MSG_SET_SAMPLING_RATE:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_SET_SAMPLING_RATE received\n");
if (msg->payload_len != sizeof(struct vPFRingSetSamplingRateMsg)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingSetSamplingRateMsg with wrong size\n");
return -1;
}
return pfring_set_sampling_rate(
vpfri->ring,
((struct vPFRingSetSamplingRateMsg *) msg->payload)->rate);
case VPFRING_CTRL_MSG_GET_BOUND_DEVICE_ADDRESS:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_GET_BOUND_DEVICE_ADDRESS received\n");
if (msg->payload_len != sizeof(u_char) * 6){
VPFRING_DEBUG_PRINTF("skipping! device address with wrong size\n");
return -1;
}
if (ret_message == NULL || ret_size != (sizeof(u_char) * 6)){
VPFRING_DEBUG_PRINTF("skipping! return buffer with wrong size\n");
return -1;
}
memcpy(ret_message, msg->payload, sizeof(u_char) * 6);
ret_val = pfring_get_bound_device_address(vpfri->ring, (u_char *) ret_message);
return ret_val;
case VPFRING_CTRL_MSG_GET_SLOT_HEADER_LEN:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_GET_SLOT_HEADER_LEN received\n");
return pfring_get_slot_header_len(vpfri->ring);
case VPFRING_CTRL_MSG_GET_NUM_QUEUED_PKTS:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_GET_NUM_QUEUED_PKTS received\n");
return pfring_get_num_queued_pkts(vpfri->ring);
case VPFRING_CTRL_MSG_ENABLE_RSS_REHASH:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_ENABLE_RSS_REHASH received\n");
return pfring_enable_rss_rehash(vpfri->ring);
case VPFRING_CTRL_MSG_SET_BPF_FILTER:
{
struct vPFRingSetBPFFilter *sbfmsg;
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_SET_BPF_FILTER received\n");
if (msg->payload_len < sizeof(struct vPFRingSetBPFFilter)){
VPFRING_DEBUG_PRINTF("skipping! vPFRingSetBPFFilter with wrong size\n");
return -1;
}
sbfmsg = (struct vPFRingSetBPFFilter *) msg->payload;
return pfring_set_bpf_filter(vpfri->ring, sbfmsg->filter_buffer);
}
case VPFRING_CTRL_MSG_REMOVE_BPF_FILTER:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_REMOVE_BPF_FILTER received\n");
return pfring_remove_bpf_filter(vpfri->ring);
case VPFRING_CTRL_MSG_SHUTDOWN:
VPFRING_DEBUG_PRINTF("message VPFRING_CTRL_MSG_SHUTDOWN received\n");
pfring_shutdown(vpfri->ring);
break;
default:
VPFRING_DEBUG_PRINTF("vpfring_ctrl_message_rcv: unrecognized msessage type!\n");
return -1;
}
return 0; //success (non negative value)
}
/* ******************************************************************************************* */
void vpfring_set_init_data(struct vNPlugDevClientInfo *client, uint32_t dev_id, uint32_t backend_eventfds_n, int *backend_eventfds, uint32_t guest_eventfds_n, int *guest_eventfds)
{
struct vPFRingInfo *vpfri = client->priv;
struct vpfring_eventfd_info eventfd_i;
/* setting the device id */
vpfri->dev_id = dev_id;
VPFRING_DEBUG_PRINTF("setting eventfds for vNPlug device with id=%d\n", vpfri->dev_id);
/* we are using just one eventfd, maybe later we can need more.. */
if (backend_eventfds_n>=1){
eventfd_i.fd = backend_eventfds[0];
eventfd_i.id = VPFRING_HOST_EVENT_RX_INT;
setsockopt(vpfri->ring->fd, 0, SO_SET_VPFRING_HOST_EVENTFD, &eventfd_i, sizeof(eventfd_i));
} else
fprintf(stderr, "[vPFRing] error: backend eventfd missing!\n");
/* setting guest eventfd for guest notifications (unused, present in the experimental version) */
//if (guest_eventfds_n>=1){
// eventfd_i.fd = guest_eventfds[0];
// eventfd_i.id = VPFRING_GUEST_EVENT_REQ_RX_INT;
// setsockopt(vpfri->ring->fd, 0, SO_SET_VPFRING_GUEST_EVENTFD, &eventfd_i, sizeof(eventfd_i));
//} else
//fprintf(stderr, "[vPFRing] error: backend eventfd missing!\n");
}
/* ******************************************************************************************* */
void vpfring_stop(struct vNPlugDevClientInfo *client)
{
struct vPFRingInfo *vpfri = client->priv;
if (vpfri == NULL){
VPFRING_DEBUG_PRINTF("error stopping ring (null)");
return;
}
VPFRING_DEBUG_PRINTF("stopping ring [device=%d]\n", vpfri->dev_id);
/* stopping eventfd signals from backend */
setsockopt(vpfri->ring->fd, 0, SO_SET_VPFRING_CLEAN_EVENTFDS, NULL, 0);
QLIST_REMOVE(vpfri, list);
}
/* ******************************************************************************************* */
void vpfring_close_and_free(struct vNPlugDevClientInfo *client)
{
struct vPFRingInfo *vpfri = client->priv;
if (vpfri == NULL){
VPFRING_DEBUG_PRINTF("error closing ring (null)");
return;
}
VPFRING_DEBUG_PRINTF("closing ring [device=%d]\n", vpfri->dev_id);
pfring_close(vpfri->ring);
VPFRING_DEBUG_PRINTF("freeing memory\n");
g_free(vpfri->vnplug_client);
g_free(vpfri);
}
/* ******************************************************************************************* */
static struct vNPlugCTRLClientInfo vpfring_client_info = {
.id = VNPLUG_CLIENT_ID_VPFRING,
.name = "vpfring",
.msg_handler = vpfring_ctrl_message_rcv,
};
static void vpfring_register(void)
{
QLIST_INIT(&vpfring_devices);
VPFRING_DEBUG_PRINTF("registering to vnplug..\n");
vnplug_ctrl_register_client(&vpfring_client_info);
}
type_init(vpfring_register);