From a0734ef18aec975dca5f91ef6d8bba66eb104400 Mon Sep 17 00:00:00 2001 From: gogapp Date: Mon, 25 Jun 2018 21:22:22 +0530 Subject: [PATCH] Implement space saving algorithm --- Makefile | 2 +- include/space_saving.h | 130 +++++++ lib/space_saving.c | 796 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 927 insertions(+), 1 deletion(-) create mode 100644 include/space_saving.h create mode 100644 lib/space_saving.c diff --git a/Makefile b/Makefile index 8b5c2d4c3..1686167b3 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ SRCS-y += sol/main.c # Libraries. SRCS-y += lib/mailbox.c lib/net.c lib/flow.c lib/ipip.c \ lib/luajit-ffi-cdata.c lib/launch.c lib/lpm.c lib/acl.c lib/varip.c \ - lib/l2.c + lib/l2.c lib/space_saving.c LDLIBS += $(LDIR) -Bstatic -lluajit-5.1 -Bdynamic -lm -lmnl CFLAGS += $(WERROR_FLAGS) -I${GATEKEEPER}/include -I/usr/local/include/luajit-2.0/ diff --git a/include/space_saving.h b/include/space_saving.h new file mode 100644 index 000000000..3068d735f --- /dev/null +++ b/include/space_saving.h @@ -0,0 +1,130 @@ +/* + * Gatekeeper - DoS protection system. + * Copyright (C) 2016 Digirati LTDA. + * + * 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 3 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, see . + */ + +#ifndef _SPACE_SAVING_H_ +#define _SPACE_SAVING_H_ + +#include + +#include "gatekeeper_gk.h" +#include "gatekeeper_net.h" +#include "gatekeeper_flow.h" + +/* Data structure for Counter Table */ +struct counter_table { + + /* Counter for IPV4 address */ + struct rte_hash *ct_ip4; + + /* Counter for IPV6 address */ + struct rte_hash *ct_ip6; +}; + +/* Data structure for Counter bucket */ +struct counter_bucket { + + int proto; + + union { + /* Bucket for IPV4 address */ + struct rte_hash *bkt_ip4; + + /* Bucket for IPV6 address */ + struct rte_hash *bkt_ip6; + } bkt; +}; + +/* Data present in a Counter bucket */ +struct bucket_data { + + int err; + struct ip_flow flow; +}; + +/* Data structure of IP data */ +struct ip_data { + + int bkt_id; + struct bucket_data bkt_data; +}; + +static int +setup_bucket_params(unsigned int socket_id, int bkt_id, int bkt_size, + int ip_ver, struct rte_hash_parameters *bkt_hash_params); + +static int +create_bucket(struct gatekeeper_if *iface, struct gk_config *gk_conf, + int bkt_id); + +static int +get_bucket(int bkt_id, int proto, struct counter_bucket *ct_bkt); + +static int +get_bucket_entry(struct counter_bucket *ct_bkt, struct ip_flow *flow, + struct bucket_data *bkt_data); + +static int +add_bucket_entry(struct counter_bucket *ct_bkt, struct ip_flow *flow, + struct bucket_data *bkt_data); + +static int +delete_bucket_entry(struct counter_bucket *ct_bkt, struct ip_flow *flow); + +static int +setup_counter_params(unsigned int socket_id, int identifier, int ht_size, + int ip_ver, struct rte_hash_parameters *ct_hash_params); + +static int +create_counter_table(struct gatekeeper_if *iface, struct gk_config *gk_conf); + +static int +get_bucket_id(struct counter_table *ct_table, struct ip_flow *flow, + int *bkt_id); + +static int +add_bucket_id(struct counter_table *ct_table, struct ip_flow *flow, + int *bkt_id); + +static int +delete_bucket_id(struct counter_table *ct_table, struct ip_flow *flow); + +static int +update_bucket_id(struct counter_table *ct_table, struct ip_flow *flow); + +static int +get_ip_data(struct counter_table *ct_table, struct ip_flow *flow, + struct ip_data *data); + +static int +add_ip_data(struct counter_table *ct_table, struct ip_flow *flow, + struct ip_data *data); + +static int +delete_ip_data(struct counter_table *ct_table, struct ip_flow *flow); + +static int +update_ip_data(struct counter_table *ct_table, struct ip_flow *flow, + struct gatekeeper_if *iface, struct gk_config *gk_conf); + +static int +space_saving(struct counter_table *ct_table, struct ip_flow *flow, + struct gatekeeper_if *iface, struct gk_config *gk_conf); + +int run(struct gatekeeper_if *iface, struct gk_config *gk_conf); +#endif /* _SPACE_SAVING_H */ + diff --git a/lib/space_saving.c b/lib/space_saving.c new file mode 100644 index 000000000..e8986f514 --- /dev/null +++ b/lib/space_saving.c @@ -0,0 +1,796 @@ +/* + * Gatekeeper - DoS protection system. + * Copyright (C) 2016 Digirati LTDA. + * + * 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 3 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, see . + */ + + +/* + * This Implementation is similar to the stream summary data structure decribed + * in the research paper on space saving algorithm by Ahmed Metwally, +<<<<<<< HEAD + * Divyakant Agrawal and Amr El Abbadi. + */ + +/* + * TODO #1 : Add a Tree based data structure such as AVL Tree or + * Van Emde Boas Tree to support sublinear bucket update operation. + */ + +/* TODO #2 : Test the written code for correctness */ + +#include + +#include "space_saving.h" + +/* Set up the parameters of a counter bucket */ +static int +setup_bucket_params(unsigned int socket_id, int bkt_size, int bkt_id, + int ip_ver, struct rte_hash_parameters *bkt_hash_params) +{ + int ret; + + int key_len = ip_ver == ETHER_TYPE_IPv4 ? + sizeof(struct in_addr) : sizeof(struct in6_addr); + + bkt_hash_params->name = NULL; + bkt_hash_params->entries = bkt_size; + bkt_hash_params->key_len = key_len; + bkt_hash_params->hash_func = DEFAULT_HASH_FUNC; + bkt_hash_params->hash_func_init_val = 0; + bkt_hash_params->reserved = 0; + + char bkt_name[64]; + ret = snprintf(bkt_name, sizeof(bkt_name), "Bucket_number_%d_%d", + ip_ver, bkt_id); + RTE_VERIFY(ret > 0 && ret < (int)sizeof(bkt_name)); + + bkt_hash_params->name = bkt_name; + bkt_hash_params->socket_id = socket_id; + + return ret; +} + +/* Create a counter bucket */ +static int +create_bucket(struct gatekeeper_if *iface, struct gk_config *gk_conf, + int bkt_id) +{ + int ret; + unsigned int socket_id; + struct rte_hash_parameters bkt_hash_params; + struct counter_bucket *ct_bkt = + (struct counter_bucket *)malloc(sizeof(struct counter_bucket)); + + socket_id = rte_lcore_to_socket_id(gk_conf->lcores[0]); + + /* + * TODO : How to determine max_size of a bucket ? + * Currently it has been set to "10000" but final values has to be + * updated after testing. + */ + + if(ipv4_if_configured(iface)) { + ret = setup_bucket_params(socket_id, bkt_id, ETHER_TYPE_IPv4, + 10000, &bkt_hash_params); + if(ret < 0) { + RTE_LOG(ERR, HASH, "The bucket parameters " + "can't be set\n"); + ret = -1; + } + + ct_bkt->bkt.bkt_ip4 = rte_hash_create(&bkt_hash_params); + if(ct_bkt->bkt.bkt_ip4 == NULL) { + RTE_LOG(ERR, HASH, "Bucket number %d could not be " + "created!\n",bkt_id); + ret = -1; + } + } + + if(ipv6_if_configured(iface)) { + ret = setup_bucket_params(socket_id, bkt_id, ETHER_TYPE_IPv6, + 10000, &bkt_hash_params); + if(ret < 0) { + RTE_LOG(ERR, HASH, "The bucket parameters " + "can't be set\n"); + ret = -1; + } + + ct_bkt->bkt.bkt_ip6 = rte_hash_create(&bkt_hash_params); + if(ct_bkt->bkt.bkt_ip6 == NULL) { + RTE_LOG(ERR, HASH, "Bucket number %d could not be " + "created!\n",bkt_id); + ret = -1; + } + } + return ret; +} + +/* Retuns a pointer to a counter bucket */ +static int +get_bucket(int bkt_id, int proto, struct counter_bucket *ct_bkt) +{ + int ret; + char bkt_name[64]; + + ret = snprintf(bkt_name, sizeof(bkt_name), + "Bucket_number_%d_%d", proto, bkt_id); + RTE_VERIFY(ret > 0 && ret < (int)sizeof(bkt_name)); + + ct_bkt->proto = proto; + + switch(proto) { + case ETHER_TYPE_IPv4: + ct_bkt->bkt.bkt_ip4 = rte_hash_find_existing(bkt_name); + if(ct_bkt->bkt.bkt_ip4 == NULL) { + RTE_LOG(ERR, HASH, "Bucket number %d is not " + "present!\n", bkt_id); + ret = -2; + } + break; + + case ETHER_TYPE_IPv6: + ct_bkt->bkt.bkt_ip6 = rte_hash_find_existing(bkt_name); + if(ct_bkt->bkt.bkt_ip6 == NULL) { + RTE_LOG(ERR, HASH, "Bucket number %d is not " + "present!\n", bkt_id); + ret = -2; + } + break; + + case ETHER_TYPE_ARP: + ret = -1; + break; + + default: + RTE_LOG(ERR, HASH, "Unknown network layer protocol\n"); + ret = -1; + break; + } + return ret; +} + +/* Returns data from a counter bucket */ +static int +get_bucket_entry(struct counter_bucket *ct_bkt, struct ip_flow *flow, + struct bucket_data *bkt_data) +{ + int ret; + + switch(flow->proto) { + case ETHER_TYPE_IPv4: + ret = rte_hash_lookup_data(ct_bkt->bkt.bkt_ip4, flow, + (void **)bkt_data); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Bucket entry is not " + "present!\n"); + ret = -1; + } + break; + + case ETHER_TYPE_IPv6: + ret = rte_hash_lookup_data(ct_bkt->bkt.bkt_ip6, flow, + (void **)bkt_data); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Bucket entry is not " + "present!\n"); + ret = -1; + } + break; + + case ETHER_TYPE_ARP: + ret = -1; + break; + + default: + RTE_LOG(ERR, HASH, "Unknown network layer protocol\n"); + ret = -1; + break; + } + return ret; +} + +/* Add data to a counter bucket */ +static int +add_bucket_entry(struct counter_bucket *ct_bkt, struct ip_flow *flow, + struct bucket_data *bkt_data) +{ + int ret; + + switch(flow->proto) { + case ETHER_TYPE_IPv4: + ret = rte_hash_add_key_data(ct_bkt->bkt.bkt_ip4, + flow, bkt_data); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Data cannot be added into " + "the bucket\n"); + ret = -1; + } + break; + + case ETHER_TYPE_IPv6: + ret = rte_hash_add_key_data(ct_bkt->bkt.bkt_ip6, + flow, bkt_data); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Data cannot be added into " + "the bucket\n"); + ret = -1; + } + break; + + case ETHER_TYPE_ARP: + ret = -1; + break; + + default: + RTE_LOG(ERR, HASH,"Unknown network layer protocol!\n"); + ret = -1; + break; + } + return ret; +} + +/* Deletes data from a counter bucket */ +static int +delete_bucket_entry(struct counter_bucket *ct_bkt, struct ip_flow *flow) +{ + int ret; + + switch(flow->proto) { + case ETHER_TYPE_IPv4: + ret = rte_hash_del_key(ct_bkt->bkt.bkt_ip4, flow); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Data cannot be deleted " + "from the bucket\n"); + ret = -1; + } + break; + + case ETHER_TYPE_IPv6: + ret = rte_hash_del_key(ct_bkt->bkt.bkt_ip6, flow); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Data cannot be deleted " + "from the bucket\n"); + ret = -1; + } + break; + + case ETHER_TYPE_ARP: + ret = -1; + break; + + default: + RTE_LOG(ERR, HASH,"Unknown network layer protocol!\n"); + ret = -1; + break; + } + return ret; +} + +/* Set up parameters for a counter table */ +static int +setup_counter_params(unsigned int socket_id, int identifier, int ht_size, + int ip_ver, struct rte_hash_parameters *ct_hash_params) +{ + + int ret; + int key_len = ip_ver == ETHER_TYPE_IPv4 ? + sizeof(struct in_addr) : sizeof(struct in6_addr); + + ct_hash_params->name = NULL; + ct_hash_params->entries = ht_size; + ct_hash_params->key_len = key_len; + ct_hash_params->hash_func = DEFAULT_HASH_FUNC; + ct_hash_params->hash_func_init_val = 0; + ct_hash_params->reserved = 0; + + char ct_name[64]; + + ret = snprintf(ct_name, sizeof(ct_name), "counter_hash_%d", identifier); + RTE_VERIFY(ret > 0 && ret < (int)sizeof(ct_name)); + + ct_hash_params->name = ct_name; + ct_hash_params->socket_id = socket_id; + + return ret; +} + +/* Create a counter table */ +static int +create_counter_table(struct gatekeeper_if *iface, struct gk_config *gk_conf) +{ + int ret; + unsigned int socket_id; + struct rte_hash_parameters ct_hash_params; + struct counter_table *ct_table = malloc(sizeof(*ct_table)); + + socket_id = rte_lcore_to_socket_id(gk_conf->lcores[0]); + + /* + * TODO : How to get max_size for counter table ? + * Currently it has been set to 1000000 but final values to be updated + * after testing. + */ + + if(ipv4_if_configured(iface)) { + ret = setup_counter_params(socket_id, 0, ETHER_TYPE_IPv4, + 1000000, &ct_hash_params); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Counter table parametets cannot " + "be set\n"); + ret = -1; + } + + ct_table->ct_ip4 = rte_hash_create(&ct_hash_params); + if(ct_table == NULL) { + RTE_LOG(ERR, HASH, "Counter table cannot be " + "created!\n"); + ret = -1; + } + } + + if(ipv6_if_configured(iface)) { + ret = setup_counter_params(socket_id, 1, ETHER_TYPE_IPv6, + 1000000, &ct_hash_params); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Counter table parametets cannot " + "be set\n"); + ret = -1; + } + + ct_table->ct_ip6 = rte_hash_create(&ct_hash_params); + if(ct_table == NULL) { + RTE_LOG(ERR, HASH, "Counter table cannot be " + "created!\n"); + ret = -1; + } + } + return ret; +} + +/* Retuns bucket id from the counter table */ +static int +get_bucket_id(struct counter_table *ct_table, struct ip_flow *flow, + int *bkt_id) +{ + int ret; + + switch(flow->proto) { + case ETHER_TYPE_IPv4: + ret = rte_hash_lookup_data(ct_table->ct_ip4, flow, + (void **)bkt_id); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Bucket id for IP entry " + "cannot be found!\n"); + ret = -1; + } + break; + + case ETHER_TYPE_IPv6: + ret = rte_hash_lookup_data(ct_table->ct_ip6, flow, + (void **)bkt_id); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Bucket id for IP entry " + "cannot be found\n"); + ret = -1; + } + break; + + case ETHER_TYPE_ARP: + ret = -1; + break; + + default: + RTE_LOG(ERR, HASH, "Unknown network layer protocol\n"); + ret = -1; + break; + } + return ret; +} + +/* Add a bucket id to the counter table */ +static int +add_bucket_id(struct counter_table *ct_table, struct ip_flow *flow, + int *bkt_id) +{ + int ret; + + switch(flow->proto) { + case ETHER_TYPE_IPv4: + ret = rte_hash_add_key_data(ct_table->ct_ip4, flow, + bkt_id); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Data cannot be added " + "into the table\n"); + ret = -1; + } + break; + + case ETHER_TYPE_IPv6: + ret = rte_hash_add_key_data(ct_table->ct_ip6, flow, + bkt_id); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Data cannot be added " + "into the table\n"); + ret = -1; + } + break; + + case ETHER_TYPE_ARP: + ret = -1; + break; + + default: + RTE_LOG(ERR, HASH,"Unknown network layer protocol!\n"); + ret = -1; + break; + } + return ret; +} + +/* Deletes a bucket id from the counter table */ +static int +delete_bucket_id(struct counter_table *ct_table, struct ip_flow *flow) +{ + int ret; + + switch(flow->proto) { + case ETHER_TYPE_IPv4: + ret = rte_hash_del_key(ct_table->ct_ip4, flow); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Data cannot be deleted " + "from the table\n"); + ret = -1; + } + break; + + case ETHER_TYPE_IPv6: + ret = rte_hash_del_key(ct_table->ct_ip6, flow); + if(ret < 0) { + RTE_LOG(ERR, HASH, "Data cannot be deleted " + "from the table\n"); + ret = -1; + } + break; + + case ETHER_TYPE_ARP: + ret = -1; + break; + + default: + RTE_LOG(ERR, HASH,"Unknown network layer protocol!\n"); + ret = -1; + break; + } + return ret; +} + +/* Updates a bucket id in the counter table */ +static int +update_bucket_id(struct counter_table *ct_table, struct ip_flow *flow) +{ + int ret; + int *bkt_id = (int *)malloc(sizeof(int)); + + ret = get_bucket_id(ct_table, flow, bkt_id); + if(ret < 0) + goto out; + + (*bkt_id)++; + + return ret; + +out: + ret = -1; + return ret; +} + +/* Returns an IP entry from the IP counter */ +static int +get_ip_data(struct counter_table *ct_table, struct ip_flow *flow, + struct ip_data *data) +{ + int ret; + int bkt_id; + struct counter_bucket ct_bkt = { 0 }; + struct bucket_data bkt_data = { 0 }; + + ret = get_bucket_id(ct_table, flow, &bkt_id); + if(ret < 0) + goto out; + + ret = get_bucket(bkt_id, flow->proto, &ct_bkt); + if(ret < 0) + goto out; + + ret = get_bucket_entry(&ct_bkt, flow, &bkt_data); + if(ret < 0) + goto out; + + data->bkt_id = bkt_id; + data->bkt_data = bkt_data; + + return ret; + +out: + ret = -1; + return ret; +} + +/* Adds an IP entry to the IP counter */ +static int +add_ip_data(struct counter_table *ct_table, struct ip_flow *flow, + struct ip_data *data) +{ + int ret; + int bkt_id = data->bkt_id; + struct counter_bucket *ct_bkt = (struct counter_bucket *) + malloc(sizeof(struct counter_bucket)); + + ret = add_bucket_id(ct_table, flow, &bkt_id); + if(ret < 0) + goto out; + + //avl_update(bkt_id, 1); + + ret = get_bucket(bkt_id, flow->proto, ct_bkt); + if(ret < 0) + goto out; + + ret = add_bucket_entry(ct_bkt, flow, &(data->bkt_data)); + if(ret < 0) + goto out; + + return ret; + +out: + ret = -1; + return ret; +} + +/* Deletes an IP entry from the IP counter */ +static int +delete_ip_data(struct counter_table *ct_table, struct ip_flow *flow) +{ + int ret; + int bkt_id; + struct counter_bucket *ct_bkt = (struct counter_bucket *) + malloc(sizeof(struct counter_bucket)); + + ret = get_bucket_id(ct_table, flow, &bkt_id); + if(ret < 0) + goto out; + + //avl_update(bkt_id, -1); + + ret = get_bucket(bkt_id, flow->proto, ct_bkt); + if(ret < 0) + goto out; + + ret = delete_bucket_id(ct_table, flow); + if(ret < 0) + goto out; + + ret = delete_bucket_entry(ct_bkt, flow); + if(ret < 0) + goto out; + + return ret; + +out: + ret = -1; + return ret; +} + +/* Moves the ip entry to next higher bucket */ +static int +update_ip_data(struct counter_table *ct_table, struct ip_flow *flow, + struct gatekeeper_if *iface, struct gk_config *gk_conf) +{ + int ret; + struct ip_data *data = (struct ip_data *) + malloc(sizeof(struct ip_data)); + + struct counter_bucket *ct_bkt = (struct counter_bucket *) + malloc(sizeof(struct counter_bucket)); + + ret = get_ip_data(ct_table, flow, data); + if(ret < 0) + goto out; + + ret = update_bucket_id(ct_table, flow); + if(ret < 0) + goto out; + + //avl_update(data->bkt_id, -1); + data->bkt_id++; + //avl_update(data->bkt_id, 1); + + ret = delete_ip_data(ct_table, flow); + if(ret < 0) + goto out; + + ret = get_bucket(data->bkt_id, flow->proto, ct_bkt); + + /* If next bucket is not found, create a new bucket */ + if(ret == -2) { + ret = create_bucket(iface, gk_conf, data->bkt_id); + /* + * if(ret < 0) + * goto out; + */ + ret = get_bucket(data->bkt_id, flow->proto, ct_bkt); + if(ret < 0) + goto out; + } + + ret = add_ip_data(ct_table, flow, data); + if(ret < 0) + goto out; + + return ret; + +out: + ret = -1; + return ret; +} + +/* +static int +iterate_counter_table(struct counter_bkt *ct_bkt, int proto, int threshold, + struct bucket_data *data) +{ + uint32_t ret; + int count = 0; + struct rte_flow *flow; + int bkt_id; + int i; + uint32_t next = 0; + + switch(proto) { + case ETHER_TYPE_IPv4: + { + time_t curr_time = time(0); + if(curr_time - start_time > 2) + break; + + ret = rte_hash_iterate(counter->ct_ip4, + (const void **)&flow, + (void **)&bkt_id, &next); + + } + break; + + case ETHER_TYPE_IPv6: + break; + + default: + RTE_LOG(ERR< HASH, "Unknown network layer protocol!\n"); + ret = -1; + break; + } + return ret; +} +*/ + +/* Bucket id of element with minimum frequency */ +int min_bkt_id; + +/* Implementation of the space saving algorithm */ +static int +space_saving(struct counter_table *ct_table, struct ip_flow *flow, + struct gatekeeper_if *iface, struct gk_config *gk_conf) +{ + int ret = 0; + int new_bkt_id; + struct bucket_data new_bkt_data = { 0 }; + + struct counter_bucket *ct_bkt = (struct counter_bucket *) + malloc(sizeof(struct counter_bucket)); + + struct ip_data *data = (struct ip_data *) + malloc(sizeof(struct ip_data)); + + uint32_t next = 0; + struct ip_flow *min_flow = (struct ip_flow *) + malloc(sizeof(struct ip_flow)); + struct bucket_data *min_bkt_data = (struct bucket_data *) + malloc(sizeof(struct bucket_data)); + + ret = get_ip_data(ct_table, flow, data); + + if(ret >= 0) { + ret = update_ip_data(ct_table, flow, iface, gk_conf); + if(ret < 0) + goto out; + } else { + ret = -1; + while(ret < 0 && min_bkt_id < 1000000) { + ret = get_bucket(min_bkt_id, flow->proto, ct_bkt); + if(ret < 0) + min_bkt_id++; + } + + switch(flow->proto) { + case ETHER_TYPE_IPv4: + ret = rte_hash_iterate(ct_bkt->bkt.bkt_ip4, + (const void **)min_flow, + (void **)min_bkt_data, &next); + if(ret < 0) + goto out; + break; + + case ETHER_TYPE_IPv6: + ret = rte_hash_iterate(ct_bkt->bkt.bkt_ip6, + (const void **)min_flow, + (void **)min_bkt_data, &next); + if(ret < 0) + goto out; + break; + + case ETHER_TYPE_ARP: + ret = -1; + break; + + default: + RTE_LOG(ERR, HASH,"Unknown network layer protocol!\n"); + goto out; + break; + } + + new_bkt_id = min_bkt_id + 1; + new_bkt_data.err = min_bkt_data->err + 1; + new_bkt_data.flow = *flow; + + ret = delete_ip_data(ct_table, min_flow); + if(ret < 0) + goto out; + + data->bkt_id = new_bkt_id; + data->bkt_data = new_bkt_data; + + ret = add_ip_data(ct_table, flow, data); + if(ret < 0) + goto out; + + } + return ret; + +out: + ret = -1; + return ret; +} + +/* + * Function to run space saving algorithm. + * TODO : Remove this function after implementing Space Saving Algorithm + * in Gatekeeper. + */ + +int run(struct gatekeeper_if *iface, struct gk_config *gk_conf) +{ + int ret = 0; + ret = create_counter_table(iface, gk_conf); + if(ret < 0) + ret = -1; + + struct counter_table *ct_table = (struct counter_table *) + malloc(sizeof(struct counter_table)); + struct ip_flow *flow = (struct ip_flow *) + malloc(sizeof(struct ip_flow)); + ret = space_saving(ct_table, flow, iface, gk_conf); + return ret; +} +