Commit 17d02668 authored by Abhijeet Joglekar's avatar Abhijeet Joglekar
Browse files

First version of the delay node agent. Tested for a series of UP/DOWN/MODIFY

events .
parent 440c75d0
SRCDIR = @srcdir@
TESTBED_SRCDIR = @top_srcdir@
OBJDIR = ../..
SUBDIR = event/delay-agent
include $(OBJDIR)/Makeconf
all: delay-agent
include $(TESTBED_SRCDIR)/GNUmakerules
CFLAGS += -pthread
#CFLAGS += -DDEBUG
CFLAGS += -O -g -Wall
CFLAGS += -I. -I${OBJDIR} -I$(SRCDIR)/../lib -I$(TESTBED_SRCDIR)/lib/libtb
CFLAGS += `elvin-config --cflags vin4mt`
LDFLAGS += -pthread -static
LDFLAGS += -L../lib -L${OBJDIR}/lib/libtb
LIBS += -levent -ltb -lcipher
#
# XXX elvin-config adds -lc which is rather bogus, and messes up -pthread
# build on freebsd. I made a vain attempt to filter it out, but
# gave up quickly. Deal with it later.
#
#LIBS += `elvin-config --libs vin4mt`
LIBS += -L/usr/local/lib -lvin4mt -lvin4c -lvin4 -lssl -lcrypto -lm
OBJS = main.o callback.o
delay-agent: $(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
$(OBJS): main.h ../lib/libevent.a
#install: $(addprefix $(INSTALL_SBINDIR)/, event-sched)
clean:
/bin/rm -f *.o delay-agent
/*
* agent-callback-dummy.c --
*
* Delay node agent callback handling.
*
*
* @COPYRIGHT@
*/
/******************************* INCLUDES **************************/
#include "main-d.h"
/******************************* INCLUDES **************************/
/******************************* EXTERNS **************************/
extern structlink_map link_map[MAX_LINKS];
extern int link_index;
extern int s_dummy;
/******************************* EXTERNS **************************/
/********************************FUNCTION DEFS *******************/
/*************************** agent_callback **********************
This function is called from the event system when an event
notification is recd. from the server. It checks whether the
notification is valid (sanity check). If not print a warning,else
call handle_pipes which does the rest of thejob
*************************** agent_callback **********************/
void agent_callback(event_handle_t handle,
event_notification_t notification, void *data)
{
#define MAX_LEN 50
char objname[MAX_LEN];
char eventtype[MAX_LEN];
int l_index = -1;
#ifdef DEBUG
info ("entering callback \n");
#endif
/* get the name of the object, eg. link0 or link1*/
if(event_notification_get_string(handle,
notification,
"OBJNAME", objname, MAX_LEN) == 0){
error("could not get the objname \n");
return;
}
/* check we are handling the objectname for which we have recd an event */
if ((l_index = check_object(objname)) == -1){
error("not handling events for this object\n");
return;
}
/* get the eventtype, eg up/down/modify*/
if(event_notification_get_string(handle,
notification,
"EVENTTYPE", eventtype, MAX_LEN) == 0){
error("could not get the eventtype \n");
return;
}
/* call function to handle this event for this object */
handle_event(objname, eventtype, notification,handle);
#ifdef DEBUG
info ("exiting callback \n");
#endif
return;
}
/******************** handle_pipes ***************************************
******************** handle_pipes ***************************************/
void handle_event (char *objname, char *eventtype,
event_notification_t notification, event_handle_t handle)
{
#ifdef DEBUG
info ("entering handle_event \n");
#endif
if(strcmp(eventtype, TBDB_EVENTTYPE_UP) == 0){
handle_link_up(objname);
}
else if(strcmp(eventtype, TBDB_EVENTTYPE_DOWN) == 0){
handle_link_down(objname);
}
else if(strcmp(eventtype, TBDB_EVENTTYPE_MODIFY) == 0){
handle_link_modify(objname, handle, notification);
}
else error("unknown link event type\n");
#ifdef DEBUG
info ("exiting handle_event \n");
#endif
}
void handle_link_up(char * linkname){
#ifdef DEBUG
info ("entering handle_link_up \n");
#endif
info("recd. UP event for link = %s\n", linkname);
#ifdef DEBUG
info ("exiting handle_link_up \n");
#endif
}
void handle_link_down(char * linkname)
{
#ifdef DEBUG
info ("entering handle_link_down \n");
#endif
info("recd. DOWN event for link = %s\n", linkname);
#ifdef DEBUG
info ("exiting handle_link_down \n");
#endif
}
void handle_link_modify(char *linkname, event_handle_t handle,
event_notification_t notification)
{
char argvalue[50];
char * argtype;
int bw = 0, delay = 0;
#ifdef DEBUG
info ("entering handle_link_modify \n");
#endif
info("recd. MODIFY event for link = %s\n", linkname);
if(event_notification_get_string(handle,
notification,
"ARGS", argvalue, 50) != 0){
argtype = strtok(argvalue,"=");
if(strcmp(argtype,"BANDWIDTH")== 0){
bw = atoi(strtok(NULL," "));
info("Bandwidth = %d \n", bw);
}else if (strcmp(argtype,"DELAY")== 0){
delay = atoi(strtok(NULL," "));
info("Delay = %d \n", delay);
}else error("unrecognized argument\n");
}
#ifdef DEBUG
info ("exiting handle_link_modify \n");
#endif
}
int check_object (char *objname)
{
return search(objname);
}
/*********************** search ********************************
This function does a linear search on the link_map and returns
the index of the link_map entry which matches with the objectname
from the event notification
There will hardly be a few entries in this table, so we dont need
anything fancier than a linear search.
*********************** search ********************************/
int search(char* objname){
/* for now we do a linear search, maybe bin search later*/
int i;
for(i = 0; i < link_index; i++){
if(strcmp(link_map[i].linkname, objname) == 0)
return i;
}
return -1;
}
/*
* agent-callback.c --
*
* Delay node agent callback handling.
*
*
* @COPYRIGHT@
*/
/******************************* INCLUDES **************************/
#include "main.h"
/******************************* INCLUDES **************************/
/******************************* EXTERNS **************************/
extern structlink_map link_map[MAX_LINKS];
extern int link_index;
extern int s_dummy;
/******************************* EXTERNS **************************/
/********************************FUNCTION DEFS *******************/
/*************************** agent_callback **********************
This function is called from the event system when an event
notification is recd. from the server. It checks whether the
notification is valid (sanity check). If not print a warning,else
call handle_pipes which does the rest of thejob
*************************** agent_callback **********************/
void agent_callback(event_handle_t handle,
event_notification_t notification, void *data)
{
#define MAX_LEN 50
char objname[MAX_LEN];
char eventtype[MAX_LEN];
int l_index;
/* get the name of the object, eg. link0 or link1*/
if(event_notification_get_string(handle,
notification,
"OBJNAME", objname, MAX_LEN) == 0){
error("could not get the objname \n");
return;
}
/* check we are handling the objectname for which we have recd an event */
if ((l_index = check_object(objname)) == -1){
error("not handling events for this object\n");
return;
}
/* get the eventtype, eg up/down/modify*/
if(event_notification_get_string(handle,
notification,
"EVENTTYPE", eventtype, MAX_LEN) == 0){
error("could not get the eventtype \n");
return;
}
/* call function to handle this event for this object */
handle_pipes(objname, eventtype,notification, handle,l_index);
return;
}
/******************** handle_pipes ***************************************
This dispatch function checks the event type and dispatches to the appropriate
routine to handle
******************** handle_pipes ***************************************/
void handle_pipes (char *objname, char *eventtype,
event_notification_t notification, event_handle_t handle,
int l_index)
{
/*link_map[index] contains the relevant info*/
/* as of now, we only support duplex links in the testbed. Also we
require that both pipes of the duplex link are changed during the
event callback. Later when we add simplex links, we will also add
support to send event which will have effect on only one side of a
duplex link.
*/
if(strcmp(link_map[l_index].linktype,"duplex") == 0){
if(strcmp(eventtype, TBDB_EVENTTYPE_UP) == 0){
handle_link_up(objname, l_index);
}
else if(strcmp(eventtype, TBDB_EVENTTYPE_DOWN) == 0){
handle_link_down(objname, l_index);
}
else if(strcmp(eventtype, TBDB_EVENTTYPE_MODIFY) == 0){
handle_link_modify(objname, l_index, handle, notification);
}
else error("unknown link event type\n");
}
else {
error( "not handling simplex links yet ");
return;
}
}
/***************** checkevent **************************************
/* checks if we are handling the link for which we got the event
***************** checkevent **************************************/
int check_object (char *objname)
{
return search(objname);
}
/*********************** search ********************************
This function does a linear search on the link_map and returns
the index of the link_map entry which matches with the objectname
from the event notification
There will hardly be a few entries in this table, so we dont need
anything fancier than a linear search.
*********************** search ********************************/
int search(char* objname){
/* for now we do a linear search, maybe bin search later*/
int i;
for(i = 0; i < link_index; i++){
if(strcmp(link_map[i].linkname, objname) == 0)
return i;
}
return -1;
}
/******************* handle_link_up **************************
This handles the link_up event. If link is already up, it returns
without doing anything. If link is down, it calls set_link_params
for looking up the link params in the link_table and configuring
them into dummynet
******************* handle_link_up ***************************/
void handle_link_up(char * linkname, int l_index)
{
/* get the pipe params from the params field of the
link_map table. Set the pipe params in dummynet
*/
info("==========================================\n");
info("recd. UP event for link = %s\n", linkname);
/* no need to do anything if link is already up*/
if(link_map[l_index].stat == LINK_UP)
return;
#if 1
set_link_params(l_index, 0);/* 0 => dont blackhole, get the plr
* from the link map table*/
link_map[l_index].stat = LINK_UP;
info("==========================================\n");
#endif
}
/******************* handle_link_down **************************
This handles the link_down event. If link is already down, it returns
without doing anything. If link is up, it calls get_link_params
to populate the link_map table with current params. It then calls
set_link_params to write back the pipe params, but with plr = 1.0,
so that the link goes down
******************* handle_link_down***************************/
void handle_link_down(char * linkname, int l_index)
{
/* get the pipe params from dummynet
* Store them in the params field of the link_map table.
* Change the pipe config so that plr = 1.0
* so that packets are blackholed
*/
info("==========================================\n");
info("recd. DOWN event for link = %s\n", linkname);
/* if link is already down, no need to do anything*/
if(link_map[l_index].stat == LINK_DOWN)
return;
#if 1
if(get_link_params(l_index) == 1){
set_link_params(l_index, 1); /* 1 => set plr = 1.0 to blackhole packets*/
link_map[l_index].stat = LINK_DOWN;
}
else error("could not get params\n");
#endif
info("==========================================\n");
}
/*********** handle_link_modify *****************************
It gets the new link params from the notification and updates
the link_map table with these params. If the link is down,
it just returns. IF the link is up, then it calls set_link_params
to set the new params
*********** handle_link_modify *****************************/
void handle_link_modify(char * linkname, int l_index,
event_handle_t handle,
event_notification_t notification)
{
/* Get the new pipe params from the notification, and then
update the new set of params by setting the params in
dummynet
*/
info("==========================================\n");
info("recd. MODIFY event for link = %s\n", linkname);
/* if the link is up, then get the params from dummynet,
get the params from the notification and then merge
and write back to dummynet
*/
if(link_map[l_index].stat == LINK_UP){
if(get_link_params(l_index) == 1)
if(get_new_link_params(l_index, handle, notification) == 1)
set_link_params(l_index, 0); /* 0 => dont blackhole, get the plr
* from the link map table*/
} else
/* link is down, so just change in the link_map*/
get_new_link_params(l_index, handle, notification);
}
/****************** get_link_params ***************************
for both the pipes of the duplex link, get the pipe params
sing getsockopt and store these params in the link map
table
****************** get_link_params ***************************/
int get_link_params(int l_index)
{
struct dn_pipe *pipes;
int fix_size;
int num_bytes, num_alloc;
void * data = NULL;
int p_index = 0;
int pipe_num;
while( p_index < 2){
pipe_num = link_map[l_index].pipes[p_index];
/* get the pipe structure from Dummynet, resizing the data
as required
*/
fix_size = sizeof(*pipes);
num_alloc = fix_size;
num_bytes = num_alloc;
data = malloc(num_bytes);
if(data == NULL){
error("malloc: cant allocate memory\n");
return 0;
}
while (num_bytes >= num_alloc) {
num_alloc = num_alloc * 2 + 200;
num_bytes = num_alloc ;
if ((data = realloc(data, num_bytes)) == NULL){
error("cant alloc memory\n");
return 0;
}
if (getsockopt(s_dummy, IPPROTO_IP, IP_DUMMYNET_GET,
data, &num_bytes) < 0){
error("error in getsockopt\n");
return 0;
}
}
/* now search the pipe list for the required pipe*/
{
void *next = data ;
struct dn_pipe *p = (struct dn_pipe *) data;
struct dn_flow_queue *q ;
int l ;
for ( ; num_bytes >= sizeof(*p) ; p = (struct dn_pipe *)next ) {
if ( p->next != (struct dn_pipe *)DN_IS_PIPE )
break ;
l = sizeof(*p) + p->fs.rq_elements * sizeof(*q) ;
next = (void *)p + l ;
num_bytes -= l ;
q = (struct dn_flow_queue *)(p+1) ;
if (pipe_num != p->pipe_nr)
continue;
/* grab pipe delay and bandwidth */
link_map[l_index].params[p_index].delay = p->delay;
link_map[l_index].params[p_index].bw = p->bandwidth;
/* get flow set parameters*/
get_flowset_params( &(p->fs), l_index, p_index);
/* get dynamic queue parameters*/
get_queue_params( &(p->fs), l_index, p_index);
}
}
free(data);
/* go for the next pipe in the duplex link*/
p_index++;
}
return 1;
}
/************ get_flowset_params ********************************
get the flowset params from the dummnet pipe data structure
************** get_flowset_params ******************************/
void get_flowset_params(struct dn_flow_set *fs, int l_index,
int p_index)
{
/* grab pointer to the params structure of the pipe in the
link_map table
*/
structpipe_params *p_params
= &(link_map[l_index].params[p_index]);
/* q size*/
p_params->q_size = fs->qsize;
/* initialise flags */
p_params->flags_p = 0;
/* q unit */
if (fs->flags_fs & DN_QSIZE_IS_BYTES)
p_params->flags_p |= PIPE_QSIZE_IN_BYTES;
/* q plr*/
#if 0
p_params->plr = fs->plr;
#endif
p_params->plr = 1.0*fs->plr/(double)(0x7fffffff);
/* hash table/bucket size */
p_params->buckets = fs->rq_size;
#if 0
/* number of queues in the pipe */
p_params->n_qs = fs->rq_elements;
#endif
/* q type and corresponding parameters*/
if (fs->flags_fs & DN_IS_RED){
p_params->flags_p |= PIPE_Q_IS_RED;
/* get RED params */
p_params->red_gred_params.w_q = fs->w_q;
p_params->red_gred_params.max_p = fs->max_p;
p_params->red_gred_params.min_th = SCALE_VAL(fs->min_th);
p_params->red_gred_params.max_th = SCALE_VAL(fs->max_th);
}else if (fs->flags_fs & DN_IS_GENTLE_RED) {
p_params->flags_p |= PIPE_Q_IS_GRED;
/* get GRED params */
p_params->red_gred_params.w_q = fs->w_q;
p_params->red_gred_params.max_p = fs->max_p;
p_params->red_gred_params.min_th = SCALE_VAL(fs->min_th);
p_params->red_gred_params.max_th = SCALE_VAL(fs->max_th);
}
/* else droptail*/
}
/********* get_queue_params ******************************
get the queue specific params like the pipe flow mask
which is used to create dynamic queues as new flows are
formed
********* get_queue_params ******************************/
void get_queue_params(struct dn_flow_set *fs,
int l_index, int p_index)
{
/* grab the queue mask. Actually a pipe can have multiple masks,
HANDLE THIS LATER
*/
structpipe_params *p_params
= &(link_map[l_index].params[p_index]);
p_params->id.proto = fs->flow_mask.proto;
p_params->id.src_ip = fs->flow_mask.src_ip;
p_params->id.src_port = fs->flow_mask.src_port;
p_params->id.dst_ip = fs->flow_mask.dst_ip;
p_params->id.dst_port = fs->flow_mask.dst_port;