Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 117 additions & 30 deletions examples/load_balancer/load_balancer.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,14 @@
#include "onvm_flow_table.h"
#include "onvm_nflib.h"
#include "onvm_pkt_helper.h"
#include "onvm_config_common.h"
#include "cJSON.h"

#define NF_TAG "load_balancer"
#define TABLE_SIZE 65536

enum lb_policy {RROBIN, RANDOM, WEIGHTED_RANDOM};

/* Struct for load balancer information */
struct loadbalance {
struct onvm_ft *ft;
Expand All @@ -95,6 +99,14 @@ struct loadbalance {

/* config file */
char *cfg_filename;

/* LB policy */
// char *policy;
enum lb_policy policy;

/* structures to store server weights */
int *weights;
int total_weight;
};

/* Struct for backend servers */
Expand All @@ -115,6 +127,9 @@ struct loadbalance *lb;
/* number of package between each print */
static uint32_t print_delay = 1000000;

/* switch for turning on debug mode */
static int debug_mode = 0;

/* onvm struct for port info lookup */
extern struct port_info *ports;

Expand All @@ -136,6 +151,7 @@ usage(const char *progname) {
printf(" - `-t SERVER_PORT` : server port ID\n");
printf(" - `-f SERVER_CONFIG` : backend server config file\n");
printf(" - `-p <print_delay>`: number of packets between each print, e.g. `-p 1` prints every packets.\n");
printf(" - `-d`: debug info including when connections are recieved and when packets are recieved.\n");
}

/*
Expand Down Expand Up @@ -164,7 +180,7 @@ parse_app_args(int argc, char *argv[], const char *progname) {
lb->client_port = RTE_MAX_ETHPORTS;
lb->server_port = RTE_MAX_ETHPORTS;

while ((c = getopt(argc, argv, "c:r:s:t:f:p:")) != -1) {
while ((c = getopt(argc, argv, "c:r:s:t:f:p:d")) != -1) {
switch (c) {
case 'c':
ret = parse_iface_ip(strdup(optarg), &lb->ip_lb_client);
Expand Down Expand Up @@ -192,11 +208,12 @@ parse_app_args(int argc, char *argv[], const char *progname) {
case 'p':
print_delay = strtoul(optarg, NULL, 10);
break;
case 'd':
debug_mode = 1;
break;
case '?':
usage(progname);
if (optopt == 'd')
RTE_LOG(INFO, APP, "Option -%c requires an argument.\n", optopt);
else if (optopt == 'p')
if (optopt == 'p')
RTE_LOG(INFO, APP, "Option -%c requires an argument.\n", optopt);
else if (isprint(optopt))
RTE_LOG(INFO, APP, "Unknown option `-%c'.\n", optopt);
Expand Down Expand Up @@ -240,49 +257,81 @@ parse_app_args(int argc, char *argv[], const char *progname) {
/*
* This function parses the backend config. It takes the filename
* and fills up the backend_server array. This includes the mac and ip
* address of the backend servers
* address of the backend servers as well as their weights
*/
static int
parse_backend_config(void) {
int ret, temp, i;
char ip[32];
char mac[32];
FILE *cfg;
parse_backend_json_config(void) {
int ret, i;
i = 0;

cfg = fopen(lb->cfg_filename, "r");
if (cfg == NULL) {
rte_exit(EXIT_FAILURE, "Error openning server \'%s\' config\n", lb->cfg_filename);
}
ret = fscanf(cfg, "%*s %d", &temp);
if (temp <= 0) {
rte_exit(EXIT_FAILURE, "Error parsing config, need at least one server configurations\n");
cJSON *config_json = onvm_config_parse_file(lb->cfg_filename);
cJSON *list_size = NULL;
cJSON *policy = NULL;
cJSON *ip_addr = NULL;
cJSON *mac_addr = NULL;
cJSON *weight = NULL;

if (config_json == NULL) {
rte_exit(EXIT_FAILURE, "%s file could not be parsed or was not found. Assure"
" the directory to the config file is being specified.\n", lb->cfg_filename);
}
lb->server_count = temp;

config_json = config_json -> child;

list_size = cJSON_GetObjectItem(config_json, "list_size");
policy = cJSON_GetObjectItem(config_json, "policy");

if (list_size == NULL) rte_exit(EXIT_FAILURE, "list_size not found/invalid\n");
if (policy == NULL) rte_exit(EXIT_FAILURE, "policy not found/invalid\n");


lb->server_count = list_size->valueint;

if (!strcmp(policy->valuestring, "RROBIN")) lb->policy = RROBIN;
else if (!strcmp(policy->valuestring, "RANDOM")) lb->policy = RANDOM;
else if (!strcmp(policy->valuestring, "WEIGHTED_RANDOM")) lb->policy = WEIGHTED_RANDOM;
else rte_exit(EXIT_FAILURE, "Invalid policy. Check server.json\n");

lb->weights = (int*)calloc(lb->server_count,sizeof(int));

lb->server = (struct backend_server *)rte_malloc("backend server info",
sizeof(struct backend_server) * lb->server_count, 0);
if (lb->server == NULL) {
rte_exit(EXIT_FAILURE, "Malloc failed, can't allocate server information\n");
}

for (i = 0; i < lb->server_count; i++) {
ret = fscanf(cfg, "%s %s", ip, mac);
if (ret != 2) {
rte_exit(EXIT_FAILURE, "Invalid backend config structure\n");
}
config_json = config_json->next;

while (config_json != NULL) {
ip_addr = cJSON_GetObjectItem(config_json, "ip");
mac_addr = cJSON_GetObjectItem(config_json, "mac_addr");
weight = cJSON_GetObjectItem(config_json, "weight");

ret = onvm_pkt_parse_ip(ip, &lb->server[i].d_ip);
if (ip_addr == NULL) rte_exit(EXIT_FAILURE, "IP not found/invalid\n");
if (mac_addr == NULL) rte_exit(EXIT_FAILURE, "MAC address not found/invalid\n");


ret = onvm_pkt_parse_ip(ip_addr->valuestring, &lb->server[i].d_ip);
if (ret < 0) {
rte_exit(EXIT_FAILURE, "Error parsing config IP address #%d\n", i);
}

ret = onvm_pkt_parse_mac(mac, lb->server[i].d_addr_bytes);
ret = onvm_pkt_parse_mac(mac_addr->valuestring, lb->server[i].d_addr_bytes);
if (ret < 0) {
rte_exit(EXIT_FAILURE, "Error parsing config MAC address #%d\n", i);
}

if (lb->policy != WEIGHTED_RANDOM) lb->weights[i] = 1;
else {
if (weight == NULL) rte_exit(EXIT_FAILURE, "Weight not found/invalid\n");
lb->weights[i] = weight->valueint;
lb->total_weight += weight->valueint;
}
config_json = config_json->next;
i++;
}
if ( i != lb->server_count) rte_exit(EXIT_FAILURE, "Invalid list_size in config file\n");
cJSON_Delete(config_json);

fclose(cfg);
printf("\nARP config:\n");
for (i = 0; i < lb->server_count; i++) {
printf("%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 " ", (lb->server[i].d_ip >> 24) & 0xFF,
Expand Down Expand Up @@ -460,10 +509,34 @@ table_add_entry(struct onvm_ft_ipv4_5tuple *key, struct flow_info **flow) {
}

lb->num_stored++;
data->dest = lb->num_stored % lb->server_count;

int i, wrand, cur_weight_sum;
switch (lb->policy)
{
case RANDOM:
data->dest = rand() % lb->server_count;
break;
case RROBIN:
data->dest = lb->num_stored % lb->server_count;
break;
case WEIGHTED_RANDOM:
wrand = rand() % lb->total_weight;
cur_weight_sum=0;
for (i = 0; i < lb->server_count; i++) {
cur_weight_sum+=lb->weights[i];
if(wrand < cur_weight_sum) {
data->dest=i;
break;
}
}
break;
default:
rte_exit(EXIT_FAILURE, "Invalid policy while adding entry to table!\n");
break;
}

data->last_pkt_cycles = lb->elapsed_cycles;
data->is_active = 0;

*flow = data;

return 0;
Expand Down Expand Up @@ -518,10 +591,12 @@ packet_handler(struct rte_mbuf *pkt, struct onvm_pkt_meta *meta,
struct rte_ipv4_hdr *ip;
struct rte_ether_hdr *ehdr;
struct flow_info *flow_info;
struct rte_tcp_hdr* tcp;
int i, ret;

ehdr = onvm_pkt_ether_hdr(pkt);
ip = onvm_pkt_ipv4_hdr(pkt);
tcp = onvm_pkt_tcp_hdr(pkt);

/* Ignore packets without ip header, also ignore packets with invalid ip */
if (ip == NULL || ip->src_addr == 0 || ip->dst_addr == 0) {
Expand Down Expand Up @@ -555,6 +630,12 @@ packet_handler(struct rte_mbuf *pkt, struct onvm_pkt_meta *meta,
for (i = 0; i < RTE_ETHER_ADDR_LEN; i++) {
flow_info->s_addr_bytes[i] = ehdr->s_addr.addr_bytes[i];
}
if(debug_mode) {
printf("New connection made with server %d.\n",flow_info->dest);
printf("Source IP: %" PRIu32 " (%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 ":%" PRIu16") made a new connection with server %d.\n", ip->src_addr,
ip->src_addr & 0xFF, (ip->src_addr >> 8) & 0xFF, (ip->src_addr >> 16) & 0xFF,
(ip->src_addr >> 24) & 0xFF, rte_be_to_cpu_16(tcp->src_port),flow_info->dest);
}
}

if (pkt->port == lb->server_port) {
Expand Down Expand Up @@ -600,6 +681,10 @@ main(int argc, char *argv[]) {
int arg_offset;
const char *progname = argv[0];

time_t t;
/* Intializes RANDOM number generator */
srand((unsigned) time(&t));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check indentation

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the issue with the indentation here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like tabs not spaces. @catherinemeadows -- do you know if we have a working linter script that checks for this kind of formatting issue in ONVM? I thought our GitHub actions would do it automatically, but it seems not.

Copy link
Contributor

@catherinemeadows catherinemeadows Aug 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in /openNetVM/style, there is documentation about manually running our linter scripts. I think the GitHub actions weren't triggered yet because there are still merge conflicts.


nf_local_ctx = onvm_nflib_init_nf_local_ctx();
onvm_nflib_start_signal_handler(nf_local_ctx, NULL);

Expand Down Expand Up @@ -636,14 +721,16 @@ main(int argc, char *argv[]) {
}

validate_iface_config();
parse_backend_config();
parse_backend_json_config();

lb->expire_time = 32;
lb->elapsed_cycles = rte_get_tsc_cycles();

onvm_nflib_run(nf_local_ctx);

onvm_nflib_stop(nf_local_ctx);

free(lb->weights);
onvm_ft_free(lb->ft);
rte_free(lb);
printf("If we reach here, program is ending\n");
Expand Down
3 changes: 0 additions & 3 deletions examples/load_balancer/server.conf

This file was deleted.

18 changes: 18 additions & 0 deletions examples/load_balancer/server.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"Info" : {
"list_size": 2,
"policy": "RANDOM"
},

"Server0": {
"ip": "10.10.1.2",
"mac_addr": "90:e2:ba:ac:16:34",
"weight": 1
},

"Server1": {
"ip": "10.10.1.3",
"mac_addr": "90:e2:ba:b3:bb:7d",
"weight": 1
}
}